AHI: build Alsa driver when alsa-bridge link lib is detected
[AROS.git] / workbench / devs / networks / prism2 / pccard.c
blob2f67b7d413e6e45418d1c96c0c50b79f12ab1a11
1 /*
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,
18 MA 02111-1307, USA.
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>
32 #include "device.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
43 struct BusContext
45 struct DevUnit *unit;
46 struct CardHandle *card_handle;
47 UBYTE *tuple_buffer;
48 UPINT config_base;
49 UPINT io_base;
50 UWORD resource_version;
51 BOOL have_card;
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,
81 UWORD value);
82 static UWORD LEWordInHook(struct BusContext *context, ULONG offset);
83 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
84 UWORD value);
87 static const ULONG product_codes[] =
89 0x000b7300,
90 0x00890001,
91 0x01010001,
92 0x01050000,
93 0x01380002,
94 0x014d0801,
95 0x01560002,
96 0x01560003,
97 0x016b0001,
98 0x016c0001,
99 0x01eb080a,
100 0x02500002,
101 0x02610002,
102 0x026f0305,
103 0x026f030b,
104 0x02741612,
105 0x02741613,
106 0x02743301,
107 0x028a0002,
108 0x02ac0002,
109 0x02d20001,
110 0x16680101,
111 0xc0010008,
112 0xc00f0000,
113 0xc2500002,
114 0xd6010002,
115 0xd6010004,
116 0xd6010005,
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},
128 {TAG_END, 0}
132 /****i* prism2.device/GetPCCardCount ***************************************
134 * NAME
135 * GetPCCardCount -- Get the number of compatible PC Cards.
137 * SYNOPSIS
138 * count = GetPCCardCount()
140 * ULONG GetPCCardCount();
142 ****************************************************************************
146 ULONG GetPCCardCount(struct DevBase *base)
148 ULONG count = 0;
149 struct BusContext *context;
151 if(CardResource != NULL)
153 if(FindPCCardUnit(0, base) != NULL)
154 count = 1;
155 else
157 context = AllocCard(base);
158 if(context != NULL)
160 count = 1;
161 FreeCard(context, base);
166 return count;
171 /****i* prism2.device/GetPCCardUnit ****************************************
173 * NAME
174 * GetPCCardUnit -- Get a unit by number.
176 * SYNOPSIS
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);
191 if(unit == NULL)
193 unit = CreatePCCardUnit(index, base);
194 if(unit != NULL)
195 AddTail((APTR)&base->pccard_units, (APTR)unit);
198 return unit;
203 /****i* prism2.device/FindPCCardUnit ***************************************
205 * NAME
206 * FindPCCardUnit -- Find a unit by number.
208 * SYNOPSIS
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;
223 if(unit == tail)
224 unit = NULL;
226 return unit;
231 /****i* prism2.device/CreatePCCardUnit *************************************
233 * NAME
234 * CreatePCCardUnit -- Create a unit.
236 * SYNOPSIS
237 * unit = CreatePCCardUnit(index)
239 * struct DevUnit *CreatePCCardUnit(ULONG);
241 * FUNCTION
242 * Creates a new unit.
244 ****************************************************************************
248 static struct DevUnit *CreatePCCardUnit(ULONG index,
249 struct DevBase *base)
251 BOOL success = TRUE;
252 struct BusContext *context;
253 struct DevUnit *unit;
255 /* Get card from system */
257 context = AllocCard(base);
258 if(context == NULL)
259 success = FALSE;
261 /* Prepare card for use */
263 if(success)
265 if(!InitialiseCard(context, base))
266 success = FALSE;
269 /* Create device driver unit */
271 if(success)
273 context->unit = unit =
274 CreateUnit(index, context, unit_tags, PCCARD_BUS, base);
275 if(unit == NULL)
276 success = FALSE;
279 if(success)
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)))
285 success = FALSE;
287 unit->insertion_function = (APTR)CardInsertedHook;
288 unit->removal_function = (APTR)CardRemovedHook;
291 if(!success)
293 if(context != NULL)
295 DeleteUnit(context->unit, base);
296 FreeCard(context, base);
298 unit = NULL;
301 return unit;
306 /****i* prism2.device/DeletePCCardUnit *************************************
308 * NAME
309 * DeletePCCardUnit -- Delete a unit.
311 * SYNOPSIS
312 * DeletePCCardUnit(unit)
314 * VOID DeletePCCardUnit(struct DevUnit *);
316 * FUNCTION
317 * Deletes a unit.
319 * INPUTS
320 * unit - Device unit (may be NULL).
322 * RESULT
323 * None.
325 ****************************************************************************
329 VOID DeletePCCardUnit(struct DevUnit *unit, struct DevBase *base)
331 struct BusContext *context;
333 if(unit != NULL)
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);
344 return;
349 /****i* prism2.device/AllocCard ********************************************
351 * NAME
352 * AllocCard -- Get card from system.
354 * SYNOPSIS
355 * unit = AllocCard()
357 * struct BusContext *AllocCard();
359 ****************************************************************************
363 static struct BusContext *AllocCard(struct DevBase *base)
365 BOOL success = TRUE;
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);
371 if(context == NULL)
372 success = FALSE;
374 if(success)
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)
384 success = FALSE;
387 if(success)
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)
407 success = FALSE;
410 if(success)
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)))
424 success = FALSE;
427 if(success)
429 if(OwnCard(card_handle) != 0)
430 success = FALSE;
433 if(success)
435 if(!IsCardCompatible(context, base))
436 success = FALSE;
439 if(!success)
441 FreeCard(context, base);
442 context = NULL;
444 return context;
449 /****i* prism2.device/FreeCard *********************************************
451 * NAME
452 * FreeCard
454 * SYNOPSIS
455 * FreeCard(context)
457 * VOID FreeCard(struct BusContext *);
459 ****************************************************************************
463 static VOID FreeCard(struct BusContext *context, struct DevBase *base)
465 struct CardHandle *card_handle;
467 if(context != NULL)
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));
490 return;
495 /****i* prism2.device/IsCardCompatible *************************************
497 * NAME
498 * IsCardCompatible
500 * SYNOPSIS
501 * compatible = IsCardCompatible(context)
503 * BOOL IsCardCompatible(struct BusContext *);
505 ****************************************************************************
509 static BOOL IsCardCompatible(struct BusContext *context,
510 struct DevBase *base)
512 BOOL success = TRUE;
513 struct CardHandle *card_handle;
514 UBYTE *tuple_buffer;
515 struct TagItem *tuple_tags = NULL;
516 ULONG code;
517 const ULONG *p;
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,
526 MAX_TUPLE_SIZE))
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++)
540 if(*p == code)
541 success = TRUE;
542 PCCard_FreeTupleInfo(tuple_tags);
544 return success;
549 /****i* prism2.device/InitialiseCard ***************************************
551 * NAME
552 * InitialiseCard
554 * SYNOPSIS
555 * success = InitialiseCard(context)
557 * BOOL InitialiseCard(struct BusContext *);
559 ****************************************************************************
563 static BOOL InitialiseCard(struct BusContext *context,
564 struct DevBase *base)
566 BOOL success = TRUE;
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,
583 MAX_TUPLE_SIZE))
584 success = FALSE;
586 if(success)
588 PCCard_FreeTupleInfo(tuple_tags);
589 tuple_tags = PCCard_GetTupleInfo(tuple_buffer);
590 if(tuple_tags == NULL)
591 success = FALSE;
594 if(success)
596 config_base_offset = GetTagData(PCCARD_RegisterBase, 0, tuple_tags);
598 PCCard_FreeTupleInfo(tuple_tags);
599 tuple_tags = NULL;
601 /* Get IO base */
603 if(!CopyTuple(card_handle, tuple_buffer, PCCARD_TPL_CFTABLEENTRY,
604 MAX_TUPLE_SIZE))
605 success = FALSE;
608 if(success)
610 tuple_tags = PCCard_GetTupleInfo(tuple_buffer);
611 if(tuple_tags == NULL)
612 success = FALSE;
615 if(success)
617 config_value = GetTagData(PCCARD_ModeNo, 0, tuple_tags);
619 io_bases =
620 (APTR)GetTagData(PCCARD_IOWinBases, (UPINT)NULL, tuple_tags);
621 if(io_bases == NULL)
622 success = FALSE;
625 /* Find the appropriate IO window */
627 if(success)
629 io_lengths =
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);
641 /* Configure card */
643 if(success)
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);
656 return success;
661 /****i* prism2.device/CardRemovedHook **************************************
663 * NAME
664 * CardRemovedHook
666 * SYNOPSIS
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);
680 return;
685 /****i* prism2.device/CardInsertedHook *************************************
687 * NAME
688 * CardInsertedHook
690 * SYNOPSIS
691 * success = CardInsertedHook(context)
693 * BOOL CardInsertedHook(struct BusContext *);
695 ****************************************************************************
699 static BOOL CardInsertedHook(struct BusContext *context,
700 struct DevBase *base)
702 BOOL success = TRUE;
704 success = IsCardCompatible(context, base);
706 if(success)
707 success = InitialiseCard(context, base);
709 if(success)
710 success = InitialiseAdapter(context->unit, TRUE, base);
712 if(!success)
713 ReleaseCard(context->card_handle, 0);
715 return success;
720 /****i* prism2.device/CardRemovedInt ***************************************
722 * NAME
723 * CardRemovedInt
725 * SYNOPSIS
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;
743 if (unit != NULL)
745 base = unit->device;
746 if((unit->flags & UNITF_ONLINE) != 0)
747 unit->flags |= UNITF_WASONLINE;
748 unit->flags &= ~(UNITF_HAVEADAPTER | UNITF_ONLINE);
750 context->have_card = FALSE;
751 if (unit != NULL)
752 Signal(unit->task, unit->card_removed_signal);
754 return;
759 /****i* prism2.device/CardInsertedInt **************************************
761 * NAME
762 * CardInsertedInt
764 * SYNOPSIS
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;
780 if (unit != NULL) {
781 base = unit->device;
782 context->have_card = TRUE;
783 Signal(unit->task, unit->card_inserted_signal);
786 return;
791 /****i* prism2.device/CardStatusInt ****************************************
793 * NAME
794 * CardStatusInt
796 * SYNOPSIS
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;
816 mask = 0;
819 if(context->unit != NULL)
820 StatusInt(context->unit, StatusInt);
822 return mask;
827 /****i* prism2.device/WordsInHook ******************************************
829 * NAME
830 * WordsInHook
832 * SYNOPSIS
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);
846 return;
851 /****i* prism2.device/WordsOutHook *****************************************
853 * NAME
854 * WordsOutHook
856 * SYNOPSIS
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);
870 return;
875 /****i* prism2.device/BEWordOutHook ****************************************
877 * NAME
878 * BEWordOutHook
880 * SYNOPSIS
881 * BEWordOutHook(context, offset, value)
883 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
885 ****************************************************************************
889 static VOID BEWordOutHook(struct BusContext *context, ULONG offset,
890 UWORD value)
892 BEWORDOUT(context->io_base + offset, value);
894 return;
899 /****i* prism2.device/LEWordInHook *****************************************
901 * NAME
902 * LEWordInHook
904 * SYNOPSIS
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 ****************************************
922 * NAME
923 * LEWordOutHook
925 * SYNOPSIS
926 * LEWordOutHook(context, offset, value)
928 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
930 ****************************************************************************
934 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
935 UWORD value)
937 LEWORDOUT(context->io_base + offset, value);
939 return;