Beautiful Code [43]
spinlock_t lock; /* lock for the device to ensure two
different layers don't access it at
the same time. */
atomic_t refcount; /* refcount to make sure the device
* persists for the right amount of time */
struct driver_dir_entry * dir;
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform-specific data (e.g. ACPI,
BIOS data relevant to device */
u32 current_state; /* Current operating state. In
ACPI-speak, this is D0-D3, D0
being fully functional, and D3
being off. */
unsigned char *saved_state; /* saved device state */
};
Every time this structure was created and registered with the kernel driver core, a new entry in a virtual filesystem was created that showed the device and any different attributes it contained. This allowed all devices in the system to be shown to userspace, in the order in which they were connected. This virtual filesystem is now called sysfs and can be seen on a Linux machine in the /sys/devices directory. An example of this structure showing a few PCI and USB devices follows:
Code View: Scroll / Show All
$ tree -d /sys/devices/
/sys/devices/pci0000:00/
|-- 0000:00:00.0
|-- 0000:00:02.0
|-- 0000:00:07.0
|-- 0000:00:1b.0
| |-- card0
| | |-- adsp
| | |-- audio
| | |-- controlC0
| | |-- dsp
| | |-- mixer
| | |-- pcmC0D0c
| | |-- pcmC0D0p
| | |-- pcmC0D1p
| | `-- subsystem -> ../../../../class/sound
| `-- driver -> ../../../bus/pci/drivers/HDA Intel
|-- 0000:00:1c.0
| |-- 0000:00:1c.0:pcie00
| |-- 0000:00:1c.0:pcie02
| |-- 0000:00:1c.0:pcie03
| |-- 0000:01:00.0
| | `-- driver -> ../../../../bus/pci/drivers/sky2
| `-- driver -> ../../../bus/pci/drivers/pcieport-driver
|-- 0000:00:1d.0
| |-- driver -> ../../../bus/pci/drivers/uhci_hcd
| `-- usb2
| |-- 2-0:1.0
| | |-- driver -> ../../../../../bus/usb/drivers/hub
| | |-- subsystem -> ../../../../../bus/usb
| | `-- usbdev2.1_ep81
| |-- driver -> ../../../../bus/usb/drivers/usb
| `-- usbdev2.1_ep00
|-- 0000:00:1d.2
| |-- driver -> ../../../bus/pci/drivers/uhci_hcd
| `-- usb4
| |-- 4-0:1.0
| | |-- driver -> ../../../../../bus/usb/drivers/hub
| | `-- usbdev4.1_ep81
| |-- 4-1
| | |-- 4-1:1.0
| | | |-- driver -> ../../../../../../bus/usb/drivers/usbhid
| | | `-- usbdev4.2_ep81
| | |-- driver -> ../../../../../bus/usb/drivers/usb
| | |-- power
| | `-- usbdev4.2_ep00
| |-- 4-2
| | |-- 4-2.1
| | | |-- 4-2.1:1.0
| | | | |-- driver -> ../../../../../../../bus/usb/drivers/usbhid
| | | | `-- usbdev4.4_ep81
| | | |-- 4-2.1:1.1
| | | | |-- driver -> ../../../../../../../bus/usb/drivers/usbhid
| | | | `-- usbdev4.4_ep82
| | | |-- driver -> ../../../../../../bus/usb/drivers/usb
| | | `-- usbdev4.4_ep00
| | |-- 4-2.2
| | | |-- 4-2.2:1.0
| | | | |-- driver -> ../../../../../../../bus/usb/drivers/usblp
| | | | |-- usbdev4.5_ep01
| | | | `-- usbdev4.5_ep81
| | | |-- driver -> ../../../../../../bus/usb/drivers/usb
| | | `-- usbdev4.5_ep00
| | |-- 4-2:1.0
| | | |-- driver -> ../../../../../../bus/usb/drivers/hub
| | | `-- usbdev4.3_ep81
| | |-- driver -> ../../../../../bus/usb/drivers/usb
| | `-- usbdev4.3_ep00
| |-- driver -> ../../../../bus/usb/drivers/usb
| `-- usbdev4.1_ep00
...
To use this structure, it is required that you embed it within another structure, causing the new structure to "inherit," in a sense, from the base structure:
Code View: Scroll / Show All
struct usb_interface {
struct usb_interface_descriptor *altsetting;
int act_altsetting; /* active alternate setting */
int num_altsetting; /* number of alternate settings*/
int max_altsetting; /* total memory allocated */
struct usb_driver *driver; /* driver */
struct device dev; /* interface specific device info */
};
The driver core operates by passing around pointers to a struct device, operating on the basic fields that are in that structure and thus are common