Registering Drivers

PCI drivers can be registered by means of pci_register_driver. The function is quite primitive. Its prime task is to fill a few remaining fields of a pci_device instance to which relevant functions have already been assigned. This instance is passed to the generic device layer using driver_register, whose mode of operation was discussed above.

More interesting than the registration process is the filling of the pci_device structure in the individual drivers as this involves not only defining the above functions that define the interfaces between the driver and the generic kernel code but also creating a list of all devices whose (sub)device and (sub)vendor IDs indicate that they are suitable for the driver.

As already noted above, the pci_device_id data structure whose definition is given below has a decisive role to play in this context.

<mod_devicetable.h>

struct pci_device_id {

_u32 vendor, device;

_u32 subvendor, subdevice;

_u32 class, class_mask;

unsigned long driver_data;

/* Vendor and device ID or PCI_ANY_ID*/

/* Data private to the driver */

You are familiar with the elements of this structure from the description of the PCI configuration space. By defining specific constants, a driver is able to refer to a particular chipset/device; class_mask also allows classes to be filtered by reference to a bitmask.

In many cases, it is neither necessary nor desirable to describe just one device. If a large number of compatible devices is supported, this would quickly result in endless declaration lists in the driver sources; these would be difficult to read and would have the tangible disadvantage that a compatible device may not be found simply because it is not included in the list of supported devices. The kernel therefore provides the wildcard constant pci_any_id that matches any identifier of a PCI device. Let us look at how this is used in the following example for the eepro100 driver (a widely used network card chipset from Intel):

drivers/net/e100/e100_main.c

#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\

PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } static struct pci_device_id e100_id_table[] = { INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), INTEL_8255X_ETHERNET_DEVICE(0x1031, 3), INTEL_8255X_ETHERNET_DEVICE(0x1032, 3), INTEL_8255X_ETHERNET_DEVICE(0x1033, 3),

INTEL_8255X_ETHERNET_DEVICE(0x245D, 2), INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7), { 0, }

Each macro expansion of intel_8255x_ethernet_device generates an entry in the table. The individual elements of the entry are given in the sequence in which they are declared in pci_device_id.

0x808 6 is the vendor ID for Intel, the manufacturer of the chipset (the driver could also have used the pre-processor constant pci_vendor_id_intel defined with the same value). Each entry holds a specific device ID that identifies all versions currently on the market. Subvendor and subdevice ID are of no relevance and are therefore represented by pci_any_id; this means that any subvendor or any subdevice is recognized as valid.

The kernel provides the pci_match_id function to compare the PCI device data with the data in an ID table. It refers to the given ID table of a pci_dev instance to ascertain whether the device is included in the table.

drivers/pci/pci-driver.c const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);

A match is found when all elements in an ID table entry and all elements in the device configuration are identical. If a field in the ID table contains the special entry pci_any_id, every value in the corresponding field of the pci_device instance is interpreted as a match.

USB (Universal Serial Bus) was developed at the end of the '90s of what is now the last century as an external bus to satisfy ever-more-demanding PC requirements and to produce solutions for new computer types such as handhelds, PDAs, and the like. As a universal external bus, USB delivers its benefits when used in conjunction with devices requiring low to medium data transfer rates such as mice, Webcams, and keyboards. However, more broadband-intensive devices such as external hard disks, CD-ROMs, and CD writers can also be operated on USB buses. The maximum transfer rate for USB 1.1 is limited to 12 MBit/second but Version 2.0 of the standard supports higher rates of up to 480 MBit/second.

When the bus was designed, special attention was focused on ease of use for inexperienced computer users. As a consequence, hotplugging and the associated transparent installation of drivers are core aspects of the USB design. In contrast to earlier PCI hotplug cards (which were difficult to obtain) and PCMCIA/PC cards (which were little used because of their high price), USB is the first bus that has made the hotplugging capabilities of the kernel available to a wide audience.

Continue reading here: Features and Mode of Operation

Was this article helpful?

+1 0