Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / devs / networks / prism2 / pccard.c
blobb2e7bf960d4e1edbb51db9599e6badc47094b7d4
1 /*
3 File: pccard.c
4 Author: Neil Cafferkey
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,
20 MA 02111-1307, USA.
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>
34 #include "device.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
44 struct BusContext
46 struct DevUnit *unit;
47 struct CardHandle *card_handle;
48 UBYTE *tuple_buffer;
49 UPINT config_base;
50 UPINT io_base;
51 UWORD resource_version;
52 BOOL have_card;
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,
82 UWORD value);
83 static UWORD LEWordInHook(struct BusContext *context, ULONG offset);
84 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
85 UWORD value);
88 static const ULONG product_codes[] =
90 0x000b7300,
91 0x00890001,
92 0x01010001,
93 0x01050000,
94 0x01380002,
95 0x014d0801,
96 0x01560002,
97 0x01560003,
98 0x016b0001,
99 0x016c0001,
100 0x01eb080a,
101 0x02500002,
102 0x02610002,
103 0x026f0305,
104 0x026f030b,
105 0x02741612,
106 0x02741613,
107 0x02743301,
108 0x028a0002,
109 0x02ac0002,
110 0x02d20001,
111 0x16680101,
112 0xc0010008,
113 0xc00f0000,
114 0xc2500002,
115 0xd6010002,
116 0xd6010004,
117 0xd6010005,
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},
129 {TAG_END, 0}
133 /****i* prism2.device/GetPCCardCount ***************************************
135 * NAME
136 * GetPCCardCount -- Get the number of compatible PC Cards.
138 * SYNOPSIS
139 * count = GetPCCardCount()
141 * ULONG GetPCCardCount();
143 ****************************************************************************
147 ULONG GetPCCardCount(struct DevBase *base)
149 ULONG count = 0;
150 struct BusContext *context;
152 if(CardResource != NULL)
154 if(FindPCCardUnit(0, base) != NULL)
155 count = 1;
156 else
158 context = AllocCard(base);
159 if(context != NULL)
161 count = 1;
162 FreeCard(context, base);
167 return count;
172 /****i* prism2.device/GetPCCardUnit ****************************************
174 * NAME
175 * GetPCCardUnit -- Get a unit by number.
177 * SYNOPSIS
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);
192 if(unit == NULL)
194 unit = CreatePCCardUnit(index, base);
195 if(unit != NULL)
196 AddTail((APTR)&base->pccard_units, (APTR)unit);
199 return unit;
204 /****i* prism2.device/FindPCCardUnit ***************************************
206 * NAME
207 * FindPCCardUnit -- Find a unit by number.
209 * SYNOPSIS
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;
224 if(unit == tail)
225 unit = NULL;
227 return unit;
232 /****i* prism2.device/CreatePCCardUnit *************************************
234 * NAME
235 * CreatePCCardUnit -- Create a unit.
237 * SYNOPSIS
238 * unit = CreatePCCardUnit(index)
240 * struct DevUnit *CreatePCCardUnit(ULONG);
242 * FUNCTION
243 * Creates a new unit.
245 ****************************************************************************
249 static struct DevUnit *CreatePCCardUnit(ULONG index,
250 struct DevBase *base)
252 BOOL success = TRUE;
253 struct BusContext *context;
254 struct DevUnit *unit;
256 /* Get card from system */
258 context = AllocCard(base);
259 if(context == NULL)
260 success = FALSE;
262 /* Prepare card for use */
264 if(success)
266 if(!InitialiseCard(context, base))
267 success = FALSE;
270 /* Create device driver unit */
272 if(success)
274 context->unit = unit =
275 CreateUnit(index, context, unit_tags, PCCARD_BUS, base);
276 if(unit == NULL)
277 success = FALSE;
280 if(success)
282 unit->insertion_function = (APTR)CardInsertedHook;
283 unit->removal_function = (APTR)CardRemovedHook;
286 if(!success)
288 if(context != NULL)
290 DeleteUnit(context->unit, base);
291 FreeCard(context, base);
293 unit = NULL;
296 return unit;
301 /****i* prism2.device/DeletePCCardUnit *************************************
303 * NAME
304 * DeletePCCardUnit -- Delete a unit.
306 * SYNOPSIS
307 * DeletePCCardUnit(unit)
309 * VOID DeletePCCardUnit(struct DevUnit *);
311 * FUNCTION
312 * Deletes a unit.
314 * INPUTS
315 * unit - Device unit (may be NULL).
317 * RESULT
318 * None.
320 ****************************************************************************
324 VOID DeletePCCardUnit(struct DevUnit *unit, struct DevBase *base)
326 struct BusContext *context;
328 if(unit != NULL)
330 context = unit->card;
331 DeleteUnit(unit, base);
332 FreeCard(context, base);
335 return;
340 /****i* prism2.device/AllocCard ********************************************
342 * NAME
343 * AllocCard -- Get card from system.
345 * SYNOPSIS
346 * unit = AllocCard()
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);
362 if(context == NULL)
363 success = FALSE;
365 if(success)
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)
375 success = FALSE;
378 if(success)
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)
398 success = FALSE;
401 if(success)
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)
413 success = FALSE;
416 if(success)
418 have_card = TRUE;
419 if(!IsCardCompatible(context, base))
420 success = FALSE;
423 if(!success)
425 FreeCard(context, base);
426 context = NULL;
428 return context;
433 /****i* prism2.device/FreeCard *********************************************
435 * NAME
436 * FreeCard
438 * SYNOPSIS
439 * FreeCard(context)
441 * VOID FreeCard(struct BusContext *);
443 ****************************************************************************
447 static VOID FreeCard(struct BusContext *context, struct DevBase *base)
449 struct CardHandle *card_handle;
451 if(context != NULL)
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));
471 return;
476 /****i* prism2.device/IsCardCompatible *************************************
478 * NAME
479 * IsCardCompatible
481 * SYNOPSIS
482 * compatible = IsCardCompatible(context)
484 * BOOL IsCardCompatible(struct BusContext *);
486 ****************************************************************************
490 static BOOL IsCardCompatible(struct BusContext *context,
491 struct DevBase *base)
493 BOOL success = TRUE;
494 struct CardHandle *card_handle;
495 UBYTE *tuple_buffer;
496 const struct TagItem *tuple_tags = NULL;
497 ULONG code;
498 const ULONG *p;
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,
507 MAX_TUPLE_SIZE))
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++)
521 if(*p == code)
522 success = TRUE;
523 PCCard_FreeTupleInfo(tuple_tags);
525 return success;
530 /****i* prism2.device/InitialiseCard ***************************************
532 * NAME
533 * InitialiseCard
535 * SYNOPSIS
536 * success = InitialiseCard(context)
538 * BOOL InitialiseCard(struct BusContext *);
540 ****************************************************************************
544 static BOOL InitialiseCard(struct BusContext *context,
545 struct DevBase *base)
547 BOOL success = TRUE;
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,
564 MAX_TUPLE_SIZE))
565 success = FALSE;
567 if(success)
569 PCCard_FreeTupleInfo(tuple_tags);
570 tuple_tags = PCCard_GetTupleInfo(tuple_buffer);
571 if(tuple_tags == NULL)
572 success = FALSE;
575 if(success)
577 config_base_offset = GetTagData(PCCARD_RegisterBase, 0, tuple_tags);
579 PCCard_FreeTupleInfo(tuple_tags);
580 tuple_tags = NULL;
582 /* Get IO base */
584 if(!CopyTuple(card_handle, tuple_buffer, PCCARD_TPL_CFTABLEENTRY,
585 MAX_TUPLE_SIZE))
586 success = FALSE;
589 if(success)
591 tuple_tags = PCCard_GetTupleInfo(tuple_buffer);
592 if(tuple_tags == NULL)
593 success = FALSE;
596 if(success)
598 config_value = GetTagData(PCCARD_ModeNo, 0, tuple_tags);
600 io_bases = (APTR)GetTagData(PCCARD_IOWinBases, NULL, tuple_tags);
601 if(io_bases == NULL)
602 success = FALSE;
605 /* Find the appropriate IO window */
607 if(success)
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);
620 /* Configure card */
622 if(success)
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);
635 return success;
640 /****i* prism2.device/CardRemovedHook **************************************
642 * NAME
643 * CardRemovedHook
645 * SYNOPSIS
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);
659 return;
664 /****i* prism2.device/CardInsertedHook *************************************
666 * NAME
667 * CardInsertedHook
669 * SYNOPSIS
670 * success = CardInsertedHook(context)
672 * BOOL CardInsertedHook(struct BusContext *);
674 ****************************************************************************
678 static BOOL CardInsertedHook(struct BusContext *context,
679 struct DevBase *base)
681 BOOL success = TRUE;
683 success = IsCardCompatible(context, base);
685 if(success)
686 success = InitialiseCard(context, base);
688 if(success)
689 success = InitialiseAdapter(context->unit, TRUE, base);
691 if(!success)
692 ReleaseCard(context->card_handle, 0);
694 return success;
699 /****i* prism2.device/CardRemovedInt ***************************************
701 * NAME
702 * CardRemovedInt
704 * SYNOPSIS
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;
722 base = unit->device;
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);
729 return;
734 /****i* prism2.device/CardInsertedInt **************************************
736 * NAME
737 * CardInsertedInt
739 * SYNOPSIS
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;
755 base = unit->device;
756 context->have_card = TRUE;
757 Signal(unit->task, unit->card_inserted_signal);
759 return;
764 /****i* prism2.device/CardStatusInt ****************************************
766 * NAME
767 * CardStatusInt
769 * SYNOPSIS
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))
784 #if 1
785 if(context->resource_version < 39)
787 /* Work around gayle interrupt bug */
789 *((volatile UBYTE *)0xda9000) = (mask ^ 0x2c) | 0xc0;
790 mask = 0;
792 #endif
794 if(context->unit != NULL)
795 StatusInt(context->unit, StatusInt);
797 return mask;
802 /****i* prism2.device/WordsInHook ******************************************
804 * NAME
805 * WordsInHook
807 * SYNOPSIS
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);
821 return;
826 /****i* prism2.device/WordsOutHook *****************************************
828 * NAME
829 * WordsOutHook
831 * SYNOPSIS
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);
845 return;
850 /****i* prism2.device/BEWordOutHook ****************************************
852 * NAME
853 * BEWordOutHook
855 * SYNOPSIS
856 * BEWordOutHook(context, offset, value)
858 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
860 ****************************************************************************
864 static VOID BEWordOutHook(struct BusContext *context, ULONG offset,
865 UWORD value)
867 BEWORDOUT(context->io_base + offset, value);
869 return;
874 /****i* prism2.device/LEWordInHook *****************************************
876 * NAME
877 * LEWordInHook
879 * SYNOPSIS
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 ****************************************
897 * NAME
898 * LEWordOutHook
900 * SYNOPSIS
901 * LEWordOutHook(context, offset, value)
903 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
905 ****************************************************************************
909 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
910 UWORD value)
912 LEWORDOUT(context->io_base + offset, value);
914 return;