/**
* \file common_bridge.c
* Support routines used to process PCI header information for bridges.
- *
+ *
* \author Ian Romanick <idr@us.ibm.com>
*/
info = malloc(sizeof(*info));
if (info != NULL) {
- pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18,
+ pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18,
0x40 - 0x18, & bytes );
info->primary_bus = buf[0x18];
/**
* Determine the primary, secondary, and subordinate buses for a bridge
- *
+ *
* Determines the IDs of the primary, secondary, and subordinate buses for
* a specified bridge. Not all bridges directly store this information
* (e.g., PCI-to-ISA bridges). For those bridges, no error is returned, but
* \return
* On success, zero is returned. If \c dev is not a bridge, \c ENODEV is
* returned.
- *
+ *
* \bug
* Host bridges are handled the same way as PCI-to-ISA bridges. This is
* almost certainly not correct.
/* If the device isn't a bridge, return an error.
*/
-
- if (((dev->device_class >> 16) & 0x0ff) != 0x06) {
- return ENODEV;
- }
- if (!priv->bridge.pci) {
+ if (((dev->device_class >> 16) & 0x0ff) != 0x06) {
return ENODEV;
}
case 0x04:
if (priv->bridge.pci == NULL)
read_bridge_info(priv);
- if (priv->header_type == 0x01) {
+ if ((priv->header_type & 0x7f) == 0x01) {
*primary_bus = priv->bridge.pci->primary_bus;
*secondary_bus = priv->bridge.pci->secondary_bus;
*subordinate_bus = priv->bridge.pci->subordinate_bus;
case 0x07:
if (priv->bridge.pcmcia == NULL)
read_bridge_info(priv);
- if (priv->header_type == 0x02) {
+ if ((priv->header_type & 0x7f) == 0x02) {
*primary_bus = priv->bridge.pcmcia->primary_bus;
*secondary_bus = priv->bridge.pcmcia->card_bus;
*subordinate_bus = priv->bridge.pcmcia->subordinate_bus;
return 0;
}
+
+#define PCI_CLASS_BRIDGE 0x06
+#define PCI_SUBCLASS_BRIDGE_PCI 0x04
+#define PCI_CLASS_MASK 0xFF
+#define PCI_SUBCLASS_MASK 0xFF
+
+struct pci_device *
+pci_device_get_parent_bridge(struct pci_device *dev)
+{
+ struct pci_id_match bridge_match = {
+ PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
+ (PCI_CLASS_BRIDGE << 16) | (PCI_SUBCLASS_BRIDGE_PCI << 8),
+ (PCI_CLASS_MASK << 16) | (PCI_SUBCLASS_MASK << 8)
+ };
+
+ struct pci_device *bridge;
+ struct pci_device_iterator *iter;
+
+ if (dev == NULL)
+ return NULL;
+
+ iter = pci_id_match_iterator_create(& bridge_match);
+ if (iter == NULL)
+ return NULL;
+
+ while ((bridge = pci_device_next(iter)) != NULL) {
+ if (bridge->domain == dev->domain) {
+ const struct pci_bridge_info *info =
+ pci_device_get_bridge_info(bridge);
+
+ if (info != NULL) {
+ if (info->secondary_bus == dev->bus) {
+ break;
+ }
+ }
+ }
+ }
+
+ pci_iterator_destroy(iter);
+
+ return bridge;
+}