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>
27 #include <proto/exec.h>
28 #include <proto/utility.h>
29 #include <proto/cardres.h>
30 #include <proto/pccard.h>
34 #include "pccard_protos.h"
35 #include "device_protos.h"
36 #include "unit_protos.h"
38 #define MAX_TUPLE_SIZE 0xff
39 #define TUPLE_BUFFER_SIZE (MAX_TUPLE_SIZE + 8)
40 #define HANDLE_PRIORITY 10
41 #define IO_WINDOW_SIZE 0x10
47 struct CardHandle
*card_handle
;
51 UWORD resource_version
;
56 /* Private prototypes */
58 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
);
59 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
60 struct DevBase
*base
);
61 static struct BusContext
*AllocCard(struct DevBase
*base
);
62 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
);
63 static BOOL
IsCardCompatible(struct BusContext
*context
,
64 struct DevBase
*base
);
65 static BOOL
InitialiseCard(struct BusContext
*context
,
66 struct DevBase
*base
);
67 static VOID
CardRemovedHook(struct BusContext
*context
,
68 struct DevBase
*base
);
69 static BOOL
CardInsertedHook(struct BusContext
*context
,
70 struct DevBase
*base
);
71 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
72 REG(a6
, APTR int_code
));
73 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
74 REG(a6
, APTR int_code
));
75 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
76 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
));
77 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
);
78 static ULONG
LongInHook(struct BusContext
*context
, ULONG offset
);
79 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
81 static VOID
WordOutHook(struct BusContext
*context
, ULONG offset
,
83 static VOID
LongOutHook(struct BusContext
*context
, ULONG offset
,
85 static VOID
LongsInHook(struct BusContext
*context
, ULONG offset
,
86 ULONG
*buffer
, ULONG count
);
87 static VOID
LongsOutHook(struct BusContext
*context
, ULONG offset
,
88 const ULONG
*buffer
, ULONG count
);
89 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
91 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
92 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
);
93 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
95 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
99 static const ULONG product_codes
[] =
109 static const struct TagItem unit_tags
[] =
111 {IOTAG_ByteIn
, (UPINT
)ByteInHook
},
112 {IOTAG_LongIn
, (UPINT
)LongInHook
},
113 {IOTAG_ByteOut
, (UPINT
)ByteOutHook
},
114 {IOTAG_WordOut
, (UPINT
)WordOutHook
},
115 {IOTAG_LongOut
, (UPINT
)LongOutHook
},
116 {IOTAG_LongsIn
, (UPINT
)LongsInHook
},
117 {IOTAG_LongsOut
, (UPINT
)LongsOutHook
},
118 {IOTAG_BEWordOut
, (UPINT
)BEWordOutHook
},
119 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
120 {IOTAG_LELongIn
, (UPINT
)LELongInHook
},
121 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
122 {IOTAG_LELongOut
, (UPINT
)LELongOutHook
},
127 /****i* etherlink3.device/GetPCCardCount ***********************************
130 * GetPCCardCount -- Get the number of compatible PC Cards.
133 * count = GetPCCardCount()
135 * ULONG GetPCCardCount();
137 ****************************************************************************
141 ULONG
GetPCCardCount(struct DevBase
*base
)
144 struct BusContext
*context
;
146 if(CardResource
!= NULL
)
148 if(FindPCCardUnit(0, base
) != NULL
)
152 context
= AllocCard(base
);
156 FreeCard(context
, base
);
166 /****i* etherlink3.device/GetPCCardUnit ************************************
169 * GetPCCardUnit -- Get a unit by number.
172 * unit = GetPCCardUnit(index)
174 * struct DevUnit *GetPCCardUnit(ULONG);
176 ****************************************************************************
180 struct DevUnit
*GetPCCardUnit(ULONG index
, struct DevBase
*base
)
182 struct DevUnit
*unit
;
184 unit
= FindPCCardUnit(index
, base
);
188 unit
= CreatePCCardUnit(index
, base
);
190 AddTail((APTR
)&base
->pccard_units
, (APTR
)unit
);
198 /****i* etherlink3.device/FindPCCardUnit ***********************************
201 * FindPCCardUnit -- Find a unit by number.
204 * unit = FindPCCardUnit(index)
206 * struct DevUnit *FindPCCardUnit(ULONG);
208 ****************************************************************************
212 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
)
214 struct DevUnit
*unit
, *tail
;
216 unit
= (APTR
)base
->pccard_units
.mlh_Head
;
217 tail
= (APTR
)&base
->pccard_units
.mlh_Tail
;
226 /****i* etherlink3.device/CreatePCCardUnit *********************************
229 * CreatePCCardUnit -- Create a unit.
232 * unit = CreatePCCardUnit(index)
234 * struct DevUnit *CreatePCCardUnit(ULONG);
237 * Creates a new unit.
239 ****************************************************************************
243 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
244 struct DevBase
*base
)
247 struct BusContext
*context
;
248 struct DevUnit
*unit
;
250 /* Get card from system */
252 context
= AllocCard(base
);
256 /* Prepare card for use */
260 if(!InitialiseCard(context
, base
))
264 /* Create device driver unit */
268 context
->unit
= unit
=
269 CreateUnit(index
, context
, unit_tags
, SECOND_GEN
,
277 if(!(WrapInt(&unit
->status_int
, base
)
278 && WrapInt(&unit
->rx_int
, base
)
279 && WrapInt(&unit
->tx_int
, base
)
280 && WrapInt(&unit
->tx_end_int
, base
)))
283 unit
->insertion_function
= (APTR
)CardInsertedHook
;
284 unit
->removal_function
= (APTR
)CardRemovedHook
;
291 DeleteUnit(context
->unit
, base
);
292 FreeCard(context
, base
);
302 /****i* etherlink3.device/DeletePCCardUnit *********************************
305 * DeletePCCardUnit -- Delete a unit.
308 * DeletePCCardUnit(unit)
310 * VOID DeletePCCardUnit(struct DevUnit *);
316 * unit - Device unit (may be NULL).
321 ****************************************************************************
325 VOID
DeletePCCardUnit(struct DevUnit
*unit
, struct DevBase
*base
)
327 struct BusContext
*context
;
331 UnwrapInt(&unit
->tx_end_int
, base
);
332 UnwrapInt(&unit
->tx_int
, base
);
333 UnwrapInt(&unit
->rx_int
, base
);
334 UnwrapInt(&unit
->status_int
, base
);
335 context
= unit
->card
;
336 DeleteUnit(unit
, base
);
337 context
->unit
= NULL
;
338 FreeCard(context
, base
);
346 /****i* etherlink3.device/AllocCard ****************************************
349 * AllocCard -- Get card from system.
352 * context = AllocCard()
354 * struct BusContext *AllocCard();
356 ****************************************************************************
360 static struct BusContext
*AllocCard(struct DevBase
*base
)
362 BOOL success
= TRUE
, have_card
= FALSE
;
363 struct BusContext
*context
;
364 struct CardHandle
*card_handle
;
365 struct Interrupt
*card_removed_int
, *card_inserted_int
, *card_status_int
;
367 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
373 context
->resource_version
=
374 ((struct Library
*)base
->card_base
)->lib_Version
;
375 context
->card_handle
= card_handle
=
376 AllocMem(sizeof(struct CardHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
377 context
->tuple_buffer
=
378 AllocVec(TUPLE_BUFFER_SIZE
, MEMF_PUBLIC
);
380 if(card_handle
== NULL
|| context
->tuple_buffer
== NULL
)
386 /* Set up card handle */
388 card_handle
->cah_CardNode
.ln_Pri
= HANDLE_PRIORITY
;
389 card_handle
->cah_CardNode
.ln_Name
=
390 base
->device
.dd_Library
.lib_Node
.ln_Name
;
391 card_handle
->cah_CardFlags
= CARDF_POSTSTATUS
;
393 card_handle
->cah_CardRemoved
= card_removed_int
=
394 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
396 card_handle
->cah_CardInserted
= card_inserted_int
=
397 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
399 card_handle
->cah_CardStatus
= card_status_int
=
400 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
402 if(card_removed_int
== NULL
|| card_inserted_int
== NULL
403 || card_status_int
== NULL
)
409 /* Try to gain access to card */
411 card_removed_int
->is_Code
= CardRemovedInt
;
412 card_removed_int
->is_Data
= context
;
413 card_inserted_int
->is_Code
= CardInsertedInt
;
414 card_inserted_int
->is_Data
= context
;
415 card_status_int
->is_Code
= (APTR
)CardStatusInt
;
416 card_status_int
->is_Data
= context
;
418 if(!(WrapInt(card_removed_int
, base
)
419 && WrapInt(card_inserted_int
, base
)
420 && WrapInt(card_status_int
, base
)))
426 if(OwnCard(card_handle
) != 0)
433 if(!IsCardCompatible(context
, base
))
439 FreeCard(context
, base
);
447 /****i* etherlink3.device/FreeCard *****************************************
450 * FreeCard -- Release a card.
455 * VOID FreeCard(struct BusContext *);
457 ****************************************************************************
461 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
)
463 struct CardHandle
*card_handle
;
467 card_handle
= context
->card_handle
;
469 if(context
->have_card
)
471 CardMiscControl(card_handle
, 0);
472 CardResetCard(card_handle
);
474 ReleaseCard(card_handle
, CARDF_REMOVEHANDLE
);
475 UnwrapInt(card_handle
->cah_CardStatus
, base
);
476 UnwrapInt(card_handle
->cah_CardInserted
, base
);
477 UnwrapInt(card_handle
->cah_CardRemoved
, base
);
479 FreeVec(card_handle
->cah_CardStatus
);
480 FreeVec(card_handle
->cah_CardInserted
);
481 FreeVec(card_handle
->cah_CardRemoved
);
482 FreeVec(context
->tuple_buffer
);
483 FreeMem(card_handle
, sizeof(struct CardHandle
));
485 FreeMem(context
, sizeof(struct BusContext
));
493 /****i* etherlink3.device/IsCardCompatible *********************************
499 * compatible = IsCardCompatible(context)
501 * BOOL IsCardCompatible(struct BusContext *);
503 ****************************************************************************
507 static BOOL
IsCardCompatible(struct BusContext
*context
,
508 struct DevBase
*base
)
511 struct CardHandle
*card_handle
;
513 const struct TagItem
*tuple_tags
= NULL
;
516 UWORD maker
= 0, product
= 0;
518 card_handle
= context
->card_handle
;
519 tuple_buffer
= context
->tuple_buffer
;
521 /* Get card's make and model */
523 if(CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_MANFID
,
526 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
527 if(tuple_tags
!= NULL
)
529 maker
= GetTagData(PCCARD_Maker
, 0, tuple_tags
);
530 product
= GetTagData(PCCARD_Product
, 0, tuple_tags
);
534 /* Check this is a card we can use */
536 code
= maker
<< 16 | product
;
537 for(success
= FALSE
, p
= product_codes
; *p
!= 0; p
++)
540 PCCard_FreeTupleInfo(tuple_tags
);
547 /****i* etherlink3.device/InitialiseCard ***********************************
553 * success = InitialiseCard(context)
555 * BOOL InitialiseCard(struct BusContext *);
557 ****************************************************************************
561 static BOOL
InitialiseCard(struct BusContext
*context
,
562 struct DevBase
*base
)
565 struct CardHandle
*card_handle
;
566 struct CardMemoryMap
*card_map
;
567 UBYTE config_value
, i
, window_count
, *tuple_buffer
;
568 const struct TagItem
*tuple_tags
= NULL
;
569 ULONG
*io_bases
, *io_lengths
, io_base_offset
= 0, config_base_offset
;
571 /* Wake up card's I/O functionality */
573 card_handle
= context
->card_handle
;
574 tuple_buffer
= context
->tuple_buffer
;
575 CardMiscControl(card_handle
,
576 CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
578 /* Get configuration data */
580 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CONFIG
,
586 PCCard_FreeTupleInfo(tuple_tags
);
587 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
588 if(tuple_tags
== NULL
)
594 config_base_offset
= GetTagData(PCCARD_RegisterBase
, 0, tuple_tags
);
596 PCCard_FreeTupleInfo(tuple_tags
);
601 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CFTABLEENTRY
,
608 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
609 if(tuple_tags
== NULL
)
615 config_value
= GetTagData(PCCARD_ModeNo
, 0, tuple_tags
);
618 (APTR
)GetTagData(PCCARD_IOWinBases
, (UPINT
)NULL
, tuple_tags
);
623 /* Find the appropriate IO window */
628 (APTR
)GetTagData(PCCARD_IOWinLengths
, (UPINT
)NULL
, tuple_tags
);
630 window_count
= GetTagData(PCCARD_IOWinCount
, 0, tuple_tags
);
632 for(i
= 0; i
< window_count
&& io_base_offset
== 0; i
++)
633 if(io_lengths
[i
] == IO_WINDOW_SIZE
)
634 io_base_offset
= io_bases
[i
];
637 PCCard_FreeTupleInfo(tuple_tags
);
643 card_map
= GetCardMap();
644 context
->config_base
=
645 (UPINT
)card_map
->cmm_AttributeMemory
+ config_base_offset
;
647 context
->io_base
= (UPINT
)card_map
->cmm_IOMemory
+ io_base_offset
;
648 BYTEOUT(context
->config_base
+ PCCARD_REG_COR
, config_value
);
649 BYTEOUT(context
->config_base
+ PCCARD_REG_CCSR
,
650 BYTEIN(context
->config_base
+ PCCARD_REG_CCSR
)
651 | PCCARD_REG_CCSRF_AUDIOENABLE
);
659 /****i* etherlink3.device/CardRemovedHook **********************************
665 * CardRemovedHook(context)
667 * VOID CardRemovedHook(struct BusContext *);
669 ****************************************************************************
673 static VOID
CardRemovedHook(struct BusContext
*context
,
674 struct DevBase
*base
)
676 ReleaseCard(context
->card_handle
, 0);
683 /****i* etherlink3.device/CardInsertedHook *********************************
689 * success = CardInsertedHook(context)
691 * BOOL CardInsertedHook(struct BusContext *);
693 ****************************************************************************
697 static BOOL
CardInsertedHook(struct BusContext
*context
,
698 struct DevBase
*base
)
702 success
= IsCardCompatible(context
, base
);
705 success
= InitialiseCard(context
, base
);
708 success
= InitialiseAdapter(context
->unit
, TRUE
, base
);
711 ReleaseCard(context
->card_handle
, 0);
718 /****i* etherlink3.device/CardRemovedInt ***********************************
724 * CardRemovedInt(context, int_code)
726 * VOID CardRemovedInt(struct BusContext *, APTR);
728 ****************************************************************************
732 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
733 REG(a6
, APTR int_code
))
735 struct DevBase
*base
;
736 struct DevUnit
*unit
;
738 /* Record loss of card and get our task to call ReleaseCard() */
740 unit
= context
->unit
;
744 if((unit
->flags
& UNITF_ONLINE
) != 0)
745 unit
->flags
|= UNITF_WASONLINE
;
746 unit
->flags
&= ~(UNITF_HAVEADAPTER
| UNITF_ONLINE
);
748 context
->have_card
= FALSE
;
750 Signal(unit
->task
, unit
->card_removed_signal
);
757 /****i* etherlink3.device/CardInsertedInt **********************************
763 * CardInsertedInt(context, int_code)
765 * VOID CardInsertedInt(struct BusContext *, APTR);
767 ****************************************************************************
771 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
772 REG(a6
, APTR int_code
))
774 struct DevBase
*base
;
775 struct DevUnit
*unit
;
777 unit
= context
->unit
;
779 context
->have_card
= TRUE
;
780 Signal(unit
->task
, unit
->card_inserted_signal
);
787 /****i* etherlink3.device/CardStatusInt ************************************
793 * mask = CardStatusInt(context, int_code, mask)
795 * UBYTE CardStatusInt(struct BusContext *, APTR, UBYTE);
797 ****************************************************************************
799 * We pretend the int_code parameter goes in A6 rather than A5 because 68k
800 * GCC can't cope with A5 and we know the parameter isn't used in this case.
804 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
805 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
))
807 if(context
->resource_version
< 39)
809 /* Work around gayle interrupt bug */
811 *((volatile UBYTE
*)0xda9000) = (mask
^ 0x2c) | 0xc0;
815 if(context
->unit
!= NULL
)
816 StatusInt(context
->unit
, StatusInt
);
823 /****i* etherlink3.device/ByteInHook ***************************************
829 * value = ByteInHook(context, offset)
831 * UBYTE ByteInHook(struct BusContext *, ULONG);
833 ****************************************************************************
837 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
)
839 return BYTEIN(context
->io_base
+ offset
);
844 /****i* etherlink3.device/LongInHook ***************************************
850 * value = LongInHook(context, offset)
852 * ULONG LongInHook(struct BusContext *, ULONG);
854 ****************************************************************************
858 static ULONG
LongInHook(struct BusContext
*context
, ULONG offset
)
860 return LONGIN(context
->io_base
+ offset
);
865 /****i* etherlink3.device/ByteOutHook **************************************
871 * ByteOutHook(context, offset, value)
873 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
875 ****************************************************************************
879 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
882 BYTEOUT(context
->io_base
+ offset
, value
);
889 /****i* etherlink3.device/WordOutHook **************************************
895 * WordOutHook(context, offset, value)
897 * VOID WordOutHook(struct BusContext *, ULONG, UWORD);
899 ****************************************************************************
903 static VOID
WordOutHook(struct BusContext
*context
, ULONG offset
,
906 WORDOUT(context
->io_base
+ offset
, value
);
913 /****i* etherlink3.device/LongOutHook **************************************
919 * LongOutHook(context, offset, value)
921 * VOID LongOutHook(struct BusContext *, ULONG, ULONG);
923 ****************************************************************************
927 static VOID
LongOutHook(struct BusContext
*context
, ULONG offset
,
930 LONGOUT(context
->io_base
+ offset
, value
);
937 /****i* etherlink3.device/LongsInHook **************************************
943 * LongsInHook(context, offset, buffer, count)
945 * VOID LongsInHook(struct BusContext *, ULONG, ULONG *, ULONG);
947 ****************************************************************************
951 static VOID
LongsInHook(struct BusContext
*context
, ULONG offset
,
952 ULONG
*buffer
, ULONG count
)
954 LONGSIN(context
->io_base
+ offset
, buffer
, count
);
961 /****i* etherlink3.device/LongsOutHook *************************************
967 * LongsOutHook(context, offset, buffer, count)
969 * VOID LongsOutHook(struct BusContext *, ULONG, const ULONG *, ULONG);
971 ****************************************************************************
975 static VOID
LongsOutHook(struct BusContext
*context
, ULONG offset
,
976 const ULONG
*buffer
, ULONG count
)
978 LONGSOUT(context
->io_base
+ offset
, buffer
, count
);
985 /****i* etherlink3.device/BEWordOutHook ************************************
991 * BEWordOutHook(context, offset, value)
993 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
995 ****************************************************************************
999 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
1002 BEWORDOUT(context
->io_base
+ offset
, value
);
1009 /****i* etherlink3.device/LEWordInHook *************************************
1015 * value = LEWordInHook(context, offset)
1017 * UWORD LEWordInHook(struct BusContext *, ULONG);
1019 ****************************************************************************
1023 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
1025 return LEWORDIN(context
->io_base
+ offset
);
1030 /****i* etherlink3.device/LELongInHook ***************************************
1036 * value = LELongInHook(context, offset)
1038 * ULONG LELongInHook(struct BusContext *, ULONG);
1040 ****************************************************************************
1044 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
)
1046 return LELONGIN(context
->io_base
+ offset
);
1051 /****i* etherlink3.device/LEWordOutHook ************************************
1057 * LEWordOutHook(context, offset, value)
1059 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
1061 ****************************************************************************
1065 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
1068 LEWORDOUT(context
->io_base
+ offset
, value
);
1075 /****i* etherlink3.device/LELongOutHook ************************************
1081 * LELongOutHook(context, offset, value)
1083 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
1085 ****************************************************************************
1089 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
1092 LELONGOUT(context
->io_base
+ offset
, value
);