Blame |
Last modification |
View Log
| RSS feed
#include <linux/pci.h>
#include <linux/module.h>
#include "pci.h"
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
int pci_hotplug
(struct device
*dev
, char **envp
, int num_envp
,
char *buffer
, int buffer_size
)
{
struct pci_dev
*pdev
;
char *scratch
;
int i
= 0;
int length
= 0;
if (!dev
)
return -ENODEV
;
pdev
= to_pci_dev
(dev
);
if (!pdev
)
return -ENODEV
;
scratch
= buffer
;
/* stuff we want to pass to /sbin/hotplug */
envp
[i
++] = scratch
;
length
+= snprintf (scratch
, buffer_size
- length
, "PCI_CLASS=%04X",
pdev
->class
);
if ((buffer_size
- length
<= 0) || (i
>= num_envp
))
return -ENOMEM
;
++length
;
scratch
+= length
;
envp
[i
++] = scratch
;
length
+= snprintf (scratch
, buffer_size
- length
, "PCI_ID=%04X:%04X",
pdev
->vendor
, pdev
->device
);
if ((buffer_size
- length
<= 0) || (i
>= num_envp
))
return -ENOMEM
;
++length
;
scratch
+= length
;
envp
[i
++] = scratch
;
length
+= snprintf (scratch
, buffer_size
- length
,
"PCI_SUBSYS_ID=%04X:%04X", pdev
->subsystem_vendor
,
pdev
->subsystem_device
);
if ((buffer_size
- length
<= 0) || (i
>= num_envp
))
return -ENOMEM
;
++length
;
scratch
+= length
;
envp
[i
++] = scratch
;
length
+= snprintf (scratch
, buffer_size
- length
, "PCI_SLOT_NAME=%s",
pci_name
(pdev
));
if ((buffer_size
- length
<= 0) || (i
>= num_envp
))
return -ENOMEM
;
envp
[i
] = 0;
return 0;
}
static int pci_visit_bus
(struct pci_visit
* fn
, struct pci_bus_wrapped
*wrapped_bus
, struct pci_dev_wrapped
*wrapped_parent
)
{
struct list_head
*ln
;
struct pci_dev
*dev
;
struct pci_dev_wrapped wrapped_dev
;
int result
= 0;
DBG
("scanning bus %02x\n", wrapped_bus
->bus
->number
);
if (fn
->pre_visit_pci_bus
) {
result
= fn
->pre_visit_pci_bus
(wrapped_bus
, wrapped_parent
);
if (result
)
return result
;
}
ln
= wrapped_bus
->bus
->devices.
next;
while (ln
!= &wrapped_bus
->bus
->devices
) {
dev
= pci_dev_b
(ln
);
ln
= ln
->next
;
memset(&wrapped_dev
, 0, sizeof(struct pci_dev_wrapped
));
wrapped_dev.
dev = dev
;
result
= pci_visit_dev
(fn
, &wrapped_dev
, wrapped_bus
);
if (result
)
return result
;
}
if (fn
->post_visit_pci_bus
)
result
= fn
->post_visit_pci_bus
(wrapped_bus
, wrapped_parent
);
return result
;
}
static int pci_visit_bridge
(struct pci_visit
* fn
,
struct pci_dev_wrapped
*wrapped_dev
,
struct pci_bus_wrapped
*wrapped_parent
)
{
struct pci_bus
*bus
;
struct pci_bus_wrapped wrapped_bus
;
int result
= 0;
DBG
("scanning bridge %02x, %02x\n", PCI_SLOT
(wrapped_dev
->dev
->devfn
),
PCI_FUNC
(wrapped_dev
->dev
->devfn
));
if (fn
->visit_pci_dev
) {
result
= fn
->visit_pci_dev
(wrapped_dev
, wrapped_parent
);
if (result
)
return result
;
}
bus
= wrapped_dev
->dev
->subordinate
;
if(bus
) {
memset(&wrapped_bus
, 0, sizeof(struct pci_bus_wrapped
));
wrapped_bus.
bus = bus
;
result
= pci_visit_bus
(fn
, &wrapped_bus
, wrapped_dev
);
}
return result
;
}
/**
* pci_visit_dev - scans the pci buses.
* Every bus and every function is presented to a custom
* function that can act upon it.
*/
int pci_visit_dev
(struct pci_visit
*fn
, struct pci_dev_wrapped
*wrapped_dev
,
struct pci_bus_wrapped
*wrapped_parent
)
{
struct pci_dev
* dev
= wrapped_dev
? wrapped_dev
->dev
: NULL
;
int result
= 0;
if (!dev
)
return 0;
if (fn
->pre_visit_pci_dev
) {
result
= fn
->pre_visit_pci_dev
(wrapped_dev
, wrapped_parent
);
if (result
)
return result
;
}
switch (dev
->class
>> 8) {
case PCI_CLASS_BRIDGE_PCI
:
result
= pci_visit_bridge
(fn
, wrapped_dev
,
wrapped_parent
);
if (result
)
return result
;
break;
default:
DBG
("scanning device %02x, %02x\n",
PCI_SLOT
(dev
->devfn
), PCI_FUNC
(dev
->devfn
));
if (fn
->visit_pci_dev
) {
result
= fn
->visit_pci_dev
(wrapped_dev
,
wrapped_parent
);
if (result
)
return result
;
}
}
if (fn
->post_visit_pci_dev
)
result
= fn
->post_visit_pci_dev
(wrapped_dev
, wrapped_parent
);
return result
;
}
EXPORT_SYMBOL
(pci_visit_dev
);