grub2: bring back build of aros-side grub2 tools
[AROS.git] / rom / hidds / ata_pci / bus_class.c
blob7b334c211dcebe0b0a3b81dab9685dc6df001cc8
1 /*
2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
7 #include <hardware/ata.h>
8 #include <hidd/ata.h>
9 #include <hidd/pci.h>
10 #include <oop/oop.h>
11 #include <utility/tagitem.h>
12 #include <proto/exec.h>
13 #include <proto/kernel.h>
14 #include <proto/oop.h>
15 #include <proto/utility.h>
17 #include "bus_class.h"
18 #include "interface_pio.h"
19 #include "interface_dma.h"
20 #include "pci.h"
22 AROS_INTH1(ata_PCI_Interrupt, struct ATA_BusData *, data)
24 AROS_INTFUNC_INIT
26 UBYTE status;
29 * The DMA status register indicates all interrupt types, not
30 * just DMA interrupts. However, if there's no DMA port, we have
31 * to rely on the busy flag, which is incompatible with IRQ sharing.
32 * We read ATA status register only once, because reading it tells
33 * the drive to deassert INTRQ.
35 if (data->bus->atapb_DMABase != 0)
37 port_t dmaStatusPort = dma_Status + data->bus->atapb_DMABase;
38 UBYTE dmastatus = inb(dmaStatusPort);
40 if (!(dmastatus & DMAF_Interrupt))
41 return FALSE;
44 * Acknowledge interrupt (note that the DMA interrupt bit should be
45 * cleared for all interrupt types).
46 * Clear DMA interrupt bit before clearing interrupt by reading status
47 * register. Otherwise, it seems that the DMA bit could get set again
48 * for a new interrupt before we clear it, resulting in a missed interrupt.
49 * Neil
51 outb(dmastatus | DMAF_Error | DMAF_Interrupt, dmaStatusPort);
52 status = inb(data->bus->atapb_IOBase + ata_Status);
54 else
56 status = inb(data->bus->atapb_IOBase + ata_Status);
58 if (status & ATAF_BUSY)
59 return FALSE;
62 data->ata_HandleIRQ(status, data->irqData);
63 return TRUE;
65 AROS_INTFUNC_EXIT
68 void ata_Raw_Interrupt(struct ATA_BusData *data, void *unused)
70 AROS_INTC1(ata_PCI_Interrupt, data);
73 OOP_Object *PCIATA__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
75 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, &msg->mID);
76 if (o)
78 struct ataBase *base = cl->UserData;
79 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
80 OOP_MethodID mDispose;
82 /* No check because we always supply this */
83 data->bus = (struct ata_ProbedBus *)GetTagData(aHidd_DriverData, 0, msg->attrList);
85 if (data->bus->atapb_DMABase)
88 * FIXME: Currently ata.device does not support shared DMA.
89 * In order to make it working, we disable DMA for secondary channel.
91 if (data->bus->atapb_BusNo > 0)
93 UBYTE dmaStatus = inb(data->bus->atapb_DMABase + dma_Status);
95 if (dmaStatus & DMAF_Simplex)
97 bug("[PCI-ATA] WARNING: Controller only supports "
98 "DMA on one bus at a time. DMAStatus=0x%02X\n", dmaStatus);
99 bug("[PCI-ATA] DMA for secondary bus disabled\n");
101 goto nodma;
105 /* We have a DMA controller and will need a buffer */
106 OOP_GetAttr(data->bus->atapb_Device->ref_Device,
107 aHidd_PCIDevice_Driver, (IPTR *)&data->pciDriver);
108 data->dmaBuf = HIDD_PCIDriver_AllocPCIMem(data->pciDriver,
109 (PRD_MAX + 1) * 2 * sizeof(struct PRDEntry));
111 nodma:
112 if (data->bus->atapb_Node.ln_Type == ATABUSNODEPRI_PROBED)
115 * We have a PCI device, install interrupt using portable PCI API.
116 * But do this only if the device is in native mode. In compatibility
117 * mode PCI configuration lies about interrupt number. Experienced
118 * on my Acer AspireOne.
119 * Perhaps this is portability issue but i don't know what to do with
120 * this. Amiga(tm) guys, please check/fix. One possibility is to switch
121 * to native mode here, but i believe in this case i would need to
122 * also set up all I/O regions. On AspireOne only BAR4 is set for IDE
123 * controller. So, also can be bad option. The best case would be if
124 * Amiga(tm) never uses compatibility mode.
125 * Pavel Fedin <pavel_fedin@mail.ru>.
127 struct Interrupt *pciInt = AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC);
129 if (pciInt)
131 pciInt->is_Node.ln_Name = ((struct Node *)cl->UserData)->ln_Name;
132 pciInt->is_Node.ln_Pri = 0;
133 pciInt->is_Data = data;
134 pciInt->is_Code = (APTR)ata_PCI_Interrupt;
136 data->irqHandle = pciInt;
137 if (HIDD_PCIDevice_AddInterrupt(data->bus->atapb_Device->ref_Device, pciInt))
139 /* Signal structure ownership */
140 data->bus->atapb_Node.ln_Succ = (struct Node *)-1;
141 return o;
144 FreeMem(pciInt, sizeof(struct Interrupt));
147 else
149 /* Legacy device. Use raw system IRQ. */
150 data->irqHandle = KrnAddIRQHandler(data->bus->atapb_INTLine, ata_Raw_Interrupt,
151 data, NULL);
152 if (data->irqHandle)
154 data->bus->atapb_Node.ln_Succ = (struct Node *)-1;
155 return o;
159 mDispose = msg->mID - moRoot_New + moRoot_Dispose;
160 OOP_DoSuperMethod(cl, o, &mDispose);
162 return NULL;
165 void DeviceFree(struct PCIDeviceRef *ref, struct ataBase *base)
167 HIDD_PCIDevice_Release(ref->ref_Device);
168 FreeMem(ref, sizeof(struct PCIDeviceRef));
171 void DeviceUnref(struct PCIDeviceRef *ref, struct ataBase *base)
173 ULONG count;
175 if (!ref)
176 return;
179 * Forbid() because dercement and fetch should be atomic.
180 * FIXME: We really need new atomics.
182 Forbid();
183 count = --ref->ref_Count;
184 Permit();
186 if (!count)
187 DeviceFree(ref, base);
190 void PCIATA__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
192 struct ataBase *base = cl->UserData;
193 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
195 if (data->dmaBuf)
196 HIDD_PCIDriver_FreePCIMem(data->pciDriver, data->dmaBuf);
198 if (data->bus->atapb_Node.ln_Type == ATABUSNODEPRI_PROBED)
200 HIDD_PCIDevice_RemoveInterrupt(data->bus->atapb_Device->ref_Device, data->irqHandle);
201 FreeMem(data->irqHandle, sizeof(struct Interrupt));
203 else
205 KrnRemIRQHandler(data->irqHandle);
208 DeviceUnref(data->bus->atapb_Device, base);
209 FreeVec(data->bus);
211 OOP_DoSuperMethod(cl, o, msg);
214 void PCIATA__Root__Get(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
216 struct ataBase *base = cl->UserData;
217 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
218 ULONG idx;
220 Hidd_ATABus_Switch(msg->attrID, idx)
222 case aoHidd_ATABus_Use80Wire:
223 if (data->bus->atapb_Device)
226 * The specification allows to specify per-device flag.
227 * However, both devices sit on the same cable, so we return
228 * TRUE if any of devices support it. We consider only a single
229 * bit because BIOSes may leave zero bits for missing drives.
231 UWORD crmask = (IOCFG_PCR0|IOCFG_PCR1) << (data->bus->atapb_BusNo << 1);
232 UWORD cfgreg = HIDD_PCIDevice_ReadConfigWord(data->bus->atapb_Device->ref_Device, IDE_IO_CFG);
234 D(bug("[PCI-ATA] Cable report bits 0x%04X\n", cfgreg & crmask));
235 *msg->storage = (cfgreg & crmask) ? TRUE : FALSE;
237 else
240 * This is ISA controller.
241 * Of course we can use 80-conductor cable on it. But there will
242 * be neither any way to detect it, nor any improvement. So FALSE.
244 *msg->storage = FALSE;
246 return;
248 case aoHidd_ATABus_UseDMA:
249 *msg->storage = data->bus->atapb_DMABase ? TRUE : FALSE;
250 return;
253 OOP_DoSuperMethod(cl, o, &msg->mID);
256 void PCIATA__Root__Set(OOP_Class *cl, OOP_Object *o, struct pRoot_Set *msg)
258 struct ataBase *base = cl->UserData;
259 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
260 struct TagItem *tstate = msg->attrList;
261 struct TagItem *tag;
263 while ((tag = NextTagItem(&tstate)))
265 ULONG idx;
267 Hidd_ATABus_Switch(tag->ti_Tag, idx)
269 case aoHidd_ATABus_IRQHandler:
270 data->ata_HandleIRQ = (APTR)tag->ti_Data;
271 break;
273 case aoHidd_ATABus_IRQData:
274 data->irqData = (APTR)tag->ti_Data;
275 break;
280 APTR PCIATA__Hidd_ATABus__GetPIOInterface(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
282 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
283 struct pio_data *pio = (struct pio_data *)OOP_DoSuperMethod(cl, o, msg);
285 if (pio)
287 pio->ioBase = data->bus->atapb_IOBase;
288 pio->ioAlt = data->bus->atapb_IOAlt;
291 return pio;
294 APTR PCIATA__Hidd_ATABus__GetDMAInterface(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
296 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
297 struct dma_data *dma;
299 /* If we don't have a DMA buffer, we cannot do DMA */
300 if (!data->dmaBuf)
301 return NULL;
303 /* If the DMA buffer is not in the first 4G, we cannot do DMA */
304 if ((IPTR)data->dmaBuf != (ULONG)(IPTR)data->dmaBuf)
305 return NULL;
307 dma = (struct dma_data *)OOP_DoSuperMethod(cl, o, msg);
308 if (dma)
310 dma->au_DMAPort = data->bus->atapb_DMABase;
311 dma->ab_PRD = data->dmaBuf;
313 /* Ensure table does not cross a 4kB boundary (required by VirtualBox,
314 if not by real hardware) */
315 if (0x1000 - ((ULONG)(IPTR)dma->ab_PRD & 0xfff) <
316 PRD_MAX * sizeof(struct PRDEntry))
318 dma->ab_PRD = (APTR)((((IPTR)dma->ab_PRD) + 0xfff) & ~0xfff);
322 return dma;
325 BOOL PCIATA__Hidd_ATABus__SetXferMode(OOP_Class *cl, OOP_Object *obj, OOP_Msg msg)
327 #if 0
329 * This code was copied from original ata.device code. There
330 * it was disabled because it is complete rubbish. According
331 * to specifications, these bits in DMA status register are
332 * informational only, and they are set by machine's firmware
333 * if it has successfully configured the drive for DMA operations.
334 * Actually, we should modify controller's timing registers here.
335 * The problem is that these registers are non-standard, and
336 * different controllers have them completely different.
337 * Or, perhaps we should simply check these registers here.
338 * Currently left as it was.
340 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
342 if (data->bus->atapb_DMAPort)
344 UBYTE type;
346 type = inb(dma_Status + unit->au_DMAPort) & 0x60;
347 if ((msg->mode >= AB_XFER_MDMA0) && (msg->mode <= AB_XFER_UDMA6))
349 type |= 1 << (5 + (msg->UnitNum & 1));
351 else
353 type &= ~(1 << (5 + (msg->UnitNum & 1)));
356 DINIT(bug("[PCI-ATA] SetXferMode: Trying to apply new DMA (%lx) status: %02lx (unit %ld)\n", unit->au_DMAPort, type, unitNum));
358 ata_outb(type, dma_Status + unit->au_DMAPort);
359 if (type != (inb(dma_Status + unit->au_DMAPort) & 0x60))
361 D(bug("[PCI-ATA] SetXferMode: Failed to modify DMA state for this device\n"));
362 return FALSE;
365 else if ((msg->mode >= AB_XFER_MDMA0) && (msg->mode <= AB_XFER_UDMA6))
367 /* DMA is not supported, we cannot set DMA modes */
368 return FALSE;
370 #endif
372 return TRUE;
375 void PCIATA__Hidd_ATABus__Shutdown(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
377 struct ATA_BusData *data = OOP_INST_DATA(cl, o);
378 port_t dmaBase = data->bus->atapb_DMABase;
380 if (dmaBase)
382 /* Shut down DMA */
383 outb(inb(dma_Command + dmaBase) & ~DMA_START, dma_Command + dmaBase);
384 outl(0, dma_PRD + dmaBase);
387 OOP_DoSuperMethod(cl, o, msg);