Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / etherlink3 / pci.c
blob23c5d7deb534ec396fa430b16fd216700251f271
1 /*
3 Copyright (C) 2004,2005 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>
26 #ifdef __amigaos4__
27 #include <expansion/pci.h>
28 #endif
30 #include <proto/exec.h>
31 #include <proto/expansion.h>
33 #include "device.h"
34 #include "pci.h"
36 #include "pci_protos.h"
37 #include "device_protos.h"
38 #include "prometheus_protos.h"
39 #include "powerpci_protos.h"
40 #include "expansion_protos.h"
41 /*#include "openpci_protos.h"*/
42 #include "unit_protos.h"
45 /* Private prototypes */
47 static struct DevUnit *FindPCIUnit(ULONG index, struct DevBase *base);
48 static struct DevUnit *CreatePCIUnit(ULONG index, struct DevBase *base);
49 static struct BusContext *AllocCard(ULONG index, struct DevBase *base);
50 static VOID FreeCard(struct BusContext *context, struct DevBase *base);
51 static BOOL AddPCIIntServer(APTR card, struct Interrupt *interrupt,
52 struct DevBase *base);
53 static VOID RemPCIIntServer(APTR card, struct Interrupt *interrupt,
54 struct DevBase *base);
55 static UBYTE ByteInHook(struct BusContext *context, ULONG offset);
56 static ULONG LongInHook(struct BusContext *context, ULONG offset);
57 static VOID ByteOutHook(struct BusContext *context, ULONG offset,
58 UBYTE value);
59 static VOID WordOutHook(struct BusContext *context, ULONG offset,
60 UWORD value);
61 static VOID LongOutHook(struct BusContext *context, ULONG offset,
62 ULONG value);
63 static VOID LongsInHook(struct BusContext *context, ULONG offset,
64 ULONG *buffer, ULONG count);
65 static VOID LongsOutHook(struct BusContext *context, ULONG offset,
66 const ULONG *buffer, ULONG count);
67 static VOID BEWordOutHook(struct BusContext *context, ULONG offset,
68 UWORD value);
69 static UWORD LEWordInHook(struct BusContext *context, ULONG offset);
70 static ULONG LELongInHook(struct BusContext *context, ULONG offset);
71 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
72 UWORD value);
73 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
74 ULONG value);
75 static APTR AllocDMAMemHook(struct BusContext *context, UPINT size,
76 UWORD alignment);
77 static VOID FreeDMAMemHook(struct BusContext *context, APTR mem);
80 const UWORD product_codes[] =
82 0x10b7, 0x1201,
83 0x10b7, 0x1202,
84 0x10b7, 0x4500,
85 0x10b7, 0x5900,
86 0x10b7, 0x5950,
87 0x10b7, 0x5951,
88 0x10b7, 0x5952,
89 0x10b7, 0x9000,
90 0x10b7, 0x9001,
91 0x10b7, 0x9004,
92 0x10b7, 0x9005,
93 0x10b7, 0x9006,
94 0x10b7, 0x900A,
95 0x10b7, 0x9050,
96 0x10b7, 0x9051,
97 0x10b7, 0x9055,
98 0x10b7, 0x9056,
99 0x10b7, 0x9058,
100 0x10b7, 0x905A,
101 0x10b7, 0x9200,
102 0x10b7, 0x9201,
103 0x10b7, 0x9210,
104 0x10b7, 0x9800,
105 0x10b7, 0x9805,
106 0xffff, 0xffff
110 static const struct TagItem unit_tags[] =
112 {IOTAG_ByteIn, (UPINT)ByteInHook},
113 {IOTAG_LongIn, (UPINT)LongInHook},
114 {IOTAG_ByteOut, (UPINT)ByteOutHook},
115 {IOTAG_WordOut, (UPINT)WordOutHook},
116 {IOTAG_LongOut, (UPINT)LongOutHook},
117 {IOTAG_LongsIn, (UPINT)LongsInHook},
118 {IOTAG_LongsOut, (UPINT)LongsOutHook},
119 {IOTAG_BEWordOut, (UPINT)BEWordOutHook},
120 {IOTAG_LEWordIn, (UPINT)LEWordInHook},
121 {IOTAG_LELongIn, (UPINT)LELongInHook},
122 {IOTAG_LEWordOut, (UPINT)LEWordOutHook},
123 {IOTAG_LELongOut, (UPINT)LELongOutHook},
124 {IOTAG_AllocDMAMem, (UPINT)AllocDMAMemHook},
125 {IOTAG_FreeDMAMem, (UPINT)FreeDMAMemHook},
126 {TAG_END, 0}
130 /****i* etherlink3.device/GetPCICount **************************************
132 * NAME
133 * GetPCICount -- Get the number of compatible PCI Cards.
135 * SYNOPSIS
136 * count = GetPCICount()
138 * ULONG GetPCICount();
140 ****************************************************************************
144 ULONG GetPCICount(struct DevBase *base)
146 ULONG count = 0;
148 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
149 if(base->prometheus_base != NULL)
150 count = GetPrometheusCount(base);
151 #endif
152 #ifdef __mc68000__
153 if(base->powerpci_base != NULL)
154 count = GetPowerPCICount(base);
155 #endif
156 #ifdef __amigaos4__
157 if(base->expansion_base != NULL)
158 count = GetExpansionCount(base);
159 #endif
160 #ifdef __MORPHOS__
161 if(base->openpci_base != NULL)
162 count = GetOpenPCICount(base);
163 #endif
165 return count;
170 /****i* etherlink3.device/GetPCIUnit ***************************************
172 * NAME
173 * GetPCIUnit -- Get a unit by number.
175 * SYNOPSIS
176 * unit = GetPCIUnit(index)
178 * struct DevUnit *GetPCIUnit(ULONG);
180 ****************************************************************************
184 struct DevUnit *GetPCIUnit(ULONG index, struct DevBase *base)
186 struct DevUnit *unit;
188 unit = FindPCIUnit(index, base);
190 if(unit == NULL)
192 unit = CreatePCIUnit(index, base);
193 if(unit != NULL)
195 AddTail((APTR)&base->pci_units, (APTR)unit);
199 return unit;
204 /****i* etherlink3.device/FindPCIUnit **************************************
206 * NAME
207 * FindPCIUnit -- Find a unit by number.
209 * SYNOPSIS
210 * unit = FindPCIUnit(index)
212 * struct DevUnit *FindPCIUnit(ULONG);
214 ****************************************************************************
218 static struct DevUnit *FindPCIUnit(ULONG index, struct DevBase *base)
220 struct DevUnit *unit, *tail;
221 BOOL found = FALSE;
223 unit = (APTR)base->pci_units.mlh_Head;
224 tail = (APTR)&base->pci_units.mlh_Tail;
226 while(unit != tail && !found)
228 if(unit->index == index)
229 found = TRUE;
230 else
231 unit = (APTR)unit->node.mln_Succ;
234 if(!found)
235 unit = NULL;
237 return unit;
242 /****i* etherlink3.device/CreatePCIUnit ************************************
244 * NAME
245 * CreatePCIUnit -- Create a PCI unit.
247 * SYNOPSIS
248 * unit = CreatePCIUnit(index)
250 * struct DevUnit *CreatePCIUnit(ULONG);
252 * FUNCTION
253 * Creates a new PCI unit.
255 ****************************************************************************
259 static struct DevUnit *CreatePCIUnit(ULONG index, struct DevBase *base)
261 BOOL success = TRUE;
262 struct BusContext *context;
263 struct DevUnit *unit = NULL;
265 context = AllocCard(index, base);
266 if(context == NULL)
267 success = FALSE;
269 if(success)
271 if(context->unit_tags == NULL)
273 context->unit_tags = unit_tags;
277 if(success)
279 context->device = base;
280 context->unit = unit = CreateUnit(index, context, context->unit_tags,
281 context->generation, PCI_BUS, base);
282 if(unit == NULL)
283 success = FALSE;
286 /* Add interrupt */
288 if(success)
290 if(!(WrapInt(&unit->status_int, base)
291 && WrapInt(&unit->rx_int, base)
292 && WrapInt(&unit->tx_int, base)
293 && WrapInt(&unit->tx_end_int, base)))
294 success = FALSE;
295 success = AddPCIIntServer(context->card, &unit->status_int, base);
298 if(!success)
300 if(context != NULL)
302 DeleteUnit(context->unit, base);
303 FreeCard(context, base);
305 unit = NULL;
308 return unit;
313 /****i* etherlink3.device/DeletePCIUnit ************************************
315 * NAME
316 * DeletePCIUnit -- Delete a unit.
318 * SYNOPSIS
319 * DeletePCIUnit(unit)
321 * VOID DeletePCIUnit(struct DevUnit *);
323 * FUNCTION
324 * Deletes a unit.
326 * INPUTS
327 * unit - Device unit (can be NULL).
329 * RESULT
330 * None.
332 ****************************************************************************
336 VOID DeletePCIUnit(struct DevUnit *unit, struct DevBase *base)
338 struct BusContext *context;
340 if(unit != NULL)
342 context = unit->card;
343 RemPCIIntServer(context->card, &unit->status_int, base);
344 UnwrapInt(&unit->tx_end_int, base);
345 UnwrapInt(&unit->tx_int, base);
346 UnwrapInt(&unit->rx_int, base);
347 UnwrapInt(&unit->status_int, base);
348 DeleteUnit(unit, base);
349 FreeCard(context, base);
352 return;
357 /****i* etherlink3.device/AllocCard ****************************************
359 * NAME
360 * AllocCard -- Get card from system.
362 * SYNOPSIS
363 * context = AllocCard(index)
365 * struct BusContext *AllocCard(ULONG);
367 ****************************************************************************
371 static struct BusContext *AllocCard(ULONG index, struct DevBase *base)
373 struct BusContext *context;
375 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
376 if(base->prometheus_base != NULL)
377 context = AllocPrometheusCard(index, base);
378 #endif
379 #ifdef __mc68000__
380 if(base->powerpci_base != NULL)
381 context = AllocPowerPCICard(index, base);
382 #endif
383 #ifdef __amigaos4__
384 if(base->expansion_base != NULL)
385 context = AllocExpansionCard(index, base);
386 #endif
387 #ifdef __MORPHOS__
388 if(base->openpci_base != NULL)
389 context = AllocOpenPCICard(index, base);
390 #endif
392 return context;
397 /****i* etherlink3.device/FreeCard *****************************************
399 * NAME
400 * FreeCard
402 * SYNOPSIS
403 * FreeCard(context)
405 * VOID FreeCard(struct BusContext *);
407 ****************************************************************************
411 static VOID FreeCard(struct BusContext *context, struct DevBase *base)
414 if(context != NULL)
416 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
417 if(base->prometheus_base != NULL)
418 FreePrometheusCard(context, base);
419 #endif
420 #ifdef __mc68000
421 if(base->powerpci_base != NULL)
422 FreePowerPCICard(context, base);
423 #endif
424 #ifdef __amigaos4__
425 if(base->expansion_base != NULL)
426 FreeExpansionCard(context, base);
427 #endif
428 #ifdef __MORPHOS__
429 if(base->openpci_base != NULL)
430 FreeOpenPCICard(context, base);
431 #endif
434 return;
439 /****i* etherlink3.device/AddPCIIntServer **********************************
441 * NAME
442 * AddPCIIntServer
444 * SYNOPSIS
445 * context = AddPCIIntServer(index)
447 * struct BusContext *AddPCIIntServer(ULONG);
449 ****************************************************************************
453 static BOOL AddPCIIntServer(APTR card, struct Interrupt *interrupt,
454 struct DevBase *base)
456 BOOL success;
458 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
459 if(base->prometheus_base != NULL)
460 success = AddPrometheusIntServer(card, interrupt, base);
461 #endif
462 #ifdef __mc68000
463 if(base->powerpci_base != NULL)
464 success = AddPowerPCIIntServer(card, interrupt, base);
465 #endif
466 #ifdef __amigaos4__
467 if(base->expansion_base != NULL)
468 success = AddExpansionIntServer(card, interrupt, base);
469 #endif
470 #ifdef __MORPHOS__
471 if(base->openpci_base != NULL)
472 success = AddOpenPCIIntServer(card, interrupt, base);
473 #endif
475 return success;
480 /****i* etherlink3.device/RemPCIIntServer **********************************
482 * NAME
483 * RemPCIIntServer
485 * SYNOPSIS
486 * RemPCIIntServer()
488 * VOID RemPCIIntServer(ULONG);
490 ****************************************************************************
494 static VOID RemPCIIntServer(APTR card, struct Interrupt *interrupt,
495 struct DevBase *base)
497 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
498 if(base->prometheus_base != NULL)
499 RemPrometheusIntServer(card, interrupt, base);
500 #endif
501 #ifdef __mc68000
502 if(base->powerpci_base != NULL)
503 RemPowerPCIIntServer(card, interrupt, base);
504 #endif
505 #ifdef __amigaos4__
506 if(base->expansion_base != NULL)
507 RemExpansionIntServer(card, interrupt, base);
508 #endif
509 #ifdef __MORPHOS__
510 if(base->openpci_base != NULL)
511 RemOpenPCIIntServer(card, interrupt, base);
512 #endif
514 return;
519 /****i* etherlink3.device/IsCardCompatible *********************************
521 * NAME
522 * IsCardCompatible
524 * SYNOPSIS
525 * compatible = IsCardCompatible(vendor_id, product_id)
527 * BOOL IsCardCompatible(UWORD, UWORD);
529 ****************************************************************************
533 BOOL IsCardCompatible(UWORD vendor_id, UWORD product_id,
534 struct DevBase *base)
536 BOOL compatible = FALSE;
537 const UWORD *p;
539 for(p = product_codes; p[0] != 0xffff; p += 2)
541 if(p[0] == vendor_id && p[1] == product_id)
542 compatible = TRUE;
545 return compatible;
550 /****i* etherlink3.device/GetGeneration ************************************
552 * NAME
553 * GetGeneration
555 * SYNOPSIS
556 * generation = GetGeneration(product_id)
558 * UWORD GetGeneration(UWORD);
560 ****************************************************************************
564 UWORD GetGeneration(UWORD product_id, struct DevBase *base)
566 UWORD generation;
568 switch(product_id)
570 case 0x5900:
571 case 0x5950:
572 case 0x5951:
573 case 0x5952:
574 generation = VORTEX_GEN;
575 break;
576 case 0x9000:
577 case 0x9050:
578 case 0x9051:
579 generation = BOOMERANG_GEN;
580 break;
581 case 0x9004:
582 case 0x9005:
583 case 0x9006:
584 case 0x900a:
585 case 0x9055:
586 case 0x9056:
587 case 0x9058:
588 case 0x905a:
589 case 0x9800:
590 case 0x9805:
591 generation = CYCLONE_GEN;
592 break;
593 default:
594 generation = TORNADO_GEN;
597 return generation;
602 /****i* etherlink3.device/ByteInHook ***************************************
604 * NAME
605 * ByteInHook
607 * SYNOPSIS
608 * value = ByteInHook(context, offset)
610 * UBYTE ByteInHook(struct BusContext *, ULONG);
612 ****************************************************************************
616 static UBYTE ByteInHook(struct BusContext *context, ULONG offset)
618 return BYTEIN(context->io_base + offset);
623 /****i* etherlink3.device/LongInHook ***************************************
625 * NAME
626 * LongInHook
628 * SYNOPSIS
629 * value = LongInHook(context, offset)
631 * ULONG LongInHook(struct BusContext *, ULONG);
633 ****************************************************************************
637 static ULONG LongInHook(struct BusContext *context, ULONG offset)
639 return LONGIN(context->io_base + offset);
644 /****i* etherlink3.device/ByteOutHook **************************************
646 * NAME
647 * ByteOutHook
649 * SYNOPSIS
650 * ByteOutHook(context, offset, value)
652 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
654 ****************************************************************************
658 static VOID ByteOutHook(struct BusContext *context, ULONG offset,
659 UBYTE value)
661 BYTEOUT(context->io_base + offset, value);
663 return;
668 /****i* etherlink3.device/WordOutHook **************************************
670 * NAME
671 * WordOutHook
673 * SYNOPSIS
674 * WordOutHook(context, offset, value)
676 * VOID WordOutHook(struct BusContext *, ULONG, UWORD);
678 ****************************************************************************
682 static VOID WordOutHook(struct BusContext *context, ULONG offset,
683 UWORD value)
685 WORDOUT(context->io_base + offset, value);
687 return;
692 /****i* etherlink3.device/LongOutHook **************************************
694 * NAME
695 * LongOutHook
697 * SYNOPSIS
698 * LongOutHook(context, offset, value)
700 * VOID LongOutHook(struct BusContext *, ULONG, ULONG);
702 ****************************************************************************
706 static VOID LongOutHook(struct BusContext *context, ULONG offset,
707 ULONG value)
709 LONGOUT(context->io_base + offset, value);
711 return;
716 /****i* etherlink3.device/LongsInHook **************************************
718 * NAME
719 * LongsInHook
721 * SYNOPSIS
722 * LongsInHook(context, offset, buffer, count)
724 * VOID LongsInHook(struct BusContext *, ULONG, ULONG *, ULONG);
726 ****************************************************************************
730 static VOID LongsInHook(struct BusContext *context, ULONG offset,
731 ULONG *buffer, ULONG count)
733 LONGSIN(context->io_base + offset, buffer, count);
735 return;
740 /****i* etherlink3.device/LongsOutHook *************************************
742 * NAME
743 * LongsOutHook
745 * SYNOPSIS
746 * LongsOutHook(context, offset, buffer, count)
748 * VOID LongsOutHook(struct BusContext *, ULONG, const ULONG *, ULONG);
750 ****************************************************************************
754 static VOID LongsOutHook(struct BusContext *context, ULONG offset,
755 const ULONG *buffer, ULONG count)
757 LONGSOUT(context->io_base + offset, buffer, count);
759 return;
764 /****i* etherlink3.device/BEWordOutHook ************************************
766 * NAME
767 * BEWordOutHook
769 * SYNOPSIS
770 * BEWordOutHook(context, offset, value)
772 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
774 ****************************************************************************
778 static VOID BEWordOutHook(struct BusContext *context, ULONG offset,
779 UWORD value)
781 BEWORDOUT(context->io_base + offset, value);
783 return;
788 /****i* etherlink3.device/LEWordInHook *************************************
790 * NAME
791 * LEWordInHook
793 * SYNOPSIS
794 * value = LEWordInHook(context, offset)
796 * UWORD LEWordInHook(struct BusContext *, ULONG);
798 ****************************************************************************
802 static UWORD LEWordInHook(struct BusContext *context, ULONG offset)
804 return LEWORDIN(context->io_base + offset);
809 /****i* etherlink3.device/LELongInHook *************************************
811 * NAME
812 * LELongInHook
814 * SYNOPSIS
815 * value = LELongInHook(context, offset)
817 * ULONG LELongInHook(struct BusContext *, ULONG);
819 ****************************************************************************
823 static ULONG LELongInHook(struct BusContext *context, ULONG offset)
825 return LELONGIN(context->io_base + offset);
830 /****i* etherlink3.device/LEWordOutHook ************************************
832 * NAME
833 * LEWordOutHook
835 * SYNOPSIS
836 * LEWordOutHook(context, offset, value)
838 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
840 ****************************************************************************
844 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
845 UWORD value)
847 LEWORDOUT(context->io_base + offset, value);
849 return;
854 /****i* etherlink3.device/LELongOutHook ************************************
856 * NAME
857 * LELongOutHook
859 * SYNOPSIS
860 * LELongOutHook(context, offset, value)
862 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
864 ****************************************************************************
868 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
869 ULONG value)
871 LELONGOUT(context->io_base + offset, value);
873 return;
878 /****i* etherlink3.device/AllocDMAMemHook **********************************
880 * NAME
881 * AllocDMAMemHook
883 * SYNOPSIS
884 * mem = AllocDMAMemHook(context, size, alignment)
886 * APTR AllocDMAMemHook(struct BusContext *, UPINT, UWORD);
888 ****************************************************************************
890 * Alignment currently must be minimum of 8 bytes.
894 static APTR AllocDMAMemHook(struct BusContext *context, UPINT size,
895 UWORD alignment)
897 struct DevBase *base;
898 APTR mem = NULL, original_mem;
900 base = context->device;
901 size += 2 * sizeof(APTR) + alignment;
902 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
903 if(base->prometheus_base != NULL)
904 original_mem = AllocPrometheusDMAMem(size, base);
905 else
906 #endif
907 original_mem = AllocMem(size, MEMF_PUBLIC);
908 if(original_mem != NULL)
910 mem = (APTR)((UPINT)(original_mem + 2 * sizeof(APTR) + alignment - 1)
911 & ~(alignment - 1));
912 *((APTR *)mem - 1) = original_mem;
913 *((UPINT *)mem - 2) = size;
916 return mem;
921 /****i* etherlink3.device/FreeDMAMemHook ***********************************
923 * NAME
924 * FreeDMAMemHook
926 * SYNOPSIS
927 * FreeDMAMemHook(context, mem)
929 * VOID FreeDMAMemHook(struct BusContext *, APTR);
931 ****************************************************************************
935 static VOID FreeDMAMemHook(struct BusContext *context, APTR mem)
937 struct DevBase *base;
939 base = context->device;
940 if(mem != NULL)
942 #if !(defined(__MORPHOS__) || defined(__amigaos4__))
943 if(base->prometheus_base != NULL)
944 FreePrometheusDMAMem(*((APTR *)mem - 1), *((UPINT *)mem - 2),
945 base);
946 else
947 #endif
948 FreeMem(*((APTR *)mem - 1), *((UPINT *)mem - 2));
951 return;