Introducing PCI Express extended capabilities:
[AROS.git] / rom / hidds / pci / pcideviceclass.c
blob80811f3f6b97caaa60b486c08cc67eabf202aaca
1 /*
2 Copyright © 2004-2013, 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 *****************************************************************************************/
54 static void setLong(OOP_Class *cl, OOP_Object *o, ULONG reg, ULONG value)
56 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
58 HIDD_PCIDriver_WriteConfigLong(dev->driver, dev->bus, dev->dev, dev->sub, reg, value);
61 static void setWord(OOP_Class *cl, OOP_Object *o, ULONG reg, UWORD value)
63 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
65 HIDD_PCIDriver_WriteConfigWord(dev->driver, dev->bus, dev->dev, dev->sub, reg, value);
68 static void setByte(OOP_Class *cl, OOP_Object *o, ULONG reg, UBYTE value)
70 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
72 HIDD_PCIDriver_WriteConfigByte(dev->driver, dev->bus, dev->dev, dev->sub, reg, value);
75 static ULONG getLong(OOP_Class *cl, OOP_Object *o, ULONG reg)
77 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
79 return HIDD_PCIDriver_ReadConfigLong(dev->driver, dev->bus, dev->dev, dev->sub, reg);
82 static UWORD getWord(OOP_Class *cl, OOP_Object *o, ULONG reg)
84 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
86 return HIDD_PCIDriver_ReadConfigWord(dev->driver, dev->bus, dev->dev, dev->sub, reg);
89 static UBYTE getByte(OOP_Class *cl, OOP_Object *o, ULONG reg)
91 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
93 return HIDD_PCIDriver_ReadConfigByte(dev->driver, dev->bus, dev->dev, dev->sub, reg);
96 /* Returns offset of capability area in config area or 0 if capability is not present */
97 static UBYTE findCapabilityOffset(OOP_Class * cl, OOP_Object *o, UBYTE capability)
99 UWORD where = 0x34; /* First cap list entry */
100 UBYTE capid = 0;
102 /* Check if capabilities present at all */
103 if ((getWord(cl, o, PCICS_STATUS) & PCISTF_CAPABILITIES) != PCISTF_CAPABILITIES)
104 return 0;
106 /* Iterate over capabilities */
107 while(where < 0xff)
109 where = getByte(cl, o, where);
111 if (where < 0x40)
112 break;
114 where &= ~3;
115 capid = getByte(cl, o, where);
117 if (capid == 0xff)
118 break;
120 if (capid == capability) return (UBYTE)where;
122 where += 1; /* next cap */
125 return 0;
128 /* Returns offset of PCI Express extended capability area in config area or 0 if capability is not present */
129 static UWORD findExpressExtendedCapabilityOffset(OOP_Class * cl, OOP_Object *o, UWORD capability)
131 UWORD where = 0x100; /* First PCI Express extended cap list entry */
132 ULONG caphdr;
134 while(where > 0xff)
136 caphdr = getLong(cl, o, where);
138 if ((caphdr & 0xffff) == capability) return (UWORD)where;
140 where = (caphdr>>20)&~3;
143 return 0;
146 UBYTE PCIDev__Hidd_PCIDevice__ReadConfigByte(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_ReadConfigByte *msg)
148 return getByte(cl, o, msg->reg);
151 UWORD PCIDev__Hidd_PCIDevice__ReadConfigWord(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_ReadConfigWord *msg)
153 return getWord(cl, o, msg->reg);
156 ULONG PCIDev__Hidd_PCIDevice__ReadConfigLong(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_ReadConfigLong *msg)
158 return getLong(cl, o, msg->reg);
161 VOID PCIDev__Hidd_PCIDevice__WriteConfigByte(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_WriteConfigByte *msg)
163 setByte(cl, o, msg->reg, msg->val);
166 VOID PCIDev__Hidd_PCIDevice__WriteConfigWord(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_WriteConfigWord *msg)
168 setWord(cl, o, msg->reg, msg->val);
171 VOID PCIDev__Hidd_PCIDevice__WriteConfigLong(OOP_Class *cl, OOP_Object *o, struct pHidd_PCIDevice_WriteConfigLong *msg)
173 setLong(cl, o, msg->reg, msg->val);
176 /*****************************************************************************************
178 NAME
179 moHidd_PCIDevice_AddInterrupt
181 SYNOPSIS
182 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_AddInterrupt *Msg);
184 OOP_Object *HIDD_PCIDriver_AddInterrupt(OOP_Object *obj, OOP_Object *device,
185 struct Interrupt *interrupt);
187 LOCATION
188 CLID_Hidd_PCIDevice
190 FUNCTION
191 Add interrupt handler for the device.
193 INPUTS
194 obj - Pointer to device object.
195 interrupt - Interrupt structure to add.
197 RESULT
198 TRUE it succesful or FALSE on failure.
200 NOTES
202 EXAMPLE
204 BUGS
206 SEE ALSO
207 moHidd_PCIDevice_RemoveInterrupt
209 INTERNALS
211 *****************************************************************************************/
213 BOOL PCIDev__Hidd_PCIDevice__AddInterrupt(OOP_Class *cl, OOP_Object *o,
214 struct pHidd_PCIDevice_AddInterrupt *msg)
216 tDeviceData *dev = OOP_INST_DATA(cl, o);
218 return HIDD_PCIDriver_AddInterrupt(dev->driver, o, msg->interrupt);
221 /*****************************************************************************************
223 NAME
224 moHidd_PCIDevice_RemoveInterrupt
226 SYNOPSIS
227 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_RemoveInterrupt *Msg);
229 OOP_Object *HIDD_PCIDevice_RemoveInterrupt(OOP_Object *obj, OOP_Object *device,
230 struct Interrupt *interrupt);
232 LOCATION
233 CLID_Hidd_PCIDevice
235 FUNCTION
236 Remove interrupt handler from the device.
238 INPUTS
239 obj - Pointer to the device object.
240 interrupt - Interrupt structure to remove.
242 RESULT
243 None.
245 NOTES
247 EXAMPLE
249 BUGS
251 SEE ALSO
252 moHidd_PCIDevice_AddInterrupt
254 INTERNALS
256 *****************************************************************************************/
258 VOID PCIDev__Hidd_PCIDevice__RemoveInterrupt(OOP_Class *cl, OOP_Object *o,
259 struct pHidd_PCIDevice_RemoveInterrupt *msg)
261 tDeviceData *dev = OOP_INST_DATA(cl, o);
263 return HIDD_PCIDriver_RemoveInterrupt(dev->driver, o, msg->interrupt);
266 /*****************************************************************************************
268 NAME
269 moHidd_PCIDevice_Obtain
271 SYNOPSIS
272 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_Obtain *Msg);
274 OOP_Object *HIDD_PCIDevice_Obtain(OOP_Object *obj, CONST_STRPTR owner);
276 LOCATION
277 CLID_Hidd_PCIDevice
279 FUNCTION
280 Lock the device for exclusive use.
282 INPUTS
283 obj - Pointer to the device object.
284 owner - A string identifying the owner.
286 RESULT
287 NULL on success or string identifying current owner.
289 NOTES
291 EXAMPLE
293 BUGS
295 SEE ALSO
296 moHidd_PCIDevice_Release
298 INTERNALS
300 *****************************************************************************************/
302 CONST_STRPTR PCIDev__Hidd_PCIDevice__Obtain(OOP_Class *cl, OOP_Object *o,
303 struct pHidd_PCIDevice_Obtain *msg)
305 tDeviceData *dev = OOP_INST_DATA(cl, o);
306 CONST_STRPTR current = NULL;
309 * FIXME: Actually this is just atomic compare and swap.
310 * I believe it should be impemented in assembler.
311 * Ouch, on Amiga such operations are unsafe, at least
312 * in CHIP memory. Too bad...
314 ObtainSemaphore(&dev->ownerLock);
316 /* While we are using semaphore, owner name is embedded in its node */
317 if (dev->ownerLock.ss_Link.ln_Name)
318 current = dev->ownerLock.ss_Link.ln_Name;
319 else
320 dev->ownerLock.ss_Link.ln_Name = (STRPTR)msg->owner;
322 ReleaseSemaphore(&dev->ownerLock);
324 return current;
327 /*****************************************************************************************
329 NAME
330 moHidd_PCIDevice_Release
332 SYNOPSIS
333 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCIDevice_Release *Msg);
335 OOP_Object *HIDD_PCIDevice_Release(OOP_Object *obj);
337 LOCATION
338 CLID_Hidd_PCIDevice
340 FUNCTION
341 Release ownership of the device.
343 INPUTS
344 obj - Pointer to the device object.
346 RESULT
347 None.
349 NOTES
350 You should call this function only on devices owned by you. Doing
351 this on someone else's devices will not do any good things.
353 EXAMPLE
355 BUGS
357 SEE ALSO
358 moHidd_PCIDevice_Obtain
360 INTERNALS
362 *****************************************************************************************/
364 VOID PCIDev__Hidd_PCIDevice__Release(OOP_Class *cl, OOP_Object *o,
365 struct pHidd_PCIDevice_Release *msg)
367 tDeviceData *dev = OOP_INST_DATA(cl, o);
369 dev->ownerLock.ss_Link.ln_Name = NULL;
373 PCIDevice::New method is invoked by base pci class. It passes to the device
374 class information about the driver this class should use and location of
375 created device on the PCI bus handled by given driver.
377 OOP_Object *PCIDev__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
379 int i;
381 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
382 if (o)
384 struct TagItem *tag, *tags;
385 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl, o);
386 OOP_Object *driver = NULL;
388 InitSemaphore(&dev->ownerLock);
390 tags=(struct TagItem *)msg->attrList;
393 Get all information passed by pci class calling OOP_NewObject()
395 while((tag = NextTagItem(&tags)))
397 ULONG idx;
399 if (IS_PCIDEV_ATTR(tag->ti_Tag, idx))
401 switch(idx)
403 case aoHidd_PCIDevice_Driver:
404 dev->driver = (OOP_Object*)tag->ti_Data;
405 driver = dev->driver;
406 break;
408 case aoHidd_PCIDevice_Bus:
409 dev->bus = tag->ti_Data;
410 break;
412 case aoHidd_PCIDevice_Dev:
413 dev->dev = tag->ti_Data;
414 break;
416 case aoHidd_PCIDevice_Sub:
417 dev->sub = tag->ti_Data;
418 break;
424 If driver is passed (*HAS TO* be passed) acquire some unchangeable
425 information regarding given device
427 if (driver)
429 UBYTE ht;
432 Get the header type in order to determine whether it is a
433 device or bridge
435 ht = getByte(cl, o, PCICS_HEADERTYPE) & PCIHT_MASK;
436 dev->isBridge = 0;
437 if (ht == PCIHT_BRIDGE)
439 dev->isBridge = 1;
440 dev->subbus = getByte(cl, o, PCIBR_SUBBUS);
443 /* Get all constant ID's */
444 dev->VendorID = getWord(cl, o, PCICS_VENDOR);
445 dev->ProductID = getWord(cl, o, PCICS_PRODUCT);
447 dev->RevisionID = getByte(cl, o, PCICS_REVISION);
448 dev->Interface = getByte(cl, o, PCICS_PROGIF);
449 dev->SubClass = getByte(cl, o, PCICS_SUBCLASS);
450 dev->Class = getByte(cl, o, PCICS_CLASS);
452 dev->SubsysVID = getWord(cl, o, PCICS_SUBVENDOR);
453 dev->SubsystemID = getWord(cl, o, PCICS_SUBSYSTEM);
455 dev->IRQLine = getByte(cl, o, PCICS_INT_PIN);
457 if (dev->IRQLine)
459 dev->INTLine = getByte(cl, o, PCICS_INT_LINE);
461 else dev->INTLine = 0;
463 dev->HeaderType = ht;
465 getPCIClassDesc(dev->Class, dev->SubClass, dev->Interface,
466 &dev->strClass, &dev->strSubClass, &dev->strInterface);
468 /* Satisfy BUG watchers ;) */
469 D(bug("[PCIDevice] %02x.%02x.%x = %04.4lx:%04.4lx (%s %s %s)\n",
470 dev->bus, dev->dev, dev->sub,
471 dev->VendorID, dev->ProductID,
472 dev->strClass, dev->strSubClass, dev->strInterface));
473 D(bug("[PCIDevice] > IRQ %u INT %u\n", dev->IRQLine, dev->INTLine));
475 // print out a warning to the user in case the interrupt line is not assigned by BIOS
476 if (dev->INTLine == 255 && !dev->isBridge)
477 bug("[PCIDevice] WARNING: Interrupt line is not assigned! Device may freeze or malfunction at use!\n");
479 /* Read two first base addresses */
480 for (i = 0; i < 2; i++)
482 dev->BaseReg[i].addr = getLong(cl, o, PCICS_BAR0 + (i << 2));
483 dev->BaseReg[i].size = sizePCIBaseReg(driver, PSD(cl), dev->bus,
484 dev->dev, dev->sub, i);
487 /* Address and size of ROM */
488 dev->RomBase = getLong(cl, o, PCICS_EXPROM_BASE);
489 dev->RomSize = sizePCIBaseReg(driver, PSD(cl), dev->bus,
490 dev->dev, dev->sub, (PCICS_EXPROM_BASE - PCICS_BAR0) >> 2);
493 Bridges specify only first two base addresses. If not bridge,
494 check the rest now
496 if (! dev->isBridge)
498 for (i = 2; i < 6; i++)
500 dev->BaseReg[i].addr = getLong(cl, o, PCICS_BAR0 + (i << 2));
501 dev->BaseReg[i].size = sizePCIBaseReg(driver, PSD(cl), dev->bus,
502 dev->dev, dev->sub, i);
508 return o;
512 PCIDevice::Get method splitted into few parts in order to make switch'es shorter.
515 static void dispatch_generic(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
517 ULONG idx;
518 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
520 idx = msg->attrID - HiddPCIDeviceAttrBase;
522 switch(idx)
524 case aoHidd_PCIDevice_Driver:
525 *msg->storage = (IPTR)dev->driver;
526 break;
528 case aoHidd_PCIDevice_Bus:
529 *msg->storage = (IPTR)dev->bus;
530 break;
532 case aoHidd_PCIDevice_Dev:
533 *msg->storage = (IPTR)dev->dev;
534 break;
536 case aoHidd_PCIDevice_Sub:
537 *msg->storage = (IPTR)dev->sub;
538 break;
540 case aoHidd_PCIDevice_VendorID:
541 *msg->storage = (IPTR)dev->VendorID;
542 break;
544 case aoHidd_PCIDevice_ProductID:
545 *msg->storage = (IPTR)dev->ProductID;
546 break;
548 case aoHidd_PCIDevice_RevisionID:
549 *msg->storage = (IPTR)dev->RevisionID;
550 break;
552 case aoHidd_PCIDevice_Interface:
553 *msg->storage = (IPTR)dev->Interface;
554 break;
556 case aoHidd_PCIDevice_Class:
557 *msg->storage = (IPTR)dev->Class;
558 break;
560 case aoHidd_PCIDevice_SubClass:
561 *msg->storage = (IPTR)dev->SubClass;
562 break;
564 case aoHidd_PCIDevice_SubsystemVendorID:
565 *msg->storage = (IPTR)dev->SubsysVID;
566 break;
568 case aoHidd_PCIDevice_SubsystemID:
569 *msg->storage = (IPTR)dev->SubsystemID;
570 break;
572 case aoHidd_PCIDevice_INTLine:
573 *msg->storage = (IPTR)dev->INTLine;
574 break;
576 case aoHidd_PCIDevice_IRQLine:
577 *msg->storage = (IPTR)dev->IRQLine;
578 break;
580 case aoHidd_PCIDevice_RomBase:
581 *msg->storage = (IPTR)dev->RomBase;
582 break;
584 case aoHidd_PCIDevice_RomSize:
585 *msg->storage = (IPTR)dev->RomSize;
586 break;
590 static void dispatch_base(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
592 ULONG idx,id;
593 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
595 idx = msg->attrID - HiddPCIDeviceAttrBase;
596 id = 0;
598 switch(idx)
600 case aoHidd_PCIDevice_Base0: id = 0; break;
601 case aoHidd_PCIDevice_Base1: id = 1; break;
602 case aoHidd_PCIDevice_Base2: id = 2; break;
603 case aoHidd_PCIDevice_Base3: id = 3; break;
604 case aoHidd_PCIDevice_Base4: id = 4; break;
605 case aoHidd_PCIDevice_Base5: id = 5; break;
608 /* Do not allow reading of more than two base addresses in case of PCI-PCI bridges */
609 if (dev->isBridge && id >= 2) { *msg->storage = 0; return; }
611 *msg->storage = (IPTR)dev->BaseReg[id].addr;
612 if ((dev->BaseReg[id].addr & PCIBAR_MASK_TYPE)==PCIBAR_TYPE_IO)
614 IPTR IOBase = 0;
615 *msg->storage &= PCIBAR_MASK_IO;
616 OOP_GetAttr(dev->driver, aHidd_PCIDriver_IOBase, &IOBase);
617 *msg->storage += IOBase;
619 else
621 *msg->storage &= PCIBAR_MASK_MEM;
625 static void dispatch_type(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
627 ULONG idx,id;
628 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
630 idx = msg->attrID - HiddPCIDeviceAttrBase;
631 id = 0;
633 switch(idx)
635 case aoHidd_PCIDevice_Type0: id = 0; break;
636 case aoHidd_PCIDevice_Type1: id = 1; break;
637 case aoHidd_PCIDevice_Type2: id = 2; break;
638 case aoHidd_PCIDevice_Type3: id = 3; break;
639 case aoHidd_PCIDevice_Type4: id = 4; break;
640 case aoHidd_PCIDevice_Type5: id = 5; break;
643 /* Do not allow reading of more than two base addresses in case of PCI-PCI bridges */
644 if (dev->isBridge && id >= 2) { *msg->storage = 0; return; }
646 *msg->storage = (IPTR)dev->BaseReg[id].addr;
647 if ((dev->BaseReg[id].addr & PCIBAR_MASK_TYPE)==PCIBAR_TYPE_IO)
649 *msg->storage &= ~PCIBAR_MASK_IO;
651 else
653 *msg->storage &= ~PCIBAR_MASK_MEM;
657 static void dispatch_size(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
659 ULONG idx,id;
660 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
662 idx = msg->attrID - HiddPCIDeviceAttrBase;
663 id = 0;
665 switch(idx)
667 case aoHidd_PCIDevice_Size0: id = 0; break;
668 case aoHidd_PCIDevice_Size1: id = 1; break;
669 case aoHidd_PCIDevice_Size2: id = 2; break;
670 case aoHidd_PCIDevice_Size3: id = 3; break;
671 case aoHidd_PCIDevice_Size4: id = 4; break;
672 case aoHidd_PCIDevice_Size5: id = 5; break;
675 /* Do not allow reading of more than two base addresses in case of PCI-PCI bridges */
676 if (dev->isBridge && id >= 2) { *msg->storage = 0; return;}
678 *msg->storage = (IPTR)dev->BaseReg[id].size;
681 static void dispatch_pci2pcibridge(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
683 ULONG idx;
684 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
686 UWORD control;
688 /* If device is not a PCI-PCI bridge, do nothing */
689 if (!dev->isBridge) { *msg->storage = 0; return; }
691 control = getWord(cl, o, PCIBR_CONTROL);
693 idx = msg->attrID - HiddPCIDeviceAttrBase;
695 switch(idx)
697 case aoHidd_PCIDevice_isBridge:
698 *msg->storage = dev->isBridge;
699 break;
701 case aoHidd_PCIDevice_SubBus:
702 *msg->storage = dev->subbus;
703 break;
705 case aoHidd_PCIDevice_MemoryBase:
706 *msg->storage = getWord(cl, o, PCIBR_MEMBASE) << 16;
707 break;
709 case aoHidd_PCIDevice_MemoryLimit:
710 *msg->storage = getWord(cl, o, PCIBR_MEMLIMIT) << 16;
711 break;
713 case aoHidd_PCIDevice_PrefetchableBase:
714 *msg->storage = getWord(cl, o, PCIBR_PREFETCHBASE) << 16;
715 break;
717 case aoHidd_PCIDevice_PrefetchableLimit:
718 *msg->storage = getWord(cl, o, PCIBR_PREFETCHLIMIT) << 16;
719 break;
721 case aoHidd_PCIDevice_IOBase:
722 *msg->storage = getByte(cl, o, PCIBR_IOBASE) << 8;
723 break;
725 case aoHidd_PCIDevice_IOLimit:
726 *msg->storage = getByte(cl, o, PCIBR_IOLIMIT) << 8;
727 break;
729 case aoHidd_PCIDevice_ISAEnable:
730 *msg->storage = (control & PCICTRLF_ISAENABLE) == PCICTRLF_ISAENABLE;
731 break;
733 case aoHidd_PCIDevice_VGAEnable:
734 *msg->storage = (control & PCICTRLF_VGAENABLE) == PCICTRLF_VGAENABLE;
735 break;
739 static void dispatch_capability(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
741 ULONG idx;
742 UBYTE capability = 0;
743 //tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
745 idx = msg->attrID - HiddPCIDeviceAttrBase;
747 switch(idx)
749 case aoHidd_PCIDevice_CapabilityPowerManagement: capability = PCICAP_POWER_MANAGEMENT;break;
750 case aoHidd_PCIDevice_CapabilityAGP: capability = PCICAP_AGP;break;
751 case aoHidd_PCIDevice_CapabilityVitalProductData: capability = PCICAP_VITAL_PRODUCT_DATA;break;
752 case aoHidd_PCIDevice_CapabilitySlotID: capability = PCICAP_SLOT_ID;break;
753 case aoHidd_PCIDevice_CapabilityMSI: capability = PCICAP_MSI;break;
754 case aoHidd_PCIDevice_CapabilityCPCIHotSwap: capability = PCICAP_CPCI_HOT_SWAP;break;
755 case aoHidd_PCIDevice_CapabilityPCIX: capability = PCICAP_PCIX;break;
756 case aoHidd_PCIDevice_CapabilityHyperTransport: capability = PCICAP_HYPER_TRANSPORT;break;
757 case aoHidd_PCIDevice_CapabilityVendorSpecific: capability = PCICAP_VENDOR_SPECIFIC;break;
758 case aoHidd_PCIDevice_CapabilityDebugPort: capability = PCICAP_DEBUG_PORT;break;
759 case aoHidd_PCIDevice_CapabilityCPCICRC: capability = PCICAP_CPCI_CR;break;
760 case aoHidd_PCIDevice_CapabilityHotPlugController: capability = PCICAP_HOT_PLUG_CONTROLLER;break;
761 case aoHidd_PCIDevice_CapabilitySSVPID: capability = PCICAP_SSVPID;break;
762 case aoHidd_PCIDevice_CapabilityAGP3: capability = PCICAP_AGP3;break;
763 case aoHidd_PCIDevice_CapabilityPCIE: capability = PCICAP_PCIE;break;
764 case aoHidd_PCIDevice_CapabilityMSIX: capability = PCICAP_MSIX;break;
765 case aoHidd_PCIDevice_CapabilityAdvancedFeatures: capability = PCICAP_ADVANCED_FEATURES;break;
768 *msg->storage = findCapabilityOffset(cl, o, capability);
771 static void dispatch_extendedcapability(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
773 ULONG idx;
774 UWORD capability = 0;
775 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
776 IPTR isPCIE = 0;
778 OOP_GetAttr(dev->driver, aHidd_PCIDevice_CapabilityPCIE, &isPCIE);
779 if(!isPCIE) { *msg->storage = 0; return; }
781 idx = msg->attrID - HiddPCIDeviceAttrBase;
783 switch(idx)
785 case aoHidd_PCIDevice_ExtendedCapabilityAER: capability = PCIEECAP_AER;break;
786 case aoHidd_PCIDevice_ExtendedCapabilityVC: capability = PCIEECAP_VC ;break;
787 case aoHidd_PCIDevice_ExtendedCapabilitySerialNumber: capability = PCIEECAP_SER;break;
788 case aoHidd_PCIDevice_ExtendedCapabilityPowerBudgeting: capability = PCIEECAP_PWR_BUDGET;break;
791 *msg->storage = findExpressExtendedCapabilityOffset(cl, o, capability);
794 typedef void (*dispatcher_t)(OOP_Class *, OOP_Object *, struct pRoot_Get *);
796 static const dispatcher_t Dispatcher[num_Hidd_PCIDevice_Attrs] =
798 [aoHidd_PCIDevice_Driver] = dispatch_generic,
799 [aoHidd_PCIDevice_Bus] = dispatch_generic,
800 [aoHidd_PCIDevice_Dev] = dispatch_generic,
801 [aoHidd_PCIDevice_Sub] = dispatch_generic,
802 [aoHidd_PCIDevice_VendorID] = dispatch_generic,
803 [aoHidd_PCIDevice_ProductID] = dispatch_generic,
804 [aoHidd_PCIDevice_RevisionID] = dispatch_generic,
805 [aoHidd_PCIDevice_Interface] = dispatch_generic,
806 [aoHidd_PCIDevice_Class] = dispatch_generic,
807 [aoHidd_PCIDevice_SubClass] = dispatch_generic,
808 [aoHidd_PCIDevice_SubsystemVendorID] = dispatch_generic,
809 [aoHidd_PCIDevice_SubsystemID] = dispatch_generic,
810 [aoHidd_PCIDevice_INTLine] = dispatch_generic,
811 [aoHidd_PCIDevice_IRQLine] = dispatch_generic,
812 [aoHidd_PCIDevice_RomBase] = dispatch_generic,
813 [aoHidd_PCIDevice_RomSize] = dispatch_generic,
814 [aoHidd_PCIDevice_Base0] = dispatch_base,
815 [aoHidd_PCIDevice_Base1] = dispatch_base,
816 [aoHidd_PCIDevice_Base2] = dispatch_base,
817 [aoHidd_PCIDevice_Base3] = dispatch_base,
818 [aoHidd_PCIDevice_Base4] = dispatch_base,
819 [aoHidd_PCIDevice_Base5] = dispatch_base,
820 [aoHidd_PCIDevice_Size0] = dispatch_size,
821 [aoHidd_PCIDevice_Size1] = dispatch_size,
822 [aoHidd_PCIDevice_Size2] = dispatch_size,
823 [aoHidd_PCIDevice_Size3] = dispatch_size,
824 [aoHidd_PCIDevice_Size4] = dispatch_size,
825 [aoHidd_PCIDevice_Size5] = dispatch_size,
826 [aoHidd_PCIDevice_Type0] = dispatch_type,
827 [aoHidd_PCIDevice_Type1] = dispatch_type,
828 [aoHidd_PCIDevice_Type2] = dispatch_type,
829 [aoHidd_PCIDevice_Type3] = dispatch_type,
830 [aoHidd_PCIDevice_Type4] = dispatch_type,
831 [aoHidd_PCIDevice_Type5] = dispatch_type,
833 /* Bridge attributes */
834 [aoHidd_PCIDevice_isBridge] = dispatch_pci2pcibridge,
835 [aoHidd_PCIDevice_SubBus] = dispatch_pci2pcibridge,
836 [aoHidd_PCIDevice_MemoryBase] = dispatch_pci2pcibridge,
837 [aoHidd_PCIDevice_MemoryLimit] = dispatch_pci2pcibridge,
838 [aoHidd_PCIDevice_PrefetchableBase] = dispatch_pci2pcibridge,
839 [aoHidd_PCIDevice_PrefetchableLimit] = dispatch_pci2pcibridge,
840 [aoHidd_PCIDevice_IOBase] = dispatch_pci2pcibridge,
841 [aoHidd_PCIDevice_IOLimit] = dispatch_pci2pcibridge,
842 [aoHidd_PCIDevice_ISAEnable] = dispatch_pci2pcibridge,
843 [aoHidd_PCIDevice_VGAEnable] = dispatch_pci2pcibridge,
845 /* Capabilities */
846 [aoHidd_PCIDevice_CapabilityPowerManagement] = dispatch_capability,
847 [aoHidd_PCIDevice_CapabilityAGP] = dispatch_capability,
848 [aoHidd_PCIDevice_CapabilityVitalProductData] = dispatch_capability,
849 [aoHidd_PCIDevice_CapabilitySlotID] = dispatch_capability,
850 [aoHidd_PCIDevice_CapabilityMSI] = dispatch_capability,
851 [aoHidd_PCIDevice_CapabilityCPCIHotSwap] = dispatch_capability,
852 [aoHidd_PCIDevice_CapabilityPCIX] = dispatch_capability,
853 [aoHidd_PCIDevice_CapabilityHyperTransport] = dispatch_capability,
854 [aoHidd_PCIDevice_CapabilityVendorSpecific] = dispatch_capability,
855 [aoHidd_PCIDevice_CapabilityDebugPort] = dispatch_capability,
856 [aoHidd_PCIDevice_CapabilityCPCICRC] = dispatch_capability,
857 [aoHidd_PCIDevice_CapabilityHotPlugController] = dispatch_capability,
858 [aoHidd_PCIDevice_CapabilitySSVPID] = dispatch_capability,
859 [aoHidd_PCIDevice_CapabilityAGP3] = dispatch_capability,
860 [aoHidd_PCIDevice_CapabilityPCIE] = dispatch_capability,
861 [aoHidd_PCIDevice_CapabilityMSIX] = dispatch_capability,
862 [aoHidd_PCIDevice_CapabilityAdvancedFeatures] = dispatch_capability,
864 /* Extended capabilities */
865 [aoHidd_PCIDevice_ExtendedCapabilityAER] = dispatch_extendedcapability,
866 [aoHidd_PCIDevice_ExtendedCapabilityVC] = dispatch_extendedcapability,
867 [aoHidd_PCIDevice_ExtendedCapabilitySerialNumber] = dispatch_extendedcapability,
868 [aoHidd_PCIDevice_ExtendedCapabilityPowerBudgeting] = dispatch_extendedcapability,
871 void PCIDev__Root__Get(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
873 ULONG idx;
874 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
876 if (IS_PCIDEV_ATTR(msg->attrID, idx))
878 if (Dispatcher[idx] != NULL)
879 Dispatcher[idx](cl, o, msg);
880 else switch(idx)
882 case aoHidd_PCIDevice_isMEM:
883 *msg->storage = (
884 (getWord(cl, o, PCICS_COMMAND) &
885 PCICMF_MEMDECODE)
886 == PCICMF_MEMDECODE);
887 break;
889 case aoHidd_PCIDevice_isIO:
890 *msg->storage = (
891 (getWord(cl, o, PCICS_COMMAND) &
892 PCICMF_IODECODE)
893 == PCICMF_IODECODE);
894 break;
896 case aoHidd_PCIDevice_isMaster:
897 *msg->storage = (
898 (getWord(cl, o, PCICS_COMMAND) &
899 PCICMF_BUSMASTER)
900 == PCICMF_BUSMASTER);
901 break;
903 case aoHidd_PCIDevice_paletteSnoop:
904 *msg->storage = (
905 (getWord(cl, o, PCICS_COMMAND) &
906 PCICMF_VGASNOOP)
907 == PCICMF_VGASNOOP);
908 break;
910 case aoHidd_PCIDevice_is66MHz:
911 *msg->storage = (
912 (getWord(cl, o, PCICS_STATUS) &
913 PCISTF_66MHZ)
914 == PCISTF_66MHZ);
915 break;
917 case aoHidd_PCIDevice_ClassDesc:
918 *msg->storage = (IPTR)dev->strClass;
919 break;
921 case aoHidd_PCIDevice_SubClassDesc:
922 *msg->storage = (IPTR)dev->strSubClass;
923 break;
925 case aoHidd_PCIDevice_InterfaceDesc:
926 *msg->storage = (IPTR)dev->strInterface;
927 break;
928 case aoHidd_PCIDevice_IRQStatus:
929 *msg->storage = (
930 (getWord(cl, o, PCICS_STATUS) &
931 PCISTF_INTERRUPT_STATUS)
932 == PCISTF_INTERRUPT_STATUS);
933 break;
934 case aoHidd_PCIDevice_CapabilitiesPresent:
935 *msg->storage = (
936 (getWord(cl, o, PCICS_STATUS) &
937 PCISTF_CAPABILITIES)
938 == PCISTF_CAPABILITIES);
939 break;
941 case aoHidd_PCIDevice_Owner:
942 *msg->storage = (IPTR)dev->ownerLock.ss_Link.ln_Name;
943 break;
945 default:
946 OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
947 break;
950 else
952 OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
956 void PCIDev__Root__Set(OOP_Class *cl, OOP_Object *o, struct pRoot_Set *msg)
958 ULONG idx;
959 tDeviceData *dev = (tDeviceData *)OOP_INST_DATA(cl,o);
960 struct TagItem *tag, *tags;
962 tags = (struct TagItem *)msg->attrList;
964 while ((tag = NextTagItem(&tags)))
966 if (IS_PCIDEV_ATTR(tag->ti_Tag, idx))
968 switch(idx)
970 case aoHidd_PCIDevice_Base0:
971 setLong(cl, o, PCICS_BAR0, tag->ti_Data);
972 dev->BaseReg[0].addr = getLong(cl, o, PCICS_BAR0);
973 break;
975 case aoHidd_PCIDevice_Base1:
976 setLong(cl, o, PCICS_BAR1, tag->ti_Data);
977 dev->BaseReg[1].addr = getLong(cl, o, PCICS_BAR1);
978 break;
980 case aoHidd_PCIDevice_Base2:
981 if (!dev->isBridge)
983 setLong(cl, o, PCICS_BAR2, tag->ti_Data);
984 dev->BaseReg[2].addr = getLong(cl, o, PCICS_BAR2);
986 break;
988 case aoHidd_PCIDevice_Base3:
989 if (!dev->isBridge)
991 setLong(cl, o, PCICS_BAR3, tag->ti_Data);
992 dev->BaseReg[3].addr = getLong(cl, o, PCICS_BAR3);
994 break;
996 case aoHidd_PCIDevice_Base4:
997 if (!dev->isBridge)
999 setLong(cl, o, PCICS_BAR4, tag->ti_Data);
1000 dev->BaseReg[4].addr = getLong(cl, o, PCICS_BAR4);
1002 break;
1004 case aoHidd_PCIDevice_Base5:
1005 if (!dev->isBridge)
1007 setLong(cl, o, PCICS_BAR5, tag->ti_Data);
1008 dev->BaseReg[5].addr = getLong(cl, o, PCICS_BAR5);
1010 break;
1012 case aoHidd_PCIDevice_RomBase:
1013 setLong(cl, o, PCICS_EXPROM_BASE, tag->ti_Data);
1014 dev->RomBase = getLong(cl, o, PCICS_EXPROM_BASE);
1015 break;
1017 case aoHidd_PCIDevice_MemoryBase:
1018 if (dev->isBridge) setWord(cl, o, PCIBR_MEMBASE, tag->ti_Data >> 16); break;
1020 case aoHidd_PCIDevice_MemoryLimit:
1021 if (dev->isBridge) setWord(cl, o, PCIBR_MEMLIMIT, tag->ti_Data >> 16); break;
1023 case aoHidd_PCIDevice_PrefetchableBase:
1024 if (dev->isBridge) setWord(cl, o, PCIBR_PREFETCHBASE, tag->ti_Data >> 16); break;
1026 case aoHidd_PCIDevice_PrefetchableLimit:
1027 if (dev->isBridge) setWord(cl, o, PCIBR_PREFETCHLIMIT, tag->ti_Data >> 16); break;
1029 case aoHidd_PCIDevice_IOBase:
1030 if (dev->isBridge) setByte(cl, o, PCIBR_IOBASE, tag->ti_Data >> 8); break;
1032 case aoHidd_PCIDevice_IOLimit:
1033 if (dev->isBridge) setByte(cl, o, PCIBR_IOLIMIT, tag->ti_Data >> 8); break;
1035 case aoHidd_PCIDevice_isIO:
1037 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_IODECODE;
1038 if (tag->ti_Data)
1039 command |= PCICMF_IODECODE;
1040 setWord(cl, o, PCICS_COMMAND, command);
1042 break;
1044 case aoHidd_PCIDevice_isMEM:
1046 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_MEMDECODE;
1047 if (tag->ti_Data)
1048 command |= PCICMF_MEMDECODE;
1049 setWord(cl, o, PCICS_COMMAND, command);
1051 break;
1053 case aoHidd_PCIDevice_isMaster:
1055 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_BUSMASTER;
1056 if (tag->ti_Data)
1057 command |= PCICMF_BUSMASTER;
1058 setWord(cl, o, PCICS_COMMAND, command);
1060 break;
1062 case aoHidd_PCIDevice_paletteSnoop:
1064 UWORD command = getWord(cl, o, PCICS_COMMAND) & ~PCICMF_VGASNOOP;
1065 if (tag->ti_Data)
1066 command |= PCICMF_VGASNOOP;
1067 setWord(cl, o, PCICS_COMMAND, command);
1069 break;
1071 case aoHidd_PCIDevice_ISAEnable:
1072 if (dev->isBridge)
1074 UWORD control = getWord(cl, o, PCIBR_CONTROL) & ~PCICTRLF_ISAENABLE;
1075 if (tag->ti_Data)
1076 control |= PCICTRLF_ISAENABLE;
1077 setWord(cl, o, PCIBR_CONTROL, control);
1079 break;
1081 case aoHidd_PCIDevice_VGAEnable:
1082 if (dev->isBridge)
1084 UWORD control = getWord(cl, o, PCIBR_CONTROL) & ~PCICTRLF_VGAENABLE;
1085 if (tag->ti_Data)
1086 control |= PCICTRLF_VGAENABLE;
1087 setWord(cl, o, PCIBR_CONTROL, control);
1089 break;
1091 default:
1092 bug("[PCIDevice] Trying to set nonsettable attribute %d!\n", idx);
1093 break;