5 Copyright (C) 2000-2006 Neil Cafferkey
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 #include <exec/types.h>
26 #include <utility/tagitem.h>
27 #include <libraries/pccard.h>
29 #include <proto/exec.h>
30 #include <proto/utility.h>
31 #include <proto/cardres.h>
32 #include <proto/pccard.h>
36 #include "pccard_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
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(d0
, UBYTE mask
),
76 REG(a1
, struct BusContext
*context
), REG(a6
, APTR int_code
));
77 static VOID
WordsInHook(struct BusContext
*context
,
78 ULONG offset
, UWORD
*buffer
, ULONG count
);
79 static VOID
WordsOutHook(struct BusContext
*context
, ULONG offset
,
80 const UWORD
*buffer
, ULONG count
);
81 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
83 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
84 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
88 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(unit_num)
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 unit
->insertion_function
= (APTR
)CardInsertedHook
;
283 unit
->removal_function
= (APTR
)CardRemovedHook
;
290 DeleteUnit(context
->unit
, base
);
291 FreeCard(context
, base
);
301 /****i* prism2.device/DeletePCCardUnit *************************************
304 * DeletePCCardUnit -- Delete a unit.
307 * DeletePCCardUnit(unit)
309 * VOID DeletePCCardUnit(struct DevUnit *);
315 * unit - Device unit (may be NULL).
320 ****************************************************************************
324 VOID
DeletePCCardUnit(struct DevUnit
*unit
, struct DevBase
*base
)
326 struct BusContext
*context
;
330 context
= unit
->card
;
331 DeleteUnit(unit
, base
);
332 FreeCard(context
, base
);
340 /****i* prism2.device/AllocCard ********************************************
343 * AllocCard -- Get card from system.
348 * struct BusContext *AllocCard();
350 ****************************************************************************
354 static struct BusContext
*AllocCard(struct DevBase
*base
)
356 BOOL success
= TRUE
, have_card
= FALSE
;
357 struct BusContext
*context
;
358 struct CardHandle
*card_handle
;
359 struct Interrupt
*card_removed_int
, *card_inserted_int
, *card_status_int
;
361 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
367 context
->resource_version
=
368 ((struct Library
*)base
->card_base
)->lib_Version
;
369 context
->card_handle
= card_handle
=
370 AllocMem(sizeof(struct CardHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
371 context
->tuple_buffer
=
372 AllocVec(TUPLE_BUFFER_SIZE
, MEMF_PUBLIC
);
374 if(card_handle
== NULL
|| context
->tuple_buffer
== NULL
)
380 /* Set up card handle */
382 card_handle
->cah_CardNode
.ln_Pri
= HANDLE_PRIORITY
;
383 card_handle
->cah_CardNode
.ln_Name
=
384 base
->device
.dd_Library
.lib_Node
.ln_Name
;
385 card_handle
->cah_CardFlags
= CARDF_POSTSTATUS
;
387 card_handle
->cah_CardRemoved
= card_removed_int
=
388 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
390 card_handle
->cah_CardInserted
= card_inserted_int
=
391 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
393 card_handle
->cah_CardStatus
= card_status_int
=
394 AllocVec(sizeof(struct Interrupt
), MEMF_PUBLIC
| MEMF_CLEAR
);
396 if(card_removed_int
== NULL
|| card_inserted_int
== NULL
397 || card_status_int
== NULL
)
403 /* Try to gain access to card */
405 card_removed_int
->is_Code
= CardRemovedInt
;
406 card_removed_int
->is_Data
= context
;
407 card_inserted_int
->is_Code
= CardInsertedInt
;
408 card_inserted_int
->is_Data
= context
;
409 card_status_int
->is_Code
= (APTR
)CardStatusInt
;
410 card_status_int
->is_Data
= context
;
412 if(OwnCard(card_handle
) != 0)
419 if(!IsCardCompatible(context
, base
))
425 FreeCard(context
, base
);
433 /****i* prism2.device/FreeCard *********************************************
441 * VOID FreeCard(struct BusContext *);
443 ****************************************************************************
447 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
)
449 struct CardHandle
*card_handle
;
453 card_handle
= context
->card_handle
;
455 if(context
->have_card
)
457 CardMiscControl(card_handle
, 0);
458 CardResetCard(card_handle
);
460 ReleaseCard(card_handle
, CARDF_REMOVEHANDLE
);
462 FreeVec(card_handle
->cah_CardStatus
);
463 FreeVec(card_handle
->cah_CardInserted
);
464 FreeVec(card_handle
->cah_CardRemoved
);
465 FreeVec(context
->tuple_buffer
);
466 FreeMem(card_handle
, sizeof(struct CardHandle
));
468 FreeMem(context
, sizeof(struct BusContext
));
476 /****i* prism2.device/IsCardCompatible *************************************
482 * compatible = IsCardCompatible(context)
484 * BOOL IsCardCompatible(struct BusContext *);
486 ****************************************************************************
490 static BOOL
IsCardCompatible(struct BusContext
*context
,
491 struct DevBase
*base
)
494 struct CardHandle
*card_handle
;
496 const struct TagItem
*tuple_tags
= NULL
;
499 UWORD maker
= 0, product
= 0;
501 card_handle
= context
->card_handle
;
502 tuple_buffer
= context
->tuple_buffer
;
504 /* Get card's make and model */
506 if(CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_MANFID
,
509 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
510 if(tuple_tags
!= NULL
)
512 maker
= GetTagData(PCCARD_Maker
, 0, tuple_tags
);
513 product
= GetTagData(PCCARD_Product
, 0, tuple_tags
);
517 /* Check this is a card we can use */
519 code
= maker
<< 16 | product
;
520 for(success
= FALSE
, p
= product_codes
; *p
!= 0; p
++)
523 PCCard_FreeTupleInfo(tuple_tags
);
530 /****i* prism2.device/InitialiseCard ***************************************
536 * success = InitialiseCard(context)
538 * BOOL InitialiseCard(struct BusContext *);
540 ****************************************************************************
544 static BOOL
InitialiseCard(struct BusContext
*context
,
545 struct DevBase
*base
)
548 struct CardHandle
*card_handle
;
549 struct CardMemoryMap
*card_map
;
550 UBYTE config_value
, i
, window_count
, *tuple_buffer
;
551 const struct TagItem
*tuple_tags
= NULL
;
552 ULONG
*io_bases
, *io_lengths
, io_base_offset
= 0, config_base_offset
;
554 /* Wake up card's I/O functionality */
556 card_handle
= context
->card_handle
;
557 tuple_buffer
= context
->tuple_buffer
;
558 CardMiscControl(card_handle
,
559 CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
561 /* Get configuration data */
563 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CONFIG
,
569 PCCard_FreeTupleInfo(tuple_tags
);
570 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
571 if(tuple_tags
== NULL
)
577 config_base_offset
= GetTagData(PCCARD_RegisterBase
, 0, tuple_tags
);
579 PCCard_FreeTupleInfo(tuple_tags
);
584 if(!CopyTuple(card_handle
, tuple_buffer
, PCCARD_TPL_CFTABLEENTRY
,
591 tuple_tags
= PCCard_GetTupleInfo(tuple_buffer
);
592 if(tuple_tags
== NULL
)
598 config_value
= GetTagData(PCCARD_ModeNo
, 0, tuple_tags
);
600 io_bases
= (APTR
)GetTagData(PCCARD_IOWinBases
, NULL
, tuple_tags
);
605 /* Find the appropriate IO window */
609 io_lengths
= (APTR
)GetTagData(PCCARD_IOWinLengths
, NULL
, tuple_tags
);
611 window_count
= GetTagData(PCCARD_IOWinCount
, 0, tuple_tags
);
613 for(i
= 0; i
< window_count
&& io_base_offset
== 0; i
++)
614 if(io_lengths
[i
] == IO_WINDOW_SIZE
)
615 io_base_offset
= io_bases
[i
];
618 PCCard_FreeTupleInfo(tuple_tags
);
624 card_map
= GetCardMap();
625 context
->config_base
=
626 (UPINT
)card_map
->cmm_AttributeMemory
+ config_base_offset
;
628 context
->io_base
= (UPINT
)card_map
->cmm_IOMemory
+ io_base_offset
;
629 BYTEOUT(context
->config_base
+ PCCARD_REG_COR
, config_value
);
630 BYTEOUT(context
->config_base
+ PCCARD_REG_CCSR
,
631 BYTEIN(context
->config_base
+ PCCARD_REG_CCSR
)
632 | PCCARD_REG_CCSRF_AUDIOENABLE
);
640 /****i* prism2.device/CardRemovedHook **************************************
646 * CardRemovedHook(context)
648 * VOID CardRemovedHook(struct BusContext *);
650 ****************************************************************************
654 static VOID
CardRemovedHook(struct BusContext
*context
,
655 struct DevBase
*base
)
657 ReleaseCard(context
->card_handle
, 0);
664 /****i* prism2.device/CardInsertedHook *************************************
670 * success = CardInsertedHook(context)
672 * BOOL CardInsertedHook(struct BusContext *);
674 ****************************************************************************
678 static BOOL
CardInsertedHook(struct BusContext
*context
,
679 struct DevBase
*base
)
683 success
= IsCardCompatible(context
, base
);
686 success
= InitialiseCard(context
, base
);
689 success
= InitialiseAdapter(context
->unit
, TRUE
, base
);
692 ReleaseCard(context
->card_handle
, 0);
699 /****i* prism2.device/CardRemovedInt ***************************************
705 * CardRemovedInt(unit)
707 * VOID CardRemovedInt(struct DevUnit *);
709 ****************************************************************************
713 static VOID
CardRemovedInt(REG(a1
, struct BusContext
*context
),
714 REG(a6
, APTR int_code
))
716 struct DevBase
*base
;
717 struct DevUnit
*unit
;
719 /* Record loss of card and get our task to call ReleaseCard() */
721 unit
= context
->unit
;
723 if((unit
->flags
& UNITF_ONLINE
) != 0)
724 unit
->flags
|= UNITF_WASONLINE
;
725 unit
->flags
&= ~(UNITF_HAVEADAPTER
| UNITF_ONLINE
);
726 context
->have_card
= FALSE
;
727 Signal(unit
->task
, unit
->card_removed_signal
);
734 /****i* prism2.device/CardInsertedInt **************************************
740 * CardInsertedInt(unit)
742 * VOID CardInsertedInt(struct DevUnit *);
744 ****************************************************************************
748 static VOID
CardInsertedInt(REG(a1
, struct BusContext
*context
),
749 REG(a6
, APTR int_code
))
751 struct DevBase
*base
;
752 struct DevUnit
*unit
;
754 unit
= context
->unit
;
756 context
->have_card
= TRUE
;
757 Signal(unit
->task
, unit
->card_inserted_signal
);
764 /****i* prism2.device/CardStatusInt ****************************************
770 * mask = CardStatusInt(mask, unit)
772 * UBYTE CardStatusInt(UBYTE mask, struct DevUnit *);
774 ****************************************************************************
776 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
777 * Since we don't use this parameter, we can lie.
781 static UBYTE
CardStatusInt(REG(d0
, UBYTE mask
),
782 REG(a1
, struct BusContext
*context
), REG(a6
, APTR int_code
))
785 if(context
->resource_version
< 39)
787 /* Work around gayle interrupt bug */
789 *((volatile UBYTE
*)0xda9000) = (mask
^ 0x2c) | 0xc0;
794 if(context
->unit
!= NULL
)
795 StatusInt(context
->unit
, StatusInt
);
802 /****i* prism2.device/WordsInHook ******************************************
808 * WordsInHook(context, offset, buffer, count)
810 * VOID WordsInHook(struct BusContext *, ULONG, UWORD *, ULONG);
812 ****************************************************************************
816 static VOID
WordsInHook(struct BusContext
*context
, ULONG offset
,
817 UWORD
*buffer
, ULONG count
)
819 WORDSIN(context
->io_base
+ offset
, buffer
, count
);
826 /****i* prism2.device/WordsOutHook *****************************************
832 * WordsOutHook(context, offset, buffer, count)
834 * VOID WordsOutHook(struct BusContext *, ULONG, const UWORD *, ULONG);
836 ****************************************************************************
840 static VOID
WordsOutHook(struct BusContext
*context
, ULONG offset
,
841 const UWORD
*buffer
, ULONG count
)
843 WORDSOUT(context
->io_base
+ offset
, buffer
, count
);
850 /****i* prism2.device/BEWordOutHook ****************************************
856 * BEWordOutHook(context, offset, value)
858 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
860 ****************************************************************************
864 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
867 BEWORDOUT(context
->io_base
+ offset
, value
);
874 /****i* prism2.device/LEWordInHook *****************************************
880 * value = LEWordInHook(context, offset)
882 * UWORD LEWordInHook(struct BusContext *, ULONG);
884 ****************************************************************************
888 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
890 return LEWORDIN(context
->io_base
+ offset
);
895 /****i* prism2.device/LEWordOutHook ****************************************
901 * LEWordOutHook(context, offset, value)
903 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
905 ****************************************************************************
909 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
912 LEWORDOUT(context
->io_base
+ offset
, value
);