revert between 56095 -> 55830 in arch
[AROS.git] / rom / hidds / pci / pcidriverclass.c
blobeaeca45e75f1f782a3c0940097d0688c426579c9
1 /*
2 Copyright © 2004-2016, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Base PCI driver class
6 Lang: English
8 I am not sure, whether this piece of code is already aware of endianess.
9 Has to be checked soon ;)
12 #include <aros/debug.h>
13 #include <exec/types.h>
14 #include <hidd/hidd.h>
15 #include <hidd/pci.h>
16 #include <oop/oop.h>
17 #include <utility/tagitem.h>
18 #include <proto/exec.h>
19 #include <proto/kernel.h>
20 #include <proto/utility.h>
21 #include <proto/oop.h>
22 #include <aros/symbolsets.h>
24 #include "pci.h"
26 OOP_Object *PCIDrv__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
28 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
29 struct DrvInstData *instance = (struct DrvInstData *)OOP_INST_DATA(cl, o);
31 instance->DirectBus = GetTagData(aHidd_PCIDriver_DirectBus, TRUE, msg->attrList);
32 instance->IOBase = GetTagData(aHidd_PCIDriver_IOBase, 0, msg->attrList);
34 return o;
38 ULONG PCIDriver::ReadConfigLong(bus, dev, sub, reg)
40 This method is not implemented here (aka it should be the abstract class),
41 and should be well defined in all PCI drivers.
43 ULONG PCIDrv__Hidd_PCIDriver__ReadConfigLong(OOP_Class *cl, OOP_Object *o,
44 struct pHidd_PCIDriver_ReadConfigLong *msg)
46 /* Wheeeee! Someone has forgotten to reimplement ReadConfigLong! */
47 bug("[PCIDriver] Alert! PCIDriver::ReadConfigLong() unimplemented!\n");
48 return 0xffffffff;
52 PCIDriver::WriteConfigLong(bus, dev, sub, reg, val)
54 This method is not implemented here (aka it should be the abstract class),
55 and should be well defined in all PCI drivers.
57 void PCIDrv__Hidd_PCIDriver__WriteConfigLong(OOP_Class *cl, OOP_Object *o,
58 struct pHidd_PCIDriver_WriteConfigLong *msg)
60 /* Wheeeee! Someone has forgotten to reimplement WriteConfigLong! */
61 bug("[PCIDriver] Alert! PCIDriver::WriteConfigLong() unimplemented!\n");
65 IPTR PCIDriver::HasExtendedConfiguration(bus, dev, sub)
67 This does not need to be implemented in the driver; in that case
68 ECAM access method is not used and extended configuration is unavailable.
70 IPTR PCIDrv__Hidd_PCIDriver__HasExtendedConfig(OOP_Class *cl, OOP_Object *o,
71 struct pHidd_PCIDriver_HasExtendedConfig *msg)
73 /* Wheeeee! Someone has forgotten to reimplement HasExtendedConfig! */
74 bug("[PCIDriver] Alert! PCIDriver::HasExtendedConfig() unimplemented!\n");
75 return (IPTR)NULL;
79 Please note, that the following methods
81 UWORD PCIDriver::ReadConfigWord()
82 UBYTE PCIDriver::ReadConfigByte()
83 VOID PCIDriver::WriteConfigWord()
84 VOID PCIDriver::WriteConfigByte()
86 *MAY* be implemented in driver class, but *DON'T HAVE TO BE*. I wrote small
87 wrappers here using ReadConfigLong and WriteConfigLong in order to simplify
88 development of PCI drivers and reduce their size.
91 UBYTE PCIDrv__Hidd_PCIDriver__ReadConfigByte(OOP_Class *cl, OOP_Object *o,
92 struct pHidd_PCIDriver_ReadConfigByte *msg)
95 * First, read whole ConfigWord from PCI config space, using defined
96 * method
98 ULONG temp = HIDD_PCIDriver_ReadConfigLong(o, msg->device, msg->bus, msg->dev, msg->sub, msg->reg & ~3);
100 // Then, return only this part of the Long which is requested
101 return (temp >> ((msg->reg & 3) * 8)) & 0xff;
104 UWORD PCIDrv__Hidd_PCIDriver__ReadConfigWord(OOP_Class *cl, OOP_Object *o,
105 struct pHidd_PCIDriver_ReadConfigWord *msg)
107 ULONG temp = HIDD_PCIDriver_ReadConfigLong(o, msg->device, msg->bus, msg->dev, msg->sub, msg->reg & ~3);
109 return (temp >> ((msg->reg & 2) * 8)) & 0xffff;
112 void PCIDrv__Hidd_PCIDriver__WriteConfigByte(OOP_Class *cl, OOP_Object *o,
113 struct pHidd_PCIDriver_WriteConfigByte *msg)
115 ULONG temp;
116 const int shift = (msg->reg & 3) * 8;
118 // Read whole Long from PCI config space.
119 temp = HIDD_PCIDriver_ReadConfigLong(o, msg->device, msg->bus, msg->dev, msg->sub, msg->reg & ~3);
121 // Modify proper part of it according to request.
122 temp = (temp & ~(0xff << shift)) | ((ULONG)msg->val << shift);
124 // And put whole Long again into PCI config space.
125 HIDD_PCIDriver_WriteConfigLong(o, msg->device, msg->bus, msg->dev, msg->sub, msg->reg & ~3, temp);
128 void PCIDrv__Hidd_PCIDriver__WriteConfigWord(OOP_Class *cl, OOP_Object *o,
129 struct pHidd_PCIDriver_WriteConfigWord *msg)
131 ULONG temp;
132 const int shift = (msg->reg & 2) * 8;
134 // Read whole Long from PCI config space.
135 temp = HIDD_PCIDriver_ReadConfigLong(o, msg->device, msg->bus, msg->dev, msg->sub, msg->reg & ~3);
137 // Modify proper part of it according to request.
138 temp = (temp & ~(0xffff << shift)) | ((ULONG)msg->val << shift);
140 // And put whole Long again into PCI config space.
141 HIDD_PCIDriver_WriteConfigLong(o, msg->device, msg->bus, msg->dev, msg->sub, msg->reg & ~3, temp);
145 PCIDriver::CPUtoPCI() converts the address as seen by CPU into the
146 address seen by the PCI bus. Do not reimplement this function, if
147 CPU and PCI address spaces are equal on the machine you're writing a
148 driver for
150 APTR PCIDrv__Hidd_PCIDriver__CPUtoPCI(OOP_Class *cl, OOP_Object *o,
151 struct pHidd_PCIDriver_CPUtoPCI *msg)
153 struct DrvInstData *instance = (struct DrvInstData *)OOP_INST_DATA(cl, o);
155 if (instance->DirectBus)
156 return (APTR)msg->address;
157 else
158 return (APTR)-1;
162 PCIDriver::PCItoCPU() is opposite to above.
164 APTR PCIDrv__Hidd_PCIDriver__PCItoCPU(OOP_Class *cl, OOP_Object *o,
165 struct pHidd_PCIDriver_PCItoCPU *msg)
167 struct DrvInstData *instance = (struct DrvInstData *)OOP_INST_DATA(cl, o);
169 if (instance->DirectBus)
170 return (APTR)msg->address;
171 else
172 return (APTR)-1;
176 PCIDriver::MapPCI(Address, Length) maps the Length bytes of PCI address
177 space at Address to the CPU address space.
179 APTR PCIDrv__Hidd_PCIDriver__MapPCI(OOP_Class *cl, OOP_Object *o,
180 struct pHidd_PCIDriver_MapPCI *msg)
183 * Generic driver in case of DirectAccess PCI bus.
184 * Our memory space is already mapped, but we may still need
185 * to perform physical to virtual translation (in case our
186 * system uses virtual addressing).
188 struct DrvInstData *instance = (struct DrvInstData *)OOP_INST_DATA(cl, o);
190 if (instance->DirectBus)
191 return HIDD_PCIDriver_PCItoCPU(o, msg->PCIAddress);
192 else
193 return (APTR)-1;
197 PCIDriver::UnmapPCI(Address, Length) unmaps the mapped PCI area previously
198 allocated with MapPCI method.
200 VOID PCIDrv__Hidd_PCIDriver__UnmapPCI(OOP_Class *cl, OOP_Object *o,
201 struct pHidd_PCIDriver_UnmapPCI *msg)
203 /* Generic driver has nothing to do here */
207 PCIDriver::AllocPCIMem(Size) allocates memory region available for
208 PCI BusMaster devices.
210 APTR PCIDrv__Hidd_PCIDriver__AllocPCIMem(OOP_Class *cl, OOP_Object *o,
211 struct pHidd_PCIDriver_AllocPCIMem *msg)
213 APTR memory = AllocVec(msg->Size + 4096 + AROS_ALIGN(sizeof(APTR)), MEMF_31BIT|MEMF_CLEAR);
214 IPTR diff;
216 diff = (IPTR)memory - (AROS_ROUNDUP2((IPTR)memory + sizeof(APTR), 4096));
217 *((APTR*)((IPTR)memory - diff - sizeof(APTR))) = memory;
219 return (APTR)((IPTR)memory - diff);
223 PCIDriver::FreePCIMemory(Address) frees previously allocated memory for PCI
224 devices
226 VOID PCIDrv__Hidd_PCIDriver__FreePCIMem(OOP_Class *cl, OOP_Object *o,
227 struct pHidd_PCIDriver_FreePCIMem *msg)
229 APTR memory = *(APTR*)((IPTR)msg->Address - sizeof(APTR));
230 FreeVec(memory);
233 static void krnIRQwrapper(void *data1, void *data2)
235 struct Interrupt *irq = (struct Interrupt *)data1;
237 AROS_INTC1(irq->is_Code, irq->is_Data);
240 /*****************************************************************************************
242 NAME
243 moHidd_PCIDriver_AddInterrupt
245 SYNOPSIS
246 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDriver_AddInterrupt *Msg);
248 OOP_Object *HIDD_PCIDriver_AddInterrupt(OOP_Object *obj, OOP_Object *device,
249 struct Interrupt *interrupt);
251 LOCATION
252 CLID_Hidd_PCIDriver
254 FUNCTION
255 Add interrupt handler for the specified device.
257 This method is present in order to provide abstraction for
258 different PCI implementations. Default implementation of
259 this method assumes 1:1 mapping between system interrupts
260 and PCI interrupts. However, on some machines this is not
261 true (an example is Amiga(tm) bridgeboards). In this case
262 you will have to provide alternate implementation of this
263 method.
265 INPUTS
266 obj - Pointer to your driver object.
267 device - A pointer to the device object.
268 interrupt - Interrupt structure to add.
270 RESULT
271 TRUE it succesful or FALSE on failure.
273 NOTES
275 EXAMPLE
277 BUGS
279 SEE ALSO
280 moHidd_PCIDriver_RemoveInterrupt
282 INTERNALS
284 *****************************************************************************************/
286 BOOL PCIDrv__Hidd_PCIDriver__AddInterrupt(OOP_Class *cl, OOP_Object *o,
287 struct pHidd_PCIDriver_AddInterrupt *msg)
289 IPTR irq;
291 OOP_GetAttr(msg->device, aHidd_PCIDevice_INTLine, &irq);
292 msg->interrupt->is_Node.ln_Succ =
293 KrnAddIRQHandler(irq, krnIRQwrapper, msg->interrupt, NULL);
294 return msg->interrupt->is_Node.ln_Succ ? TRUE : FALSE;
297 /*****************************************************************************************
299 NAME
300 moHidd_PCIDriver_RemoveInterrupt
302 SYNOPSIS
303 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDriver_RemoveInterrupt *Msg);
305 OOP_Object *HIDD_PCIDriver_RemoveInterrupt(OOP_Object *obj, OOP_Object *device,
306 struct Interrupt *interrupt);
308 LOCATION
309 CLID_Hidd_PCIDriver
311 FUNCTION
312 Remove interrupt handler from the specified device.
314 This method is present in order to provide abstraction for
315 different PCI implementations. Default implementation of
316 this method assumes 1:1 mapping between system interrupts
317 and PCI interrupts. However, on some machines this is not
318 true (an example is Amiga(tm) bridgeboards). In this case
319 you will have to provide alternate implementation of this
320 method.
322 INPUTS
323 obj - Pointer to your driver object.
324 device - A pointer to the device object.
325 interrupt - Interrupt structure to remove.
327 RESULT
328 None.
330 NOTES
332 EXAMPLE
334 BUGS
336 SEE ALSO
337 moHidd_PCIDriver_AddInterrupt
339 INTERNALS
341 *****************************************************************************************/
343 VOID PCIDrv__Hidd_PCIDriver__RemoveInterrupt(OOP_Class *cl, OOP_Object *o,
344 struct pHidd_PCIDriver_RemoveInterrupt *msg)
346 KrnRemIRQHandler(msg->interrupt->is_Node.ln_Succ);
349 VOID PCIDrv__Root__Get(OOP_Class *cl, OOP_Object *o,
350 struct pRoot_Get *msg)
352 ULONG idx;
353 struct DrvInstData *instance = (struct DrvInstData *)OOP_INST_DATA(cl, o);
355 if (IS_PCIDRV_ATTR(msg->attrID, idx))
357 switch(idx)
359 case aoHidd_PCIDriver_DirectBus:
360 *msg->storage = (IPTR)instance->DirectBus;
361 break;
363 case aoHidd_PCIDriver_IOBase:
364 *msg->storage = (IPTR)instance->IOBase;
365 break;
367 case aoHidd_PCIDriver_IRQRoutingTable:
368 *msg->storage = (IPTR)0;
369 break;
371 default:
372 OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
373 break;
376 else
378 OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);