130 lines
4.0 KiB
Plaintext
130 lines
4.0 KiB
Plaintext
|
|
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.
|
|
|