2 Copyright © 2004-2012, The AROS Development Team. All rights reserved
9 #include <aros/bootloader.h>
10 #include <aros/debug.h>
11 #include <aros/symbolsets.h>
12 #include <exec/exec.h>
13 #include <exec/resident.h>
14 #include <exec/tasks.h>
15 #include <exec/memory.h>
16 #include <exec/nodes.h>
17 #include <utility/utility.h>
18 #include <libraries/expansion.h>
19 #include <libraries/configvars.h>
21 #include <dos/dosextens.h>
22 #include <dos/filehandler.h>
24 #include <proto/exec.h>
25 #include <proto/timer.h>
26 #include <proto/bootloader.h>
27 #include <proto/expansion.h>
34 #include LC_LIBDEFS_FILE
36 /* Add a bootnode using expansion.library */
37 BOOL
ata_RegisterVolume(ULONG StartCyl
, ULONG EndCyl
, struct ata_Unit
*unit
)
39 struct ExpansionBase
*ExpansionBase
;
40 struct DeviceNode
*devnode
;
41 TEXT dosdevname
[4] = "HD0";
42 const ULONG IdDOS
= AROS_MAKE_ID('D','O','S','\001');
43 const ULONG IdCDVD
= AROS_MAKE_ID('C','D','V','D');
45 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",
52 /* This should be dealt with using some sort of volume manager or such. */
53 switch (unit
->au_DevType
)
55 case DG_DIRECT_ACCESS
:
61 D(bug("[ATA>>]:-ata_RegisterVolume called on unknown devicetype\n"));
64 if (unit
->au_UnitNum
< 10)
65 dosdevname
[2] += unit
->au_UnitNum
% 10;
67 dosdevname
[2] = 'A' - 10 + unit
->au_UnitNum
;
69 pp
[0] = (IPTR
)dosdevname
;
70 pp
[1] = (IPTR
)MOD_NAME_STRING
;
71 pp
[2] = unit
->au_UnitNum
;
72 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
73 pp
[DE_SIZEBLOCK
+ 4] = 1 << (unit
->au_SectorShift
- 2);
74 pp
[DE_NUMHEADS
+ 4] = unit
->au_Heads
;
75 pp
[DE_SECSPERBLOCK
+ 4] = 1;
76 pp
[DE_BLKSPERTRACK
+ 4] = unit
->au_Sectors
;
77 pp
[DE_RESERVEDBLKS
+ 4] = 2;
78 pp
[DE_LOWCYL
+ 4] = StartCyl
;
79 pp
[DE_HIGHCYL
+ 4] = EndCyl
;
80 pp
[DE_NUMBUFFERS
+ 4] = 10;
81 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_31BIT
;
82 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
83 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
84 pp
[DE_BOOTPRI
+ 4] = ((unit
->au_DevType
== DG_DIRECT_ACCESS
) ? 0 : 10);
85 pp
[DE_DOSTYPE
+ 4] = ((unit
->au_DevType
== DG_DIRECT_ACCESS
) ? IdDOS
: IdCDVD
);
86 pp
[DE_CONTROL
+ 4] = 0;
87 pp
[DE_BOOTBLOCKS
+ 4] = 2;
89 devnode
= MakeDosNode(pp
);
93 D(bug("[ATA>>]:-ata_RegisterVolume: '%b', type=0x%08lx with StartCyl=%d, EndCyl=%d .. ",
94 devnode
->dn_Name
, pp
[DE_DOSTYPE
+ 4], StartCyl
, EndCyl
));
96 AddBootNode(pp
[DE_BOOTPRI
+ 4], ADNF_STARTPROC
, devnode
, NULL
);
102 CloseLibrary((struct Library
*)ExpansionBase
);
108 static AROS_INTH1(ATAResetHandler
,struct ata_Bus
*, bus
)
112 struct ata_Unit
*unit
;
116 for (i
= 0; i
< MAX_BUSUNITS
; i
++)
118 unit
= bus
->ab_Units
[i
];
121 if(unit
->au_DMAPort
!= 0)
124 BUS_OUTL(0, dma_PRD
, unit
->au_DMAPort
);
129 /* Disable interrupts */
130 BUS_OUT(0x2, ata_AltControl
, bus
->ab_Alt
);
138 * This routine needs to be called by bus probe code in order to register a device.
139 * IOBase - base address of primary I/O registers on your bus.
140 * IOAlt - base address of secondary I/O register bank. Zero if no secondary bank
141 * is present. (IDE splitter on Amiga(tm), for example).
142 * DMABase - base address of DMA controller on your bus. Zero if DMA is not supported.
144 * driver - structure holding pointers to I/O functions (for speedup)
145 * driverData - driver-specific data, whatever it needs.
147 * Flags: - ARBF_80Wire
148 * Set if your drive is connected using 80-wire cable. Enables high-speed
149 * UDMA modes (where appropriate).
150 * - ARBF_EarlyInterrupt
151 * Setup interrupt handler before IDE bus probe to catch possible spurious
152 * interrupts (IDE splitter disables access to ata_devcon register)
154 * When a HIDD subsystem is implemented, these parameters will become HIDD attributes.
156 void ata_RegisterBus(IPTR IOBase
, IPTR IOAlt
, IPTR INTLine
, IPTR DMABase
, ULONG Flags
,
157 const struct ata_BusDriver
*driver
, APTR driverData
, struct ataBase
*ATABase
)
160 * ata bus - this is going to be created and linked to the master list here
167 * initialize structure
169 ab
= (struct ata_Bus
*) AllocVecPooled(ATABase
->ata_MemPool
, sizeof(struct ata_Bus
));
173 ab
->ab_Base
= ATABase
;
174 ab
->ab_Port
= IOBase
;
176 ab
->ab_IRQ
= INTLine
;
177 ab
->ab_Dev
[0] = DEV_NONE
;
178 ab
->ab_Dev
[1] = DEV_NONE
;
180 ab
->ab_SleepySignal
= 0;
181 ab
->ab_BusNum
= ATABase
->ata__buscount
++;
183 ab
->ab_Units
[0] = NULL
;
184 ab
->ab_Units
[1] = NULL
;
186 ab
->ab_HandleIRQ
= NULL
;
187 ab
->ab_Driver
= driver
;
188 ab
->ab_DriverData
= driverData
;
190 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));
191 D(bug("[ATA>>] ata_RegisterBus: IRQ %d, IO: %x:%x, DMA: %x\n", INTLine
, IOBase
, IOAlt
, DMABase
));
194 * DMABase is also used for reporting interrupt status, so NoDMA == TRUE
195 * is not equal to DMABase == 0.
197 if (DMABase
&& (!ATABase
->ata_NoDMA
))
199 /* Allocate DMA PRD. Due to the nature of PCI bus it must be in 32-bit memory. */
200 ab
->ab_PRD
= AllocMem((PRD_MAX
+ 1) * 2 * sizeof(struct PRDEntry
), MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_31BIT
);
204 if ((0x10000 - ((IPTR
)ab
->ab_PRD
& 0xffff)) < PRD_MAX
* sizeof(struct PRDEntry
))
205 ab
->ab_PRD
= (void*)((((IPTR
)ab
->ab_PRD
)+0xffff) &~ 0xffff);
209 D(bug("[ATA>>] Failed to allocate DMA PRD! Disabling DMA for the bus.\n"));
215 * add reset handler for this bus
217 ab
->ab_ResetInt
.is_Code
= (VOID_FUNC
)ATAResetHandler
;
218 ab
->ab_ResetInt
.is_Data
= ab
;
219 AddResetCallback(&ab
->ab_ResetInt
);
221 /* catch possible spurious interrupts */
222 if (Flags
& ARBF_EarlyInterrupt
)
223 ab
->ab_Driver
->CreateInterrupt(ab
);
226 * scan bus - try to locate all devices (disables irq)
229 for (i
= 0; i
< MAX_BUSUNITS
; i
++)
231 if (ab
->ab_Dev
[i
] > DEV_UNKNOWN
)
233 ab
->ab_Units
[i
] = AllocVecPooled(ATABase
->ata_MemPool
,
234 sizeof(struct ata_Unit
));
235 ab
->ab_Units
[i
]->au_DMAPort
= DMABase
;
236 ab
->ab_Units
[i
]->au_Flags
= (Flags
& ARBF_80Wire
) ? AF_80Wire
: 0;
237 ata_init_unit(ab
, i
);
241 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]));
245 * note: this happens no matter there are devices or not
246 * sort of almost-ready-for-hotplug ;)
248 AddTail((struct List
*)&ATABase
->ata_Buses
, (struct Node
*)ab
);
252 * This init routine has +127 priority, so it runs after all
253 * bus scanners have done their job.
254 * It initializes all discovered units.
256 static int ata_Scan(struct ataBase
*base
)
258 struct SignalSemaphore ssem
;
259 struct ata_Bus
* node
;
260 struct Task
*parent
= FindTask(NULL
);
262 D(bug("[ATA--] ata_Scan: Initialising Bus Tasks..\n"));
263 InitSemaphore(&ssem
);
264 ForeachNode(&base
->ata_Buses
, node
)
266 NewCreateTask(TASKTAG_PC
, BusTaskCode
,
267 TASKTAG_NAME
, "ATA[PI] Subsystem",
268 TASKTAG_STACKSIZE
, STACK_SIZE
,
269 TASKTAG_PRI
, TASK_PRI
,
270 TASKTAG_TASKMSGPORT
, &node
->ab_MsgPort
,
272 TASKTAG_ARG2
, parent
,
273 TASKTAG_ARG3
, &ssem
,
276 /* Initial handshake */
277 Wait(SIGBREAKF_CTRL_C
);
281 * wait for all buses to complete their init
283 D(bug("[ATA--] ata_Scan: Waiting for Buses to finish Initialising\n"));
284 ObtainSemaphore(&ssem
);
289 ReleaseSemaphore(&ssem
);
290 D(bug("[ATA--] ata_Scan: Finished\n"));
292 /* Try to setup daemon task looking for diskchanges */
293 NewCreateTask(TASKTAG_PC
, DaemonCode
,
294 TASKTAG_NAME
, "ATA.daemon",
295 TASKTAG_STACKSIZE
, STACK_SIZE
,
296 TASKTAG_PRI
, TASK_PRI
- 1, /* The daemon should have a little bit lower Pri as handler tasks */
304 Here shall we start. Make function static as it shouldn't be visible from
307 static int ata_init(LIBBASETYPEPTR LIBBASE
)
309 struct BootLoaderBase
*BootLoaderBase
;
311 D(bug("[ATA--] ata_init: ata.device Initialization\n"));
314 * I've decided to use memory pools again. Alloc everything needed from
315 * a pool, so that we avoid memory fragmentation.
317 LIBBASE
->ata_MemPool
= CreatePool(MEMF_CLEAR
| MEMF_PUBLIC
| MEMF_SEM_PROTECTED
, 8192, 4096);
318 if (LIBBASE
->ata_MemPool
== NULL
)
321 D(bug("[ATA--] ata_init: MemPool @ %p\n", LIBBASE
->ata_MemPool
));
323 /* Set default ata.device config options */
324 LIBBASE
->ata_32bit
= FALSE
;
325 LIBBASE
->ata_NoMulti
= FALSE
;
326 LIBBASE
->ata_NoDMA
= FALSE
;
327 LIBBASE
->ata_Poll
= FALSE
;
328 LIBBASE
->ata_CmdLine
= NULL
;
331 * start initialization:
332 * obtain kernel parameters
334 BootLoaderBase
= OpenResource("bootloader.resource");
335 D(bug("[ATA--] ata_init: BootloaderBase = %p\n", BootLoaderBase
));
336 if (BootLoaderBase
!= NULL
)
341 list
= (struct List
*)GetBootInfo(BL_Args
);
344 ForeachNode(list
, node
)
346 if (strncmp(node
->ln_Name
, "ATA=", 4) == 0)
349 * Remember the entire command line.
350 * Bus drivers (for example PCI one) may want it.
352 LIBBASE
->ata_CmdLine
= &node
->ln_Name
[4];
354 if (strstr(LIBBASE
->ata_CmdLine
, "32bit"))
356 D(bug("[ATA ] ata_init: Using 32-bit IO transfers\n"));
357 LIBBASE
->ata_32bit
= TRUE
;
359 if (strstr(LIBBASE
->ata_CmdLine
, "nomulti"))
361 D(bug("[ATA ] ata_init: Disabled multisector transfers\n"));
362 LIBBASE
->ata_NoMulti
= TRUE
;
364 if (strstr(LIBBASE
->ata_CmdLine
, "nodma"))
366 D(bug("[ATA ] ata_init: Disabled DMA transfers\n"));
367 LIBBASE
->ata_NoDMA
= TRUE
;
369 if (strstr(LIBBASE
->ata_CmdLine
, "poll"))
371 D(bug("[ATA ] ata_init: Using polling to detect end of busy state\n"));
372 LIBBASE
->ata_Poll
= TRUE
;
379 /* Initialize BUS list */
380 NEWLIST(&LIBBASE
->ata_Buses
);
387 LIBBASETYPEPTR LIBBASE
,
388 struct IORequest
*iorq
,
401 iorq
->io_Error
= IOERR_OPENFAIL
;
406 struct ata_Bus
*b
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
409 * Extract bus and device numbers
411 bus
= unitnum
>> 1; // 0xff00 >> 8
412 dev
= (unitnum
& 0x1); // 0x00ff
419 b
= (struct ata_Bus
*)b
->ab_Node
.mln_Succ
;
424 if (b
->ab_Node
.mln_Succ
== NULL
)
430 if (b
->ab_Units
[dev
] == NULL
)
436 iorq
->io_Device
= &LIBBASE
->ata_Device
;
437 iorq
->io_Unit
= &b
->ab_Units
[dev
]->au_Unit
;
440 b
->ab_Units
[dev
]->au_Unit
.unit_OpenCnt
++;
445 /* Close given device */
448 LIBBASETYPEPTR LIBBASE
,
449 struct IORequest
*iorq
452 struct ata_Unit
*unit
= (struct ata_Unit
*)iorq
->io_Unit
;
454 /* First of all make the important fields of struct IORequest invalid! */
455 iorq
->io_Unit
= (struct Unit
*)~0;
457 /* Decrease use counters of unit */
458 unit
->au_Unit
.unit_OpenCnt
--;
463 ADD2INITLIB(ata_init
, 0)
464 ADD2INITLIB(ata_Scan
, 127)
466 ADD2CLOSEDEV(close
, 0)
467 /* vim: set ts=8 sts=4 et : */