3 Copyright (C) 2000-2011 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <exec/types.h>
24 #include <utility/tagitem.h>
25 #include <libraries/pccard.h>
26 #include <resources/card.h>
28 #include <proto/exec.h>
29 #include <proto/utility.h>
30 #include <proto/cardres.h>
31 #include <proto/pccard.h>
35 #include "pccard_protos.h"
36 #include "device_protos.h"
37 #include "unit_protos.h"
39 #define MAX_TUPLE_SIZE 0xff
40 #define TUPLE_BUFFER_SIZE (MAX_TUPLE_SIZE + 8)
41 #define HANDLE_PRIORITY 10
42 #define IO_WINDOW_SIZE 0x10
48 struct CardHandle
*card_handle
;
52 UWORD resource_version
;
57 /* Private prototypes */
59 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
);
60 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
61 struct DevBase
*base
);
62 static struct BusContext
*AllocCard(struct DevBase
*base
);
63 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
);
64 static BOOL
IsCardCompatible(struct BusContext
*context
,
65 struct DevBase
*base
);
66 static BOOL
InitialiseCard(struct BusContext
*context
,
67 struct DevBase
*base
);
68 static VOID
CardRemovedHook(struct BusContext
*context
,
69 struct DevBase
*base
);
70 static BOOL
CardInsertedHook(struct BusContext
*context
,
71 struct DevBase
*base
);
72 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
73 REG(a6
, APTR int_code
));
74 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
75 REG(a6
, APTR int_code
));
76 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
77 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
));
78 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
);
79 static ULONG
LongInHook(struct BusContext
*context
, ULONG offset
);
80 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
82 static VOID
WordOutHook(struct BusContext
*context
, ULONG offset
,
84 static VOID
LongOutHook(struct BusContext
*context
, ULONG offset
,
86 static VOID
LongsInHook(struct BusContext
*context
, ULONG offset
,
87 ULONG
*buffer
, ULONG count
);
88 static VOID
LongsOutHook(struct BusContext
*context
, ULONG offset
,
89 const ULONG
*buffer
, ULONG count
);
90 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
92 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
93 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
);
94 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
96 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
100 static const ULONG product_codes
[] =
110 static struct TagItem unit_tags
[] =
112 {IOTAG_ByteIn
, (UPINT
)ByteInHook
},
113 {IOTAG_LongIn
, (UPINT
)LongInHook
},
114 {IOTAG_ByteOut
, (UPINT
)ByteOutHook
},
115 {IOTAG_WordOut
, (UPINT
)WordOutHook
},
116 {IOTAG_LongOut
, (UPINT
)LongOutHook
},
117 {IOTAG_LongsIn
, (UPINT
)LongsInHook
},
118 {IOTAG_LongsOut
, (UPINT
)LongsOutHook
},
119 {IOTAG_BEWordOut
, (UPINT
)BEWordOutHook
},
120 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
121 {IOTAG_LELongIn
, (UPINT
)LELongInHook
},
122 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
123 {IOTAG_LELongOut
, (UPINT
)LELongOutHook
},
128 /****i* etherlink3.device/GetPCCardCount ***********************************
131 * GetPCCardCount -- Get the number of compatible PC Cards.
134 * count = GetPCCardCount()
136 * ULONG GetPCCardCount();
138 ****************************************************************************
142 ULONG
GetPCCardCount(struct DevBase
*base
)
145 struct BusContext
*context
;
147 if(CardResource
!= NULL
)
149 if(FindPCCardUnit(0, base
) != NULL
)
153 context
= AllocCard(base
);
157 FreeCard(context
, base
);
167 /****i* etherlink3.device/GetPCCardUnit ************************************
170 * GetPCCardUnit -- Get a unit by number.
173 * unit = GetPCCardUnit(index)
175 * struct DevUnit *GetPCCardUnit(ULONG);
177 ****************************************************************************
181 struct DevUnit
*GetPCCardUnit(ULONG index
, struct DevBase
*base
)
183 struct DevUnit
*unit
;
185 unit
= FindPCCardUnit(index
, base
);
189 unit
= CreatePCCardUnit(index
, base
);
191 AddTail((APTR
)&base
->pccard_units
, (APTR
)unit
);
199 /****i* etherlink3.device/FindPCCardUnit ***********************************
202 * FindPCCardUnit -- Find a unit by number.
205 * unit = FindPCCardUnit(index)
207 * struct DevUnit *FindPCCardUnit(ULONG);
209 ****************************************************************************
213 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
)
215 struct DevUnit
*unit
, *tail
;
217 unit
= (APTR
)base
->pccard_units
.mlh_Head
;
218 tail
= (APTR
)&base
->pccard_units
.mlh_Tail
;
227 /****i* etherlink3.device/CreatePCCardUnit *********************************
230 * CreatePCCardUnit -- Create a unit.
233 * unit = CreatePCCardUnit(index)
235 * struct DevUnit *CreatePCCardUnit(ULONG);
238 * Creates a new unit.
240 ****************************************************************************
244 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
245 struct DevBase
*base
)
248 struct BusContext
*context
;
249 struct DevUnit
*unit
;
251 /* Get card from system */
253 context
= AllocCard(base
);
257 /* Prepare card for use */
261 if(!InitialiseCard(context
, base
))
265 /* Create device driver unit */
269 context
->unit
= unit
=
270 CreateUnit(index
, context
, unit_tags
, SECOND_GEN
,
278 if(!(WrapInt(&unit
->status_int
, base
)
279 && WrapInt(&unit
->rx_int
, base
)
280 && WrapInt(&unit
->tx_int
, base
)
281 && WrapInt(&unit
->tx_end_int
, base
)))
284 unit
->insertion_function
= (APTR
)CardInsertedHook
;
285 unit
->removal_function
= (APTR
)CardRemovedHook
;
292 DeleteUnit(context
->unit
, base
);
293 FreeCard(context
, base
);
303 /****i* etherlink3.device/DeletePCCardUnit *********************************
306 * DeletePCCardUnit -- Delete a unit.
309 * DeletePCCardUnit(unit)
311 * VOID DeletePCCardUnit(struct DevUnit *);
317 * unit - Device unit (may be NULL).
322 ****************************************************************************
326 VOID
DeletePCCardUnit(struct DevUnit
*unit
, struct DevBase
*base
)
328 struct BusContext
*context
;
332 UnwrapInt(&unit
->tx_end_int
, base
);
333 UnwrapInt(&unit
->tx_int
, base
);
334 UnwrapInt(&unit
->rx_int
, base
);
335 UnwrapInt(&unit
->status_int
, base
);
336 context
= unit
->card
;
337 DeleteUnit(unit
, base
);
338 context
->unit
= NULL
;
339 FreeCard(context
, base
);
347 /****i* etherlink3.device/AllocCard ****************************************
350 * AllocCard -- Get card from system.
353 * context = AllocCard()
355 * struct BusContext *AllocCard();
357 ****************************************************************************
361 static struct BusContext
*AllocCard(struct DevBase
*base
)
364 struct BusContext
*context
;
365 struct CardHandle
*card_handle
;
366 struct Interrupt
*card_removed_int
, *card_inserted_int
, *card_status_int
;
368 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
374 context
->resource_version
=
375 ((struct Library
*)base
->card_base
)->lib_Version
;
376 context
->card_handle
= card_handle
=
377 AllocMem(sizeof(struct CardHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
378 context
->tuple_buffer
=
379 AllocVec(TUPLE_BUFFER_SIZE
, MEMF_PUBLIC
);
381 if(card_handle
== NULL
|| context
->tuple_buffer
== NULL
)
387 /* Set up card handle */
389 card_handle
->cah_CardNode
.ln_Pri
= HANDLE_PRIORITY
;
390 card_handle
->cah_CardNode
.ln_Name
=
391 base
->device
.dd_Library
.lib_Node
.ln_Name
;
392 card_handle
->cah_CardFlags
= CARDF_POSTSTATUS
;
394 card_handle
->cah_CardRemoved
= card_removed_int
=
395 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
397 card_handle
->cah_CardInserted
= card_inserted_int
=
398 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
400 card_handle
->cah_CardStatus
= card_status_int
=
401 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
403 if(card_removed_int
== NULL
|| card_inserted_int
== NULL
404 || card_status_int
== NULL
)
410 /* Try to gain access to card */
412 card_removed_int
->is_Code
= CardRemovedInt
;
413 card_removed_int
->is_Data
= context
;
414 card_inserted_int
->is_Code
= CardInsertedInt
;
415 card_inserted_int
->is_Data
= context
;
416 card_status_int
->is_Code
= (APTR
)CardStatusInt
;
417 card_status_int
->is_Data
= context
;
419 if(!(WrapCardInt(card_removed_int
, base
)
420 && WrapCardInt(card_inserted_int
, base
)
421 && WrapCardInt(card_status_int
, base
)))
427 if(OwnCard(card_handle
) != 0)
433 context
->have_card
= TRUE
;
434 if(!IsCardCompatible(context
, base
))
440 FreeCard(context
, base
);
448 /****i* etherlink3.device/FreeCard *****************************************
451 * FreeCard -- Release a card.
456 * VOID FreeCard(struct BusContext *);
458 ****************************************************************************
462 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
)
464 struct CardHandle
*card_handle
;
468 card_handle
= context
->card_handle
;
470 if(context
->have_card
)
472 CardMiscControl(card_handle
, 0);
473 CardResetCard(card_handle
);
475 ReleaseCard(card_handle
, CARDF_REMOVEHANDLE
);
476 UnwrapCardInt(card_handle
->cah_CardStatus
, base
);
477 UnwrapCardInt(card_handle
->cah_CardInserted
, base
);
478 UnwrapCardInt(card_handle
->cah_CardRemoved
, base
);
480 FreeVec(card_handle
->cah_CardStatus
);
481 FreeVec(card_handle
->cah_CardInserted
);
482 FreeVec(card_handle
->cah_CardRemoved
);
483 FreeVec(context
->tuple_buffer
);
484 FreeMem(card_handle
, sizeof(struct CardHandle
));
486 FreeMem(context
, sizeof(struct BusContext
));
494 /****i* etherlink3.device/IsCardCompatible *********************************
500 * compatible = IsCardCompatible(context)
502 * BOOL IsCardCompatible(struct BusContext *);
504 ****************************************************************************
508 static BOOL
IsCardCompatible(struct BusContext
*context
,
509 struct DevBase
*base
)
512 struct CardHandle
*card_handle
;
514 struct TagItem
*tuple_tags
= NULL
;
517 UWORD maker
= 0, product
= 0;
519 card_handle
= context
->card_handle
;
520 tuple_buffer
= context
->tuple_buffer
;
522 /* Get card's make and model */
524 if(CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_MANFID
,
527 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
528 if(tuple_tags
!= NULL
)
530 maker
= GetTagData(PCCARD_Maker
, 0, tuple_tags
);
531 product
= GetTagData(PCCARD_Product
, 0, tuple_tags
);
535 /* Check this is a card we can use */
537 code
= maker
<< 16 | product
;
538 for(success
= FALSE
, p
= product_codes
; *p
!= 0; p
++)
541 PCCard_FreeTupleInfo(tuple_tags
);
548 /****i* etherlink3.device/InitialiseCard ***********************************
554 * success = InitialiseCard(context)
556 * BOOL InitialiseCard(struct BusContext *);
558 ****************************************************************************
562 static BOOL
InitialiseCard(struct BusContext
*context
,
563 struct DevBase
*base
)
566 struct CardHandle
*card_handle
;
567 struct CardMemoryMap
*card_map
;
568 UBYTE config_value
, i
, window_count
, *tuple_buffer
;
569 struct TagItem
*tuple_tags
= NULL
;
570 ULONG
*io_bases
, *io_lengths
, io_base_offset
= 0, config_base_offset
;
572 /* Wake up card's I/O functionality */
574 card_handle
= context
->card_handle
;
575 tuple_buffer
= context
->tuple_buffer
;
576 CardMiscControl(card_handle
,
577 CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
579 /* Get configuration data */
581 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CONFIG
,
587 PCCard_FreeTupleInfo(tuple_tags
);
588 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
589 if(tuple_tags
== NULL
)
595 config_base_offset
= GetTagData(PCCARD_RegisterBase
, 0, tuple_tags
);
597 PCCard_FreeTupleInfo(tuple_tags
);
602 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CFTABLEENTRY
,
609 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
610 if(tuple_tags
== NULL
)
616 config_value
= GetTagData(PCCARD_ModeNo
, 0, tuple_tags
);
619 (APTR
)GetTagData(PCCARD_IOWinBases
, (UPINT
)NULL
, tuple_tags
);
624 /* Find the appropriate IO window */
629 (APTR
)GetTagData(PCCARD_IOWinLengths
, (UPINT
)NULL
, tuple_tags
);
631 window_count
= GetTagData(PCCARD_IOWinCount
, 0, tuple_tags
);
633 for(i
= 0; i
< window_count
&& io_base_offset
== 0; i
++)
634 if(io_lengths
[i
] == IO_WINDOW_SIZE
)
635 io_base_offset
= io_bases
[i
];
638 PCCard_FreeTupleInfo(tuple_tags
);
644 card_map
= GetCardMap();
645 context
->config_base
=
646 (UPINT
)card_map
->cmm_AttributeMemory
+ config_base_offset
;
648 context
->io_base
= (UPINT
)card_map
->cmm_IOMemory
+ io_base_offset
;
649 BYTEOUT(context
->config_base
+ PCCARD_REG_COR
, config_value
);
650 BYTEOUT(context
->config_base
+ PCCARD_REG_CCSR
,
651 BYTEIN(context
->config_base
+ PCCARD_REG_CCSR
)
652 | PCCARD_REG_CCSRF_AUDIOENABLE
);
660 /****i* etherlink3.device/CardRemovedHook **********************************
666 * CardRemovedHook(context)
668 * VOID CardRemovedHook(struct BusContext *);
670 ****************************************************************************
674 static VOID
CardRemovedHook(struct BusContext
*context
,
675 struct DevBase
*base
)
677 ReleaseCard(context
->card_handle
, 0);
684 /****i* etherlink3.device/CardInsertedHook *********************************
690 * success = CardInsertedHook(context)
692 * BOOL CardInsertedHook(struct BusContext *);
694 ****************************************************************************
698 static BOOL
CardInsertedHook(struct BusContext
*context
,
699 struct DevBase
*base
)
703 success
= IsCardCompatible(context
, base
);
706 success
= InitialiseCard(context
, base
);
709 success
= InitialiseAdapter(context
->unit
, TRUE
, base
);
712 ReleaseCard(context
->card_handle
, 0);
719 /****i* etherlink3.device/CardRemovedInt ***********************************
725 * CardRemovedInt(context, int_code)
727 * VOID CardRemovedInt(struct BusContext *, APTR);
729 ****************************************************************************
733 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
734 REG(a6
, APTR int_code
))
736 struct DevBase
*base
;
737 struct DevUnit
*unit
;
739 /* Record loss of card and get our task to call ReleaseCard() */
741 unit
= context
->unit
;
745 if((unit
->flags
& UNITF_ONLINE
) != 0)
746 unit
->flags
|= UNITF_WASONLINE
;
747 unit
->flags
&= ~(UNITF_HAVEADAPTER
| UNITF_ONLINE
);
749 context
->have_card
= FALSE
;
751 Signal(unit
->task
, unit
->card_removed_signal
);
758 /****i* etherlink3.device/CardInsertedInt **********************************
764 * CardInsertedInt(context, int_code)
766 * VOID CardInsertedInt(struct BusContext *, APTR);
768 ****************************************************************************
772 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
773 REG(a6
, APTR int_code
))
775 struct DevBase
*base
;
776 struct DevUnit
*unit
;
778 unit
= context
->unit
;
781 context
->have_card
= TRUE
;
782 Signal(unit
->task
, unit
->card_inserted_signal
);
790 /****i* etherlink3.device/CardStatusInt ************************************
796 * mask = CardStatusInt(context, int_code, mask)
798 * UBYTE CardStatusInt(struct BusContext *, APTR, UBYTE);
800 ****************************************************************************
802 * We pretend the int_code parameter goes in A6 rather than A5 because 68k
803 * GCC can't cope with A5 and we know the parameter isn't used in this case.
807 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
808 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
))
810 if(context
->resource_version
< 39)
812 /* Work around gayle interrupt bug */
814 *((volatile UBYTE
*)0xda9000) = (mask
^ 0x2c) | 0xc0;
818 if(context
->unit
!= NULL
)
819 StatusInt(context
->unit
, StatusInt
);
826 /****i* etherlink3.device/ByteInHook ***************************************
832 * value = ByteInHook(context, offset)
834 * UBYTE ByteInHook(struct BusContext *, ULONG);
836 ****************************************************************************
840 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
)
842 return BYTEIN(context
->io_base
+ offset
);
847 /****i* etherlink3.device/LongInHook ***************************************
853 * value = LongInHook(context, offset)
855 * ULONG LongInHook(struct BusContext *, ULONG);
857 ****************************************************************************
861 static ULONG
LongInHook(struct BusContext
*context
, ULONG offset
)
863 return LONGIN(context
->io_base
+ offset
);
868 /****i* etherlink3.device/ByteOutHook **************************************
874 * ByteOutHook(context, offset, value)
876 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
878 ****************************************************************************
882 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
885 BYTEOUT(context
->io_base
+ offset
, value
);
892 /****i* etherlink3.device/WordOutHook **************************************
898 * WordOutHook(context, offset, value)
900 * VOID WordOutHook(struct BusContext *, ULONG, UWORD);
902 ****************************************************************************
906 static VOID
WordOutHook(struct BusContext
*context
, ULONG offset
,
909 WORDOUT(context
->io_base
+ offset
, value
);
916 /****i* etherlink3.device/LongOutHook **************************************
922 * LongOutHook(context, offset, value)
924 * VOID LongOutHook(struct BusContext *, ULONG, ULONG);
926 ****************************************************************************
930 static VOID
LongOutHook(struct BusContext
*context
, ULONG offset
,
933 LONGOUT(context
->io_base
+ offset
, value
);
940 /****i* etherlink3.device/LongsInHook **************************************
946 * LongsInHook(context, offset, buffer, count)
948 * VOID LongsInHook(struct BusContext *, ULONG, ULONG *, ULONG);
950 ****************************************************************************
954 static VOID
LongsInHook(struct BusContext
*context
, ULONG offset
,
955 ULONG
*buffer
, ULONG count
)
957 LONGSIN(context
->io_base
+ offset
, buffer
, count
);
964 /****i* etherlink3.device/LongsOutHook *************************************
970 * LongsOutHook(context, offset, buffer, count)
972 * VOID LongsOutHook(struct BusContext *, ULONG, const ULONG *, ULONG);
974 ****************************************************************************
978 static VOID
LongsOutHook(struct BusContext
*context
, ULONG offset
,
979 const ULONG
*buffer
, ULONG count
)
981 LONGSOUT(context
->io_base
+ offset
, buffer
, count
);
988 /****i* etherlink3.device/BEWordOutHook ************************************
994 * BEWordOutHook(context, offset, value)
996 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
998 ****************************************************************************
1002 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
1005 BEWORDOUT(context
->io_base
+ offset
, value
);
1012 /****i* etherlink3.device/LEWordInHook *************************************
1018 * value = LEWordInHook(context, offset)
1020 * UWORD LEWordInHook(struct BusContext *, ULONG);
1022 ****************************************************************************
1026 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
1028 return LEWORDIN(context
->io_base
+ offset
);
1033 /****i* etherlink3.device/LELongInHook ***************************************
1039 * value = LELongInHook(context, offset)
1041 * ULONG LELongInHook(struct BusContext *, ULONG);
1043 ****************************************************************************
1047 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
)
1049 return LELONGIN(context
->io_base
+ offset
);
1054 /****i* etherlink3.device/LEWordOutHook ************************************
1060 * LEWordOutHook(context, offset, value)
1062 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
1064 ****************************************************************************
1068 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
1071 LEWORDOUT(context
->io_base
+ offset
, value
);
1078 /****i* etherlink3.device/LELongOutHook ************************************
1084 * LELongOutHook(context, offset, value)
1086 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
1088 ****************************************************************************
1092 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
1095 LELONGOUT(context
->io_base
+ offset
, value
);