Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / common / ata.device / ata_init.c
blob6c602cd80309a7cfea007dcfa183d5332c9d8473
1 /*
2 Copyright © 2004-2009, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
8 /*
9 * PARTIAL CHANGELOG:
10 * DATE NAME ENTRY
11 * ---------- ------------------ -------------------------------------------------------------------
12 * 2008-04-25 P. Fedin Brought back device discovery for old machines without PCI IDE controllers
13 * 2008-01-25 T. Wiszkowski Rebuilt, rearranged and partially fixed 60% of the code here
14 * Enabled implementation to scan for other PCI IDE controllers
15 * Implemented ATAPI Packet Support for both read and write
16 * Corrected ATAPI DMA handling
17 * Fixed major IDE enumeration bugs severely handicapping transfers with more than one controller
18 * Compacted source and implemented major ATA support procedure
19 * Improved DMA and Interrupt management
20 * Removed obsolete code
21 * 2008-01-26 T. Wiszkowski Added 'nodma' flag for ata driver
22 * Moved variables out of global scope
23 * Replaced static variables
24 * 2008-02-08 T. Wiszkowski Fixed DMA accesses for direct scsi devices,
25 * Corrected IO Areas to allow ATA to talk to PCI controllers
26 * 2008-02-24 T. Wiszkowski Corrected unit open function
27 * 2008-03-03 T. Wiszkowski Added drive reselection + setup delay on Init
28 * 2008-03-23 T. Wiszkowski Corrected Alternative Command block position
29 * 2008-03-30 T. Wiszkowski Added workaround for interrupt collision handling; fixed SATA in LEGACY mode.
30 * nForce and Intel SATA chipsets should now be operational.
31 * 2008-04-03 T. Wiszkowski Fixed IRQ flood issue, eliminated and reduced obsolete / redundant code
32 * 2008-04-07 T. Wiszkowski Changed bus timeout mechanism
33 * 2008-04-07 M. Schulz The SiL3114 chip yields Class 0x01 and SubClass 0x80. Therefore it will
34 * not be find with the generic enumeration. Do an explicit search after it
35 * since ata.device may handle it in legacy mode without any issues.
36 * 2008-05-11 T. Wiszkowski Remade the ata trannsfers altogether, corrected the pio/irq handling
37 * medium removal, device detection, bus management and much more
38 * 2008-05-18 T. Wiszkowski corrected device naming to handle cases where more than 10 physical units may be available
39 * 2008-06-24 P. Fedin Added 'NoMulti' flag to disable multisector transfers
40 * 2009-03-05 T. Wiszkowski remade timeouts, added timer-based and benchmark-based delays.
43 #define DEBUG 0
44 #include <aros/debug.h>
46 #include <aros/symbolsets.h>
48 #include <exec/types.h>
49 #include <exec/exec.h>
50 #include <exec/resident.h>
51 #include <exec/tasks.h>
52 #include <exec/memory.h>
53 #include <exec/nodes.h>
54 #include <utility/utility.h>
55 #include <oop/oop.h>
56 #include <libraries/expansion.h>
57 #include <libraries/configvars.h>
59 #include <dos/bptr.h>
60 #include <dos/filehandler.h>
61 #include <string.h>
63 #include <proto/exec.h>
64 #include <proto/timer.h>
65 #include <proto/bootloader.h>
66 #include <proto/expansion.h>
68 #include <oop/oop.h>
69 #include <hidd/pci.h>
70 #include <proto/oop.h>
72 #include "ata.h"
73 #include "timer.h"
75 #include LC_LIBDEFS_FILE
77 typedef struct
79 struct ataBase *ATABase;
80 UWORD CurrentBus;
81 } EnumeratorArgs;
83 struct ata_ProbedBus
85 struct Node atapb_Node;
86 IPTR atapb_IOBase;
87 IPTR atapb_IOAlt;
88 IPTR atapb_INTLine;
89 IPTR atapb_DMABase;
90 EnumeratorArgs *atapb_a;
91 BOOL atapb_Has80Wire;
94 struct ata_LegacyBus
96 struct Node atalb_Node;
97 IPTR atalb_IOBase;
98 IPTR atalb_IOAlt;
99 IPTR atalb_INTLine;
100 IPTR atalb_DMABase;
101 UBYTE atalb_ControllerID;
102 UBYTE atalb_BusID;
105 #define ATABUSNODEPRI_PROBED 0
106 #define ATABUSNODEPRI_PROBEDLEGACY 100
107 #define ATABUSNODEPRI_LEGACY 50
109 #define RANGESIZE0 8
110 #define RANGESIZE1 4
112 /* static list of io/irqs that we can handle */
113 static struct ata__legacybus
115 ULONG lb_Port;
116 ULONG lb_Alt;
117 UBYTE lb_IRQ;
118 UBYTE lb_ControllerID;
119 UBYTE lb_Bus;
120 } LegacyBuses[] =
122 {0x1f0, 0x3f4, 14, 0, 0},
123 {0x170, 0x374, 15, 0, 1},
124 {0x168, 0x36c, 10, 1, 0},
125 {0x1e8, 0x3ec, 11, 1, 1},
126 {0, 0, 0, 0, 0},
129 /* Add a bootnode using expansion.library */
130 BOOL ata_RegisterVolume(ULONG StartCyl, ULONG EndCyl, struct ata_Unit *unit)
132 struct ExpansionBase *ExpansionBase;
133 struct DeviceNode *devnode;
134 IPTR *pp;
135 TEXT dosdevname[4] = "HD0", *handler;
136 UWORD len;
138 ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",
139 40L);
141 if (ExpansionBase)
143 pp = AllocMem(24*sizeof(IPTR), MEMF_PUBLIC | MEMF_CLEAR);
145 if (pp)
147 /* This should be dealt with using some sort of volume manager or such. */
148 switch (unit->au_DevType)
150 case DG_DIRECT_ACCESS:
151 break;
152 case DG_CDROM:
153 dosdevname[0] = 'C';
154 break;
155 default:
156 D(bug("[ATA>>]:-ata_RegisterVolume called on unknown devicetype\n"));
159 if (unit->au_UnitNum < 10)
160 dosdevname[2] += unit->au_UnitNum % 10;
161 else
162 dosdevname[2] = 'A' - 10 + unit->au_UnitNum;
163 pp[0] = (IPTR)dosdevname;
164 pp[1] = (IPTR)MOD_NAME_STRING;
165 pp[2] = unit->au_UnitNum;
166 pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS;
167 pp[DE_SIZEBLOCK + 4] = 1 << (unit->au_SectorShift - 2);
168 pp[DE_NUMHEADS + 4] = unit->au_Heads;
169 pp[DE_SECSPERBLOCK + 4] = 1;
170 pp[DE_BLKSPERTRACK + 4] = unit->au_Sectors;
171 pp[DE_RESERVEDBLKS + 4] = 2;
172 pp[DE_LOWCYL + 4] = StartCyl;
173 pp[DE_HIGHCYL + 4] = EndCyl;
174 pp[DE_NUMBUFFERS + 4] = 10;
175 pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC | MEMF_CHIP;
176 pp[DE_MAXTRANSFER + 4] = 0x00200000;
177 pp[DE_MASK + 4] = 0x7FFFFFFE;
178 pp[DE_BOOTPRI + 4] = ((!unit->au_DevType) ? 0 : 10);
179 pp[DE_DOSTYPE + 4] = 0x444F5301;
180 pp[DE_BOOTBLOCKS + 4] = 2;
181 devnode = MakeDosNode(pp);
183 if (devnode)
185 if(unit->au_DevType == DG_DIRECT_ACCESS)
186 handler = "afs.handler";
187 else
188 handler = "cdrom.handler";
189 len = strlen(handler);
190 if ((devnode->dn_Handler =
191 MKBADDR(AllocMem(AROS_BSTR_MEMSIZE4LEN(len),
192 MEMF_PUBLIC | MEMF_CLEAR
197 CopyMem(handler, AROS_BSTR_ADDR(devnode->dn_Handler), len);
198 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
200 D(bug("[ATA>>]:-ata_RegisterVolume: '%s' with StartCyl=%d, EndCyl=%d .. ",
201 &(devnode->dn_Ext.dn_AROS.dn_DevName[0]), StartCyl, EndCyl));
202 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, 0);
203 D(bug("done\n"));
205 return TRUE;
210 CloseLibrary((struct Library *)ExpansionBase);
213 return FALSE;
216 static void ata_RegisterBus(IPTR IOBase, IPTR IOAlt, IPTR INTLine,
217 IPTR DMABase, BOOL has80Wire, EnumeratorArgs *a)
220 * ata bus - this is going to be created and linked to the master list here
222 struct ata_Bus *ab;
224 UWORD i;
227 * initialize structure
229 ab = (struct ata_Bus*) AllocVecPooled(a->ATABase->ata_MemPool, sizeof(struct ata_Bus));
230 if (ab == NULL)
231 return;
233 ab->ab_Base = a->ATABase;
234 ab->ab_Port = IOBase;
235 ab->ab_Alt = IOAlt;
236 ab->ab_IRQ = INTLine;
237 ab->ab_Dev[0] = DEV_NONE;
238 ab->ab_Dev[1] = DEV_NONE;
239 ab->ab_Flags = 0;
240 ab->ab_SleepySignal = 0;
241 ab->ab_BusNum = a->CurrentBus++;
242 ab->ab_Timeout = 0;
243 ab->ab_Units[0] = NULL;
244 ab->ab_Units[1] = NULL;
245 ab->ab_IntHandler = (HIDDT_IRQ_Handler *)AllocVecPooled(a->ATABase->ata_MemPool, sizeof(HIDDT_IRQ_Handler));
246 ab->ab_Task = NULL;
247 ab->ab_HandleIRQ = NULL;
249 D(bug("[ATA>>] ata_RegisterBus: Analysing bus %d, units %d and %d\n", ab->ab_BusNum, ab->ab_BusNum<<1, (ab->ab_BusNum<<1)+1));
250 D(bug("[ATA>>] ata_RegisterBus: IRQ %d, IO: %x:%x, DMA: %x\n", INTLine, IOBase, IOAlt, DMABase));
253 * allocate DMA PRD
255 ab->ab_PRD = AllocVecPooled(a->ATABase->ata_MemPool, (PRD_MAX+1) * 2 * sizeof(struct PRDEntry));
256 if ((0x10000 - ((ULONG)ab->ab_PRD & 0xffff)) < PRD_MAX * sizeof(struct PRDEntry))
257 ab->ab_PRD = (void*)((((IPTR)ab->ab_PRD)+0xffff) &~ 0xffff);
260 * scan bus - try to locate all devices (disables irq)
262 ata_InitBus(ab);
263 for (i = 0; i < MAX_BUSUNITS; i++)
265 if (ab->ab_Dev[i] > DEV_UNKNOWN)
267 ab->ab_Units[i] = AllocVecPooled(a->ATABase->ata_MemPool,
268 sizeof(struct ata_Unit));
269 ab->ab_Units[i]->au_DMAPort = DMABase;
270 ab->ab_Units[i]->au_Flags = has80Wire ? AF_80Wire : 0;
271 ata_init_unit(ab, i);
275 D(bug("[ATA>>] ata_RegisterBus: Bus %ld: Unit 0 - %x, Unit 1 - %x\n", ab->ab_BusNum, ab->ab_Dev[0], ab->ab_Dev[1]));
278 * start things up :)
279 * note: this happens no matter there are devices or not
280 * sort of almost-ready-for-hotplug ;)
282 AddTail((struct List*)&a->ATABase->ata_Buses, (struct Node*)ab);
286 * PCI BUS ENUMERATOR
287 * collect ALL ata/ide capable devices (including SATA and other) and
288 * spawn concurrent tasks.
290 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
293 static
294 AROS_UFH3(void, ata_PCIEnumerator_h,
295 AROS_UFHA(struct Hook *, hook, A0),
296 AROS_UFHA(OOP_Object *, Device, A2),
297 AROS_UFHA(APTR, message,A1))
299 AROS_USERFUNC_INIT
302 * parameters we will want to acquire
304 IPTR ProductID,
305 VendorID,
306 DMABase,
307 INTLine,
308 IOBase,
309 IOAlt,
310 IOSize,
311 AltSize,
312 SubClass,
313 Interface,
314 ATAIOConfig;
316 BOOL _usablebus = FALSE;
319 * the PCI Attr Base
321 OOP_AttrBase HiddPCIDeviceAttrBase = OOP_ObtainAttrBase(IID_Hidd_PCIDevice);
324 * message to get 80-wire cable report
326 struct pHidd_PCIDevice_ReadConfigLong ataioconfigmsg =
328 OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigLong),
329 0x54,
333 * enumerator params
335 EnumeratorArgs *a = (EnumeratorArgs*)hook->h_Data;
338 * temporary variables
340 int x;
343 * obtain more or less useful data
345 OOP_GetAttr(Device, aHidd_PCIDevice_VendorID, &VendorID);
346 OOP_GetAttr(Device, aHidd_PCIDevice_ProductID, &ProductID);
347 OOP_GetAttr(Device, aHidd_PCIDevice_Base4, &DMABase);
348 OOP_GetAttr(Device, aHidd_PCIDevice_SubClass, &SubClass);
349 OOP_GetAttr(Device, aHidd_PCIDevice_Interface, &Interface);
351 if (a->ATABase->ata_NoDMA || !(Interface & 0x80))
352 DMABase = 0;
354 ATAIOConfig = OOP_DoMethod(Device, (OOP_Msg)&ataioconfigmsg);
357 * we can have up to two buses assigned to this device
359 for (x = 0; SubClass != 0 && SubClass != 7 && x < MAX_DEVICEBUSES; x++)
361 struct ata_LegacyBus *_legacyBus = NULL;
362 BOOL isLegacy = FALSE;
364 if (x == 0)
366 bug("[ATA ] ata_PCIEnumerator_h: Found IDE device %04x:%04x\n", VendorID, ProductID);
370 * obtain I/O bases and interrupt line
372 if ((Interface & (1 << (x << 1))) || SubClass != 1)
374 switch (x)
376 case 0:
377 OOP_GetAttr(Device, aHidd_PCIDevice_Base0, &IOBase);
378 OOP_GetAttr(Device, aHidd_PCIDevice_Size0, &IOSize);
379 OOP_GetAttr(Device, aHidd_PCIDevice_Base1, &IOAlt);
380 OOP_GetAttr(Device, aHidd_PCIDevice_Size1, &AltSize);
381 break;
382 case 1:
383 OOP_GetAttr(Device, aHidd_PCIDevice_Base2, &IOBase);
384 OOP_GetAttr(Device, aHidd_PCIDevice_Size2, &IOSize);
385 OOP_GetAttr(Device, aHidd_PCIDevice_Base3, &IOAlt);
386 OOP_GetAttr(Device, aHidd_PCIDevice_Size3, &AltSize);
387 break;
389 OOP_GetAttr(Device, aHidd_PCIDevice_INTLine, &INTLine);
391 else if ((_legacyBus = (struct ata_LegacyBus *)
392 a->ATABase->ata__legacybuses.lh_Head)->atalb_ControllerID == 0)
394 Remove((struct Node *)_legacyBus);
395 IOBase = _legacyBus->atalb_IOBase;
396 IOAlt = _legacyBus->atalb_IOAlt;
397 INTLine = _legacyBus->atalb_INTLine;
398 FreeMem(_legacyBus, sizeof(struct ata_LegacyBus));
399 isLegacy = TRUE;
400 IOSize = RANGESIZE0;
401 AltSize = RANGESIZE1;
403 else
405 bug("[ATA ] ata_PCIEnumerator_h: Ran out of legacy buses\n");
406 IOBase = 0;
409 if (IOBase != (IPTR)NULL && IOSize == RANGESIZE0
410 && AltSize == RANGESIZE1)
412 struct ata_ProbedBus *probedbus;
413 D(bug("[ATA ] ata_PCIEnumerator_h: Adding Bus %d - IRQ %d, IO: %x:%x, DMA: %x\n", x, INTLine, IOBase, IOAlt, DMABase));
414 if ((probedbus = AllocMem(sizeof(struct ata_ProbedBus), MEMF_CLEAR | MEMF_PUBLIC)) != (IPTR)NULL)
416 probedbus->atapb_IOBase = IOBase;
417 probedbus->atapb_IOAlt = IOAlt;
418 probedbus->atapb_INTLine = INTLine;
419 if (DMABase != 0)
420 probedbus->atapb_DMABase = DMABase + (x << 3);
421 probedbus->atapb_a = a;
422 probedbus->atapb_Has80Wire =
423 (ATAIOConfig & (0x30 << (x << 1))) || SubClass != 0x1;
425 if (isLegacy)
427 D(bug("[ATA ] ata_PCIEnumerator_h: Device using Legacy-Bus IOPorts\n"));
428 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_PROBEDLEGACY - (a->ATABase->ata__buscount++);
430 else
431 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_PROBED - (a->ATABase->ata__buscount++);
433 Enqueue((struct List *)&a->ATABase->ata__probedbuses, (struct Node *)probedbus);
434 _usablebus = TRUE;
439 if (_usablebus)
441 struct TagItem attrs[] =
443 { aHidd_PCIDevice_isIO, TRUE },
444 { aHidd_PCIDevice_isMaster, DMABase != 0 },
445 { TAG_DONE, 0UL }
447 OOP_SetAttrs(Device, attrs);
450 /* check dma status if applicable */
451 if (DMABase != 0)
452 D(bug("[ATA ] ata_PCIEnumerator_h: Bus0 DMA Status %02x, Bus1 DMA Status %02x\n", ata_in(2, DMABase), ata_in(10, DMABase)));
454 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice);
456 AROS_USERFUNC_EXIT
460 void ata_Scan(struct ataBase *base)
462 OOP_Object *pci;
463 struct SignalSemaphore ssem;
464 struct ata_ProbedBus *probedbus;
466 struct Node* node;
467 EnumeratorArgs Args=
469 base,
473 D(bug("[ATA--] ata_Scan: Enumerating devices\n"));
475 if (base->ata_ScanFlags & ATA_SCANPCI) {
476 D(bug("[ATA--] ata_Scan: Checking for supported PCI devices ..\n"));
477 pci = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL);
479 if (pci)
481 struct Hook FindHook = {
482 h_Entry: (IPTR (*)())ata_PCIEnumerator_h,
483 h_Data: &Args
486 struct TagItem Requirements[] = {
487 {tHidd_PCI_Class, 0x01},
488 {TAG_DONE, 0x00}
491 struct pHidd_PCI_EnumDevices enummsg = {
492 mID: OOP_GetMethodID(IID_Hidd_PCI, moHidd_PCI_EnumDevices),
493 callback: &FindHook,
494 requirements: (struct TagItem *)&Requirements,
495 }, *msg = &enummsg;
497 OOP_DoMethod(pci, (OOP_Msg)msg);
499 OOP_DisposeObject(pci);
502 if (base->ata_ScanFlags & ATA_SCANLEGACY) {
503 struct ata_LegacyBus *legacybus;
504 D(bug("[ATA--] ata_Scan: Adding Remaining Legacy-Buses\n"));
505 while ((legacybus = (struct ata_LegacyBus *)
506 RemHead((struct List *)&base->ata__legacybuses)) != NULL)
508 if ((probedbus = AllocMem(sizeof(struct ata_ProbedBus), MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
510 probedbus->atapb_IOBase = legacybus->atalb_IOBase;
511 probedbus->atapb_IOAlt = legacybus->atalb_IOAlt;
512 probedbus->atapb_INTLine = legacybus->atalb_INTLine;
513 probedbus->atapb_DMABase = (IPTR)NULL;
514 probedbus->atapb_Has80Wire = FALSE;
515 probedbus->atapb_a = &Args;
516 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_LEGACY - (base->ata__buscount++);
517 D(bug("[ATA--] ata_Scan: Adding Legacy Bus - IO: %x:%x\n",
518 probedbus->atapb_IOBase, probedbus->atapb_IOAlt));
519 Enqueue((struct List *)&base->ata__probedbuses, (struct Node *)&probedbus->atapb_Node);
522 FreeMem(legacybus, sizeof(struct ata_LegacyBus));
525 D(bug("[ATA--] ata_Scan: Registering Probed Buses..\n"));
526 while ((probedbus = (struct ata_ProbedBus *)
527 RemHead((struct List *)&base->ata__probedbuses)) != NULL)
529 ata_RegisterBus(
530 probedbus->atapb_IOBase,
531 probedbus->atapb_IOAlt,
532 probedbus->atapb_INTLine,
533 probedbus->atapb_DMABase,
534 probedbus->atapb_Has80Wire,
535 probedbus->atapb_a);
537 FreeMem(probedbus, sizeof(struct ata_ProbedBus));
540 D(bug("[ATA--] ata_Scan: Initialising Bus Tasks..\n"));
541 InitSemaphore(&ssem);
542 ForeachNode(&base->ata_Buses, node)
544 ata_InitBusTask((struct ata_Bus*)node, &ssem);
548 * wait for all buses to complete their init
550 D(bug("[ATA--] ata_Scan: Waiting for Buses to finish Initialising\n"));
551 ObtainSemaphore(&ssem);
554 * and leave.
556 ReleaseSemaphore(&ssem);
557 D(bug("[ATA--] ata_Scan: Finished\n"));
561 Here shall we start. Make function static as it shouldn't be visible from
562 outside.
564 static int ata_init(LIBBASETYPEPTR LIBBASE)
566 struct BootLoaderBase *BootLoaderBase;
567 struct ata_LegacyBus *_legacybus;
568 int i;
570 D(bug("[ATA--] ata_init: ata.device Initialization\n"));
573 * I've decided to use memory pools again. Alloc everything needed from
574 * a pool, so that we avoid memory fragmentation.
576 LIBBASE->ata_MemPool = CreatePool(MEMF_CLEAR | MEMF_PUBLIC | MEMF_SEM_PROTECTED , 8192, 4096);
577 if (LIBBASE->ata_MemPool == NULL)
578 return FALSE;
580 D(bug("[ATA--] ata_init: MemPool @ %p\n", LIBBASE->ata_MemPool));
582 /* Prepare lists for probed/found ide buses */
583 NEWLIST((struct List *)&LIBBASE->ata__legacybuses);
584 NEWLIST((struct List *)&LIBBASE->ata__probedbuses);
586 /* Build the list of possible legacy-bus ports */
587 for (i = 0; LegacyBuses[i].lb_Port != 0 ; i++)
589 if ((_legacybus = AllocMem(sizeof(struct ata_LegacyBus), MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
591 D(bug("[ATA--] ata_init: Prepare Legacy Bus %d:%d entry [IOPorts %x:%x IRQ %d]\n", LegacyBuses[i].lb_ControllerID, LegacyBuses[i].lb_Bus, LegacyBuses[i].lb_Port, LegacyBuses[i].lb_Alt, LegacyBuses[i].lb_IRQ));
593 _legacybus->atalb_IOBase = (IPTR)LegacyBuses[i].lb_Port;
594 _legacybus->atalb_IOAlt = (IPTR)LegacyBuses[i].lb_Alt;
595 _legacybus->atalb_INTLine = (IPTR)LegacyBuses[i].lb_IRQ;
596 _legacybus->atalb_ControllerID = (IPTR)LegacyBuses[i].lb_ControllerID;
597 _legacybus->atalb_BusID = (IPTR)LegacyBuses[i].lb_Bus;
598 AddTail(&LIBBASE->ata__legacybuses, &_legacybus->atalb_Node);
602 /* Set default ata.device config options */
603 LIBBASE->ata_ScanFlags = ATA_SCANPCI | ATA_SCANLEGACY;
604 LIBBASE->ata_32bit = FALSE;
605 LIBBASE->ata_NoMulti = FALSE;
606 LIBBASE->ata_NoDMA = FALSE;
609 * start initialization:
610 * obtain kernel parameters
612 BootLoaderBase = OpenResource("bootloader.resource");
613 D(bug("[ATA--] ata_init: BootloaderBase = %p\n", BootLoaderBase));
614 if (BootLoaderBase != NULL)
616 struct List *list;
617 struct Node *node;
619 list = (struct List *)GetBootInfo(BL_Args);
620 if (list)
622 ForeachNode(list, node)
624 if (strncmp(node->ln_Name, "ATA=", 4) == 0)
626 if (strstr(node->ln_Name, "nopci"))
628 D(bug("[ATA ] ata_init: Disabling PCI device scan\n"));
629 LIBBASE->ata_ScanFlags &= ~ATA_SCANPCI;
631 if (strstr(node->ln_Name, "nolegacy"))
633 D(bug("[ATA ] ata_init: Disabling Legacy ports\n"));
634 LIBBASE->ata_ScanFlags &= ~ATA_SCANLEGACY;
636 if (strstr(node->ln_Name, "32bit"))
638 D(bug("[ATA ] ata_init: Using 32-bit IO transfers\n"));
639 LIBBASE->ata_32bit = TRUE;
641 if (strstr(node->ln_Name, "nomulti"))
643 D(bug("[ATA ] ata_init: Disabled multisector transfers\n"));
644 LIBBASE->ata_NoMulti = TRUE;
646 if (strstr(node->ln_Name, "nodma"))
648 D(bug("[ATA ] ata_init: Disabled DMA transfers\n"));
649 LIBBASE->ata_NoDMA = TRUE;
657 * Initialize BUS list
659 LIBBASE->ata_Buses.mlh_Head = (struct MinNode*) &LIBBASE->ata_Buses.mlh_Tail;
660 LIBBASE->ata_Buses.mlh_Tail = NULL;
661 LIBBASE->ata_Buses.mlh_TailPred = (struct MinNode*) &LIBBASE->ata_Buses.mlh_Head;
664 * Find all suitable devices ..
666 ata_Scan(LIBBASE);
668 /* Try to setup daemon task looking for diskchanges */
669 ata_InitDaemonTask(LIBBASE);
670 return TRUE;
673 static int open
675 LIBBASETYPEPTR LIBBASE,
676 struct IORequest *iorq,
677 ULONG unitnum,
678 ULONG flags
682 * device location
684 ULONG bus, dev;
687 * Assume it failed
689 iorq->io_Error = IOERR_OPENFAIL;
692 * actual bus
694 struct ata_Bus *b = (struct ata_Bus*)LIBBASE->ata_Buses.mlh_Head;
697 * Extract bus and device numbers
699 bus = unitnum >> 1; // 0xff00 >> 8
700 dev = (unitnum & 0x1); // 0x00ff
703 * locate bus
705 while (bus--)
707 b = (struct ata_Bus*)b->ab_Node.mln_Succ;
708 if (b == NULL)
709 return FALSE;
712 if (b->ab_Node.mln_Succ == NULL)
713 return FALSE;
716 * locate unit
718 if (b->ab_Units[dev] == NULL)
719 return FALSE;
722 * set up iorequest
724 iorq->io_Device = &LIBBASE->ata_Device;
725 iorq->io_Unit = &b->ab_Units[dev]->au_Unit;
726 iorq->io_Error = 0;
728 b->ab_Units[dev]->au_Unit.unit_OpenCnt++;
730 return TRUE;
733 /* Close given device */
734 static int close
736 LIBBASETYPEPTR LIBBASE,
737 struct IORequest *iorq
740 struct ata_Unit *unit = (struct ata_Unit *)iorq->io_Unit;
742 /* First of all make the important fields of struct IORequest invalid! */
743 iorq->io_Unit = (struct Unit *)~0;
745 /* Decrease use counters of unit */
746 unit->au_Unit.unit_OpenCnt--;
748 return TRUE;
751 ADD2INITLIB(ata_init, 0)
752 ADD2OPENDEV(open, 0)
753 ADD2CLOSEDEV(close, 0)
754 ADD2LIBS("irq.hidd", 0, static struct Library *, __irqhidd)
755 /* vim: set ts=8 sts=4 et : */