revert between 56095 -> 55830 in arch
[AROS.git] / rom / hidds / pci / pcideviceclass.c
blob1d5a0b1730723b6c6d9b3e1466142fd6e6c794db
1 /*
2 Copyright © 2004-2016, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: PCI device class
6 Lang: English
7 */
9 #include <exec/types.h>
10 #include <hidd/pci.h>
11 #include <oop/oop.h>
12 #include <utility/tagitem.h>
13 #include <proto/exec.h>
14 #include <proto/utility.h>
15 #include <proto/oop.h>
17 #include "pci.h"
18 #include "pcie.h"
19 #include "pciutil.h"
21 #include <aros/debug.h>
23 /*****************************************************************************************
25 NAME
26 aoHidd_PCIDevice_Owner
28 SYNOPSIS
29 [..G], APTR
31 LOCATION
32 CLID_Hidd_PCIDevice
34 FUNCTION
35 Returns name of current device's owner or NULL if the device is
36 not owned by anyone.
38 NOTES
39 This attribute is provided for diagnostics utilities like PCITool.
40 There is no need to check current owner before attempting to own
41 the device. moHidd_PCIDevice_Obtain method performs this check
42 and owns the device atomically.
44 EXAMPLE
46 BUGS
48 SEE ALSO
50 INTERNALS
52 *****************************************************************************************/
53 static IPTR hasExtendedConfig(OOP_Class *cl, OOP_Object *o)
55 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
57 return dev->extendedconfig;
60 static void setLong(OOP_Class *cl, OOP_Object *o, ULONG reg, ULONG value)
62 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
64 HIDD_PCIDriver_WriteConfigLong(dev->driver, (OOP_Object *)dev, dev->bus, dev->dev, dev->sub, reg, value);
67 static void setWord(OOP_Class *cl, OOP_Object *o, ULONG reg, UWORD value)
69 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
71 HIDD_PCIDriver_WriteConfigWord(dev->driver, (OOP_Object *)dev, dev->bus, dev->dev, dev->sub, reg, value);
74 static void setByte(OOP_Class *cl, OOP_Object *o, ULONG reg, UBYTE value)
76 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
78 HIDD_PCIDriver_WriteConfigByte(dev->driver, (OOP_Object *)dev, dev->bus, dev->dev, dev->sub, reg, value);
81 static ULONG getLong(OOP_Class *cl, OOP_Object *o, ULONG reg)
83 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
85 return HIDD_PCIDriver_ReadConfigLong(dev->driver, (OOP_Object *)dev, dev->bus, dev->dev, dev->sub, reg);
88 static UWORD getWord(OOP_Class *cl, OOP_Object *o, ULONG reg)
90 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
92 return HIDD_PCIDriver_ReadConfigWord(dev->driver, (OOP_Object *)dev, dev->bus, dev->dev, dev->sub, reg);
95 static UBYTE getByte(OOP_Class *cl, OOP_Object *o, ULONG reg)
97 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
99 return HIDD_PCIDriver_ReadConfigByte(dev->driver, (OOP_Object *)dev, dev->bus, dev->dev, dev->sub, reg);
102 /* Returns offset of capability area in config area or 0 if capability is not present */
103 static UBYTE findCapabilityOffset(OOP_Class * cl, OOP_Object *o, UBYTE capability)
105 UWORD where = 0x34; /* First cap list entry */
106 UBYTE capid = 0;
108 /* Check if capabilities present at all */
109 if ((getWord(cl, o, PCICS_STATUS) & PCISTF_CAPABILITIES) != PCISTF_CAPABILITIES)
110 return 0;
112 /* Iterate over capabilities */
113 while(where < 0xff)
115 where = getByte(cl, o, where);
117 if (where < 0x40)
118 break;
120 where &= ~3;
121 capid = getByte(cl, o, where);
123 if (capid == 0xff)
124 break;
126 if (capid == capability) return (UBYTE)where;
128 where += 1; /* next cap */
131 return 0;
134 /* Returns offset of PCI Express extended capability or 0 if capability is not present */
135 static UWORD findExpressExtendedCapabilityOffset(OOP_Class * cl, OOP_Object *o, UWORD capability)
137 UWORD where = 0x100; /* First PCI Express extended cap list entry */
138 ULONG caphdr;
140 while((where > 0xff) && (where < 0xfff))
142 caphdr = getLong(cl, o, where);
143 if( (caphdr == -1) || (caphdr == 0)) return 0;
145 if ((caphdr & 0xffff) == capability) return (UWORD)where;
147 where = (caphdr>>20)&~3;
150 return 0;
153 BOOL PCIDev__Hidd_PCIDevice__HasExtendedConfig(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_HasExtendedConfig *msg)
155 return hasExtendedConfig(cl, o);
158 UBYTE PCIDev__Hidd_PCIDevice__ReadConfigByte(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_ReadConfigByte *msg)
160 return getByte(cl, o, msg->reg);
163 UWORD PCIDev__Hidd_PCIDevice__ReadConfigWord(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_ReadConfigWord *msg)
165 return getWord(cl, o, msg->reg);
168 ULONG PCIDev__Hidd_PCIDevice__ReadConfigLong(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_ReadConfigLong *msg)
170 return getLong(cl, o, msg->reg);
173 VOID PCIDev__Hidd_PCIDevice__WriteConfigByte(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_WriteConfigByte *msg)
175 setByte(cl, o, msg->reg, msg->val);
178 VOID PCIDev__Hidd_PCIDevice__WriteConfigWord(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_WriteConfigWord *msg)
180 setWord(cl, o, msg->reg, msg->val);
183 VOID PCIDev__Hidd_PCIDevice__WriteConfigLong(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_WriteConfigLong *msg)
185 setLong(cl, o, msg->reg, msg->val);
188 /*****************************************************************************************
190 NAME
191 moHidd_PCIDevice_AddInterrupt
193 SYNOPSIS
194 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_AddInterrupt *Msg);
196 OOP_Object *HIDD_PCIDriver_AddInterrupt(OOP_Object *obj, OOP_Object *device,
197 struct Interrupt *interrupt);
199 LOCATION
200 CLID_Hidd_PCIDevice
202 FUNCTION
203 Add interrupt handler for the device.
205 INPUTS
206 obj - Pointer to device object.
207 interrupt - Interrupt structure to add.
209 RESULT
210 TRUE it successful or FALSE on failure.
212 NOTES
214 EXAMPLE
216 BUGS
218 SEE ALSO
219 moHidd_PCIDevice_RemoveInterrupt
221 INTERNALS
223 *****************************************************************************************/
225 BOOL PCIDev__Hidd_PCIDevice__AddInterrupt(OOP_Class *cl, OOP_Object *o,
226 struct pHidd_PCIDevice_AddInterrupt *msg)
228 tDeviceData *dev = OOP_INST_DATA(cl, o);
230 return HIDD_PCIDriver_AddInterrupt(dev->driver, o, msg->interrupt);
233 /*****************************************************************************************
235 NAME
236 moHidd_PCIDevice_RemoveInterrupt
238 SYNOPSIS
239 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_RemoveInterrupt *Msg);
241 OOP_Object *HIDD_PCIDevice_RemoveInterrupt(OOP_Object *obj, OOP_Object *device,
242 struct Interrupt *interrupt);
244 LOCATION
245 CLID_Hidd_PCIDevice
247 FUNCTION
248 Remove interrupt handler from the device.
250 INPUTS
251 obj - Pointer to the device object.
252 interrupt - Interrupt structure to remove.
254 RESULT
255 None.
257 NOTES
259 EXAMPLE
261 BUGS
263 SEE ALSO
264 moHidd_PCIDevice_AddInterrupt
266 INTERNALS
268 *****************************************************************************************/
270 VOID PCIDev__Hidd_PCIDevice__RemoveInterrupt(OOP_Class *cl, OOP_Object *o,
271 struct pHidd_PCIDevice_RemoveInterrupt *msg)
273 tDeviceData *dev = OOP_INST_DATA(cl, o);
275 return HIDD_PCIDriver_RemoveInterrupt(dev->driver, o, msg->interrupt);
278 /*****************************************************************************************
280 NAME
281 moHidd_PCIDevice_Obtain
283 SYNOPSIS
284 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_Obtain *Msg);
286 OOP_Object *HIDD_PCIDevice_Obtain(OOP_Object *obj, CONST_STRPTR owner);
288 LOCATION
289 CLID_Hidd_PCIDevice
291 FUNCTION
292 Lock the device for exclusive use.
294 INPUTS
295 obj - Pointer to the device object.
296 owner - A string identifying the owner.
298 RESULT
299 NULL on success or string identifying current owner.
301 NOTES
303 EXAMPLE
305 BUGS
307 SEE ALSO
308 moHidd_PCIDevice_Release
310 INTERNALS
312 *****************************************************************************************/
314 CONST_STRPTR PCIDev__Hidd_PCIDevice__Obtain(OOP_Class *cl, OOP_Object *o,
315 struct pHidd_PCIDevice_Obtain *msg)
317 tDeviceData *dev = OOP_INST_DATA(cl, o);
318 CONST_STRPTR current = NULL;
321 * FIXME: Actually this is just atomic compare and swap.
322 * I believe it should be impemented in assembler.
323 * Ouch, on Amiga such operations are unsafe, at least
324 * in CHIP memory. Too bad...
326 ObtainSemaphore(&dev->ownerLock);
328 /* While we are using semaphore, owner name is embedded in its node */
329 if (dev->ownerLock.ss_Link.ln_Name)
330 current = dev->ownerLock.ss_Link.ln_Name;
331 else
332 dev->ownerLock.ss_Link.ln_Name = (STRPTR)msg->owner;
334 ReleaseSemaphore(&dev->ownerLock);
336 return current;
339 /*****************************************************************************************
341 NAME
342 moHidd_PCIDevice_Release
344 SYNOPSIS
345 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_Release *Msg);
347 OOP_Object *HIDD_PCIDevice_Release(OOP_Object *obj);
349 LOCATION
350 CLID_Hidd_PCIDevice
352 FUNCTION
353 Release ownership of the device.
355 INPUTS
356 obj - Pointer to the device object.
358 RESULT
359 None.
361 NOTES
362 You should call this function only on devices owned by you. Doing
363 this on someone else's devices will not do any good things.
365 EXAMPLE
367 BUGS
369 SEE ALSO
370 moHidd_PCIDevice_Obtain
372 INTERNALS
374 *****************************************************************************************/
376 VOID PCIDev__Hidd_PCIDevice__Release(OOP_Class *cl, OOP_Object *o,
377 struct pHidd_PCIDevice_Release *msg)
379 tDeviceData *dev = OOP_INST_DATA(cl, o);
381 dev->ownerLock.ss_Link.ln_Name = NULL;
385 PCIDevice::New method is invoked by base pci class. It passes to the device
386 class information about the driver this class should use and location of
387 created device on the PCI bus handled by given driver.
389 OOP_Object *PCIDev__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
391 int i;
393 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
394 if (o)
396 struct TagItem *tag, *tags;
397 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl, o);
398 OOP_Object *driver = NULL;
400 InitSemaphore(&dev->ownerLock);
402 tags=(struct TagItem *)msg->attrList;
405 Get all information passed by pci class calling OOP_NewObject()
407 while((tag = NextTagItem(&tags)))
409 ULONG idx;
411 if (IS_PCIDEV_ATTR(tag->ti_Tag, idx))
413 switch(idx)
415 case aoHidd_PCIDevice_Driver:
416 dev->driver = (OOP_Object*)tag->ti_Data;
417 driver = dev->driver;
418 break;
420 case aoHidd_PCIDevice_Bus:
421 dev->bus = tag->ti_Data;
422 break;
424 case aoHidd_PCIDevice_Dev:
425 dev->dev = tag->ti_Data;
426 break;
428 case aoHidd_PCIDevice_Sub:
429 dev->sub = tag->ti_Data;
430 break;
432 case aoHidd_PCIDevice_ExtendedConfig:
433 dev->extendedconfig = tag->ti_Data;
434 break;
440 If driver is passed (*HAS TO* be passed) acquire some unchangeable
441 information regarding given device
443 if (driver)
445 UBYTE ht;
448 Get the header type in order to determine whether it is a
449 device or bridge
451 ht = getByte(cl, o, PCICS_HEADERTYPE) & PCIHT_MASK;
452 dev->isBridge = 0;
453 if (ht == PCIHT_BRIDGE)
455 dev->isBridge = 1;
456 dev->secbus = getByte(cl, o, PCIBR_SECBUS);
459 /* Get all constant ID's */
460 dev->VendorID = getWord(cl, o, PCICS_VENDOR);
461 dev->ProductID = getWord(cl, o, PCICS_PRODUCT);
463 dev->RevisionID = getByte(cl, o, PCICS_REVISION);
464 dev->Interface = getByte(cl, o, PCICS_PROGIF);
465 dev->SubClass = getByte(cl, o, PCICS_SUBCLASS);
466 dev->Class = getByte(cl, o, PCICS_CLASS);
468 dev->SubsysVID = getWord(cl, o, PCICS_SUBVENDOR);
469 dev->SubsystemID = getWord(cl, o, PCICS_SUBSYSTEM);
471 dev->IRQLine = getByte(cl, o, PCICS_INT_PIN);
473 if (dev->IRQLine)
475 dev->INTLine = getByte(cl, o, PCICS_INT_LINE);
477 else dev->INTLine = 0;
479 dev->HeaderType = ht;
481 getPCIClassDesc(dev->Class, dev->SubClass, dev->Interface,
482 &dev->strClass, &dev->strSubClass, &dev->strInterface);
484 /* Satisfy BUG watchers ;) */
485 D(bug("[PCIDevice] %02x.%02x.%x = %04.4lx:%04.4lx (%s %s %s)\n",
486 dev->bus, dev->dev, dev->sub,
487 dev->VendorID, dev->ProductID,
488 dev->strClass, dev->strSubClass, dev->strInterface));
489 D(bug("[PCIDevice] > IRQ %u INT %u\n", dev->IRQLine, dev->INTLine));
491 // print out a warning to the user in case the interrupt line is not assigned by BIOS
492 if (dev->INTLine == 255 && !dev->isBridge)
493 bug("[PCIDevice] WARNING: Interrupt line is not assigned! Device may freeze or malfunction at use!\n");
495 /* Read two first base addresses */
496 for (i = 0; i < 2; i++)
498 dev->BaseReg[i].addr = getLong(cl, o, PCICS_BAR0 + (i << 2));
499 dev->BaseReg[i].size = sizePCIBaseReg(driver, PSD(cl), dev, dev->bus,
500 dev->dev, dev->sub, i);
503 /* Address and size of ROM */
504 dev->RomBase = getLong(cl, o, PCICS_EXPROM_BASE);
505 dev->RomSize = sizePCIBaseReg(driver, PSD(cl), dev, dev->bus,
506 dev->dev, dev->sub, (PCICS_EXPROM_BASE - PCICS_BAR0) >> 2);
509 Bridges specify only first two base addresses. If not bridge,
510 check the rest now
512 if (! dev->isBridge)
514 for (i = 2; i < 6; i++)
516 dev->BaseReg[i].addr = getLong(cl, o, PCICS_BAR0 + (i << 2));
517 dev->BaseReg[i].size = sizePCIBaseReg(driver, PSD(cl), dev, dev->bus,
518 dev->dev, dev->sub, i);
524 return o;
528 PCIDevice::Get method splitted into few parts in order to make switch'es shorter.
531 static void dispatch_generic(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
533 ULONG idx;
534 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
536 idx = msg->attrID - HiddPCIDeviceAttrBase;
538 switch(idx)
540 case aoHidd_PCIDevice_Driver:
541 *msg->storage = (IPTR)dev->driver;
542 break;
544 case aoHidd_PCIDevice_Bus:
545 *msg->storage = (IPTR)dev->bus;
546 break;
548 case aoHidd_PCIDevice_Dev:
549 *msg->storage = (IPTR)dev->dev;
550 break;
552 case aoHidd_PCIDevice_Sub:
553 *msg->storage = (IPTR)dev->sub;
554 break;
556 case aoHidd_PCIDevice_VendorID:
557 *msg->storage = (IPTR)dev->VendorID;
558 break;
560 case aoHidd_PCIDevice_ProductID:
561 *msg->storage = (IPTR)dev->ProductID;
562 break;
564 case aoHidd_PCIDevice_RevisionID:
565 *msg->storage = (IPTR)dev->RevisionID;
566 break;
568 case aoHidd_PCIDevice_Interface:
569 *msg->storage = (IPTR)dev->Interface;
570 break;
572 case aoHidd_PCIDevice_Class:
573 *msg->storage = (IPTR)dev->Class;
574 break;
576 case aoHidd_PCIDevice_SubClass:
577 *msg->storage = (IPTR)dev->SubClass;
578 break;
580 case aoHidd_PCIDevice_SubsystemVendorID:
581 *msg->storage = (IPTR)dev->SubsysVID;
582 break;
584 case aoHidd_PCIDevice_SubsystemID:
585 *msg->storage = (IPTR)dev->SubsystemID;
586 break;
588 case aoHidd_PCIDevice_IRQLine:
589 *msg->storage = (IPTR)dev->IRQLine;
590 break;
592 case aoHidd_PCIDevice_RomBase:
593 *msg->storage = (IPTR)dev->RomBase;
594 break;
596 case aoHidd_PCIDevice_RomSize:
597 *msg->storage = (IPTR)dev->RomSize;
598 break;
600 case aoHidd_PCIDevice_ExtendedConfig:
601 *msg->storage = (IPTR)dev->extendedconfig;
602 break;
604 case aoHidd_PCIDevice_ConfigSize:
605 if(dev->extendedconfig) {
606 *msg->storage = 4096;
607 } else {
608 *msg->storage = 256;
610 break;
615 static void dispatch_base(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
617 ULONG idx,id;
618 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
620 idx = msg->attrID - HiddPCIDeviceAttrBase;
621 id = 0;
623 switch(idx)
625 case aoHidd_PCIDevice_Base0: id = 0; break;
626 case aoHidd_PCIDevice_Base1: id = 1; break;
627 case aoHidd_PCIDevice_Base2: id = 2; break;
628 case aoHidd_PCIDevice_Base3: id = 3; break;
629 case aoHidd_PCIDevice_Base4: id = 4; break;
630 case aoHidd_PCIDevice_Base5: id = 5; break;
633 /* Do not allow reading of more than two base addresses in case of PCI-PCI bridges */
634 if (dev->isBridge && id >= 2) { *msg->storage = 0; return; }
636 *msg->storage = (IPTR)dev->BaseReg[id].addr;
637 if ((dev->BaseReg[id].addr & PCIBAR_MASK_TYPE)==PCIBAR_TYPE_IO)
639 IPTR IOBase = 0;
640 *msg->storage &= PCIBAR_MASK_IO;
641 OOP_GetAttr(dev->driver, aHidd_PCIDriver_IOBase, &IOBase);
642 *msg->storage += IOBase;
644 else
646 *msg->storage &= PCIBAR_MASK_MEM;
650 static void dispatch_type(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
652 ULONG idx,id;
653 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
655 idx = msg->attrID - HiddPCIDeviceAttrBase;
656 id = 0;
658 switch(idx)
660 case aoHidd_PCIDevice_Type0: id = 0; break;
661 case aoHidd_PCIDevice_Type1: id = 1; break;
662 case aoHidd_PCIDevice_Type2: id = 2; break;
663 case aoHidd_PCIDevice_Type3: id = 3; break;
664 case aoHidd_PCIDevice_Type4: id = 4; break;
665 case aoHidd_PCIDevice_Type5: id = 5; break;
668 /* Do not allow reading of more than two base addresses in case of PCI-PCI bridges */
669 if (dev->isBridge && id >= 2) { *msg->storage = 0; return; }
671 *msg->storage = (IPTR)dev->BaseReg[id].addr;
672 if ((dev->BaseReg[id].addr & PCIBAR_MASK_TYPE)==PCIBAR_TYPE_IO)
674 *msg->storage &= ~PCIBAR_MASK_IO;
676 else
678 *msg->storage &= ~PCIBAR_MASK_MEM;
682 static void dispatch_size(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
684 ULONG idx,id;
685 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
687 idx = msg->attrID - HiddPCIDeviceAttrBase;
688 id = 0;
690 switch(idx)
692 case aoHidd_PCIDevice_Size0: id = 0; break;
693 case aoHidd_PCIDevice_Size1: id = 1; break;
694 case aoHidd_PCIDevice_Size2: id = 2; break;
695 case aoHidd_PCIDevice_Size3: id = 3; break;
696 case aoHidd_PCIDevice_Size4: id = 4; break;
697 case aoHidd_PCIDevice_Size5: id = 5; break;
700 /* Do not allow reading of more than two base addresses in case of PCI-PCI bridges */
701 if (dev->isBridge && id >= 2) { *msg->storage = 0; return;}
703 *msg->storage = (IPTR)dev->BaseReg[id].size;
706 static void dispatch_pci2pcibridge(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
708 ULONG idx;
709 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
711 UWORD control;
713 /* If device is not a PCI-PCI bridge, do nothing */
714 if (!dev->isBridge) { *msg->storage = 0; return; }
716 control = getWord(cl, o, PCIBR_CONTROL);
718 idx = msg->attrID - HiddPCIDeviceAttrBase;
720 switch(idx)
722 case aoHidd_PCIDevice_isBridge:
723 *msg->storage = dev->isBridge;
724 break;
726 case aoHidd_PCIDevice_SecBus:
727 *msg->storage = dev->secbus;
728 break;
730 case aoHidd_PCIDevice_MemoryBase:
731 *msg->storage = getWord(cl, o, PCIBR_MEMBASE) << 16;
732 break;
734 case aoHidd_PCIDevice_MemoryLimit:
735 *msg->storage = getWord(cl, o, PCIBR_MEMLIMIT) << 16;
736 break;
738 case aoHidd_PCIDevice_PrefetchableBase:
739 *msg->storage = getWord(cl, o, PCIBR_PREFETCHBASE) << 16;
740 break;
742 case aoHidd_PCIDevice_PrefetchableLimit:
743 *msg->storage = getWord(cl, o, PCIBR_PREFETCHLIMIT) << 16;
744 break;
746 case aoHidd_PCIDevice_IOBase:
747 *msg->storage = getByte(cl, o, PCIBR_IOBASE) << 8;
748 break;
750 case aoHidd_PCIDevice_IOLimit:
751 *msg->storage = getByte(cl, o, PCIBR_IOLIMIT) << 8;
752 break;
754 case aoHidd_PCIDevice_ISAEnable:
755 *msg->storage = (control & PCICTRLF_ISAENABLE) == PCICTRLF_ISAENABLE;
756 break;
758 case aoHidd_PCIDevice_VGAEnable:
759 *msg->storage = (control & PCICTRLF_VGAENABLE) == PCICTRLF_VGAENABLE;
760 break;
764 static void dispatch_capability(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
766 ULONG idx;
767 UBYTE capability = 0;
768 //tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
770 idx = msg->attrID - HiddPCIDeviceAttrBase;
772 switch(idx)
774 case aoHidd_PCIDevice_CapabilityPowerManagement: capability = PCICAP_POWER_MANAGEMENT;break;
775 case aoHidd_PCIDevice_CapabilityAGP: capability = PCICAP_AGP;break;
776 case aoHidd_PCIDevice_CapabilityVitalProductData: capability = PCICAP_VITAL_PRODUCT_DATA;break;
777 case aoHidd_PCIDevice_CapabilitySlotID: capability = PCICAP_SLOT_ID;break;
778 case aoHidd_PCIDevice_CapabilityMSI: capability = PCICAP_MSI;break;
779 case aoHidd_PCIDevice_CapabilityCPCIHotSwap: capability = PCICAP_CPCI_HOT_SWAP;break;
780 case aoHidd_PCIDevice_CapabilityPCIX: capability = PCICAP_PCIX;break;
781 case aoHidd_PCIDevice_CapabilityHyperTransport: capability = PCICAP_HYPER_TRANSPORT;break;
782 case aoHidd_PCIDevice_CapabilityVendorSpecific: capability = PCICAP_VENDOR_SPECIFIC;break;
783 case aoHidd_PCIDevice_CapabilityDebugPort: capability = PCICAP_DEBUG_PORT;break;
784 case aoHidd_PCIDevice_CapabilityCPCICRC: capability = PCICAP_CPCI_CR;break;
785 case aoHidd_PCIDevice_CapabilityHotPlugController: capability = PCICAP_HOT_PLUG_CONTROLLER;break;
786 case aoHidd_PCIDevice_CapabilitySSVPID: capability = PCICAP_SSVPID;break;
787 case aoHidd_PCIDevice_CapabilityAGP3: capability = PCICAP_AGP3;break;
788 case aoHidd_PCIDevice_CapabilityPCIE: capability = PCICAP_PCIE;break;
789 case aoHidd_PCIDevice_CapabilityMSIX: capability = PCICAP_MSIX;break;
790 case aoHidd_PCIDevice_CapabilityAdvancedFeatures: capability = PCICAP_ADVANCED_FEATURES;break;
793 *msg->storage = findCapabilityOffset(cl, o, capability);
796 static void dispatch_extendedcapability(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
798 ULONG idx;
799 UWORD capability = 0;
801 if(!hasExtendedConfig(cl, o))
803 D(bug("[PCIDevice] HasExtendedConfig = NULL\n"));
804 *msg->storage = 0;
805 return;
808 D(bug("[PCIDevice] HasExtendedConfig != NULL!\n"));
810 idx = msg->attrID - HiddPCIDeviceAttrBase;
812 switch(idx)
814 case aoHidd_PCIDevice_ExtendedCapabilityAER: capability = PCIEECAP_AER;break;
815 case aoHidd_PCIDevice_ExtendedCapabilityVC: capability = PCIEECAP_VC ;break;
816 case aoHidd_PCIDevice_ExtendedCapabilitySerialNumber: capability = PCIEECAP_SER;break;
817 case aoHidd_PCIDevice_ExtendedCapabilityPowerBudgeting: capability = PCIEECAP_PWR_BUDGET;break;
820 *msg->storage = findExpressExtendedCapabilityOffset(cl, o, capability);
822 return;
825 typedef void (*dispatcher_t)(OOP_Class *, OOP_Object *, struct pRoot_Get *);
827 static const dispatcher_t Dispatcher[num_Hidd_PCIDevice_Attrs] =
829 [aoHidd_PCIDevice_Driver] = dispatch_generic,
830 [aoHidd_PCIDevice_Bus] = dispatch_generic,
831 [aoHidd_PCIDevice_Dev] = dispatch_generic,
832 [aoHidd_PCIDevice_Sub] = dispatch_generic,
833 [aoHidd_PCIDevice_VendorID] = dispatch_generic,
834 [aoHidd_PCIDevice_ProductID] = dispatch_generic,
835 [aoHidd_PCIDevice_RevisionID] = dispatch_generic,
836 [aoHidd_PCIDevice_Interface] = dispatch_generic,
837 [aoHidd_PCIDevice_Class] = dispatch_generic,
838 [aoHidd_PCIDevice_SubClass] = dispatch_generic,
839 [aoHidd_PCIDevice_SubsystemVendorID] = dispatch_generic,
840 [aoHidd_PCIDevice_SubsystemID] = dispatch_generic,
841 [aoHidd_PCIDevice_IRQLine] = dispatch_generic,
842 [aoHidd_PCIDevice_RomBase] = dispatch_generic,
843 [aoHidd_PCIDevice_RomSize] = dispatch_generic,
844 [aoHidd_PCIDevice_ExtendedConfig] = dispatch_generic,
845 [aoHidd_PCIDevice_ConfigSize] = dispatch_generic,
846 [aoHidd_PCIDevice_Base0] = dispatch_base,
847 [aoHidd_PCIDevice_Base1] = dispatch_base,
848 [aoHidd_PCIDevice_Base2] = dispatch_base,
849 [aoHidd_PCIDevice_Base3] = dispatch_base,
850 [aoHidd_PCIDevice_Base4] = dispatch_base,
851 [aoHidd_PCIDevice_Base5] = dispatch_base,
852 [aoHidd_PCIDevice_Size0] = dispatch_size,
853 [aoHidd_PCIDevice_Size1] = dispatch_size,
854 [aoHidd_PCIDevice_Size2] = dispatch_size,
855 [aoHidd_PCIDevice_Size3] = dispatch_size,
856 [aoHidd_PCIDevice_Size4] = dispatch_size,
857 [aoHidd_PCIDevice_Size5] = dispatch_size,
858 [aoHidd_PCIDevice_Type0] = dispatch_type,
859 [aoHidd_PCIDevice_Type1] = dispatch_type,
860 [aoHidd_PCIDevice_Type2] = dispatch_type,
861 [aoHidd_PCIDevice_Type3] = dispatch_type,
862 [aoHidd_PCIDevice_Type4] = dispatch_type,
863 [aoHidd_PCIDevice_Type5] = dispatch_type,
865 /* Bridge attributes */
866 [aoHidd_PCIDevice_isBridge] = dispatch_pci2pcibridge,
867 [aoHidd_PCIDevice_SecBus] = dispatch_pci2pcibridge,
868 [aoHidd_PCIDevice_MemoryBase] = dispatch_pci2pcibridge,
869 [aoHidd_PCIDevice_MemoryLimit] = dispatch_pci2pcibridge,
870 [aoHidd_PCIDevice_PrefetchableBase] = dispatch_pci2pcibridge,
871 [aoHidd_PCIDevice_PrefetchableLimit] = dispatch_pci2pcibridge,
872 [aoHidd_PCIDevice_IOBase] = dispatch_pci2pcibridge,
873 [aoHidd_PCIDevice_IOLimit] = dispatch_pci2pcibridge,
874 [aoHidd_PCIDevice_ISAEnable] = dispatch_pci2pcibridge,
875 [aoHidd_PCIDevice_VGAEnable] = dispatch_pci2pcibridge,
877 /* Capabilities */
878 [aoHidd_PCIDevice_CapabilityPowerManagement] = dispatch_capability,
879 [aoHidd_PCIDevice_CapabilityAGP] = dispatch_capability,
880 [aoHidd_PCIDevice_CapabilityVitalProductData] = dispatch_capability,
881 [aoHidd_PCIDevice_CapabilitySlotID] = dispatch_capability,
882 [aoHidd_PCIDevice_CapabilityMSI] = dispatch_capability,
883 [aoHidd_PCIDevice_CapabilityCPCIHotSwap] = dispatch_capability,
884 [aoHidd_PCIDevice_CapabilityPCIX] = dispatch_capability,
885 [aoHidd_PCIDevice_CapabilityHyperTransport] = dispatch_capability,
886 [aoHidd_PCIDevice_CapabilityVendorSpecific] = dispatch_capability,
887 [aoHidd_PCIDevice_CapabilityDebugPort] = dispatch_capability,
888 [aoHidd_PCIDevice_CapabilityCPCICRC] = dispatch_capability,
889 [aoHidd_PCIDevice_CapabilityHotPlugController] = dispatch_capability,
890 [aoHidd_PCIDevice_CapabilitySSVPID] = dispatch_capability,
891 [aoHidd_PCIDevice_CapabilityAGP3] = dispatch_capability,
892 [aoHidd_PCIDevice_CapabilityPCIE] = dispatch_capability,
893 [aoHidd_PCIDevice_CapabilityMSIX] = dispatch_capability,
894 [aoHidd_PCIDevice_CapabilityAdvancedFeatures] = dispatch_capability,
896 /* Extended capabilities */
897 [aoHidd_PCIDevice_ExtendedCapabilityAER] = dispatch_extendedcapability,
898 [aoHidd_PCIDevice_ExtendedCapabilityVC] = dispatch_extendedcapability,
899 [aoHidd_PCIDevice_ExtendedCapabilitySerialNumber] = dispatch_extendedcapability,
900 [aoHidd_PCIDevice_ExtendedCapabilityPowerBudgeting] = dispatch_extendedcapability,
903 void PCIDev__Root__Get(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
905 ULONG idx;
906 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
908 if (IS_PCIDEV_ATTR(msg->attrID, idx))
910 if (Dispatcher[idx] != NULL)
911 Dispatcher[idx](cl, o, msg);
912 else switch(idx)
914 case aoHidd_PCIDevice_isMEM:
915 *msg->storage = (
916 (getWord(cl, o, PCICS_COMMAND) &
917 PCICMF_MEMDECODE)
918 == PCICMF_MEMDECODE);
919 break;
921 case aoHidd_PCIDevice_isIO:
922 *msg->storage = (
923 (getWord(cl, o, PCICS_COMMAND) &
924 PCICMF_IODECODE)
925 == PCICMF_IODECODE);
926 break;
928 case aoHidd_PCIDevice_isMaster:
929 *msg->storage = (
930 (getWord(cl, o, PCICS_COMMAND) &
931 PCICMF_BUSMASTER)
932 == PCICMF_BUSMASTER);
933 break;
935 case aoHidd_PCIDevice_paletteSnoop:
936 *msg->storage = (
937 (getWord(cl, o, PCICS_COMMAND) &
938 PCICMF_VGASNOOP)
939 == PCICMF_VGASNOOP);
940 break;
942 case aoHidd_PCIDevice_is66MHz:
943 *msg->storage = (
944 (getWord(cl, o, PCICS_STATUS) &
945 PCISTF_66MHZ)
946 == PCISTF_66MHZ);
947 break;
949 case aoHidd_PCIDevice_ClassDesc:
950 *msg->storage = (IPTR)dev->strClass;
951 break;
953 case aoHidd_PCIDevice_SubClassDesc:
954 *msg->storage = (IPTR)dev->strSubClass;
955 break;
957 case aoHidd_PCIDevice_InterfaceDesc:
958 *msg->storage = (IPTR)dev->strInterface;
959 break;
961 case aoHidd_PCIDevice_INTLine:
962 *msg->storage = getByte(cl, o, PCICS_INT_LINE);
963 break;
965 case aoHidd_PCIDevice_IRQStatus:
966 *msg->storage = (
967 (getWord(cl, o, PCICS_STATUS) &
968 PCISTF_INTERRUPT_STATUS)
969 == PCISTF_INTERRUPT_STATUS);
970 break;
972 case aoHidd_PCIDevice_CapabilitiesPresent:
973 *msg->storage = (
974 (getWord(cl, o, PCICS_STATUS) &
975 PCISTF_CAPABILITIES)
976 == PCISTF_CAPABILITIES);
977 break;
979 case aoHidd_PCIDevice_Owner:
980 *msg->storage = (IPTR)dev->ownerLock.ss_Link.ln_Name;
981 break;
983 default:
984 OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
985 break;
988 else
990 OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
994 void PCIDev__Root__Set(OOP_Class *cl, OOP_Object *o, struct pRoot_Set *msg)
996 ULONG idx;
997 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
998 struct TagItem *tag, *tags;
1000 tags = (struct TagItem *)msg->attrList;
1002 while ((tag = NextTagItem(&tags)))
1004 if (IS_PCIDEV_ATTR(tag->ti_Tag, idx))
1006 switch(idx)
1008 case aoHidd_PCIDevice_Base0:
1009 setLong(cl, o, PCICS_BAR0, tag->ti_Data);
1010 dev->BaseReg[0].addr = getLong(cl, o, PCICS_BAR0);
1011 break;
1013 case aoHidd_PCIDevice_Base1:
1014 setLong(cl, o, PCICS_BAR1, tag->ti_Data);
1015 dev->BaseReg[1].addr = getLong(cl, o, PCICS_BAR1);
1016 break;
1018 case aoHidd_PCIDevice_Base2:
1019 if (!dev->isBridge)
1021 setLong(cl, o, PCICS_BAR2, tag->ti_Data);
1022 dev->BaseReg[2].addr = getLong(cl, o, PCICS_BAR2);
1024 break;
1026 case aoHidd_PCIDevice_Base3:
1027 if (!dev->isBridge)
1029 setLong(cl, o, PCICS_BAR3, tag->ti_Data);
1030 dev->BaseReg[3].addr = getLong(cl, o, PCICS_BAR3);
1032 break;
1034 case aoHidd_PCIDevice_Base4:
1035 if (!dev->isBridge)
1037 setLong(cl, o, PCICS_BAR4, tag->ti_Data);
1038 dev->BaseReg[4].addr = getLong(cl, o, PCICS_BAR4);
1040 break;
1042 case aoHidd_PCIDevice_Base5:
1043 if (!dev->isBridge)
1045 setLong(cl, o, PCICS_BAR5, tag->ti_Data);
1046 dev->BaseReg[5].addr = getLong(cl, o, PCICS_BAR5);
1048 break;
1050 case aoHidd_PCIDevice_RomBase:
1051 setLong(cl, o, PCICS_EXPROM_BASE, tag->ti_Data);
1052 dev->RomBase = getLong(cl, o, PCICS_EXPROM_BASE);
1053 break;
1055 case aoHidd_PCIDevice_MemoryBase:
1056 if (dev->isBridge) setWord(cl, o, PCIBR_MEMBASE, tag->ti_Data >> 16);
1057 break;
1059 case aoHidd_PCIDevice_MemoryLimit:
1060 if (dev->isBridge) setWord(cl, o, PCIBR_MEMLIMIT, tag->ti_Data >> 16);
1061 break;
1063 case aoHidd_PCIDevice_PrefetchableBase:
1064 if (dev->isBridge) setWord(cl, o, PCIBR_PREFETCHBASE, tag->ti_Data >> 16);
1065 break;
1067 case aoHidd_PCIDevice_PrefetchableLimit:
1068 if (dev->isBridge) setWord(cl, o, PCIBR_PREFETCHLIMIT, tag->ti_Data >> 16);
1069 break;
1071 case aoHidd_PCIDevice_IOBase:
1072 if (dev->isBridge) setByte(cl, o, PCIBR_IOBASE, tag->ti_Data >> 8);
1073 break;
1075 case aoHidd_PCIDevice_IOLimit:
1076 if (dev->isBridge) setByte(cl, o, PCIBR_IOLIMIT, tag->ti_Data >> 8);
1077 break;
1079 case aoHidd_PCIDevice_isIO:
1081 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_IODECODE;
1082 if (tag->ti_Data)
1083 command |= PCICMF_IODECODE;
1084 setWord(cl, o, PCICS_COMMAND, command);
1086 break;
1088 case aoHidd_PCIDevice_isMEM:
1090 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_MEMDECODE;
1091 if (tag->ti_Data)
1092 command |= PCICMF_MEMDECODE;
1093 setWord(cl, o, PCICS_COMMAND, command);
1095 break;
1097 case aoHidd_PCIDevice_isMaster:
1099 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_BUSMASTER;
1100 if (tag->ti_Data)
1101 command |= PCICMF_BUSMASTER;
1102 setWord(cl, o, PCICS_COMMAND, command);
1104 break;
1106 case aoHidd_PCIDevice_paletteSnoop:
1108 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_VGASNOOP;
1109 if (tag->ti_Data)
1110 command |= PCICMF_VGASNOOP;
1111 setWord(cl, o, PCICS_COMMAND, command);
1113 break;
1115 case aoHidd_PCIDevice_ISAEnable:
1116 if (dev->isBridge)
1118 UWORD control = getWord(cl, o, PCIBR_CONTROL) & ~PCICTRLF_ISAENABLE;
1119 if (tag->ti_Data)
1120 control |= PCICTRLF_ISAENABLE;
1121 setWord(cl, o, PCIBR_CONTROL, control);
1123 break;
1125 case aoHidd_PCIDevice_VGAEnable:
1126 if (dev->isBridge)
1128 UWORD control = getWord(cl, o, PCIBR_CONTROL) & ~PCICTRLF_VGAENABLE;
1129 if (tag->ti_Data)
1130 control |= PCICTRLF_VGAENABLE;
1131 setWord(cl, o, PCIBR_CONTROL, control);
1133 break;
1135 case aoHidd_PCIDevice_INTLine:
1137 dev->INTLine = tag->ti_Data;
1138 setByte(cl, o, PCICS_INT_LINE, dev->INTLine);
1140 break;
1142 default:
1143 bug("[PCIDevice] Trying to set nonsettable attribute %d!\n", idx);
1144 break;