Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / etherlink3 / device.c
blob037ba7f87f298927c4a22f81bed9d1e214d652ad
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 <exec/resident.h>
25 #include <exec/errors.h>
26 #include <utility/utility.h>
27 #include "initializers.h"
29 #include <proto/exec.h>
30 /*#include <proto/alib.h>*/
31 #include <clib/alib_protos.h>
32 #include <proto/utility.h>
34 #include "device.h"
36 #include "device_protos.h"
37 #include "pci_protos.h"
38 #include "pccard_protos.h"
39 #include "request_protos.h"
42 /* Private prototypes */
44 static struct DevBase *DevInit(REG(d0, struct DevBase *dev_base),
45 REG(a0, APTR seg_list), REG(BASE_REG, struct DevBase *base));
46 static APTR DevExpunge(REG(BASE_REG, struct DevBase *base));
47 static APTR DevReserved();
48 static VOID DeleteDevice(struct DevBase *base);
51 /* Return an error immediately if someone tries to run the device */
53 LONG Main()
55 return -1;
59 const TEXT device_name[] = DEVICE_NAME;
60 const TEXT version_string[] =
61 DEVICE_NAME " " STR(VERSION) "." STR(REVISION) " (" DATE ")\n";
62 const TEXT utility_name[] = UTILITYNAME;
63 static const TEXT prometheus_name[] = "prometheus.library";
64 static const TEXT powerpci_name[] = "powerpci.library";
65 const TEXT pccard_name[] = "pccard.library";
66 const TEXT card_name[] = "card.resource";
67 const TEXT timer_name[] = TIMERNAME;
70 static const APTR vectors[] =
72 (APTR)DevOpen,
73 (APTR)DevClose,
74 (APTR)DevExpunge,
75 (APTR)DevReserved,
76 (APTR)DevBeginIO,
77 (APTR)DevAbortIO,
78 (APTR)-1
82 #ifdef __MORPHOS__
83 #pragma pack(2)
84 #endif
85 static const struct
87 SMALLINITBYTEDEF(type);
88 SMALLINITPINTDEF(name);
89 SMALLINITBYTEDEF(flags);
90 SMALLINITWORDDEF(version);
91 SMALLINITWORDDEF(revision);
92 SMALLINITPINTDEF(id_string);
93 INITENDDEF;
95 init_data =
97 SMALLINITBYTE(OFFSET(Node, ln_Type), NT_DEVICE),
98 SMALLINITPINT(OFFSET(Node, ln_Name), device_name),
99 SMALLINITBYTE(OFFSET(Library, lib_Flags), LIBF_SUMUSED | LIBF_CHANGED),
100 SMALLINITWORD(OFFSET(Library, lib_Version), VERSION),
101 SMALLINITWORD(OFFSET(Library, lib_Revision), REVISION),
102 SMALLINITPINT(OFFSET(Library, lib_IdString), version_string),
103 INITEND
105 #ifdef __MORPHOS__
106 #pragma pack()
107 #endif
110 static const APTR init_table[] =
112 (APTR)sizeof(struct DevBase),
113 (APTR)vectors,
114 (APTR)&init_data,
115 (APTR)DevInit
119 const struct Resident rom_tag =
121 RTC_MATCHWORD,
122 (struct Resident *)&rom_tag,
123 (APTR)(&rom_tag + 1),
124 RTF_AUTOINIT,
125 VERSION,
126 NT_DEVICE,
128 (STRPTR)device_name,
129 (STRPTR)version_string,
130 (APTR)init_table
134 static const ULONG rx_tags[] =
136 S2_CopyToBuff,
137 S2_CopyToBuff16,
141 static const ULONG tx_tags[] =
143 S2_CopyFromBuff,
144 S2_CopyFromBuff16,
145 S2_CopyFromBuff32
150 /****i* etherlink3.device/DevInit ******************************************
152 * NAME
153 * DevInit
155 * SYNOPSIS
156 * dev_base = DevInit(dev_base, seg_list)
158 * struct DevBase *DevInit(struct DevBase *, APTR);
160 ****************************************************************************
164 static struct DevBase *DevInit(REG(d0, struct DevBase *dev_base),
165 REG(a0, APTR seg_list), REG(BASE_REG, struct DevBase *base))
167 BOOL success = TRUE;
169 /* Initialise base structure */
171 dev_base->sys_base = (APTR)base;
172 base = dev_base;
173 base->seg_list = seg_list;
174 NewList((APTR)(&base->pci_units));
175 NewList((APTR)(&base->isa_units));
176 NewList((APTR)(&base->pccard_units));
178 /* Open libraries, resources and devices */
180 base->utility_base = (APTR)OpenLibrary(utility_name, UTILITY_VERSION);
181 base->prometheus_base = OpenLibrary(prometheus_name, PROMETHEUS_VERSION);
182 if(base->prometheus_base == NULL)
183 base->powerpci_base = OpenLibrary(powerpci_name, POWERPCI_VERSION);
184 #ifdef __MORPHOS__
185 base->openpci_base = OpenLibrary(openpci_name, OPENPCI_VERSION);
186 #endif
187 base->pccard_base = OpenLibrary(pccard_name, PCCARD_VERSION);
188 if(base->pccard_base != NULL)
189 base->card_base = OpenResource(card_name);
191 if(base->utility_base == NULL || base->prometheus_base == NULL
192 && base->powerpci_base == NULL && base->openpci_base == NULL
193 && (base->pccard_base == NULL || base->card_base == NULL))
194 success = FALSE;
196 if(OpenDevice(timer_name, UNIT_ECLOCK, (APTR)&base->timer_request, 0)
197 != 0)
198 success = FALSE;
200 #ifdef __MORPHOS__
201 base->wrapper_int_code = (APTR)&int_trap;
202 #endif
204 if(!success)
206 DeleteDevice(base);
207 base = NULL;
210 return base;
215 /****i* etherlink3.device/DevOpen ******************************************
217 * NAME
218 * DevOpen
220 * SYNOPSIS
221 * error = DevOpen(request, unit_num, flags)
223 * BYTE DevOpen(struct IOSana2Req *, ULONG, ULONG);
225 ****************************************************************************
229 BYTE DevOpen(REG(a1, struct IOSana2Req *request),
230 REG(d0, ULONG unit_num), REG(d1, ULONG flags),
231 REG(BASE_REG, struct DevBase *base))
233 struct DevUnit *unit;
234 BYTE error = 0;
235 struct Opener *opener;
236 struct TagItem *tag_list;
237 UWORD i;
239 base->device.dd_Library.lib_OpenCnt++;
240 base->device.dd_Library.lib_Flags &= ~LIBF_DELEXP;
242 request->ios2_Req.io_Unit = NULL;
243 tag_list = request->ios2_BufferManagement;
244 request->ios2_BufferManagement = NULL;
246 /* Check request size */
248 if(request->ios2_Req.io_Message.mn_Length < sizeof(struct IOSana2Req))
249 error = IOERR_OPENFAIL;
251 /* Get the requested unit */
253 if(error == 0)
255 request->ios2_Req.io_Unit = (APTR)(unit = GetUnit(unit_num, base));
256 if(unit == NULL)
257 error = IOERR_OPENFAIL;
260 /* Handle device sharing */
262 if(error == 0)
264 if(unit->open_count != 0 && ((unit->flags & UNITF_SHARED) == 0
265 || (flags & SANA2OPF_MINE) != 0))
266 error = IOERR_UNITBUSY;
267 unit->open_count++;
270 if(error == 0)
272 if((flags & SANA2OPF_MINE) == 0)
273 unit->flags |= UNITF_SHARED;
274 else if((flags & SANA2OPF_PROM) != 0)
275 unit->flags |= UNITF_PROM;
277 /* Set up buffer-management structure and get hooks */
279 request->ios2_BufferManagement = opener =
280 AllocVec(sizeof(struct Opener), MEMF_PUBLIC | MEMF_CLEAR);
281 if(opener == NULL)
282 error = IOERR_OPENFAIL;
285 if(error == 0)
287 NewList(&opener->read_port.mp_MsgList);
288 opener->read_port.mp_Flags = PA_IGNORE;
289 NewList((APTR)&opener->initial_stats);
291 for(i = 0; i < 2; i++)
292 opener->rx_function = (APTR)GetTagData(rx_tags[i],
293 (UPINT)opener->rx_function, tag_list);
294 for(i = 0; i < 3; i++)
295 opener->tx_function = (APTR)GetTagData(tx_tags[i],
296 (UPINT)opener->tx_function, tag_list);
298 opener->filter_hook = (APTR)GetTagData(S2_PacketFilter, (UPINT)NULL,
299 tag_list);
300 opener->dma_tx_function =
301 (APTR)GetTagData(S2_DMACopyFromBuff32, (UPINT)NULL, tag_list);
303 Disable();
304 AddTail((APTR)&unit->openers, (APTR)opener);
305 Enable();
308 /* Back out if anything went wrong */
310 if(error != 0)
311 CloseUnit(request, base);
313 /* Return */
315 request->ios2_Req.io_Error = error;
316 return error;
321 /****i* etherlink3.device/DevClose *****************************************
323 * NAME
324 * DevClose
326 * SYNOPSIS
327 * seg_list = DevClose(request)
329 * APTR DevClose(struct IOSana2Req *);
331 ****************************************************************************
335 APTR DevClose(REG(a1, struct IOSana2Req *request),
336 REG(BASE_REG, struct DevBase *base))
338 APTR seg_list = NULL;
340 /* Close the unit */
342 CloseUnit(request, base);
344 /* Expunge the device if a delayed expunge is pending */
346 if(base->device.dd_Library.lib_OpenCnt == 0)
348 if((base->device.dd_Library.lib_Flags & LIBF_DELEXP) != 0)
349 seg_list = DevExpunge(base);
352 return seg_list;
357 /****i* etherlink3.device/DevExpunge ***************************************
359 * NAME
360 * DevExpunge
362 * SYNOPSIS
363 * seg_list = DevExpunge()
365 * APTR DevExpunge(VOID);
367 ****************************************************************************
371 static APTR DevExpunge(REG(BASE_REG, struct DevBase *base))
373 APTR seg_list;
375 if(base->device.dd_Library.lib_OpenCnt == 0)
377 seg_list = base->seg_list;
378 Remove((APTR)base);
379 DeleteDevice(base);
381 else
383 base->device.dd_Library.lib_Flags |= LIBF_DELEXP;
384 seg_list = NULL;
387 return seg_list;
392 /****i* etherlink3.device/DevReserved **************************************
394 * NAME
395 * DevReserved
397 * SYNOPSIS
398 * result = DevReserved()
400 * APTR DevReserved(VOID);
402 ****************************************************************************
406 static APTR DevReserved()
408 return NULL;
413 /****i* etherlink3.device/DevBeginIO ***************************************
415 * NAME
416 * DevBeginIO
418 * SYNOPSIS
419 * DevBeginIO(request)
421 * VOID DevBeginIO(struct IORequest *);
423 ****************************************************************************
427 VOID DevBeginIO(REG(a1, struct IOSana2Req *request),
428 REG(BASE_REG, struct DevBase *base))
430 struct DevUnit *unit;
432 request->ios2_Req.io_Error = 0;
433 unit = (APTR)request->ios2_Req.io_Unit;
435 if(AttemptSemaphore(&unit->access_lock))
436 ServiceRequest(request, base);
437 else
438 PutRequest(unit->request_ports[GENERAL_QUEUE], (APTR)request, base);
440 return;
445 /****i* etherlink3.device/DevAbortIO ***************************************
447 * NAME
448 * DevAbortIO -- Try to stop a request.
450 * SYNOPSIS
451 * DevAbortIO(request)
453 * VOID DevAbortIO(struct IOSana2Req *);
455 * FUNCTION
456 * Do our best to halt the progress of a request.
458 ****************************************************************************
460 * Disable() used instead of a semaphore because device uses interrupts.
464 VOID DevAbortIO(REG(a1, struct IOSana2Req *request),
465 REG(BASE_REG, struct DevBase *base))
467 struct DevUnit *unit;
469 unit = (APTR)request->ios2_Req.io_Unit;
471 Disable();
472 if(request->ios2_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE &&
473 (request->ios2_Req.io_Flags & IOF_QUICK) == 0)
475 Remove((APTR)request);
476 request->ios2_Req.io_Error = IOERR_ABORTED;
477 request->ios2_WireError = S2WERR_GENERIC_ERROR;
478 ReplyMsg((APTR)request);
480 Enable();
482 return;
487 /****i* etherlink3.device/DeleteDevice *************************************
489 * NAME
490 * DeleteDevice
492 * SYNOPSIS
493 * DeleteDevice()
495 * VOID DeleteDevice(VOID);
497 ****************************************************************************
501 VOID DeleteDevice(struct DevBase *base)
503 UWORD neg_size, pos_size;
505 /* Close devices */
507 CloseDevice((APTR)&base->timer_request);
509 /* Close libraries */
511 if(base->openpci_base != NULL)
512 CloseLibrary(base->openpci_base);
513 if(base->pccard_base != NULL)
514 CloseLibrary(base->pccard_base);
515 if(base->powerpci_base != NULL)
516 CloseLibrary(base->powerpci_base);
517 if(base->prometheus_base != NULL)
518 CloseLibrary(base->prometheus_base);
519 if(base->utility_base != NULL)
520 CloseLibrary((APTR)base->utility_base);
522 /* Free device's memory */
524 neg_size = base->device.dd_Library.lib_NegSize;
525 pos_size = base->device.dd_Library.lib_PosSize;
526 FreeMem((UBYTE *)base - neg_size, pos_size + neg_size);
528 return;
533 /****i* etherlink3.device/CloseUnit ****************************************
535 * NAME
536 * CloseUnit
538 * SYNOPSIS
539 * CloseUnit(request)
541 * VOID CloseUnit(struct IOSana2Req *);
543 ****************************************************************************
547 VOID CloseUnit(struct IOSana2Req *request, struct DevBase *base)
549 struct DevUnit *unit;
550 struct Opener *opener;
552 /* Free buffer-management resources */
554 base->device.dd_Library.lib_OpenCnt--;
555 opener = (APTR)request->ios2_BufferManagement;
556 if(opener != NULL)
558 Disable();
559 Remove((APTR)opener);
560 Enable();
561 FreeVec(opener);
564 /* Delete the unit if it's no longer in use */
566 unit = (APTR)request->ios2_Req.io_Unit;
567 if(unit != NULL)
569 if((--unit->open_count) == 0)
571 Remove((APTR)unit);
572 switch(unit->bus)
574 case PCI_BUS:
575 DeletePCIUnit(unit, base);
576 break;
577 #ifndef __AROS__
578 case PCCARD_BUS:
579 DeletePCCardUnit(unit, base);
580 break;
581 #endif
586 return;
591 /****i* etherlink3.device/GetUnit ******************************************
593 * NAME
594 * GetUnit -- Get a unit by number.
596 * SYNOPSIS
597 * unit = GetUnit(unit_num)
599 * struct DevUnit *GetUnit(ULONG);
601 ****************************************************************************
605 struct DevUnit *GetUnit(ULONG unit_num, struct DevBase *base)
607 struct DevUnit *unit;
608 ULONG pci_limit, pccard_limit;
610 pci_limit = GetPCICount(base);
611 #ifndef __AROS__
612 pccard_limit = pci_limit + GetPCCardCount(base);
613 #endif
615 if(unit_num < pci_limit)
616 unit = GetPCIUnit(unit_num, base);
617 #ifndef __AROS__
618 else if(unit_num < pccard_limit)
619 unit = GetPCCardUnit(unit_num - pci_limit, base);
620 #endif
621 else
622 unit = NULL;
624 return unit;
629 /****i* etherlink3.device/WrapInt ******************************************
631 * NAME
632 * WrapInt
634 ****************************************************************************
638 BOOL WrapInt(struct Interrupt *interrupt, struct DevBase *base)
640 BOOL success = TRUE;
641 #if defined(__amigaos4__) || defined(__MORPHOS__)
642 APTR *int_data;
644 int_data = AllocMem(2 * sizeof(APTR), MEMF_PUBLIC | MEMF_CLEAR);
645 if(int_data != NULL)
647 int_data[0] = interrupt->is_Code;
648 int_data[1] = interrupt->is_Data;
649 interrupt->is_Code = base->wrapper_int_code;
650 interrupt->is_Data = int_data;
652 else
653 success = FALSE;
654 #endif
656 return success;
661 /****i* etherlink3.device/UnwrapInt ****************************************
663 * NAME
664 * UnwrapInt
666 ****************************************************************************
670 VOID UnwrapInt(struct Interrupt *interrupt, struct DevBase *base)
672 if(interrupt->is_Code == base->wrapper_int_code)
673 FreeMem(interrupt->is_Data, 2 * sizeof(APTR));
675 return;