2 Copyright © 2004-2013, The AROS Development Team. All rights reserved
9 #define __OOP_NOMETHODBASES__
11 #include <aros/bootloader.h>
12 #include <aros/debug.h>
13 #include <aros/symbolsets.h>
14 #include <exec/exec.h>
15 #include <exec/resident.h>
16 #include <exec/tasks.h>
17 #include <exec/memory.h>
18 #include <exec/nodes.h>
19 #include <hidd/hidd.h>
20 #include <utility/utility.h>
21 #include <libraries/expansion.h>
22 #include <libraries/configvars.h>
24 #include <dos/dosextens.h>
25 #include <dos/filehandler.h>
27 #include <proto/exec.h>
28 #include <proto/timer.h>
29 #include <proto/bootloader.h>
30 #include <proto/expansion.h>
31 #include <proto/oop.h>
38 #include LC_LIBDEFS_FILE
40 /* Add a bootnode using expansion.library */
41 BOOL
ata_RegisterVolume(ULONG StartCyl
, ULONG EndCyl
, struct ata_Unit
*unit
)
43 struct ExpansionBase
*ExpansionBase
;
44 struct DeviceNode
*devnode
;
45 TEXT dosdevname
[4] = "HD0";
46 const ULONG IdDOS
= AROS_MAKE_ID('D','O','S','\001');
47 const ULONG IdCDVD
= AROS_MAKE_ID('C','D','V','D');
49 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",
56 /* This should be dealt with using some sort of volume manager or such. */
57 switch (unit
->au_DevType
)
59 case DG_DIRECT_ACCESS
:
65 D(bug("[ATA>>]:-ata_RegisterVolume called on unknown devicetype\n"));
68 if (unit
->au_UnitNum
< 10)
69 dosdevname
[2] += unit
->au_UnitNum
% 10;
71 dosdevname
[2] = 'A' - 10 + unit
->au_UnitNum
;
73 pp
[0] = (IPTR
)dosdevname
;
74 pp
[1] = (IPTR
)MOD_NAME_STRING
;
75 pp
[2] = unit
->au_UnitNum
;
76 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
77 pp
[DE_SIZEBLOCK
+ 4] = 1 << (unit
->au_SectorShift
- 2);
78 pp
[DE_NUMHEADS
+ 4] = unit
->au_Heads
;
79 pp
[DE_SECSPERBLOCK
+ 4] = 1;
80 pp
[DE_BLKSPERTRACK
+ 4] = unit
->au_Sectors
;
81 pp
[DE_RESERVEDBLKS
+ 4] = 2;
82 pp
[DE_LOWCYL
+ 4] = StartCyl
;
83 pp
[DE_HIGHCYL
+ 4] = EndCyl
;
84 pp
[DE_NUMBUFFERS
+ 4] = 10;
85 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_31BIT
;
86 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
87 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
88 pp
[DE_BOOTPRI
+ 4] = ((unit
->au_DevType
== DG_DIRECT_ACCESS
) ? 0 : 10);
89 pp
[DE_DOSTYPE
+ 4] = ((unit
->au_DevType
== DG_DIRECT_ACCESS
) ? IdDOS
: IdCDVD
);
90 pp
[DE_CONTROL
+ 4] = 0;
91 pp
[DE_BOOTBLOCKS
+ 4] = 2;
93 devnode
= MakeDosNode(pp
);
97 D(bug("[ATA>>]:-ata_RegisterVolume: '%b', type=0x%08lx with StartCyl=%d, EndCyl=%d .. ",
98 devnode
->dn_Name
, pp
[DE_DOSTYPE
+ 4], StartCyl
, EndCyl
));
100 AddBootNode(pp
[DE_BOOTPRI
+ 4], ADNF_STARTPROC
, devnode
, NULL
);
106 CloseLibrary((struct Library
*)ExpansionBase
);
112 static AROS_INTH1(ATAResetHandler
,struct ata_Bus
*, bus
)
116 struct ata_Unit
*unit
;
120 for (i
= 0; i
< MAX_BUSUNITS
; i
++)
122 unit
= bus
->ab_Units
[i
];
125 if(unit
->au_DMAPort
!= 0)
128 BUS_OUTL(0, dma_PRD
, unit
->au_DMAPort
);
133 /* Disable interrupts */
134 BUS_OUT(0x2, ata_AltControl
, bus
->ab_Alt
);
142 * This routine needs to be called by bus probe code in order to register a device.
143 * IOBase - base address of primary I/O registers on your bus.
144 * IOAlt - base address of secondary I/O register bank. Zero if no secondary bank
145 * is present. (IDE splitter on Amiga(tm), for example).
146 * DMABase - base address of DMA controller on your bus. Zero if DMA is not supported.
148 * driver - structure holding pointers to I/O functions (for speedup)
149 * driverData - driver-specific data, whatever it needs.
151 * Flags: - ARBF_80Wire
152 * Set if your drive is connected using 80-wire cable. Enables high-speed
153 * UDMA modes (where appropriate).
154 * - ARBF_EarlyInterrupt
155 * Setup interrupt handler before IDE bus probe to catch possible spurious
156 * interrupts (IDE splitter disables access to ata_devcon register)
158 * When a HIDD subsystem is implemented, these parameters will become HIDD attributes.
160 void ata_RegisterBus(IPTR IOBase
, IPTR IOAlt
, IPTR INTLine
, IPTR DMABase
, ULONG Flags
,
161 const struct ata_BusDriver
*driver
, APTR driverData
, struct ataBase
*ATABase
)
164 * ata bus - this is going to be created and linked to the master list here
171 * initialize structure
173 ab
= (struct ata_Bus
*) AllocVecPooled(ATABase
->ata_MemPool
, sizeof(struct ata_Bus
));
177 ab
->ab_Base
= ATABase
;
178 ab
->ab_Port
= IOBase
;
180 ab
->ab_IRQ
= INTLine
;
181 ab
->ab_Dev
[0] = DEV_NONE
;
182 ab
->ab_Dev
[1] = DEV_NONE
;
184 ab
->ab_SleepySignal
= 0;
185 ab
->ab_BusNum
= ATABase
->ata__buscount
++;
187 ab
->ab_Units
[0] = NULL
;
188 ab
->ab_Units
[1] = NULL
;
190 ab
->ab_HandleIRQ
= NULL
;
191 ab
->ab_Driver
= driver
;
192 ab
->ab_DriverData
= driverData
;
194 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));
195 D(bug("[ATA>>] ata_RegisterBus: IRQ %d, IO: %x:%x, DMA: %x\n", INTLine
, IOBase
, IOAlt
, DMABase
));
198 * DMABase is also used for reporting interrupt status, so NoDMA == TRUE
199 * is not equal to DMABase == 0.
201 if (DMABase
&& (!ATABase
->ata_NoDMA
))
203 /* Allocate DMA PRD. Due to the nature of PCI bus it must be in 32-bit memory. */
204 ab
->ab_PRD
= AllocMem((PRD_MAX
+ 1) * 2 * sizeof(struct PRDEntry
), MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_31BIT
);
208 if ((0x10000 - ((IPTR
)ab
->ab_PRD
& 0xffff)) < PRD_MAX
* sizeof(struct PRDEntry
))
209 ab
->ab_PRD
= (void*)((((IPTR
)ab
->ab_PRD
)+0xffff) &~ 0xffff);
213 D(bug("[ATA>>] Failed to allocate DMA PRD! Disabling DMA for the bus.\n"));
219 * add reset handler for this bus
221 ab
->ab_ResetInt
.is_Code
= (VOID_FUNC
)ATAResetHandler
;
222 ab
->ab_ResetInt
.is_Data
= ab
;
223 AddResetCallback(&ab
->ab_ResetInt
);
225 /* catch possible spurious interrupts */
226 if (Flags
& ARBF_EarlyInterrupt
)
227 ab
->ab_Driver
->CreateInterrupt(ab
);
230 * scan bus - try to locate all devices (disables irq)
233 for (i
= 0; i
< MAX_BUSUNITS
; i
++)
235 if (ab
->ab_Dev
[i
] > DEV_UNKNOWN
)
237 ab
->ab_Units
[i
] = AllocVecPooled(ATABase
->ata_MemPool
,
238 sizeof(struct ata_Unit
));
239 ab
->ab_Units
[i
]->au_DMAPort
= DMABase
;
240 ab
->ab_Units
[i
]->au_Flags
= (Flags
& ARBF_80Wire
) ? AF_80Wire
: 0;
241 ata_init_unit(ab
, i
);
245 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]));
249 * note: this happens no matter there are devices or not
250 * sort of almost-ready-for-hotplug ;)
252 AddTail((struct List
*)&ATABase
->ata_Buses
, (struct Node
*)ab
);
256 * This init routine has +127 priority, so it runs after all
257 * bus scanners have done their job.
258 * It initializes all discovered units.
260 static int ata_Scan(struct ataBase
*base
)
262 struct SignalSemaphore ssem
;
263 struct ata_Bus
* node
;
264 struct Task
*parent
= FindTask(NULL
);
266 D(bug("[ATA--] ata_Scan: Initialising Bus Tasks..\n"));
267 InitSemaphore(&ssem
);
268 ForeachNode(&base
->ata_Buses
, node
)
270 NewCreateTask(TASKTAG_PC
, BusTaskCode
,
271 TASKTAG_NAME
, "ATA[PI] Subsystem",
272 TASKTAG_STACKSIZE
, STACK_SIZE
,
273 TASKTAG_PRI
, TASK_PRI
,
274 TASKTAG_TASKMSGPORT
, &node
->ab_MsgPort
,
276 TASKTAG_ARG2
, parent
,
277 TASKTAG_ARG3
, &ssem
,
280 /* Initial handshake */
281 Wait(SIGBREAKF_CTRL_C
);
285 * wait for all buses to complete their init
287 D(bug("[ATA--] ata_Scan: Waiting for Buses to finish Initialising\n"));
288 ObtainSemaphore(&ssem
);
293 ReleaseSemaphore(&ssem
);
294 D(bug("[ATA--] ata_Scan: Finished\n"));
296 /* Try to setup daemon task looking for diskchanges */
297 NewCreateTask(TASKTAG_PC
, DaemonCode
,
298 TASKTAG_NAME
, "ATA.daemon",
299 TASKTAG_STACKSIZE
, STACK_SIZE
,
300 TASKTAG_PRI
, TASK_PRI
- 1, /* The daemon should have a little bit lower Pri as handler tasks */
307 /* Keep order the same as order of IDs in struct ataBase! */
308 static CONST_STRPTR attrBaseIDs
[] =
316 Here shall we start. Make function static as it shouldn't be visible from
319 static int ata_init(struct ataBase
*ATABase
)
323 struct BootLoaderBase
*BootLoaderBase
;
325 D(bug("[ATA--] ata_init: ata.device Initialization\n"));
328 * I've decided to use memory pools again. Alloc everything needed from
329 * a pool, so that we avoid memory fragmentation.
331 ATABase
->ata_MemPool
= CreatePool(MEMF_CLEAR
| MEMF_PUBLIC
| MEMF_SEM_PROTECTED
, 8192, 4096);
332 if (ATABase
->ata_MemPool
== NULL
)
335 D(bug("[ATA--] ata_init: MemPool @ %p\n", ATABase
->ata_MemPool
));
337 if (OOP_ObtainAttrBasesArray(&ATABase
->hwAttrBase
, attrBaseIDs
))
340 hwRoot
= OOP_NewObject(NULL
, CLID_HW_Root
, NULL
);
344 HWBase
= OOP_GetMethodID(IID_HW
, 0);
345 if (!HW_AddDriver(hwRoot
, ATABase
->ataClass
, NULL
))
348 /* Set default ata.device config options */
349 ATABase
->ata_32bit
= FALSE
;
350 ATABase
->ata_NoMulti
= FALSE
;
351 ATABase
->ata_NoDMA
= FALSE
;
352 ATABase
->ata_Poll
= FALSE
;
353 ATABase
->ata_CmdLine
= NULL
;
356 * start initialization:
357 * obtain kernel parameters
359 BootLoaderBase
= OpenResource("bootloader.resource");
360 D(bug("[ATA--] ata_init: BootloaderBase = %p\n", BootLoaderBase
));
361 if (BootLoaderBase
!= NULL
)
366 list
= (struct List
*)GetBootInfo(BL_Args
);
369 ForeachNode(list
, node
)
371 if (strncmp(node
->ln_Name
, "ATA=", 4) == 0)
374 * Remember the entire command line.
375 * Bus drivers (for example PCI one) may want it.
377 ATABase
->ata_CmdLine
= &node
->ln_Name
[4];
379 if (strstr(ATABase
->ata_CmdLine
, "32bit"))
381 D(bug("[ATA ] ata_init: Using 32-bit IO transfers\n"));
382 ATABase
->ata_32bit
= TRUE
;
384 if (strstr(ATABase
->ata_CmdLine
, "nomulti"))
386 D(bug("[ATA ] ata_init: Disabled multisector transfers\n"));
387 ATABase
->ata_NoMulti
= TRUE
;
389 if (strstr(ATABase
->ata_CmdLine
, "nodma"))
391 D(bug("[ATA ] ata_init: Disabled DMA transfers\n"));
392 ATABase
->ata_NoDMA
= TRUE
;
394 if (strstr(ATABase
->ata_CmdLine
, "poll"))
396 D(bug("[ATA ] ata_init: Using polling to detect end of busy state\n"));
397 ATABase
->ata_Poll
= TRUE
;
404 /* Initialize BUS list */
405 NEWLIST(&ATABase
->ata_Buses
);
410 static int ata_expunge(struct ataBase
*ATABase
)
415 * CLID_HW is a singletone, you can get it as many times as you want.
416 * Here we save up some space in struct ataBase by obtaining hwclass
417 * object and its MethodBase only when we need it. This happens rarely,
418 * so small performance loss is OK here.
420 OOP_Object
*hwRoot
= OOP_NewObject(NULL
, CLID_HW
, NULL
);
421 OOP_MethodID HWBase
= OOP_GetMethodID(IID_HW
, 0);
423 HW_RemoveDriver(hwRoot
, ATABase
->ataObj
);
426 OOP_ReleaseAttrBasesArray(&ATABase
->hwAttrBase
, attrBaseIDs
);
433 LIBBASETYPEPTR LIBBASE
,
434 struct IORequest
*iorq
,
447 iorq
->io_Error
= IOERR_OPENFAIL
;
452 struct ata_Bus
*b
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
455 * Extract bus and device numbers
457 bus
= unitnum
>> 1; // 0xff00 >> 8
458 dev
= (unitnum
& 0x1); // 0x00ff
465 b
= (struct ata_Bus
*)b
->ab_Node
.mln_Succ
;
470 if (b
->ab_Node
.mln_Succ
== NULL
)
476 if (b
->ab_Units
[dev
] == NULL
)
482 iorq
->io_Device
= &LIBBASE
->ata_Device
;
483 iorq
->io_Unit
= &b
->ab_Units
[dev
]->au_Unit
;
486 b
->ab_Units
[dev
]->au_Unit
.unit_OpenCnt
++;
491 /* Close given device */
494 LIBBASETYPEPTR LIBBASE
,
495 struct IORequest
*iorq
498 struct ata_Unit
*unit
= (struct ata_Unit
*)iorq
->io_Unit
;
500 /* First of all make the important fields of struct IORequest invalid! */
501 iorq
->io_Unit
= (struct Unit
*)~0;
503 /* Decrease use counters of unit */
504 unit
->au_Unit
.unit_OpenCnt
--;
509 ADD2INITLIB(ata_init
, 0)
510 ADD2EXPUNGELIB(ata_expunge
, 0)
511 ADD2INITLIB(ata_Scan
, 127)
513 ADD2CLOSEDEV(close
, 0)
514 /* vim: set ts=8 sts=4 et : */