130 lines
		
	
	
	
		
			4 KiB
			
		
	
	
	
		
			Text
		
	
	
	
	
	
		
		
			
		
	
	
			130 lines
		
	
	
	
		
			4 KiB
			
		
	
	
	
		
			Text
		
	
	
	
	
	
|   | 
 | ||
|  | 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.  | ||
|  | 
 |