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 |
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 00000000000..f7ec9d625bf --- /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 00000000000..dd62c7b80b3 --- /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 00000000000..2d1d893a5e5 --- /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 00000000000..58cc5dc8fd3 --- /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 00000000000..12447787d32 --- /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 00000000000..c66912bfe86 --- /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 |