Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / etherlink3 / isa.c
blob9fd1eb2561619fdaa4e9a152ed602604648354ff
1 /*
3 Copyright (C) 2000-2006 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/utility.h>*/
25 #include <libraries/isapnp.h>
27 #include <proto/exec.h>
28 #include <proto/utility.h>
29 #include <proto/isapnp.h>
31 #include "device.h"
33 #include "isa_protos.h"
34 #include "unit_protos.h"
37 struct BusContext
39 struct DevUnit *unit;
40 struct ISAPNP_Device *card;
41 UPINT io_base;
42 APTR lock;
46 /* Private prototypes */
48 static struct DevUnit *FindISAUnit(ULONG index, struct DevBase *base);
49 static struct DevUnit *CreateISAUnit(ULONG index, struct DevBase *base);
50 static struct BusContext *AllocCard(ULONG index, struct DevBase *base);
51 static VOID FreeCard(struct BusContext *card, struct DevBase *base);
52 static BOOL IsCardCompatible(struct ISAPNP_Device *card,
53 struct DevBase *base);
54 /*static BOOL InitialiseCard(struct BusContext *card, 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);
77 static const UWORD product_codes[] =
79 0x6d50, 0x5090,
80 0x6d50, 0x5091,
81 0x6d50, 0x5094,
82 0x6d50, 0x5095,
83 0x6d50, 0x5098,
84 /* 'PNP', 0x80f7,
85 'PNP', 0x80f8,*/
90 static const struct TagItem unit_tags[] =
92 {IOTAG_ByteIn, (UPINT)ByteInHook},
93 {IOTAG_LongIn, (UPINT)LongInHook},
94 {IOTAG_ByteOut, (UPINT)ByteOutHook},
95 {IOTAG_WordOut, (UPINT)WordOutHook},
96 {IOTAG_LongOut, (UPINT)LongOutHook},
97 {IOTAG_LongsIn, (UPINT)LongsInHook},
98 {IOTAG_LongsOut, (UPINT)LongsOutHook},
99 {IOTAG_BEWordOut, (UPINT)BEWordOutHook},
100 {IOTAG_LEWordIn, (UPINT)LEWordInHook},
101 {IOTAG_LELongIn, (UPINT)LELongInHook},
102 {IOTAG_LEWordOut, (UPINT)LEWordOutHook},
103 {IOTAG_LELongOut, (UPINT)LELongOutHook},
104 {TAG_END, 0}
108 /****i* etherlink3.device/GetISACount **************************************
110 * NAME
111 * GetISACount -- Get the number of compatible ISA cards.
113 * SYNOPSIS
114 * count = GetISACount()
116 * ULONG GetISACount();
118 ****************************************************************************
122 ULONG GetISACount(struct DevBase *base)
124 ULONG count = 0;
125 struct ISAPNP_Device *card = NULL;
127 while((card = ISAPNP_FindDevice(card, -1, -1, -1)) != NULL)
129 if(IsCardCompatible(card, base))
130 count++;
133 return count;
138 /****i* etherlink3.device/GetISAUnit ***************************************
140 * NAME
141 * GetISAUnit -- Get a unit by number.
143 * SYNOPSIS
144 * unit = GetISAUnit(index)
146 * struct DevUnit *GetISAUnit(ULONG);
148 ****************************************************************************
152 struct DevUnit *GetISAUnit(ULONG index, struct DevBase *base)
154 struct DevUnit *unit;
155 struct BusContext *card;
157 unit = FindISAUnit(index, base);
159 if(unit == NULL)
161 card = CreateISAUnit(index, base);
162 if(card != NULL)
164 unit = card->unit;
165 AddTail((APTR)&base->isa_units, (APTR)unit);
169 return unit;
174 /****i* etherlink3.device/FindISAUnit **************************************
176 * NAME
177 * FindISAUnit -- Find an existing unit by number.
179 * SYNOPSIS
180 * unit = FindISAUnit(index)
182 * struct DevUnit *FindISAUnit(ULONG);
184 ****************************************************************************
188 static struct DevUnit *FindISAUnit(ULONG index, struct DevBase *base)
190 struct DevUnit *unit, *tail;
191 BOOL found = FALSE;
193 unit = (APTR)base->isa_units.mlh_Head;
194 tail = (APTR)&base->isa_units.mlh_Tail;
196 while(unit != tail && !found)
198 if(unit->index == index)
199 found = TRUE;
200 else
201 unit = (APTR)unit->node.mln_Succ;
204 if(!found)
205 unit = NULL;
207 return unit;
212 /****i* etherlink3.device/CreateISAUnit ************************************
214 * NAME
215 * CreateISAUnit -- Create an ISA unit.
217 * SYNOPSIS
218 * unit = CreateISAUnit(index)
220 * struct DevUnit *CreateISAUnit(ULONG);
222 * FUNCTION
223 * Creates a new ISA unit.
225 ****************************************************************************
229 struct DevUnit *CreateISAUnit(ULONG index, struct DevBase *base)
231 BOOL success = TRUE;
232 struct BusContext *context;
233 struct DevUnit *unit;
234 UWORD generation, id, i;
235 UPINT io_base, id_port;
237 context = AllocCard(index, base);
238 if(context == NULL)
239 success = FALSE;
243 #if 0 /* Stuff below is for non-PnP only? */
245 /* Send initialisation ID sequence */
247 id_port = 0xef0100; /* !!! */
248 BYTEOUT(id_port, 0);
249 BYTEOUT(id_port, 0);
251 id = 0xff;
252 for(i = 0; i < 0xff; i++)
254 BYTEOUT(id_port, (UBYTE)id);
255 id <<= 1;
256 if ((id & 0x100) != 0)
257 id ^= 0xcf;
260 /* Activate adapter */
262 BYTEOUT(id_port, 0xff);
264 io_base = 0xef0300;
265 generation = FIRST_GEN;
266 #endif
269 if(success)
271 generation = SECOND_GEN;
272 unit = CreateUnit(unit_num, NULL, io_base, generation, ISA_BUS, base);
273 if(unit == NULL)
274 success = FALSE;
277 /* Add interrupt */
279 if(success)
280 AddIntServer(x, &unit->status_int);
282 if(!success)
284 DeleteISAUnit(unit, base);
285 unit = NULL;
288 return unit;
293 /****i* etherlink3.device/DeleteISAUnit ************************************
295 * NAME
296 * DeleteISAUnit -- Delete a unit.
298 * SYNOPSIS
299 * DeleteISAUnit(unit)
301 * VOID DeleteISAUnit(struct DevUnit *);
303 * FUNCTION
304 * Deletes a unit.
306 * INPUTS
307 * unit - Device unit (can be NULL).
309 * RESULT
310 * None.
312 ****************************************************************************
316 VOID DeleteISAUnit(struct DevUnit *unit, struct DevBase *base)
318 if(unit != NULL)
320 RemIntServer(x, &unit->status_int);
321 DeleteUnit(unit, base);
324 return;
329 /****i* etherlink3.device/AllocCard ****************************************
331 * NAME
332 * AllocCard -- Get card from system.
334 * SYNOPSIS
335 * unit = AllocCard()
337 * struct BusContext *AllocCard();
339 ****************************************************************************
343 static struct BusContext *AllocCard(ULONG index, struct DevBase *base)
345 BOOL success = TRUE;
346 struct BusContext *context;
347 struct ISAPNP_Device *card = NULL;
348 ULONG i;
350 /* Find a compatible card */
352 card = AllocMem(sizeof(struct BusContext), MEMF_PUBLIC | MEMF_CLEAR);
353 if(card == NULL)
354 success = FALSE;
356 if(success)
358 while(i <= index)
360 card = ISAPNP_FindDevice(card, -1, -1, -1);
361 if(IsCardCompatible(card, base))
362 i++;
364 context->card = card;
367 /* Get base address */
369 if(success)
373 /* Lock card */
375 if(success)
377 context->lock = ISAPNP_LockDevices(ISAPNP_LOCKF_NONE, card);
378 if(context->lock == NULL)
379 success = FALSE;
382 if(!success)
384 FreeCard(context, base);
387 return card;
392 /****i* etherlink3.device/FreeCard *****************************************
394 * NAME
395 * FreeCard
397 ****************************************************************************
401 static VOID FreeCard(struct BusContext *context, struct DevBase *base)
403 struct ISAPNP_Device *card = NULL;
405 if(context != NULL)
407 /* Unlock card */
409 ISAPNP_UnlockDevices(context->lock);
411 FreeMem(context, sizeof(struct BusContext));
414 return;
419 /****i* etherlink3.device/IsCardCompatible *********************************
421 * NAME
422 * IsCardCompatible
424 * SYNOPSIS
425 * compatible = IsCardCompatible(card)
427 * BOOL IsCardCompatible(struct ISAPNP_Device *);
429 ****************************************************************************
433 static BOOL IsCardCompatible(struct ISAPNP_Device *card,
434 struct DevBase *base)
436 struct ISAPNP_Identifier *id, *tail;
437 BOOL compatible = FALSE;
438 const UWORD *p;
440 id = (APTR)card->isapnpd_IDs.mlh_Head;
441 tail = (APTR)&card->isapnpd_IDs.mlh_Tail;
443 while(id != tail)
445 vendor_id =
446 ISAPNP_MAKE_ID(id->isapnpid_Vendor[0], id->isapnpid_Vendor[1],
447 id->isapnpid_Vendor[2]);
448 product_id = id->isapnpid_ProductID;
450 for(p = product_codes; p[0] != 0; p += 2)
452 if(p[0] == vendor_id && p[1] == product_id)
453 compatible = TRUE;
456 id = (APTR)id->isapnpid_MinNode.mln_Succ;
459 return compatible;
464 /****i* etherlink3.device/ByteInHook ***************************************
466 * NAME
467 * ByteInHook
469 * SYNOPSIS
470 * value = ByteInHook(context, offset)
472 * UBYTE ByteInHook(struct BusContext *, ULONG);
474 ****************************************************************************
478 static UBYTE ByteInHook(struct BusContext *context, ULONG offset)
480 return BYTEIN(context->io_base + offset);
485 /****i* etherlink3.device/LongInHook ***************************************
487 * NAME
488 * LongInHook
490 * SYNOPSIS
491 * value = LongInHook(context, offset)
493 * ULONG LongInHook(struct BusContext *, ULONG);
495 ****************************************************************************
499 static ULONG LongInHook(struct BusContext *context, ULONG offset)
501 return LONGIN(context->io_base + offset);
506 /****i* etherlink3.device/ByteOutHook **************************************
508 * NAME
509 * ByteOutHook
511 * SYNOPSIS
512 * ByteOutHook(context, offset, value)
514 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
516 ****************************************************************************
520 static VOID ByteOutHook(struct BusContext *context, ULONG offset,
521 UBYTE value)
523 BYTEOUT(context->io_base + offset, value);
525 return;
530 /****i* etherlink3.device/WordOutHook **************************************
532 * NAME
533 * WordOutHook
535 * SYNOPSIS
536 * WordOutHook(context, offset, value)
538 * VOID WordOutHook(struct BusContext *, ULONG, UWORD);
540 ****************************************************************************
544 static VOID WordOutHook(struct BusContext *context, ULONG offset,
545 UWORD value)
547 WORDOUT(context->io_base + offset, value);
549 return;
554 /****i* etherlink3.device/LongOutHook **************************************
556 * NAME
557 * LongOutHook
559 * SYNOPSIS
560 * LongOutHook(context, offset, value)
562 * VOID LongOutHook(struct BusContext *, ULONG, ULONG);
564 ****************************************************************************
568 static VOID LongOutHook(struct BusContext *context, ULONG offset,
569 ULONG value)
571 LONGOUT(context->io_base + offset, value);
573 return;
578 /****i* etherlink3.device/LongsInHook **************************************
580 * NAME
581 * LongsInHook
583 * SYNOPSIS
584 * LongsInHook(context, offset, buffer, count)
586 * VOID LongsInHook(struct BusContext *, ULONG, ULONG *, ULONG);
588 ****************************************************************************
592 static VOID LongsInHook(struct BusContext *context, ULONG offset,
593 ULONG *buffer, ULONG count)
595 LONGSIN(context->io_base + offset, buffer, count);
597 return;
602 /****i* etherlink3.device/LongsOutHook *************************************
604 * NAME
605 * LongsOutHook
607 * SYNOPSIS
608 * LongsOutHook(context, offset, buffer, count)
610 * VOID LongsOutHook(struct BusContext *, ULONG, const ULONG *, ULONG);
612 ****************************************************************************
616 static VOID LongsOutHook(struct BusContext *context, ULONG offset,
617 const ULONG *buffer, ULONG count)
619 LONGSOUT(context->io_base + offset, buffer, count);
621 return;
626 /****i* etherlink3.device/BEWordOutHook ************************************
628 * NAME
629 * BEWordOutHook
631 * SYNOPSIS
632 * BEWordOutHook(context, offset, value)
634 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
636 ****************************************************************************
640 static VOID BEWordOutHook(struct BusContext *context, ULONG offset,
641 UWORD value)
643 BEWORDOUT(context->io_base + offset, value);
645 return;
650 /****i* etherlink3.device/LEWordInHook *************************************
652 * NAME
653 * LEWordInHook
655 * SYNOPSIS
656 * value = LEWordInHook(context, offset)
658 * UWORD LEWordInHook(struct BusContext *, ULONG);
660 ****************************************************************************
664 static UWORD LEWordInHook(struct BusContext *context, ULONG offset)
666 return LEWORDIN(context->io_base + offset);
671 /****i* etherlink3.device/LELongInHook ***************************************
673 * NAME
674 * LELongInHook
676 * SYNOPSIS
677 * value = LELongInHook(context, offset)
679 * ULONG LELongInHook(struct BusContext *, ULONG);
681 ****************************************************************************
685 static ULONG LELongInHook(struct BusContext *context, ULONG offset)
687 return LELONGIN(context->io_base + offset);
692 /****i* etherlink3.device/LEWordOutHook ************************************
694 * NAME
695 * LEWordOutHook
697 * SYNOPSIS
698 * LEWordOutHook(context, offset, value)
700 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
702 ****************************************************************************
706 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
707 UWORD value)
709 LEWORDOUT(context->io_base + offset, value);
711 return;
716 /****i* etherlink3.device/LELongOutHook ************************************
718 * NAME
719 * LELongOutHook
721 * SYNOPSIS
722 * LELongOutHook(context, offset, value)
724 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
726 ****************************************************************************
730 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
731 ULONG value)
733 LELONGOUT(context->io_base + offset, value);
735 return;