- Bus probes all devices
- Bus registers all drivers usable for the bus
- Bus then 'binds' driver to each device discovered:
- When device_register is called for a device, it is inserted into the end of this list.
- The bus object also contains a list of all drivers of that bus type.
- These are the two events which trigger driver binding.
- If a match is found, the device's driver field is set to the driver and the driver's probe callback is called.
- This gives the driver a chance to verify that it really does support the hardware, and that it's in a working state.
- When a driver is attached to a device, the device is inserted into the driver's list of devices.
- Upon the successful completion of probe, the device is registered with the class to which it belongs
- Device drivers belong to one and only one class, and that is set in the driver's devclass field.
- devclass_add_device() is called to enumerate the device within the class and actually register it with the class
- The bus's list of devices is iterated over to find a match
- Devices that already have a driver are skipped.
- When a device is removed, the reference count for it will eventually go to 0.
- When it does, the remove callback of the driver is called.
When a bus driver probes and finds devices, it registers the device:
int device_register(struct device * dev);
struct device {
struct list_head g_list; // Node in the global device list.
struct list_head node; // Node in device's parent's children list.
struct list_head bus_list; // Node in device's bus's devices list.
struct list_head driver_list; // Node in device's driver's devices list.
struct list_head intf_list; // List of intf_data. Each interface supported
struct list_head children; // List of child devices.
struct device * parent;
char name[DEVICE_NAME_SIZE]; // ASCII description of device.
char bus_id[BUS_ID_SIZE]; // ASCII representation of device's bus position <bus>:<slot>.<id>
spinlock_t lock; // Spinlock for the device.
atomic_t refcount; // Reference count on the device.
struct bus_type * bus; // Pointer to struct bus_type that device belongs to.
struct driver_dir_entry dir; // Device's sysfs directory.
u32 class_num; // Class-enumerated value of the device.
struct device_driver *driver; // Pointer to struct device_driver that controls the device.
void *driver_data; // Driver-specific data.
void *platform_data; // Bus, GPIO etc.. pre-DTS?
u32 current_state; // Current power state of the device.
unsigned char *saved_state; // Pointer to saved state of the device.
void (*release)(struct device * dev);
};A device class describes a type of device, like an audio or network device. Device classes are agnostic with respect to what bus a device resides on. There is no list of devices in the device class. Only list of drivers, which then have a list of devices
Adding a device to it
- Each time a device is added to the class, the class's devnum field is incremented and assigned to the device.
- The field is never decremented, so if the device is removed from the class and re-added, it will receive a different enumerated value.
class struct:
struct device_class {
char * name;
rwlock_t lock;
u32 devnum;
struct list_head node;
struct list_head drivers;
struct list_head intf_list;
struct driver_dir_entry dir;
struct driver_dir_entry device_dir;
struct driver_dir_entry driver_dir;
devclass_add add_device;
devclass_remove remove_device;
};Example class:
struct device_class input_devclass = {
.name = "input",
.add_device = input_add_device,
.remove_device = input_remove_device,
};Adding/removing device classes:
int devclass_register(struct device_class * cls);
void devclass_unregister(struct device_class * cls);A kobject is an object of type struct kobject Kobjects have a name and a reference count. A kobject also has a parent pointer (allowing objects to be arranged into hierarchies), a specific type, and, usually, a representation in the sysfs virtual filesystem. No structure should EVER have more than one kobject embedded within it. A ktype is the type of object that embeds a kobject. The ktype controls what happens to the kobject when it is created and destroyed.
A kset is a group of kobjects. When you see a sysfs directory full of other directories, generally each of those directories corresponds to a kobject in the same kset.
devres is basically linked list of arbitrarily sized memory areas associated with a struct device. Each devres entry is associated with a release function. Managed interface is created for resources commonly used by device drivers using devres. For example, coherent DMA memory is acquired using dma_alloc_coherent(). The managed version is called dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except for the DMA memory allocated using it is managed and will be automatically released on driver detach.
- Devres is memory types usable for drivers
- Alloc is all managed so it is automatically released
Example:
struct dma_devres {
size_t size;
void *vaddr;
dma_addr_t dma_handle;
};
static void dmam_coherent_release(struct device *dev, void *res)
{
struct dma_devres *this = res;
dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
}
dmam_alloc_coherent(dev, size, dma_handle, gfp)
{
struct dma_devres *dr;
void *vaddr;
dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
...
/* alloc DMA memory as usual */
vaddr = dma_alloc_coherent(...);
...
/* record size, vaddr, dma_handle in dr */
dr->vaddr = vaddr;
...
devres_add(dev, dr);
return vaddr;
}Step 0: Read include/linux/device.h for object and function definitions
Step 1: Registering the bus driver.
struct bus_type pci_bus_type = {
.name = "pci",
};- Register the bus type.
static int __init pci_driver_init(void)
{
return bus_register(&pci_bus_type);
}
subsys_initcall(pci_driver_init);- Export the bus type for others to use.
extern struct bus_type pci_bus_type;
EXPORT_SYMBOL(pci_bus_type);- This will cause the bus to show up in /sys/bus/pci/ with two subdirectories: 'devices' and 'drivers'.
Step 2: Registering Devices.
struct pci_dev {
...
struct device dev; /* Generic device interface */
...
};-
Initialize the device on registration.
-
Register the device.
Once the generic device has been initialized, it can be registered with the driver model core by doing:
device_register(&dev->dev);Step 3: Registering Drivers.
struct pci_driver {
...
struct device_driver driver;
};- After initializing thedriver, register it:
driver_register(&drv->driver);Step 4: Define Generic Methods for Drivers.
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.probe = pci_device_probe;
drv->driver.resume = pci_device_resume;
drv->driver.suspend = pci_device_suspend;
drv->driver.remove = pci_device_remove;
/* register with core */
driver_register(&drv->driver);