分类: LINUX
2006-09-20 14:54:04
Linux Device Drivers, 2nd Edition2nd Edition June 2001 0-59600-008-1, Order Number: 0081 586 pages, $39.95 |
Chapter 15
Overview of Peripheral BusesContents:
Whereas Chapter 8, "Hardware Management" introduced the lowest levels of hardware control, this chapter provides an overview of the higher-level bus architectures. A bus is made up of both an electrical interface and a programming interface. In this chapter, we deal with the programming interface.
rudo% lspci | cut -d: -f1-2
00:00.0 Host bridge
00:01.0 PCI bridge
00:07.0 ISA bridge
00:07.1 IDE interface
00:07.3 Bridge
00:07.4 USB Controller
00:09.0 SCSI storage controller
00:0b.0 Multimedia video controller
01:05.0 VGA compatible controller
rudo% cat /proc/bus/pci/devices | cut -d\ -f1,3
0000 0
0008 0
0038 0
0039 0
003b 0
003c b
0048 a
0058 b
0128 aTo see how PCI works, we'll start from system boot, since that's when the devices are configured.
- struct pci_dev;
- struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
- struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from);
- int pci_enable_device(struct pci_dev *dev);
- struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
#ifndef CONFIG_PCI
# error "This driver needs PCI support to be available"
#endif
int jail_find_all_devices(void)
{
struct pci_dev *dev = NULL;
int found;
if (!pci_present())
return -ENODEV;
for (found=0; found < JAIL_MAX_DEV;) {
dev = pci_find_device(JAIL_VENDOR, JAIL_ID, dev);
if (!dev) /* no more devices are there */
break;
/* do device-specific actions and count the device */
found += jail_init_one(dev);
}
return (index == 0) ? -ENODEV : 0;
}
struct devid {unsigned short vendor, device} devlist[] = {
{JAIL_VENDOR1, JAIL_DEVICE1},
{JAIL_VENDOR2, JAIL_DEVICE2},
/* ... */
{ 0, 0 }
};
/* ... */
for (found=0; found < JAIL_MAX_DEV;) {
struct devid *idptr;
dev = pci_find_class(JAIL_CLASS, dev);
if (!dev) /* no more devices are there */
break;
for (idptr = devlist; idptr->vendor; idptr++) {
if (dev->vendor != idptr->vendor) continue;
if (dev->device != idptr->device) continue;
break;
}
if (!idptr->vendor) continue; /* not one of ours */
jail_init_one(dev); /* device-specific initialization */
found++;
}
- int pci_read_config_byte(struct pci_dev *dev, int where, u8 *ptr);
- int pci_read_config_word(struct pci_dev *dev, int where, u16 *ptr);
- int pci_read_config_dword(struct pci_dev *dev, int where, u32 *ptr);
- int pci_write_config_byte (struct pci_dev *dev, int where, u8 val);
- int pci_write_config_word (struct pci_dev *dev, int where, u16 val);
- int pci_write_config_dword (struct pci_dev *dev, int where, u32 val);
morgana% dd bs=256 skip=4 count=1 if=/proc/pcidata | ./pcidump
1+0 records in
1+0 records out
Compulsory registers:
Vendor id: 8086
Device id: 1223
I/O space enabled: n
Memory enabled: y
Master enabled: y
Revision id (decimal): 0
Programmer Interface: 00
Class of device: 0400
Header type: 00
Multi function device: n
Optional registers:
Base Address 0: f1000000
Base Address 0 Is I/O: n
Base Address 0 is 64-bits: n
Base Address 0 is below-1M: n
Base Address 0 is prefetchable: n
Does generate interrupts: y
Interrupt line (decimal): 10
Interrupt pin (decimal): 1
- unsigned long pci_resource_start(struct pci_dev *dev, int bar);
- unsigned long pci_resource_end(struct pci_dev *dev, int bar);
- unsigned long pci_resource_flags(struct pci_dev *dev, int bar);
static u32 addresses[] = {
PCI_BASE_ADDRESS_0,
PCI_BASE_ADDRESS_1,
PCI_BASE_ADDRESS_2,
PCI_BASE_ADDRESS_3,
PCI_BASE_ADDRESS_4,
PCI_BASE_ADDRESS_5,
0
};
int pciregions_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *data)
{
/* this macro helps in keeping the following lines short */
#define PRINTF(fmt, args...) sprintf(buf+len, fmt, ## args)
len=0;
/* Loop through the devices (code not printed in the book) */
/* Print the address regions of this device */
for (i=0; addresses[i]; i++) {
u32 curr, mask, size;
char *type;
pci_read_config_dword(dev, addresses[i],&curr);
cli();
pci_write_config_dword(dev, addresses[i],~0);
pci_read_config_dword(dev, addresses[i],&mask);
pci_write_config_dword(dev, addresses[i],curr);
sti();
if (!mask)
continue; /* there may be other regions */
/*
* apply the I/O or memory mask to current position.
* note that I/O is limited to 0xffff, and 64-bit is not
* supported by this simple implementation
*/
if (curr & PCI_BASE_ADDRESS_SPACE_IO) {
curr &= PCI_BASE_ADDRESS_IO_MASK;
} else {
curr &= PCI_BASE_ADDRESS_MEM_MASK;
}
len += PRINTF("\tregion %i: mask 0x%08lx, now at 0x%08lx\n",
i, (unsigned long)mask,
(unsigned long)curr);
/* extract the type, and the programmable bits */
if (mask & PCI_BASE_ADDRESS_SPACE_IO) {
type = "I/O"; mask &= PCI_BASE_ADDRESS_IO_MASK;
size = (~mask + 1) & 0xffff; /* Bleah */
} else {
type = "mem"; mask &= PCI_BASE_ADDRESS_MEM_MASK;
size = ~mask + 1;
}
len += PRINTF("\tregion %i: type %s, size %i (%i%s)\n", i,
type, size,
(size & 0xfffff) == 0 ? size >> 20 :
(size & 0x3ff) == 0 ? size >> 10 : size,
(size & 0xfffff) == 0 ? "MB" :
(size & 0x3ff) == 0 ? "KB" : "B");
if (len > PAGE_SIZE / 2) {
len += PRINTF("... more info skipped ...\n");
*eof = 1; return len;
}
}
return len;
}Bus 0, device 13, fun 0 (id 8086-1223)
region 0: mask 0xfffff000, now at 0xf1000000
region 0: type mem, size 4096 (4KB)result = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &myirq);
if (result) { /* deal with error */ }
- void pci_insert_device(struct pci_dev *dev, struct pci_bus *bus);
- void pci_remove_device(struct pci_dev *dev);
- struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
- const struct pci_device_id *id_table;
- int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
- void (*remove)(struct pci_dev *dev);
- int (*suspend)(struct pci_dev *dev, u32 state);
- int (*resume)(struct pci_dev *dev);
struct pci_ops {
int (*read_byte)(struct pci_dev *, int where, u8 *val);
int (*read_word)(struct pci_dev *, int where, u16 *val);
int (*read_dword)(struct pci_dev *, int where, u32 *val);
int (*write_byte)(struct pci_dev *, int where, u8 val);
int (*write_word)(struct pci_dev *, int where, u16 val);
int (*write_dword)(struct pci_dev *, int where, u32 val);
};dev->bus->ops->read_byte();An ISA device can be equipped with I/O ports, memory areas, and interrupt lines.
PCI and ISA are the most commonly used peripheral interfaces in the PC world, but they aren't the only ones. Here's a summary of the features of other buses found in the PC market.
MCA
This section, as usual, summarizes the symbols introduced in the chapter.
- #include
- CONFIG_PCI
This header includes symbolic names for the PCI registers and several vendor and device ID values.
- struct pci_dev;
- struct pci_device_id;
- struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from);
- struct pci_dev *pci_find_class(unsigned int class, struct pci_dev *from);
- int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
- int pci_read_config_word(struct pci_dev *dev, int where, u16 *val);
- int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val);
- int pci_write_config_byte (struct pci_dev *dev, int where, u8 *val);
- int pci_write_config_word (struct pci_dev *dev, int where, u16 *val);
- int pci_write_config_dword (struct pci_dev *dev, int where, u32 *val);
Back to:
© 2001, O'Reilly & Associates, Inc.