diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /Documentation/driver-model | |
download | linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.bz2 |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'Documentation/driver-model')
-rw-r--r-- | Documentation/driver-model/binding.txt | 102 | ||||
-rw-r--r-- | Documentation/driver-model/bus.txt | 160 | ||||
-rw-r--r-- | Documentation/driver-model/class.txt | 162 | ||||
-rw-r--r-- | Documentation/driver-model/device.txt | 154 | ||||
-rw-r--r-- | Documentation/driver-model/driver.txt | 287 | ||||
-rw-r--r-- | Documentation/driver-model/interface.txt | 129 | ||||
-rw-r--r-- | Documentation/driver-model/overview.txt | 114 | ||||
-rw-r--r-- | Documentation/driver-model/platform.txt | 99 | ||||
-rw-r--r-- | Documentation/driver-model/porting.txt | 445 |
9 files changed, 1652 insertions, 0 deletions
diff --git a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt new file mode 100644 index 000000000000..f7ec9d625bfc --- /dev/null +++ b/Documentation/driver-model/binding.txt @@ -0,0 +1,102 @@ + +Driver Binding + +Driver binding is the process of associating a device with a device +driver that can control it. Bus drivers have typically handled this +because there have been bus-specific structures to represent the +devices and the drivers. With generic device and device driver +structures, most of the binding can take place using common code. + + +Bus +~~~ + +The bus type structure contains a list of all devices that are on that bus +type in the system. 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. When driver_register is called +for a driver, it is inserted at the end of this list. These are the +two events which trigger driver binding. + + +device_register +~~~~~~~~~~~~~~~ + +When a new device is added, the bus's list of drivers is iterated over +to find one that supports it. In order to determine that, the device +ID of the device must match one of the device IDs that the driver +supports. The format and semantics for comparing IDs is bus-specific. +Instead of trying to derive a complex state machine and matching +algorithm, it is up to the bus driver to provide a callback to compare +a device against the IDs of a driver. The bus returns 1 if a match was +found; 0 otherwise. + +int match(struct device * dev, struct device_driver * drv); + +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. + +Device Class +~~~~~~~~~~~~ + +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, which happens with the +class's register_dev callback. + +NOTE: The device class structures and core routines to manipulate them +are not in the mainline kernel, so the discussion is still a bit +speculative. + + +Driver +~~~~~~ + +When a driver is attached to a device, the device is inserted into the +driver's list of devices. + + +sysfs +~~~~~ + +A symlink is created in the bus's 'devices' directory that points to +the device's directory in the physical hierarchy. + +A symlink is created in the driver's 'devices' directory that points +to the device's directory in the physical hierarchy. + +A directory for the device is created in the class's directory. A +symlink is created in that directory that points to the device's +physical location in the sysfs tree. + +A symlink can be created (though this isn't done yet) in the device's +physical directory to either its class directory, or the class's +top-level directory. One can also be created to point to its driver's +directory also. + + +driver_register +~~~~~~~~~~~~~~~ + +The process is almost identical for when a new driver is added. +The bus's list of devices is iterated over to find a match. Devices +that already have a driver are skipped. All the devices are iterated +over, to bind as many devices as possible to the driver. + + +Removal +~~~~~~~ + +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. It +is removed from the driver's list of devices and the reference count +of the driver is decremented. All symlinks between the two are removed. + +When a driver is removed, the list of devices that it supports is +iterated over, and the driver's remove callback is called for each +one. The device is removed from that list and the symlinks removed. + diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt new file mode 100644 index 000000000000..dd62c7b80b3f --- /dev/null +++ b/Documentation/driver-model/bus.txt @@ -0,0 +1,160 @@ + +Bus Types + +Definition +~~~~~~~~~~ + +struct bus_type { + char * name; + + struct subsystem subsys; + struct kset drivers; + struct kset devices; + + struct bus_attribute * bus_attrs; + struct device_attribute * dev_attrs; + struct driver_attribute * drv_attrs; + + int (*match)(struct device * dev, struct device_driver * drv); + int (*hotplug) (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + int (*suspend)(struct device * dev, u32 state); + int (*resume)(struct device * dev); +}; + +int bus_register(struct bus_type * bus); + + +Declaration +~~~~~~~~~~~ + +Each bus type in the kernel (PCI, USB, etc) should declare one static +object of this type. They must initialize the name field, and may +optionally initialize the match callback. + +struct bus_type pci_bus_type = { + .name = "pci", + .match = pci_bus_match, +}; + +The structure should be exported to drivers in a header file: + +extern struct bus_type pci_bus_type; + + +Registration +~~~~~~~~~~~~ + +When a bus driver is initialized, it calls bus_register. This +initializes the rest of the fields in the bus object and inserts it +into a global list of bus types. Once the bus object is registered, +the fields in it are usable by the bus driver. + + +Callbacks +~~~~~~~~~ + +match(): Attaching Drivers to Devices +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The format of device ID structures and the semantics for comparing +them are inherently bus-specific. Drivers typically declare an array +of device IDs of devices they support that reside in a bus-specific +driver structure. + +The purpose of the match callback is provide the bus an opportunity to +determine if a particular driver supports a particular device by +comparing the device IDs the driver supports with the device ID of a +particular device, without sacrificing bus-specific functionality or +type-safety. + +When a driver is registered with the bus, the bus's list of devices is +iterated over, and the match callback is called for each device that +does not have a driver associated with it. + + + +Device and Driver Lists +~~~~~~~~~~~~~~~~~~~~~~~ + +The lists of devices and drivers are intended to replace the local +lists that many buses keep. They are lists of struct devices and +struct device_drivers, respectively. Bus drivers are free to use the +lists as they please, but conversion to the bus-specific type may be +necessary. + +The LDM core provides helper functions for iterating over each list. + +int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, + int (*fn)(struct device *, void *)); + +int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)); + +These helpers iterate over the respective list, and call the callback +for each device or driver in the list. All list accesses are +synchronized by taking the bus's lock (read currently). The reference +count on each object in the list is incremented before the callback is +called; it is decremented after the next object has been obtained. The +lock is not held when calling the callback. + + +sysfs +~~~~~~~~ +There is a top-level directory named 'bus'. + +Each bus gets a directory in the bus directory, along with two default +directories: + + /sys/bus/pci/ + |-- devices + `-- drivers + +Drivers registered with the bus get a directory in the bus's drivers +directory: + + /sys/bus/pci/ + |-- devices + `-- drivers + |-- Intel ICH + |-- Intel ICH Joystick + |-- agpgart + `-- e100 + +Each device that is discovered on a bus of that type gets a symlink in +the bus's devices directory to the device's directory in the physical +hierarchy: + + /sys/bus/pci/ + |-- devices + | |-- 00:00.0 -> ../../../root/pci0/00:00.0 + | |-- 00:01.0 -> ../../../root/pci0/00:01.0 + | `-- 00:02.0 -> ../../../root/pci0/00:02.0 + `-- drivers + + +Exporting Attributes +~~~~~~~~~~~~~~~~~~~~ +struct bus_attribute { + struct attribute attr; + ssize_t (*show)(struct bus_type *, char * buf); + ssize_t (*store)(struct bus_type *, const char * buf, size_t count); +}; + +Bus drivers can export attributes using the BUS_ATTR macro that works +similarly to the DEVICE_ATTR macro for devices. For example, a definition +like this: + +static BUS_ATTR(debug,0644,show_debug,store_debug); + +is equivalent to declaring: + +static bus_attribute bus_attr_debug; + +This can then be used to add and remove the attribute from the bus's +sysfs directory using: + +int bus_create_file(struct bus_type *, struct bus_attribute *); +void bus_remove_file(struct bus_type *, struct bus_attribute *); + + diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt new file mode 100644 index 000000000000..2d1d893a5e5d --- /dev/null +++ b/Documentation/driver-model/class.txt @@ -0,0 +1,162 @@ + +Device Classes + + +Introduction +~~~~~~~~~~~~ +A device class describes a type of device, like an audio or network +device. The following device classes have been identified: + +<Insert List of Device Classes Here> + + +Each device class defines a set of semantics and a programming interface +that devices of that class adhere to. Device drivers are the +implemention of that programming interface for a particular device on +a particular bus. + +Device classes are agnostic with respect to what bus a device resides +on. + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ +The device class structure looks like: + + +typedef int (*devclass_add)(struct device *); +typedef void (*devclass_remove)(struct device *); + +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; +}; + +A typical device class definition would look like: + +struct device_class input_devclass = { + .name = "input", + .add_device = input_add_device, + .remove_device = input_remove_device, +}; + +Each device class structure should be exported in a header file so it +can be used by drivers, extensions and interfaces. + +Device classes are registered and unregistered with the core using: + +int devclass_register(struct device_class * cls); +void devclass_unregister(struct device_class * cls); + + +Devices +~~~~~~~ +As devices are bound to drivers, they are added to the device class +that the driver belongs to. Before the driver model core, this would +typically happen during the driver's probe() callback, once the device +has been initialized. It now happens after the probe() callback +finishes from the core. + +The device is enumerated in the class. 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. + +The class is allowed to create a class-specific structure for the +device and store it in the device's class_data pointer. + +There is no list of devices in the device class. Each driver has a +list of devices that it supports. The device class has a list of +drivers of that particular class. To access all of the devices in the +class, iterate over the device lists of each driver in the class. + + +Device Drivers +~~~~~~~~~~~~~~ +Device drivers are added to device classes when they are registered +with the core. A driver specifies the class it belongs to by setting +the struct device_driver::devclass field. + + +sysfs directory structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There is a top-level sysfs directory named 'class'. + +Each class gets a directory in the class directory, along with two +default subdirectories: + + class/ + `-- input + |-- devices + `-- drivers + + +Drivers registered with the class get a symlink in the drivers/ directory +that points to the driver's directory (under its bus directory): + + class/ + `-- input + |-- devices + `-- drivers + `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ + + +Each device gets a symlink in the devices/ directory that points to the +device's directory in the physical hierarchy: + + class/ + `-- input + |-- devices + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + `-- drivers + + +Exporting Attributes +~~~~~~~~~~~~~~~~~~~~ +struct devclass_attribute { + struct attribute attr; + ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off); +}; + +Class drivers can export attributes using the DEVCLASS_ATTR macro that works +similarly to the DEVICE_ATTR macro for devices. For example, a definition +like this: + +static DEVCLASS_ATTR(debug,0644,show_debug,store_debug); + +is equivalent to declaring: + +static devclass_attribute devclass_attr_debug; + +The bus driver can add and remove the attribute from the class's +sysfs directory using: + +int devclass_create_file(struct device_class *, struct devclass_attribute *); +void devclass_remove_file(struct device_class *, struct devclass_attribute *); + +In the example above, the file will be named 'debug' in placed in the +class's directory in sysfs. + + +Interfaces +~~~~~~~~~~ +There may exist multiple mechanisms for accessing the same device of a +particular class type. Device interfaces describe these mechanisms. + +When a device is added to a device class, the core attempts to add it +to every interface that is registered with the device class. + diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt new file mode 100644 index 000000000000..58cc5dc8fd3e --- /dev/null +++ b/Documentation/driver-model/device.txt @@ -0,0 +1,154 @@ + +The Basic Device Structure +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +struct device { + struct list_head g_list; + struct list_head node; + struct list_head bus_list; + struct list_head driver_list; + struct list_head intf_list; + struct list_head children; + struct device * parent; + + char name[DEVICE_NAME_SIZE]; + char bus_id[BUS_ID_SIZE]; + + spinlock_t lock; + atomic_t refcount; + + struct bus_type * bus; + struct driver_dir_entry dir; + + u32 class_num; + + struct device_driver *driver; + void *driver_data; + void *platform_data; + + u32 current_state; + unsigned char *saved_state; + + void (*release)(struct device * dev); +}; + +Fields +~~~~~~ +g_list: Node in the global device list. + +node: Node in device's parent's children list. + +bus_list: Node in device's bus's devices list. + +driver_list: Node in device's driver's devices list. + +intf_list: List of intf_data. There is one structure allocated for + each interface that the device supports. + +children: List of child devices. + +parent: *** FIXME *** + +name: ASCII description of device. + Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]" + +bus_id: ASCII representation of device's bus position. This + field should be a name unique across all devices on the + bus type the device belongs to. + + Example: PCI bus_ids are in the form of + <bus number>:<slot number>.<function number> + This name is unique across all PCI devices in the system. + +lock: Spinlock for the device. + +refcount: Reference count on the device. + +bus: Pointer to struct bus_type that device belongs to. + +dir: Device's sysfs directory. + +class_num: Class-enumerated value of the device. + +driver: Pointer to struct device_driver that controls the device. + +driver_data: Driver-specific data. + +platform_data: Platform data specific to the device. + +current_state: Current power state of the device. + +saved_state: Pointer to saved state of the device. This is usable by + the device driver controlling the device. + +release: Callback to free the device after all references have + gone away. This should be set by the allocator of the + device (i.e. the bus driver that discovered the device). + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ +The bus driver that discovers the device uses this to register the +device with the core: + +int device_register(struct device * dev); + +The bus should initialize the following fields: + + - parent + - name + - bus_id + - bus + +A device is removed from the core when its reference count goes to +0. The reference count can be adjusted using: + +struct device * get_device(struct device * dev); +void put_device(struct device * dev); + +get_device() will return a pointer to the struct device passed to it +if the reference is not already 0 (if it's in the process of being +removed already). + +A driver can access the lock in the device structure using: + +void lock_device(struct device * dev); +void unlock_device(struct device * dev); + + +Attributes +~~~~~~~~~~ +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); +}; + +Attributes of devices can be exported via drivers using a simple +procfs-like interface. + +Please see Documentation/filesystems/sysfs.txt for more information +on how sysfs works. + +Attributes are declared using a macro called DEVICE_ATTR: + +#define DEVICE_ATTR(name,mode,show,store) + +Example: + +DEVICE_ATTR(power,0644,show_power,store_power); + +This declares a structure of type struct device_attribute named +'dev_attr_power'. This can then be added and removed to the device's +directory using: + +int device_create_file(struct device *device, struct device_attribute * entry); +void device_remove_file(struct device * dev, struct device_attribute * attr); + +Example: + +device_create_file(dev,&dev_attr_power); +device_remove_file(dev,&dev_attr_power); + +The file name will be 'power' with a mode of 0644 (-rw-r--r--). + diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt new file mode 100644 index 000000000000..12447787d329 --- /dev/null +++ b/Documentation/driver-model/driver.txt @@ -0,0 +1,287 @@ + +Device Drivers + +struct device_driver { + char * name; + struct bus_type * bus; + + rwlock_t lock; + atomic_t refcount; + + list_t bus_list; + list_t devices; + + struct driver_dir_entry dir; + + int (*probe) (struct device * dev); + int (*remove) (struct device * dev); + + int (*suspend) (struct device * dev, u32 state, u32 level); + int (*resume) (struct device * dev, u32 level); + + void (*release) (struct device_driver * drv); +}; + + + +Allocation +~~~~~~~~~~ + +Device drivers are statically allocated structures. Though there may +be multiple devices in a system that a driver supports, struct +device_driver represents the driver as a whole (not a particular +device instance). + +Initialization +~~~~~~~~~~~~~~ + +The driver must initialize at least the name and bus fields. It should +also initialize the devclass field (when it arrives), so it may obtain +the proper linkage internally. It should also initialize as many of +the callbacks as possible, though each is optional. + +Declaration +~~~~~~~~~~~ + +As stated above, struct device_driver objects are statically +allocated. Below is an example declaration of the eepro100 +driver. This declaration is hypothetical only; it relies on the driver +being converted completely to the new model. + +static struct device_driver eepro100_driver = { + .name = "eepro100", + .bus = &pci_bus_type, + .devclass = ðernet_devclass, /* when it's implemented */ + + .probe = eepro100_probe, + .remove = eepro100_remove, + .suspend = eepro100_suspend, + .resume = eepro100_resume, +}; + +Most drivers will not be able to be converted completely to the new +model because the bus they belong to has a bus-specific structure with +bus-specific fields that cannot be generalized. + +The most common example of this are device ID structures. A driver +typically defines an array of device IDs that it supports. The format +of these structures and the semantics for comparing device IDs are +completely bus-specific. Defining them as bus-specific entities would +sacrifice type-safety, so we keep bus-specific structures around. + +Bus-specific drivers should include a generic struct device_driver in +the definition of the bus-specific driver. Like this: + +struct pci_driver { + const struct pci_device_id *id_table; + struct device_driver driver; +}; + +A definition that included bus-specific fields would look like +(using the eepro100 driver again): + +static struct pci_driver eepro100_driver = { + .id_table = eepro100_pci_tbl, + .driver = { + .name = "eepro100", + .bus = &pci_bus_type, + .devclass = ðernet_devclass, /* when it's implemented */ + .probe = eepro100_probe, + .remove = eepro100_remove, + .suspend = eepro100_suspend, + .resume = eepro100_resume, + }, +}; + +Some may find the syntax of embedded struct initialization awkward or +even a bit ugly. So far, it's the best way we've found to do what we want... + +Registration +~~~~~~~~~~~~ + +int driver_register(struct device_driver * drv); + +The driver registers the structure on startup. For drivers that have +no bus-specific fields (i.e. don't have a bus-specific driver +structure), they would use driver_register and pass a pointer to their +struct device_driver object. + +Most drivers, however, will have a bus-specific structure and will +need to register with the bus using something like pci_driver_register. + +It is important that drivers register their driver structure as early as +possible. Registration with the core initializes several fields in the +struct device_driver object, including the reference count and the +lock. These fields are assumed to be valid at all times and may be +used by the device model core or the bus driver. + + +Transition Bus Drivers +~~~~~~~~~~~~~~~~~~~~~~ + +By defining wrapper functions, the transition to the new model can be +made easier. Drivers can ignore the generic structure altogether and +let the bus wrapper fill in the fields. For the callbacks, the bus can +define generic callbacks that forward the call to the bus-specific +callbacks of the drivers. + +This solution is intended to be only temporary. In order to get class +information in the driver, the drivers must be modified anyway. Since +converting drivers to the new model should reduce some infrastructural +complexity and code size, it is recommended that they are converted as +class information is added. + +Access +~~~~~~ + +Once the object has been registered, it may access the common fields of +the object, like the lock and the list of devices. + +int driver_for_each_dev(struct device_driver * drv, void * data, + int (*callback)(struct device * dev, void * data)); + +The devices field is a list of all the devices that have been bound to +the driver. The LDM core provides a helper function to operate on all +the devices a driver controls. This helper locks the driver on each +node access, and does proper reference counting on each device as it +accesses it. + + +sysfs +~~~~~ + +When a driver is registered, a sysfs directory is created in its +bus's directory. In this directory, the driver can export an interface +to userspace to control operation of the driver on a global basis; +e.g. toggling debugging output in the driver. + +A future feature of this directory will be a 'devices' directory. This +directory will contain symlinks to the directories of devices it +supports. + + + +Callbacks +~~~~~~~~~ + + int (*probe) (struct device * dev); + +probe is called to verify the existence of a certain type of +hardware. This is called during the driver binding process, after the +bus has verified that the device ID of a device matches one of the +device IDs supported by the driver. + +This callback only verifies that there actually is supported hardware +present. It may allocate a driver-specific structure, but it should +not do any initialization of the hardware itself. The device-specific +structure may be stored in the device's driver_data field. + + int (*init) (struct device * dev); + +init is called during the binding stage. It is called after probe has +successfully returned and the device has been registered with its +class. It is responsible for initializing the hardware. + + int (*remove) (struct device * dev); + +remove is called to dissociate a driver with a device. This may be +called if a device is physically removed from the system, if the +driver module is being unloaded, or during a reboot sequence. + +It is up to the driver to determine if the device is present or +not. It should free any resources allocated specifically for the +device; i.e. anything in the device's driver_data field. + +If the device is still present, it should quiesce the device and place +it into a supported low-power state. + + int (*suspend) (struct device * dev, u32 state, u32 level); + +suspend is called to put the device in a low power state. There are +several stages to successfully suspending a device, which is denoted in +the @level parameter. Breaking the suspend transition into several +stages affords the platform flexibility in performing device power +management based on the requirements of the system and the +user-defined policy. + +SUSPEND_NOTIFY notifies the device that a suspend transition is about +to happen. This happens on system power state transitions to verify +that all devices can successfully suspend. + +A driver may choose to fail on this call, which should cause the +entire suspend transition to fail. A driver should fail only if it +knows that the device will not be able to be resumed properly when the +system wakes up again. It could also fail if it somehow determines it +is in the middle of an operation too important to stop. + +SUSPEND_DISABLE tells the device to stop I/O transactions. When it +stops transactions, or what it should do with unfinished transactions +is a policy of the driver. After this call, the driver should not +accept any other I/O requests. + +SUSPEND_SAVE_STATE tells the device to save the context of the +hardware. This includes any bus-specific hardware state and +device-specific hardware state. A pointer to this saved state can be +stored in the device's saved_state field. + +SUSPEND_POWER_DOWN tells the driver to place the device in the low +power state requested. + +Whether suspend is called with a given level is a policy of the +platform. Some levels may be omitted; drivers must not assume the +reception of any level. However, all levels must be called in the +order above; i.e. notification will always come before disabling; +disabling the device will come before suspending the device. + +All calls are made with interrupts enabled, except for the +SUSPEND_POWER_DOWN level. + + int (*resume) (struct device * dev, u32 level); + +Resume is used to bring a device back from a low power state. Like the +suspend transition, it happens in several stages. + +RESUME_POWER_ON tells the driver to set the power state to the state +before the suspend call (The device could have already been in a low +power state before the suspend call to put in a lower power state). + +RESUME_RESTORE_STATE tells the driver to restore the state saved by +the SUSPEND_SAVE_STATE suspend call. + +RESUME_ENABLE tells the driver to start accepting I/O transactions +again. Depending on driver policy, the device may already have pending +I/O requests. + +RESUME_POWER_ON is called with interrupts disabled. The other resume +levels are called with interrupts enabled. + +As with the various suspend stages, the driver must not assume that +any other resume calls have been or will be made. Each call should be +self-contained and not dependent on any external state. + + +Attributes +~~~~~~~~~~ +struct driver_attribute { + struct attribute attr; + ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); +}; + +Device drivers can export attributes via their sysfs directories. +Drivers can declare attributes using a DRIVER_ATTR macro that works +identically to the DEVICE_ATTR macro. + +Example: + +DRIVER_ATTR(debug,0644,show_debug,store_debug); + +This is equivalent to declaring: + +struct driver_attribute driver_attr_debug; + +This can then be used to add and remove the attribute from the +driver's directory using: + +int driver_create_file(struct device_driver *, struct driver_attribute *); +void driver_remove_file(struct device_driver *, struct driver_attribute *); diff --git a/Documentation/driver-model/interface.txt b/Documentation/driver-model/interface.txt new file mode 100644 index 000000000000..c66912bfe866 --- /dev/null +++ b/Documentation/driver-model/interface.txt @@ -0,0 +1,129 @@ + +Device Interfaces + +Introduction +~~~~~~~~~~~~ + +Device interfaces are the logical interfaces of device classes that correlate +directly to userspace interfaces, like device nodes. + +Each device class may have multiple interfaces through which you can +access the same device. An input device may support the mouse interface, +the 'evdev' interface, and the touchscreen interface. A SCSI disk would +support the disk interface, the SCSI generic interface, and possibly a raw +device interface. + +Device interfaces are registered with the class they belong to. As devices +are added to the class, they are added to each interface registered with +the class. The interface is responsible for determining whether the device +supports the interface or not. + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ + +struct device_interface { + char * name; + rwlock_t lock; + u32 devnum; + struct device_class * devclass; + + struct list_head node; + struct driver_dir_entry dir; + + int (*add_device)(struct device *); + int (*add_device)(struct intf_data *); +}; + +int interface_register(struct device_interface *); +void interface_unregister(struct device_interface *); + + +An interface must specify the device class it belongs to. It is added +to that class's list of interfaces on registration. + + +Interfaces can be added to a device class at any time. Whenever it is +added, each device in the class is passed to the interface's +add_device callback. When an interface is removed, each device is +removed from the interface. + + +Devices +~~~~~~~ +Once a device is added to a device class, it is added to each +interface that is registered with the device class. The class +is expected to place a class-specific data structure in +struct device::class_data. The interface can use that (along with +other fields of struct device) to determine whether or not the driver +and/or device support that particular interface. + + +Data +~~~~ + +struct intf_data { + struct list_head node; + struct device_interface * intf; + struct device * dev; + u32 intf_num; +}; + +int interface_add_data(struct interface_data *); + +The interface is responsible for allocating and initializing a struct +intf_data and calling interface_add_data() to add it to the device's list +of interfaces it belongs to. This list will be iterated over when the device +is removed from the class (instead of all possible interfaces for a class). +This structure should probably be embedded in whatever per-device data +structure the interface is allocating anyway. + +Devices are enumerated within the interface. This happens in interface_add_data() +and the enumerated value is stored in the struct intf_data for that device. + +sysfs +~~~~~ +Each interface is given a directory in the directory of the device +class it belongs to: + +Interfaces get a directory in the class's directory as well: + + class/ + `-- input + |-- devices + |-- drivers + |-- mouse + `-- evdev + +When a device is added to the interface, a symlink is created that points +to the device's directory in the physical hierarchy: + + class/ + `-- input + |-- devices + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + |-- drivers + | `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ + |-- mouse + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + `-- evdev + `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + + +Future Plans +~~~~~~~~~~~~ +A device interface is correlated directly with a userspace interface +for a device, specifically a device node. For instance, a SCSI disk +exposes at least two interfaces to userspace: the standard SCSI disk +interface and the SCSI generic interface. It might also export a raw +device interface. + +Many interfaces have a major number associated with them and each +device gets a minor number. Or, multiple interfaces might share one +major number, and each will receive a range of minor numbers (like in +the case of input devices). + +These major and minor numbers could be stored in the interface +structure. Major and minor allocations could happen when the interface +is registered with the class, or via a helper function. + diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt new file mode 100644 index 000000000000..44662735cf81 --- /dev/null +++ b/Documentation/driver-model/overview.txt @@ -0,0 +1,114 @@ +The Linux Kernel Device Model + +Patrick Mochel <mochel@osdl.org> + +26 August 2002 + + +Overview +~~~~~~~~ + +This driver model is a unification of all the current, disparate driver models +that are currently in the kernel. It is intended to augment the +bus-specific drivers for bridges and devices by consolidating a set of data +and operations into globally accessible data structures. + +Current driver models implement some sort of tree-like structure (sometimes +just a list) for the devices they control. But, there is no linkage between +the different bus types. + +A common data structure can provide this linkage with little overhead: when a +bus driver discovers a particular device, it can insert it into the global +tree as well as its local tree. In fact, the local tree becomes just a subset +of the global tree. + +Common data fields can also be moved out of the local bus models into the +global model. Some of the manipulations of these fields can also be +consolidated. Most likely, manipulation functions will become a set +of helper functions, which the bus drivers wrap around to include any +bus-specific items. + +The common device and bridge interface currently reflects the goals of the +modern PC: namely the ability to do seamless Plug and Play, power management, +and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures +us that any device in the system may fit any of these criteria.) + +In reality, not every bus will be able to support such operations. But, most +buses will support a majority of those operations, and all future buses will. +In other words, a bus that doesn't support an operation is the exception, +instead of the other way around. + + + +Downstream Access +~~~~~~~~~~~~~~~~~ + +Common data fields have been moved out of individual bus layers into a common +data structure. But, these fields must still be accessed by the bus layers, +and sometimes by the device-specific drivers. + +Other bus layers are encouraged to do what has been done for the PCI layer. +struct pci_dev now looks like this: + +struct pci_dev { + ... + + struct device device; +}; + +Note first that it is statically allocated. This means only one allocation on +device discovery. Note also that it is at the _end_ of struct pci_dev. This is +to make people think about what they're doing when switching between the bus +driver and the global driver; and to prevent against mindless casts between +the two. + +The PCI bus layer freely accesses the fields of struct device. It knows about +the structure of struct pci_dev, and it should know the structure of struct +device. PCI devices that have been converted generally do not touch the fields +of struct device. More precisely, device-specific drivers should not touch +fields of struct device unless there is a strong compelling reason to do so. + +This abstraction is prevention of unnecessary pain during transitional phases. +If the name of the field changes or is removed, then every downstream driver +will break. On the other hand, if only the bus layer (and not the device +layer) accesses struct device, it is only that layer that needs to change. + + +User Interface +~~~~~~~~~~~~~~ + +By virtue of having a complete hierarchical view of all the devices in the +system, exporting a complete hierarchical view to userspace becomes relatively +easy. This has been accomplished by implementing a special purpose virtual +file system named sysfs. It is hence possible for the user to mount the +whole sysfs filesystem anywhere in userspace. + +This can be done permanently by providing the following entry into the +/etc/fstab (under the provision that the mount point does exist, of course): + +none /sys sysfs defaults 0 0 + +Or by hand on the command line: + +# mount -t sysfs sysfs /sys + +Whenever a device is inserted into the tree, a directory is created for it. +This directory may be populated at each layer of discovery - the global layer, +the bus layer, or the device layer. + +The global layer currently creates two files - 'name' and 'power'. The +former only reports the name of the device. The latter reports the +current power state of the device. It will also be used to set the current +power state. + +The bus layer may also create files for the devices it finds while probing the +bus. For example, the PCI layer currently creates 'irq' and 'resource' files +for each PCI device. + +A device-specific driver may also export files in its directory to expose +device-specific data or tunable interfaces. + +More information about the sysfs directory layout can be found in +the other documents in this directory and in the file +Documentation/filesystems/sysfs.txt. + diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt new file mode 100644 index 000000000000..5eee3e0bfc4c --- /dev/null +++ b/Documentation/driver-model/platform.txt @@ -0,0 +1,99 @@ +Platform Devices and Drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Platform devices +~~~~~~~~~~~~~~~~ +Platform devices are devices that typically appear as autonomous +entities in the system. This includes legacy port-based devices and +host bridges to peripheral buses. + + +Platform drivers +~~~~~~~~~~~~~~~~ +Drivers for platform devices are typically very simple and +unstructured. Either the device was present at a particular I/O port +and the driver was loaded, or it was not. There was no possibility +of hotplugging or alternative discovery besides probing at a specific +I/O address and expecting a specific response. + + +Other Architectures, Modern Firmware, and new Platforms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These devices are not always at the legacy I/O ports. This is true on +other architectures and on some modern architectures. In most cases, +the drivers are modified to discover the devices at other well-known +ports for the given platform. However, the firmware in these systems +does usually know where exactly these devices reside, and in some +cases, it's the only way of discovering them. + + +The Platform Bus +~~~~~~~~~~~~~~~~ +A platform bus has been created to deal with these issues. First and +foremost, it groups all the legacy devices under a common bus, and +gives them a common parent if they don't already have one. + +But, besides the organizational benefits, the platform bus can also +accommodate firmware-based enumeration. + + +Device Discovery +~~~~~~~~~~~~~~~~ +The platform bus has no concept of probing for devices. Devices +discovery is left up to either the legacy drivers or the +firmware. These entities are expected to notify the platform of +devices that it discovers via the bus's add() callback: + + platform_bus.add(parent,bus_id). + + +Bus IDs +~~~~~~~ +Bus IDs are the canonical names for the devices. There is no globally +standard addressing mechanism for legacy devices. In the IA-32 world, +we have Pnp IDs to use, as well as the legacy I/O ports. However, +neither tell what the device really is or have any meaning on other +platforms. + +Since both PnP IDs and the legacy I/O ports (and other standard I/O +ports for specific devices) have a 1:1 mapping, we map the +platform-specific name or identifier to a generic name (at least +within the scope of the kernel). + +For example, a serial driver might find a device at I/O 0x3f8. The +ACPI firmware might also discover a device with PnP ID (_HID) +PNP0501. Both correspond to the same device and should be mapped to the +canonical name 'serial'. + +The bus_id field should be a concatenation of the canonical name and +the instance of that type of device. For example, the device at I/O +port 0x3f8 should have a bus_id of "serial0". This places the +responsibility of enumerating devices of a particular type up to the +discovery mechanism. But, they are the entity that should know best +(as opposed to the platform bus driver). + + +Drivers +~~~~~~~ +Drivers for platform devices should have a name that is the same as +the canonical name of the devices they support. This allows the +platform bus driver to do simple matching with the basic data +structures to determine if a driver supports a certain device. + +For example, a legacy serial driver should have a name of 'serial' and +register itself with the platform bus. + + +Driver Binding +~~~~~~~~~~~~~~ +Legacy drivers assume they are bound to the device once they start up +and probe an I/O port. Divorcing them from this will be a difficult +process. However, that shouldn't prevent us from implementing +firmware-based enumeration. + +The firmware should notify the platform bus about devices before the +legacy drivers have had a chance to load. Once the drivers are loaded, +they driver model core will attempt to bind the driver to any +previously-discovered devices. Once that has happened, it will be free +to discover any other devices it pleases. + diff --git a/Documentation/driver-model/porting.txt b/Documentation/driver-model/porting.txt new file mode 100644 index 000000000000..ff2fef2107f0 --- /dev/null +++ b/Documentation/driver-model/porting.txt @@ -0,0 +1,445 @@ + +Porting Drivers to the New Driver Model + +Patrick Mochel + +7 January 2003 + + +Overview + +Please refer to Documentation/driver-model/*.txt for definitions of +various driver types and concepts. + +Most of the work of porting devices drivers to the new model happens +at the bus driver layer. This was intentional, to minimize the +negative effect on kernel drivers, and to allow a gradual transition +of bus drivers. + +In a nutshell, the driver model consists of a set of objects that can +be embedded in larger, bus-specific objects. Fields in these generic +objects can replace fields in the bus-specific objects. + +The generic objects must be registered with the driver model core. By +doing so, they will exported via the sysfs filesystem. sysfs can be +mounted by doing + + # mount -t sysfs sysfs /sys + + + +The Process + +Step 0: Read include/linux/device.h for object and function definitions. + +Step 1: Registering the bus driver. + + +- Define a struct bus_type for the bus driver. + +struct bus_type pci_bus_type = { + .name = "pci", +}; + + +- Register the bus type. + This should be done in the initialization function for the bus type, + which is usually the module_init(), or equivalent, function. + +static int __init pci_driver_init(void) +{ + return bus_register(&pci_bus_type); +} + +subsys_initcall(pci_driver_init); + + + The bus type may be unregistered (if the bus driver may be compiled + as a module) by doing: + + bus_unregister(&pci_bus_type); + + +- Export the bus type for others to use. + + Other code may wish to reference the bus type, so declare it in a + shared header file and export the symbol. + +From include/linux/pci.h: + +extern struct bus_type pci_bus_type; + + +From file the above code appears in: + +EXPORT_SYMBOL(pci_bus_type); + + + +- This will cause the bus to show up in /sys/bus/pci/ with two + subdirectories: 'devices' and 'drivers'. + +# tree -d /sys/bus/pci/ +/sys/bus/pci/ +|-- devices +`-- drivers + + + +Step 2: Registering Devices. + +struct device represents a single device. It mainly contains metadata +describing the relationship the device has to other entities. + + +- Embedd a struct device in the bus-specific device type. + + +struct pci_dev { + ... + struct device dev; /* Generic device interface */ + ... +}; + + It is recommended that the generic device not be the first item in + the struct to discourage programmers from doing mindless casts + between the object types. Instead macros, or inline functions, + should be created to convert from the generic object type. + + +#define to_pci_dev(n) container_of(n, struct pci_dev, dev) + +or + +static inline struct pci_dev * to_pci_dev(struct kobject * kobj) +{ + return container_of(n, struct pci_dev, dev); +} + + This allows the compiler to verify type-safety of the operations + that are performed (which is Good). + + +- Initialize the device on registration. + + When devices are discovered or registered with the bus type, the + bus driver should initialize the generic device. The most important + things to initialize are the bus_id, parent, and bus fields. + + The bus_id is an ASCII string that contains the device's address on + the bus. The format of this string is bus-specific. This is + necessary for representing devices in sysfs. + + parent is the physical parent of the device. It is important that + the bus driver sets this field correctly. + + The driver model maintains an ordered list of devices that it uses + for power management. This list must be in order to guarantee that + devices are shutdown before their physical parents, and vice versa. + The order of this list is determined by the parent of registered + devices. + + Also, the location of the device's sysfs directory depends on a + device's parent. sysfs exports a directory structure that mirrors + the device hierarchy. Accurately setting the parent guarantees that + sysfs will accurately represent the hierarchy. + + The device's bus field is a pointer to the bus type the device + belongs to. This should be set to the bus_type that was declared + and initialized before. + + Optionally, the bus driver may set the device's name and release + fields. + + The name field is an ASCII string describing the device, like + + "ATI Technologies Inc Radeon QD" + + The release field is a callback that the driver model core calls + when the device has been removed, and all references to it have + been released. More on this in a moment. + + +- 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); + + It can later be unregistered by doing: + + device_unregister(&dev->dev); + + This should happen on buses that support hotpluggable devices. + If a bus driver unregisters a device, it should not immediately free + it. It should instead wait for the driver model core to call the + device's release method, then free the bus-specific object. + (There may be other code that is currently referencing the device + structure, and it would be rude to free the device while that is + happening). + + + When the device is registered, a directory in sysfs is created. + The PCI tree in sysfs looks like: + +/sys/devices/pci0/ +|-- 00:00.0 +|-- 00:01.0 +| `-- 01:00.0 +|-- 00:02.0 +| `-- 02:1f.0 +| `-- 03:00.0 +|-- 00:1e.0 +| `-- 04:04.0 +|-- 00:1f.0 +|-- 00:1f.1 +| |-- ide0 +| | |-- 0.0 +| | `-- 0.1 +| `-- ide1 +| `-- 1.0 +|-- 00:1f.2 +|-- 00:1f.3 +`-- 00:1f.5 + + Also, symlinks are created in the bus's 'devices' directory + that point to the device's directory in the physical hierarchy. + +/sys/bus/pci/devices/ +|-- 00:00.0 -> ../../../devices/pci0/00:00.0 +|-- 00:01.0 -> ../../../devices/pci0/00:01.0 +|-- 00:02.0 -> ../../../devices/pci0/00:02.0 +|-- 00:1e.0 -> ../../../devices/pci0/00:1e.0 +|-- 00:1f.0 -> ../../../devices/pci0/00:1f.0 +|-- 00:1f.1 -> ../../../devices/pci0/00:1f.1 +|-- 00:1f.2 -> ../../../devices/pci0/00:1f.2 +|-- 00:1f.3 -> ../../../devices/pci0/00:1f.3 +|-- 00:1f.5 -> ../../../devices/pci0/00:1f.5 +|-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0 +|-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0 +|-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0 +`-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0 + + + +Step 3: Registering Drivers. + +struct device_driver is a simple driver structure that contains a set +of operations that the driver model core may call. + + +- Embed a struct device_driver in the bus-specific driver. + + Just like with devices, do something like: + +struct pci_driver { + ... + struct device_driver driver; +}; + + +- Initialize the generic driver structure. + + When the driver registers with the bus (e.g. doing pci_register_driver()), + initialize the necessary fields of the driver: the name and bus + fields. + + +- Register the driver. + + After the generic driver has been initialized, call + + driver_register(&drv->driver); + + to register the driver with the core. + + When the driver is unregistered from the bus, unregister it from the + core by doing: + + driver_unregister(&drv->driver); + + Note that this will block until all references to the driver have + gone away. Normally, there will not be any. + + +- Sysfs representation. + + Drivers are exported via sysfs in their bus's 'driver's directory. + For example: + +/sys/bus/pci/drivers/ +|-- 3c59x +|-- Ensoniq AudioPCI +|-- agpgart-amdk7 +|-- e100 +`-- serial + + +Step 4: Define Generic Methods for Drivers. + +struct device_driver defines a set of operations that the driver model +core calls. Most of these operations are probably similar to +operations the bus already defines for drivers, but taking different +parameters. + +It would be difficult and tedious to force every driver on a bus to +simultaneously convert their drivers to generic format. Instead, the +bus driver should define single instances of the generic methods that +forward call to the bus-specific drivers. For instance: + + +static int pci_device_remove(struct device * dev) +{ + struct pci_dev * pci_dev = to_pci_dev(dev); + struct pci_driver * drv = pci_dev->driver; + + if (drv) { + if (drv->remove) + drv->remove(pci_dev); + pci_dev->driver = NULL; + } + return 0; +} + + +The generic driver should be initialized with these methods before it +is registered. + + /* 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); + + +Ideally, the bus should only initialize the fields if they are not +already set. This allows the drivers to implement their own generic +methods. + + +Step 5: Support generic driver binding. + +The model assumes that a device or driver can be dynamically +registered with the bus at any time. When registration happens, +devices must be bound to a driver, or drivers must be bound to all +devices that it supports. + +A driver typically contains a list of device IDs that it supports. The +bus driver compares these IDs to the IDs of devices registered with it. +The format of the device IDs, and the semantics for comparing them are +bus-specific, so the generic model does attempt to generalize them. + +Instead, a bus may supply a method in struct bus_type that does the +comparison: + + int (*match)(struct device * dev, struct device_driver * drv); + +match should return '1' if the driver supports the device, and '0' +otherwise. + +When a device is registered, the bus's list of drivers is iterated +over. bus->match() is called for each one until a match is found. + +When a driver is registered, the bus's list of devices is iterated +over. bus->match() is called for each device that is not already +claimed by a driver. + +When a device is successfully bound to a device, device->driver is +set, the device is added to a per-driver list of devices, and a +symlink is created in the driver's sysfs directory that points to the +device's physical directory: + +/sys/bus/pci/drivers/ +|-- 3c59x +| `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0 +|-- Ensoniq AudioPCI +|-- agpgart-amdk7 +| `-- 00:00.0 -> ../../../../devices/pci0/00:00.0 +|-- e100 +| `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0 +`-- serial + + +This driver binding should replace the existing driver binding +mechanism the bus currently uses. + + +Step 6: Supply a hotplug callback. + +Whenever a device is registered with the driver model core, the +userspace program /sbin/hotplug is called to notify userspace. +Users can define actions to perform when a device is inserted or +removed. + +The driver model core passes several arguments to userspace via +environment variables, including + +- ACTION: set to 'add' or 'remove' +- DEVPATH: set to the device's physical path in sysfs. + +A bus driver may also supply additional parameters for userspace to +consume. To do this, a bus must implement the 'hotplug' method in +struct bus_type: + + int (*hotplug) (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + +This is called immediately before /sbin/hotplug is executed. + + +Step 7: Cleaning up the bus driver. + +The generic bus, device, and driver structures provide several fields +that can replace those defined privately to the bus driver. + +- Device list. + +struct bus_type contains a list of all devices registered with the bus +type. This includes all devices on all instances of that bus type. +An internal list that the bus uses may be removed, in favor of using +this one. + +The core provides an iterator to access these devices. + +int bus_for_each_dev(struct bus_type * bus, struct device * start, + void * data, int (*fn)(struct device *, void *)); + + +- Driver list. + +struct bus_type also contains a list of all drivers registered with +it. An internal list of drivers that the bus driver maintains may +be removed in favor of using the generic one. + +The drivers may be iterated over, like devices: + +int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)); + + +Please see drivers/base/bus.c for more information. + + +- rwsem + +struct bus_type contains an rwsem that protects all core accesses to +the device and driver lists. This can be used by the bus driver +internally, and should be used when accessing the device or driver +lists the bus maintains. + + +- Device and driver fields. + +Some of the fields in struct device and struct device_driver duplicate +fields in the bus-specific representations of these objects. Feel free +to remove the bus-specific ones and favor the generic ones. Note +though, that this will likely mean fixing up all the drivers that +reference the bus-specific fields (though those should all be 1-line +changes). + |