3 Copyright (C) 2000-2014 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
46 struct CardHandle
*card_handle
;
50 UWORD resource_version
;
55 /* Private prototypes */
57 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
);
58 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
59 struct DevBase
*base
);
60 static struct BusContext
*AllocCard(struct DevBase
*base
);
61 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
);
62 static BOOL
IsCardCompatible(struct BusContext
*context
,
63 struct DevBase
*base
);
64 static BOOL
InitialiseCard(struct BusContext
*context
,
65 struct DevBase
*base
);
66 static VOID
CardRemovedHook(struct BusContext
*context
,
67 struct DevBase
*base
);
68 static BOOL
CardInsertedHook(struct BusContext
*context
,
69 struct DevBase
*base
);
70 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
71 REG(a6
, APTR int_code
));
72 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
73 REG(a6
, APTR int_code
));
74 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
75 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
));
76 static VOID
WordsInHook(struct BusContext
*context
,
77 ULONG offset
, UWORD
*buffer
, ULONG count
);
78 static VOID
WordsOutHook(struct BusContext
*context
, ULONG offset
,
79 const UWORD
*buffer
, ULONG count
);
80 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
82 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
83 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
87 static const ULONG product_codes
[] =
122 static const struct TagItem unit_tags
[] =
124 {IOTAG_WordsIn
, (UPINT
)WordsInHook
},
125 {IOTAG_WordsOut
, (UPINT
)WordsOutHook
},
126 {IOTAG_BEWordOut
, (UPINT
)BEWordOutHook
},
127 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
128 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
133 /****i* prism2.device/GetPCCardCount ***************************************
136 * GetPCCardCount -- Get the number of compatible PC Cards.
139 * count = GetPCCardCount()
141 * ULONG GetPCCardCount();
143 ****************************************************************************
147 ULONG
GetPCCardCount(struct DevBase
*base
)
150 struct BusContext
*context
;
152 if(CardResource
!= NULL
)
154 if(FindPCCardUnit(0, base
) != NULL
)
158 context
= AllocCard(base
);
162 FreeCard(context
, base
);
172 /****i* prism2.device/GetPCCardUnit ****************************************
175 * GetPCCardUnit -- Get a unit by number.
178 * unit = GetPCCardUnit(index)
180 * struct DevUnit *GetPCCardUnit(ULONG);
182 ****************************************************************************
186 struct DevUnit
*GetPCCardUnit(ULONG index
, struct DevBase
*base
)
188 struct DevUnit
*unit
;
190 unit
= FindPCCardUnit(index
, base
);
194 unit
= CreatePCCardUnit(index
, base
);
196 AddTail((APTR
)&base
->pccard_units
, (APTR
)unit
);
204 /****i* prism2.device/FindPCCardUnit ***************************************
207 * FindPCCardUnit -- Find a unit by number.
210 * unit = FindPCCardUnit(index)
212 * struct DevUnit *FindPCCardUnit(ULONG);
214 ****************************************************************************
218 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
)
220 struct DevUnit
*unit
, *tail
;
222 unit
= (APTR
)base
->pccard_units
.mlh_Head
;
223 tail
= (APTR
)&base
->pccard_units
.mlh_Tail
;
232 /****i* prism2.device/CreatePCCardUnit *************************************
235 * CreatePCCardUnit -- Create a unit.
238 * unit = CreatePCCardUnit(index)
240 * struct DevUnit *CreatePCCardUnit(ULONG);
243 * Creates a new unit.
245 ****************************************************************************
249 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
250 struct DevBase
*base
)
253 struct BusContext
*context
;
254 struct DevUnit
*unit
;
256 /* Get card from system */
258 context
= AllocCard(base
);
262 /* Prepare card for use */
266 if(!InitialiseCard(context
, base
))
270 /* Create device driver unit */
274 context
->unit
= unit
=
275 CreateUnit(index
, context
, unit_tags
, PCCARD_BUS
, base
);
282 if(!(WrapInt(&unit
->status_int
, base
)
283 && WrapInt(&unit
->rx_int
, base
)
284 && WrapInt(&unit
->tx_int
, base
)
285 && WrapInt(&unit
->info_int
, base
)))
288 unit
->insertion_function
= (APTR
)CardInsertedHook
;
289 unit
->removal_function
= (APTR
)CardRemovedHook
;
296 DeleteUnit(context
->unit
, base
);
297 FreeCard(context
, base
);
307 /****i* prism2.device/DeletePCCardUnit *************************************
310 * DeletePCCardUnit -- Delete a unit.
313 * DeletePCCardUnit(unit)
315 * VOID DeletePCCardUnit(struct DevUnit *);
321 * unit - Device unit (may be NULL).
326 ****************************************************************************
330 VOID
DeletePCCardUnit(struct DevUnit
*unit
, struct DevBase
*base
)
332 struct BusContext
*context
;
336 UnwrapInt(&unit
->info_int
, base
);
337 UnwrapInt(&unit
->tx_int
, base
);
338 UnwrapInt(&unit
->rx_int
, base
);
339 UnwrapInt(&unit
->status_int
, base
);
340 context
= unit
->card
;
341 DeleteUnit(unit
, base
);
342 FreeCard(context
, base
);
350 /****i* prism2.device/AllocCard ********************************************
353 * AllocCard -- Get card from system.
358 * struct BusContext *AllocCard();
360 ****************************************************************************
364 static struct BusContext
*AllocCard(struct DevBase
*base
)
367 struct BusContext
*context
;
368 struct CardHandle
*card_handle
;
369 struct Interrupt
*card_removed_int
, *card_inserted_int
, *card_status_int
;
371 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
377 context
->resource_version
=
378 ((struct Library
*)base
->card_base
)->lib_Version
;
379 context
->card_handle
= card_handle
=
380 AllocMem(sizeof(struct CardHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
381 context
->tuple_buffer
=
382 AllocVec(TUPLE_BUFFER_SIZE
, MEMF_PUBLIC
);
384 if(card_handle
== NULL
|| context
->tuple_buffer
== NULL
)
390 /* Set up card handle */
392 card_handle
->cah_CardNode
.ln_Pri
= HANDLE_PRIORITY
;
393 card_handle
->cah_CardNode
.ln_Name
=
394 base
->device
.dd_Library
.lib_Node
.ln_Name
;
395 card_handle
->cah_CardFlags
= CARDF_POSTSTATUS
;
397 card_handle
->cah_CardRemoved
= card_removed_int
=
398 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
400 card_handle
->cah_CardInserted
= card_inserted_int
=
401 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
403 card_handle
->cah_CardStatus
= card_status_int
=
404 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
406 if(card_removed_int
== NULL
|| card_inserted_int
== NULL
407 || card_status_int
== NULL
)
413 /* Try to gain access to card */
415 card_removed_int
->is_Code
= CardRemovedInt
;
416 card_removed_int
->is_Data
= context
;
417 card_inserted_int
->is_Code
= CardInsertedInt
;
418 card_inserted_int
->is_Data
= context
;
419 card_status_int
->is_Code
= (APTR
)CardStatusInt
;
420 card_status_int
->is_Data
= context
;
422 if(!(WrapCardInt(card_removed_int
, base
)
423 && WrapCardInt(card_inserted_int
, base
)
424 && WrapCardInt(card_status_int
, base
)))
430 if(OwnCard(card_handle
) != 0)
436 if(!IsCardCompatible(context
, base
))
442 FreeCard(context
, base
);
450 /****i* prism2.device/FreeCard *********************************************
458 * VOID FreeCard(struct BusContext *);
460 ****************************************************************************
464 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
)
466 struct CardHandle
*card_handle
;
470 card_handle
= context
->card_handle
;
472 if(context
->have_card
)
474 CardMiscControl(card_handle
, 0);
475 CardResetCard(card_handle
);
477 ReleaseCard(card_handle
, CARDF_REMOVEHANDLE
);
478 UnwrapCardInt(card_handle
->cah_CardStatus
, base
);
479 UnwrapCardInt(card_handle
->cah_CardInserted
, base
);
480 UnwrapCardInt(card_handle
->cah_CardRemoved
, base
);
482 FreeVec(card_handle
->cah_CardStatus
);
483 FreeVec(card_handle
->cah_CardInserted
);
484 FreeVec(card_handle
->cah_CardRemoved
);
485 FreeVec(context
->tuple_buffer
);
486 FreeMem(card_handle
, sizeof(struct CardHandle
));
488 FreeMem(context
, sizeof(struct BusContext
));
496 /****i* prism2.device/IsCardCompatible *************************************
502 * compatible = IsCardCompatible(context)
504 * BOOL IsCardCompatible(struct BusContext *);
506 ****************************************************************************
510 static BOOL
IsCardCompatible(struct BusContext
*context
,
511 struct DevBase
*base
)
514 struct CardHandle
*card_handle
;
516 const struct TagItem
*tuple_tags
= NULL
;
519 UWORD maker
= 0, product
= 0;
521 card_handle
= context
->card_handle
;
522 tuple_buffer
= context
->tuple_buffer
;
524 /* Get card's make and model */
526 if(CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_MANFID
,
529 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
530 if(tuple_tags
!= NULL
)
532 maker
= GetTagData(PCCARD_Maker
, 0, tuple_tags
);
533 product
= GetTagData(PCCARD_Product
, 0, tuple_tags
);
537 /* Check this is a card we can use */
539 code
= maker
<< 16 | product
;
540 for(success
= FALSE
, p
= product_codes
; *p
!= 0; p
++)
543 PCCard_FreeTupleInfo(tuple_tags
);
550 /****i* prism2.device/InitialiseCard ***************************************
556 * success = InitialiseCard(context)
558 * BOOL InitialiseCard(struct BusContext *);
560 ****************************************************************************
564 static BOOL
InitialiseCard(struct BusContext
*context
,
565 struct DevBase
*base
)
568 struct CardHandle
*card_handle
;
569 struct CardMemoryMap
*card_map
;
570 UBYTE config_value
, i
, window_count
, *tuple_buffer
;
571 const struct TagItem
*tuple_tags
= NULL
;
572 ULONG
*io_bases
, *io_lengths
, io_base_offset
= 0, config_base_offset
;
574 /* Wake up card's I/O functionality */
576 card_handle
= context
->card_handle
;
577 tuple_buffer
= context
->tuple_buffer
;
578 CardMiscControl(card_handle
,
579 CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
581 /* Get configuration data */
583 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CONFIG
,
589 PCCard_FreeTupleInfo(tuple_tags
);
590 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
591 if(tuple_tags
== NULL
)
597 config_base_offset
= GetTagData(PCCARD_RegisterBase
, 0, tuple_tags
);
599 PCCard_FreeTupleInfo(tuple_tags
);
604 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CFTABLEENTRY
,
611 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
612 if(tuple_tags
== NULL
)
618 config_value
= GetTagData(PCCARD_ModeNo
, 0, tuple_tags
);
621 (APTR
)GetTagData(PCCARD_IOWinBases
, (UPINT
)NULL
, tuple_tags
);
626 /* Find the appropriate IO window */
631 (APTR
)GetTagData(PCCARD_IOWinLengths
, (UPINT
)NULL
, tuple_tags
);
633 window_count
= GetTagData(PCCARD_IOWinCount
, 0, tuple_tags
);
635 for(i
= 0; i
< window_count
&& io_base_offset
== 0; i
++)
636 if(io_lengths
[i
] == IO_WINDOW_SIZE
)
637 io_base_offset
= io_bases
[i
];
640 PCCard_FreeTupleInfo(tuple_tags
);
646 card_map
= GetCardMap();
647 context
->config_base
=
648 (UPINT
)card_map
->cmm_AttributeMemory
+ config_base_offset
;
650 context
->io_base
= (UPINT
)card_map
->cmm_IOMemory
+ io_base_offset
;
651 BYTEOUT(context
->config_base
+ PCCARD_REG_COR
, config_value
);
652 BYTEOUT(context
->config_base
+ PCCARD_REG_CCSR
,
653 BYTEIN(context
->config_base
+ PCCARD_REG_CCSR
)
654 | PCCARD_REG_CCSRF_AUDIOENABLE
);
662 /****i* prism2.device/CardRemovedHook **************************************
668 * CardRemovedHook(context)
670 * VOID CardRemovedHook(struct BusContext *);
672 ****************************************************************************
676 static VOID
CardRemovedHook(struct BusContext
*context
,
677 struct DevBase
*base
)
679 ReleaseCard(context
->card_handle
, 0);
686 /****i* prism2.device/CardInsertedHook *************************************
692 * success = CardInsertedHook(context)
694 * BOOL CardInsertedHook(struct BusContext *);
696 ****************************************************************************
700 static BOOL
CardInsertedHook(struct BusContext
*context
,
701 struct DevBase
*base
)
705 success
= IsCardCompatible(context
, base
);
708 success
= InitialiseCard(context
, base
);
711 success
= InitialiseAdapter(context
->unit
, TRUE
, base
);
714 ReleaseCard(context
->card_handle
, 0);
721 /****i* prism2.device/CardRemovedInt ***************************************
727 * CardRemovedInt(context)
729 * VOID CardRemovedInt(struct BusContext *);
731 ****************************************************************************
735 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
736 REG(a6
, APTR int_code
))
738 struct DevBase
*base
;
739 struct DevUnit
*unit
;
741 /* Record loss of card and get our task to call ReleaseCard() */
743 unit
= context
->unit
;
747 if((unit
->flags
& UNITF_ONLINE
) != 0)
748 unit
->flags
|= UNITF_WASONLINE
;
749 unit
->flags
&= ~(UNITF_HAVEADAPTER
| UNITF_ONLINE
);
751 context
->have_card
= FALSE
;
753 Signal(unit
->task
, unit
->card_removed_signal
);
760 /****i* prism2.device/CardInsertedInt **************************************
766 * CardInsertedInt(context)
768 * VOID CardInsertedInt(struct BusContext *);
770 ****************************************************************************
774 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
775 REG(a6
, APTR int_code
))
777 struct DevBase
*base
;
778 struct DevUnit
*unit
;
780 unit
= context
->unit
;
783 context
->have_card
= TRUE
;
784 Signal(unit
->task
, unit
->card_inserted_signal
);
792 /****i* prism2.device/CardStatusInt ****************************************
798 * mask = CardStatusInt(context, int_code, mask)
800 * UBYTE CardStatusInt(struct BusContext *, APTR, UBYTE);
802 ****************************************************************************
804 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
805 * Since we don't use this parameter, we can lie.
809 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
810 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
))
812 if(context
->resource_version
< 39)
814 /* Work around gayle interrupt bug */
816 *((volatile UBYTE
*)0xda9000) = (mask
^ 0x2c) | 0xc0;
820 if(context
->unit
!= NULL
)
821 StatusInt(context
->unit
, StatusInt
);
828 /****i* prism2.device/WordsInHook ******************************************
834 * WordsInHook(context, offset, buffer, count)
836 * VOID WordsInHook(struct BusContext *, ULONG, UWORD *, ULONG);
838 ****************************************************************************
842 static VOID
WordsInHook(struct BusContext
*context
, ULONG offset
,
843 UWORD
*buffer
, ULONG count
)
845 WORDSIN(context
->io_base
+ offset
, buffer
, count
);
852 /****i* prism2.device/WordsOutHook *****************************************
858 * WordsOutHook(context, offset, buffer, count)
860 * VOID WordsOutHook(struct BusContext *, ULONG, const UWORD *, ULONG);
862 ****************************************************************************
866 static VOID
WordsOutHook(struct BusContext
*context
, ULONG offset
,
867 const UWORD
*buffer
, ULONG count
)
869 WORDSOUT(context
->io_base
+ offset
, buffer
, count
);
876 /****i* prism2.device/BEWordOutHook ****************************************
882 * BEWordOutHook(context, offset, value)
884 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
886 ****************************************************************************
890 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
893 BEWORDOUT(context
->io_base
+ offset
, value
);
900 /****i* prism2.device/LEWordInHook *****************************************
906 * value = LEWordInHook(context, offset)
908 * UWORD LEWordInHook(struct BusContext *, ULONG);
910 ****************************************************************************
914 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
916 return LEWORDIN(context
->io_base
+ offset
);
921 /****i* prism2.device/LEWordOutHook ****************************************
927 * LEWordOutHook(context, offset, value)
929 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
931 ****************************************************************************
935 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
938 LEWORDOUT(context
->io_base
+ offset
, value
);