3 Copyright (C) 2000-2010 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
[] =
121 static struct TagItem unit_tags
[] =
123 {IOTAG_WordsIn
, (UPINT
)WordsInHook
},
124 {IOTAG_WordsOut
, (UPINT
)WordsOutHook
},
125 {IOTAG_BEWordOut
, (UPINT
)BEWordOutHook
},
126 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
127 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
132 /****i* prism2.device/GetPCCardCount ***************************************
135 * GetPCCardCount -- Get the number of compatible PC Cards.
138 * count = GetPCCardCount()
140 * ULONG GetPCCardCount();
142 ****************************************************************************
146 ULONG
GetPCCardCount(struct DevBase
*base
)
149 struct BusContext
*context
;
151 if(CardResource
!= NULL
)
153 if(FindPCCardUnit(0, base
) != NULL
)
157 context
= AllocCard(base
);
161 FreeCard(context
, base
);
171 /****i* prism2.device/GetPCCardUnit ****************************************
174 * GetPCCardUnit -- Get a unit by number.
177 * unit = GetPCCardUnit(index)
179 * struct DevUnit *GetPCCardUnit(ULONG);
181 ****************************************************************************
185 struct DevUnit
*GetPCCardUnit(ULONG index
, struct DevBase
*base
)
187 struct DevUnit
*unit
;
189 unit
= FindPCCardUnit(index
, base
);
193 unit
= CreatePCCardUnit(index
, base
);
195 AddTail((APTR
)&base
->pccard_units
, (APTR
)unit
);
203 /****i* prism2.device/FindPCCardUnit ***************************************
206 * FindPCCardUnit -- Find a unit by number.
209 * unit = FindPCCardUnit(index)
211 * struct DevUnit *FindPCCardUnit(ULONG);
213 ****************************************************************************
217 static struct DevUnit
*FindPCCardUnit(ULONG index
, struct DevBase
*base
)
219 struct DevUnit
*unit
, *tail
;
221 unit
= (APTR
)base
->pccard_units
.mlh_Head
;
222 tail
= (APTR
)&base
->pccard_units
.mlh_Tail
;
231 /****i* prism2.device/CreatePCCardUnit *************************************
234 * CreatePCCardUnit -- Create a unit.
237 * unit = CreatePCCardUnit(index)
239 * struct DevUnit *CreatePCCardUnit(ULONG);
242 * Creates a new unit.
244 ****************************************************************************
248 static struct DevUnit
*CreatePCCardUnit(ULONG index
,
249 struct DevBase
*base
)
252 struct BusContext
*context
;
253 struct DevUnit
*unit
;
255 /* Get card from system */
257 context
= AllocCard(base
);
261 /* Prepare card for use */
265 if(!InitialiseCard(context
, base
))
269 /* Create device driver unit */
273 context
->unit
= unit
=
274 CreateUnit(index
, context
, unit_tags
, PCCARD_BUS
, base
);
281 if(!(WrapInt(&unit
->status_int
, base
)
282 && WrapInt(&unit
->rx_int
, base
)
283 && WrapInt(&unit
->tx_int
, base
)
284 && WrapInt(&unit
->info_int
, base
)))
287 unit
->insertion_function
= (APTR
)CardInsertedHook
;
288 unit
->removal_function
= (APTR
)CardRemovedHook
;
295 DeleteUnit(context
->unit
, base
);
296 FreeCard(context
, base
);
306 /****i* prism2.device/DeletePCCardUnit *************************************
309 * DeletePCCardUnit -- Delete a unit.
312 * DeletePCCardUnit(unit)
314 * VOID DeletePCCardUnit(struct DevUnit *);
320 * unit - Device unit (may be NULL).
325 ****************************************************************************
329 VOID
DeletePCCardUnit(struct DevUnit
*unit
, struct DevBase
*base
)
331 struct BusContext
*context
;
335 UnwrapInt(&unit
->info_int
, base
);
336 UnwrapInt(&unit
->tx_int
, base
);
337 UnwrapInt(&unit
->rx_int
, base
);
338 UnwrapInt(&unit
->status_int
, base
);
339 context
= unit
->card
;
340 DeleteUnit(unit
, base
);
341 FreeCard(context
, base
);
349 /****i* prism2.device/AllocCard ********************************************
352 * AllocCard -- Get card from system.
357 * struct BusContext *AllocCard();
359 ****************************************************************************
363 static struct BusContext
*AllocCard(struct DevBase
*base
)
366 struct BusContext
*context
;
367 struct CardHandle
*card_handle
;
368 struct Interrupt
*card_removed_int
, *card_inserted_int
, *card_status_int
;
370 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
376 context
->resource_version
=
377 ((struct Library
*)base
->card_base
)->lib_Version
;
378 context
->card_handle
= card_handle
=
379 AllocMem(sizeof(struct CardHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
380 context
->tuple_buffer
=
381 AllocVec(TUPLE_BUFFER_SIZE
, MEMF_PUBLIC
);
383 if(card_handle
== NULL
|| context
->tuple_buffer
== NULL
)
389 /* Set up card handle */
391 card_handle
->cah_CardNode
.ln_Pri
= HANDLE_PRIORITY
;
392 card_handle
->cah_CardNode
.ln_Name
=
393 base
->device
.dd_Library
.lib_Node
.ln_Name
;
394 card_handle
->cah_CardFlags
= CARDF_POSTSTATUS
;
396 card_handle
->cah_CardRemoved
= card_removed_int
=
397 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
399 card_handle
->cah_CardInserted
= card_inserted_int
=
400 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
402 card_handle
->cah_CardStatus
= card_status_int
=
403 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
405 if(card_removed_int
== NULL
|| card_inserted_int
== NULL
406 || card_status_int
== NULL
)
412 /* Try to gain access to card */
414 card_removed_int
->is_Code
= CardRemovedInt
;
415 card_removed_int
->is_Data
= context
;
416 card_inserted_int
->is_Code
= CardInsertedInt
;
417 card_inserted_int
->is_Data
= context
;
418 card_status_int
->is_Code
= (APTR
)CardStatusInt
;
419 card_status_int
->is_Data
= context
;
421 if(!(WrapCardInt(card_removed_int
, base
)
422 && WrapCardInt(card_inserted_int
, base
)
423 && WrapCardInt(card_status_int
, base
)))
429 if(OwnCard(card_handle
) != 0)
435 if(!IsCardCompatible(context
, base
))
441 FreeCard(context
, base
);
449 /****i* prism2.device/FreeCard *********************************************
457 * VOID FreeCard(struct BusContext *);
459 ****************************************************************************
463 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
)
465 struct CardHandle
*card_handle
;
469 card_handle
= context
->card_handle
;
471 if(context
->have_card
)
473 CardMiscControl(card_handle
, 0);
474 CardResetCard(card_handle
);
476 ReleaseCard(card_handle
, CARDF_REMOVEHANDLE
);
477 UnwrapCardInt(card_handle
->cah_CardStatus
, base
);
478 UnwrapCardInt(card_handle
->cah_CardInserted
, base
);
479 UnwrapCardInt(card_handle
->cah_CardRemoved
, base
);
481 FreeVec(card_handle
->cah_CardStatus
);
482 FreeVec(card_handle
->cah_CardInserted
);
483 FreeVec(card_handle
->cah_CardRemoved
);
484 FreeVec(context
->tuple_buffer
);
485 FreeMem(card_handle
, sizeof(struct CardHandle
));
487 FreeMem(context
, sizeof(struct BusContext
));
495 /****i* prism2.device/IsCardCompatible *************************************
501 * compatible = IsCardCompatible(context)
503 * BOOL IsCardCompatible(struct BusContext *);
505 ****************************************************************************
509 static BOOL
IsCardCompatible(struct BusContext
*context
,
510 struct DevBase
*base
)
513 struct CardHandle
*card_handle
;
515 struct TagItem
*tuple_tags
= NULL
;
518 UWORD maker
= 0, product
= 0;
520 card_handle
= context
->card_handle
;
521 tuple_buffer
= context
->tuple_buffer
;
523 /* Get card's make and model */
525 if(CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_MANFID
,
528 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
529 if(tuple_tags
!= NULL
)
531 maker
= GetTagData(PCCARD_Maker
, 0, tuple_tags
);
532 product
= GetTagData(PCCARD_Product
, 0, tuple_tags
);
536 /* Check this is a card we can use */
538 code
= maker
<< 16 | product
;
539 for(success
= FALSE
, p
= product_codes
; *p
!= 0; p
++)
542 PCCard_FreeTupleInfo(tuple_tags
);
549 /****i* prism2.device/InitialiseCard ***************************************
555 * success = InitialiseCard(context)
557 * BOOL InitialiseCard(struct BusContext *);
559 ****************************************************************************
563 static BOOL
InitialiseCard(struct BusContext
*context
,
564 struct DevBase
*base
)
567 struct CardHandle
*card_handle
;
568 struct CardMemoryMap
*card_map
;
569 UBYTE config_value
, i
, window_count
, *tuple_buffer
;
570 struct TagItem
*tuple_tags
= NULL
;
571 ULONG
*io_bases
, *io_lengths
, io_base_offset
= 0, config_base_offset
;
573 /* Wake up card's I/O functionality */
575 card_handle
= context
->card_handle
;
576 tuple_buffer
= context
->tuple_buffer
;
577 CardMiscControl(card_handle
,
578 CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
580 /* Get configuration data */
582 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CONFIG
,
588 PCCard_FreeTupleInfo(tuple_tags
);
589 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
590 if(tuple_tags
== NULL
)
596 config_base_offset
= GetTagData(PCCARD_RegisterBase
, 0, tuple_tags
);
598 PCCard_FreeTupleInfo(tuple_tags
);
603 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CFTABLEENTRY
,
610 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
611 if(tuple_tags
== NULL
)
617 config_value
= GetTagData(PCCARD_ModeNo
, 0, tuple_tags
);
620 (APTR
)GetTagData(PCCARD_IOWinBases
, (UPINT
)NULL
, tuple_tags
);
625 /* Find the appropriate IO window */
630 (APTR
)GetTagData(PCCARD_IOWinLengths
, (UPINT
)NULL
, tuple_tags
);
632 window_count
= GetTagData(PCCARD_IOWinCount
, 0, tuple_tags
);
634 for(i
= 0; i
< window_count
&& io_base_offset
== 0; i
++)
635 if(io_lengths
[i
] == IO_WINDOW_SIZE
)
636 io_base_offset
= io_bases
[i
];
639 PCCard_FreeTupleInfo(tuple_tags
);
645 card_map
= GetCardMap();
646 context
->config_base
=
647 (UPINT
)card_map
->cmm_AttributeMemory
+ config_base_offset
;
649 context
->io_base
= (UPINT
)card_map
->cmm_IOMemory
+ io_base_offset
;
650 BYTEOUT(context
->config_base
+ PCCARD_REG_COR
, config_value
);
651 BYTEOUT(context
->config_base
+ PCCARD_REG_CCSR
,
652 BYTEIN(context
->config_base
+ PCCARD_REG_CCSR
)
653 | PCCARD_REG_CCSRF_AUDIOENABLE
);
661 /****i* prism2.device/CardRemovedHook **************************************
667 * CardRemovedHook(context)
669 * VOID CardRemovedHook(struct BusContext *);
671 ****************************************************************************
675 static VOID
CardRemovedHook(struct BusContext
*context
,
676 struct DevBase
*base
)
678 ReleaseCard(context
->card_handle
, 0);
685 /****i* prism2.device/CardInsertedHook *************************************
691 * success = CardInsertedHook(context)
693 * BOOL CardInsertedHook(struct BusContext *);
695 ****************************************************************************
699 static BOOL
CardInsertedHook(struct BusContext
*context
,
700 struct DevBase
*base
)
704 success
= IsCardCompatible(context
, base
);
707 success
= InitialiseCard(context
, base
);
710 success
= InitialiseAdapter(context
->unit
, TRUE
, base
);
713 ReleaseCard(context
->card_handle
, 0);
720 /****i* prism2.device/CardRemovedInt ***************************************
726 * CardRemovedInt(context)
728 * VOID CardRemovedInt(struct BusContext *);
730 ****************************************************************************
734 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
735 REG(a6
, APTR int_code
))
737 struct DevBase
*base
;
738 struct DevUnit
*unit
;
740 /* Record loss of card and get our task to call ReleaseCard() */
742 unit
= context
->unit
;
746 if((unit
->flags
& UNITF_ONLINE
) != 0)
747 unit
->flags
|= UNITF_WASONLINE
;
748 unit
->flags
&= ~(UNITF_HAVEADAPTER
| UNITF_ONLINE
);
750 context
->have_card
= FALSE
;
752 Signal(unit
->task
, unit
->card_removed_signal
);
759 /****i* prism2.device/CardInsertedInt **************************************
765 * CardInsertedInt(context)
767 * VOID CardInsertedInt(struct BusContext *);
769 ****************************************************************************
773 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
774 REG(a6
, APTR int_code
))
776 struct DevBase
*base
;
777 struct DevUnit
*unit
;
779 unit
= context
->unit
;
782 context
->have_card
= TRUE
;
783 Signal(unit
->task
, unit
->card_inserted_signal
);
791 /****i* prism2.device/CardStatusInt ****************************************
797 * mask = CardStatusInt(context, int_code, mask)
799 * UBYTE CardStatusInt(struct BusContext *, APTR, UBYTE);
801 ****************************************************************************
803 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
804 * Since we don't use this parameter, we can lie.
808 static UBYTE
CardStatusInt(REG(a1
, struct BusContext
*context
),
809 REG(a6
, APTR int_code
), REG(d0
, UBYTE mask
))
811 if(context
->resource_version
< 39)
813 /* Work around gayle interrupt bug */
815 *((volatile UBYTE
*)0xda9000) = (mask
^ 0x2c) | 0xc0;
819 if(context
->unit
!= NULL
)
820 StatusInt(context
->unit
, StatusInt
);
827 /****i* prism2.device/WordsInHook ******************************************
833 * WordsInHook(context, offset, buffer, count)
835 * VOID WordsInHook(struct BusContext *, ULONG, UWORD *, ULONG);
837 ****************************************************************************
841 static VOID
WordsInHook(struct BusContext
*context
, ULONG offset
,
842 UWORD
*buffer
, ULONG count
)
844 WORDSIN(context
->io_base
+ offset
, buffer
, count
);
851 /****i* prism2.device/WordsOutHook *****************************************
857 * WordsOutHook(context, offset, buffer, count)
859 * VOID WordsOutHook(struct BusContext *, ULONG, const UWORD *, ULONG);
861 ****************************************************************************
865 static VOID
WordsOutHook(struct BusContext
*context
, ULONG offset
,
866 const UWORD
*buffer
, ULONG count
)
868 WORDSOUT(context
->io_base
+ offset
, buffer
, count
);
875 /****i* prism2.device/BEWordOutHook ****************************************
881 * BEWordOutHook(context, offset, value)
883 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
885 ****************************************************************************
889 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
892 BEWORDOUT(context
->io_base
+ offset
, value
);
899 /****i* prism2.device/LEWordInHook *****************************************
905 * value = LEWordInHook(context, offset)
907 * UWORD LEWordInHook(struct BusContext *, ULONG);
909 ****************************************************************************
913 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
915 return LEWORDIN(context
->io_base
+ offset
);
920 /****i* prism2.device/LEWordOutHook ****************************************
926 * LEWordOutHook(context, offset, value)
928 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
930 ****************************************************************************
934 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
937 LEWORDOUT(context
->io_base
+ offset
, value
);