/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver xhci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
.probe = xhci_pci_probe,
.remove = xhci_pci_remove,
/* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#endif
};
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = { {
/* handle any USB 3.0 xHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
.driver_data = (unsigned long) &xhci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd),
/*
* generic hardware linkage
*/
.irq = xhci_irq,
.flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
/*
* basic lifecycle operations
*/
.reset = NULL, /* set in xhci_init_driver() */
.start = xhci_run,
.stop = xhci_stop,
.shutdown = xhci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.alloc_streams = xhci_alloc_streams,
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.enable_device = xhci_enable_device,
.update_hub_device = xhci_update_hub_device,
.reset_device = xhci_discover_or_reset_device,
/*
* scheduling support
*/
.get_frame_number = xhci_get_frame,
/*
* root hub support
*/
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
.get_resuming_ports = xhci_get_resuming_ports,
/*
* call back when device connected and addressed
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
};
const struct attribute_group *usb_device_groups[] = {
&dev_attr_grp, //属性组信息
&dev_string_attr_grp, //属性字符串组
NULL
};
static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
&dev_attr_bNumInterfaces.attr,
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
&dev_attr_bMaxPower.attr,
/* device attributes */
&dev_attr_urbnum.attr,
&dev_attr_idVendor.attr,
&dev_attr_idProduct.attr,
&dev_attr_bcdDevice.attr,
&dev_attr_bDeviceClass.attr,
&dev_attr_bDeviceSubClass.attr,
&dev_attr_bDeviceProtocol.attr,
&dev_attr_bNumConfigurations.attr,
&dev_attr_bMaxPacketSize0.attr,
&dev_attr_speed.attr,
&dev_attr_busnum.attr,
&dev_attr_devnum.attr,
&dev_attr_devpath.attr,
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
&dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
&dev_attr_removable.attr,
&dev_attr_ltm_capable.attr,
NULL,
};
static struct attribute_group dev_string_attr_grp = {
.attrs = dev_string_attrs,
.is_visible = dev_string_attrs_are_visible,
};
static struct attribute *dev_string_attrs[] = {
&dev_attr_manufacturer.attr,
&dev_attr_product.attr,
&dev_attr_serial.attr,
NULL
};
*dev_string_attrs[]
和 *dev_attrs[]
对应系统目录结构信息为:
[root@szclou /sys/devices/platform/nuc970-ehci/usb1]#ls
1-0:1.0 bmAttributes maxchild
authorized busnum product
authorized_default configuration quirks
avoid_reset_quirk descriptors removable
bConfigurationValue dev remove
bDeviceClass devnum serial
bDeviceProtocol devpath speed
bDeviceSubClass driver subsystem
bMaxPacketSize0 ep_00 uevent
bMaxPower idProduct urbnum
bNumConfigurations idVendor version
bNumInterfaces ltm_capable
bcdDevice manufacturer
在usb规范中,一个usb设备通过一些层级结构的描述符来描述。在linux内核中,通过usb_device
结构来表示一个usb设备,通常一个usb设备有一个设备描述符,一个或多个配置描述符,以及一个或多个接口描述符。设备描述符用来描述设备的信息,包含厂家ID,产品ID等:
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength;//设备描述符的字节数大小,为0x12
__u8 bDescriptorType;//描述符类型编号,为0x01
__le16 bcdUSB;//USB版本号
__u8 bDeviceClass;//USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型
//0x00不是在设备描述符中定义的,如HID
__u8 bDeviceSubClass;//usb分配的子类代码,同上,值由USB规定和分配的
__u8 bDeviceProtocol;//USB分配的设备协议代码,同上
__u8 bMaxPacketSize0;//端点0的最大包的大小
__le16 idVendor;//厂商编号
__le16 idProduct;//产品编号
__le16 bcdDevice;//设备出厂编号
__u8 iManufacturer;//描述厂商字符串的索引
__u8 iProduct;//描述产品字符串的索引
__u8 iSerialNumber;//描述设备序列号字符串的索引
__u8 bNumConfigurations;//可能的配置数量
} __attribute__ ((packed));
drivers/usb/core/driver.c
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.need_parent_lock = true,
};
struct device_driver
struct device_driver {
const char *name; //与设备匹配时会用到的驱动名,一样就匹配成
struct bus_type *bus; //在注册函数platform_driver_register中指定
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
enum probe_type probe_type;
const struct of_device_id *of_match_table; //与设备树匹配,名称一样就匹配成功
const struct acpi_device_id *acpi_match_table;
int (*probe) (struct device *dev); //调用注册函数指定
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
struct usb_device_driver usb_generic_driver
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
struct usb_driver hub_driver
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,//hub探测接口
.disconnect = hub_disconnect,
.suspend = hub_suspend,//hub挂起,涉及到PM电源管理驱动控制
.resume = hub_resume,//hub恢复
.reset_resume = hub_reset_resume,//通过对hub复位来引发复位
.pre_reset = hub_pre_reset,//与PM电源管理系统相关
.post_reset = hub_post_reset,//与PM电源管理系统相关
.unlocked_ioctl = hub_ioctl,
.id_table = hub_id_table,//hub id表
.supports_autosuspend = 1,
};
struct usb_device_id
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling which of the other fields are used to
* match against new devices. Any field except for driver_info may be
* used, although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a device.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @bInterfaceNumber: Number of interface; composite devices may use
* fixed interface numbers to differentiate between vendor-specific
* interfaces.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/*表示下面哪些字段(产品、设备类别、接口类)可以进行匹配*/
/* which fields to match against? */
__u16 match_flags;
/*用于产品的匹配*/
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/*用于设备类别的匹配*/
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/*用于接口类别的匹配*/
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* Used for vendor-specific interface matches */
__u8 bInterfaceNumber;
/* not matched against */
kernel_ulong_t driver_info
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
而hub_id_table
分别初始化了三个usb_device_id结构体:
static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_GENESYS_LOGIC,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_CLASS_HUB},
{ } /* Terminating entry */
};
第1个结构体成员
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS,
//表示需匹配的字段
.idVendor = USB_VENDOR_GENESYS_LOGIC,
//匹配的字段
.bInterfaceClass = USB_CLASS_HUB
//匹配的字段
第2个结构体成员
.match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
//表示需匹配的字段
.bDeviceClass = USB_CLASS_HUB
//匹配的字段
第3个结构体成员
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
//表示需匹配的字段
.bInterfaceClass = USB_CLASS_HUB
//匹配的字段
综上所述,match_flags 表示哪些字段匹配,而对应匹配的字段就是idVendor
、bInterfaceClass
,bDeviceClass
,bInterfaceClass
,这里在下面会分析如何使用。
在linux内核中,配置描述符和接口描述符用usb_host_config
结构来表示,在设备描述符中bNumConfigurations
的值为多少就有多少个usb_host_config
,usb_host_config
中包含了usb设备的配置描述符,以及接口描述符。
usb设备的配置描述符用usb_config_descriptor结构来表示:
/* USB_DT_CONFIG: Configuration descriptor information.
*
* USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
* descriptor type is different. Highspeed-capable devices can look
* different depending on what speed they're currently running. Only
* devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
* descriptors.
*/
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
在Linux内核中用usb_interface
结构来描述一个接口设备,配置描述符中的bNumInterfaces
的值为多少就有多少个usb_interface
。linux内核中用usb_host_interface
结构表示接口描述,在该结构中包含了该接口的接口描述符,usb_host_interface
结构位于usb_interface
结构中。接口描述符定义如下:
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
usb设备用usb_device
结构来表示,它表示一个物理的usb设备。
通过下面的接口判断是否是usb设备:
static inline int is_usb_device(const struct device *dev)
usb接口通过usb_interface
结构来表示,表示一个usb设备的某个接口。
通过下面的接口判断设备是否为usb接口设备:
static inline int is_usb_interface(const struct device *dev)
和usb设备对应,在linux内核usb设备驱动模型中,usb驱动分为设备驱动和接口驱动,usb设备驱动用来解析和配置usb接口设备,以及注册usb的接口设备。
usb的设备驱动在内核中用usb_device_driver
结构表示:
struct usb_device_driver {
const char *name;
int (*probe) (struct usb_device *udev);
void (*disconnect) (struct usb_device *udev);
int (*suspend) (struct usb_device *udev, pm_message_t message);
int (*resume) (struct usb_device *udev, pm_message_t message);
struct usbdrv_wrap drvwrap;
unsigned int supports_autosuspend:1;
};
usb的接口驱动在内核中用usb_driver
结构表示:
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
void *buf);
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);
int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int disable_hub_initiated_lpm:1;
unsigned int soft_unbind:1;
};
在usb_device_driver
和usb_driver
结构中都包含一个usbdrv_wrap
类型的drvwrap
成员,该成员结构定义如下:
struct usbdrv_wrap {
struct device_driver driver;
int for_devices;
};
其中driver
成员是usb驱动结构中内嵌的device_driver
对象,是设备驱动模型的driver部件。for_device
成员用来表示该驱动是usb设备驱动还是usb接口驱动。for_device
的值为1表示usb设备驱动,为0表示usb接口驱动。
内核中通过下面的接口判断usb驱动是设备驱动还是接口驱动:
static inline int is_usb_device_driver(struct device_driver *drv)
usb设备驱动的注册和注销接口如下:
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner);
void usb_deregister_device_driver(struct usb_device_driver *udriver);
设备驱动注册函数中对drvwrap.for_devices
成员赋值为1,表示注册的usb驱动是usb设备驱动,并且调用driver_register
接口将drvwrap.driver
注册到内核设备驱动模型中。代码如下:
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;
retval = driver_register(&new_udriver->drvwrap.driver);
usb接口驱动的注册和注销接口如下:
/* use a define to avoid include chaining to get THIS_MODULE & friends */
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
extern void usb_deregister(struct usb_driver *);
接口驱动注册函数中对drvwrap.for_devices
成员赋值为0,表示注册的是一个usb接口驱动,并且调用driver_register
接口将drvwrap.driver
注册到内核设备驱动模型中。代码如下:
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver);
usb设备驱动模型是内核设备驱动模型的应用,它包含usb总线,usb设备和usb驱动,以及用户空间视图的sysfs等。
usb总线的作用是维护所有的usb设备和usb驱动,以及为usb设备和usb驱动创建关联,以达到用户通过usb驱动操作关联的usb设备的目的。
usb总线在内核中的定义如下:
drivers/usb/core/driver.c
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.need_parent_lock = true,
};
总线名称为usb,即在/sys/bus/
目录下存在usb目录,表示usb总线。
match
函数指针用来进行设备和驱动的匹配,当向总线上添加一个usb设备(或usb驱动)时,linux内核设备驱动模型核心就会遍历usb总线上的驱动(或设备),并为其调用usb总线的match方法,以判断新插入的设备能否被某个驱动处理。match方法成功返回1,否则返回0。当内核设备驱动核心得到匹配成功的结果后就会为usb设备和usb驱动创建关联,并调用驱动的probe函数。
在usb总线的match方法中需要判断驱动和设备的类型,设备和驱动都分为usb设备和接口两个类型。对于设备类型和设备驱动类型的匹配,直接返回成功,而对于接口设备和接口驱动的匹配,则需要通过接口驱动的id_table
成员中的信息和接口设备的信息进行匹配。id_table
由usb接口驱动设置,用来描述该驱动能处理那些设备。
usb设备分为usb设备和usb接口设备两种,通常一个usb物理设备关联一个usb设备对象,usb设备对象关联一个或多个usb接口对象。
当一个新的usb设备对象或者usb设备接口对象被注册到usb总线上的时候,内核设备驱动核心为其在usb总线上查找能处理其的驱动,并执行驱动的probe
函数,以初始化设备和提供相关操作函数。
usb驱动也分为usb设备驱动和usb接口设备,usb设备驱动用来处理usb设备,usb接口驱动用来处理usb接口。通常大部分usb驱动都是usb接口驱动,比如usb存储,usb串口等。
在usb子系统初始化的时候会注册一个与设备相关的usb通用设备驱动,由usb总线match函数的代码可知该驱动能匹配所有usb设备。
当usb hub的事件线程监测到设备接入后,会向usb总线上注册新接入的设备,注册的设备首先将和usb通用驱动进行绑定,在usb通用驱动的probe函数中再申请注册usb接口设备。当usb接口设备注册到usb总线上时,再进行接口设备和接口驱动的绑定。
sysfs是内核设备驱动模型的用户空间视图,usb子系统在sysfs中的路径是/sys/bus/usb目录。该目录下存在devices和drivers目录,用来呈现usb总线上的设备和驱动。
generic驱动在usb子系统初始化的时候由usb核心注册。该驱动负责处理所有的usb物理设备,当usb hub驱动监测到设备接入后,会向usb总线上注册新接入的设备,注册的设备首先将会和usb通用设备驱动关联,并调用usb_generic_driver
的probe函数。
在usb_generic_driver
的probe函数中,将对设备进行配置和解析,并向usb总线注册该usb设备的设备接口设备。
当接口设备注册到usb总线上时,设备驱动核心将会为其在usb总线上查找和关联驱动,并调用关联驱动的probe函数。
```c
/*
* Init
*/
static int __init usb_init(void)
{
...
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
...
}
```c
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
{
int retval = 0;
...
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;
retval = driver_register(&new_udriver->drvwrap.driver);
//klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
...
}
EXPORT_SYMBOL_GPL(usb_register_device_driver);
比如插入一个4G模块,将由usb_generic_driver配置4G模块的所有接口,并将接口注册到usb总线上,然后由设备驱动模型核心再为4G模块的所有接口在usb总线上查找和关联4G相关的驱动。
usb的hub驱动也是一个usb总线上的接口驱动,root hub设备由usb的host控制器驱动来创建和注册,当host驱动向usb总线注册了root hub设备的时候就会匹配到usb的hub驱动。
hub驱动会不停的监测新设备的接入。当hub驱动监测到新usb设备接入时会向内核设备驱动模型核心申请和注册usb设备,新设备所属总线为usb总线,所以当设备注册到usb总线上时,内核设备驱动模型核心会在usb总线上为其查找和绑定合适的usb驱动。
usb的主控制器驱动结构为hc_driver
,对应的usb主控制器设备的结构为usb_hcd
,hc_driver
用来处理相应的usb_hcd
。usb的控制器属于上一级的总线设备驱动模型的子节点,比如硬件上挂在pci总线上的usb控制器本身由pci核心来枚举,pci总线上的所有设备抽象为pci_dev
结构,驱动抽象为pci_driver
结构。当pci总线上枚举到pci_dev
设备并注册设备后,将会调用pci_driver
的probe
函数并绑定pci_driver
,在pci_drive
r的probe
函数中,将创建和添加usb_hcd
,同时从pci的pci_device_id
中获取到hc_driver
,并将hc_driver
和usb_hcd
绑定。
硬件主机控制器Host Controller之上运行的是HCD,是对主机控制器硬件的一个抽象,实现核心层与控制器之间的对话接口,USB HCD包含多种USB接口规范:
(1)UHCI:Intel提供,通用主机控制接口,USB1.0/1.1;
(2)OHCI:微软提供,开放主机控制接口,USB1.0/1.1;
(3)EHCI:增强主机控制接口,USB2.0;
linux内核中用usb_hcd
类型来描述一个usb主控制器,一个usb主控制器通常对应一个usb_bus
类型的总线(此总线非设备驱动模型之总线)来维护该控制器上的设备树。
一个usb主控制器通常对应一个root hub
设备,root hub
设备是usb_device
结构类型的。root hub
作为usb总线(usb_bus
)设备树上的其它usb设备的父设备,它被关联在usb_bus
结构中。
root hub
作为usb_device
类型的对象,其关联的设备驱动模型的总线是usb总线,关联的设备驱动是usb hub
驱动。在添加usb_hcd
的时候,将会注册usb_bus
以及root hub
。root hub被初始化和注册后和usb hub驱动创建关联,之后的事就交给hub驱动和hub线程了。
控制器驱动主要提供控制器的硬件操作。比如中断设置,提供控制器的初始化,开始停止,urb入队出队,usb端点屏蔽使能,hub状态获取,数据通信控制等功能。
USB Core这个模块是纯软件部分,并不代表一个设备,是独立于硬件的协议栈,它是所有USB设备赖以生存的模块,即USB子系统的核心。代码位于kernel/drivers/usb/core
目录下。
USB Core为设备驱动程序提供服务,提供一个用于访问和控制USB硬件的接口,而不用考虑系统当前使用的哪种HOST Controller。USB Core将用户的请求映射到相关的HCD,用户不能直接访问HCD。USB Core就是HCD与USB设备的桥梁。
USB Subsystem Framework
The following chart shows the framework of the USB subsystem in Linux. Like i2c, the USB subsystem can be divided into three layers: ** Device Driver Layer - USB Core - Controller Driver Layer*
The usb protocol is a complex protocol,The currently involved versions are usb1.0, usb2.0, usb3.0. If you open the kernel usb host directory, you will find that the following contains various forms of controller drivers such as ohci, uhci, ehci, xhci, and whci.
USB的初始化函数在kernel/drivers/usb/core/usb.c
中定义,主要完成bus_register
(USB总线注册)、usb_major_init
(注册usb主控器字符设备)、usb_register
(注册usbfs驱动)、usb_hub_init
(USB Hub初始化,注册hub驱动、创建内核守护线程来监测hub端口的状态变化)等工作。
usb_init
usb_int
初始化整个usb系统的基础部分。(drivers/usb/core/usb.c
)
/*
* Init
*/
static int __init usb_init(void)
{
int retval;
if (usb_disabled()) {
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
usb_init_pool_max();
usb_debugfs_init();//初始化debugfs
usb_acpi_register();//注册usb acpi总线
retval = bus_register(&usb_bus_type);//注册总线,总线名称bus->name名字为 usb
...
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);//注册usb总线通知链。
...
retval = usb_major_init();//注册usb主设备号
...
retval = usb_register(&usbfs_driver);//注册usbfs接口驱动
...
retval = usb_devio_init();//初始化usb字符设备io空间
...
retval = usb_hub_init();//初始化并注册usb hub驱动,申请hub工作队列
...
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);//注册usb通用驱动。
...
}
bus_register(&usb_bus_type);
bus_register_notifier
usb_major_init()
usb_register(&usbfs_driver);
usb_hub_init -> usb_register(&hub_driver)
usb_register_device_driver(&usb_generic_driver, THIS_MODULE)
由usb总线的定义可知,总线名称为“usb”,匹配方法为usb_device_match
函数,uevent
方法为usb_uevent
。
总线名称bus->name
名字为usb
usb_init
–>bus_register
注册名称bus->name
名字为 usb
的总线
drivers/bash/bus.c
注意: 内核启动过程,在USB core加载之前也会有bus_register
总线注册的调用
[ 0.238943] drivers/base/bus.c:bus_register:bus: 'platform': registered
[ 0.246652] drivers/base/bus.c:bus_register:bus: 'cpu': registered
[ 0.254096] drivers/base/bus.c:bus_register:bus: 'memory': registered
[ 0.262313] drivers/base/bus.c:bus_register:bus: 'container': registered
[ 0.279808] drivers/base/bus.c:bus_register:bus: 'workqueue': registered
[ 0.486090] drivers/base/bus.c:bus_register:bus: 'gpio': registered
[ 0.493597] drivers/base/bus.c:bus_register:bus: 'virtio': registered
[ 0.511692] drivers/base/bus.c:bus_register:bus: 'pci': registered
[ 0.527454] drivers/base/bus.c:bus_register:bus: 'pci_express': registered
[ 0.535598] drivers/base/bus.c:bus_register:bus: 'rapidio': registered
[ 0.543488] drivers/base/bus.c:bus_register:bus: 'isa': registered
[ 0.550793] drivers/base/bus.c:bus_register:bus: 'node': registered
[ 0.592103] drivers/base/bus.c:bus_register:bus: 'spi': registered
[ 0.599533] drivers/base/bus.c:bus_register:bus: 'i2c': registered
[ 1.296609] drivers/base/bus.c:bus_register:bus: 'pnp': registered
[ 1.306813] drivers/base/bus.c:bus_register:bus: 'parport': registered
[ 1.348520] drivers/base/bus.c:bus_register:bus: 'scsi': registered
[ 1.430888] drivers/base/bus.c:bus_register:bus: 'mdio_bus': registered
/**
* bus_register - register a driver-core subsystem
* @bus: bus to register
*
* Once we have that, we register the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the subsystem.
*/
int bus_register(struct bus_type *bus)
{
int retval;
struct subsys_private *priv;
struct lock_class_key *key = &bus->lock_key;
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->bus = bus;
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
//初始化usb kset
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
//注册usb kset
retval = kset_register(&priv->subsys);
if (retval)
goto out;
retval = bus_create_file(bus, &bus_attr_uevent);
...
//初始化devices kset并注册在usb kset下
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj);
...
/初始化drivers kset并注册在usb kset下
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
INIT_LIST_HEAD(&priv->interfaces);
__mutex_init(&priv->mutex, "subsys mutex", key);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
retval = add_probe_files(bus);
...
retval = bus_add_groups(bus, bus->bus_groups);
...
...
}
EXPORT_SYMBOL_GPL(bus_register);
总结:注册usb类型的kset
, 然后在usb
类型的kset
下添加devices
和drivers
两个kset
.
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
通知链是linux内核用来实现异步通知的一种机制,通知链由一个通知链头结构和一些通知链上的block组成。usb核心会把一些事件发送到通知链,通知链核心将遍历通知链上的所有block,并调用block的回调函数以实现异步的效果。
总线上的通知链头结构包含在总线结构的p成员结构中。
usb总线通知链初始化的时候注册了一个通知块usb_bus_nb
,该通知块定义如下:
static struct notifier_block usb_bus_nb = {
.notifier_call = usb_bus_notify,
};
通知块回调函数为usb_bus_notify
,该函数接收处理总线上添加或删除设备/接口设备的事件,当usb核心向内核设备驱动模型中添加或删除usb设备或接口设备后,向usb总线上发送通知,在usb_bus_notify
通知处理函数中,向sysfs添加或删除设备或接口设备的属性文件。
retval = usb_major_init();
在usb_major_init
函数中调用register_chrdev
接口向内核注册了usb主设备号,usb的主设备号用USB_MAJOR
宏定义,该宏定义的值为180
。
retval = usb_devio_init();
usb_devio_init
函数中,首先按最大值为usb设备申请字符设备:retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device");
...
cdev_init(&usb_device_cdev, &usbdev_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
...
}
usb_notifier_list
上注册通知块usbdev_nb
:usb_register_notify(&usbdev_nb);
usbdev_nb
定义如下:
static struct notifier_block usbdev_nb = {
.notifier_call = usbdev_notify,
};
在usbdev_notify
回调函数中判读如果有usb设备移除了,就会做一些相应的文件io回收释放等操作。
usb_init
–>usb_register
在分析usb_register()函数前先看下hub_driver
结构体:
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,//hub探测接口
.disconnect = hub_disconnect,
.suspend = hub_suspend,//hub挂起,涉及到PM电源管理驱动控制
.resume = hub_resume,//hub恢复
.reset_resume = hub_reset_resume,//通过对hub复位来引发复位
.pre_reset = hub_pre_reset,//与PM电源管理系统相关
.post_reset = hub_post_reset,//与PM电源管理系统相关
.unlocked_ioctl = hub_ioctl,
.id_table = hub_id_table,//hub id表
.supports_autosuspend = 1,
};
usb_device_id
hub_id_table
对应结构体 struct usb_device_id
:
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling which of the other fields are used to
* match against new devices. Any field except for driver_info may be
* used, although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a device.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @bInterfaceNumber: Number of interface; composite devices may use
* fixed interface numbers to differentiate between vendor-specific
* interfaces.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/*表示下面哪些字段(产品、设备类别、接口类)可以进行匹配*/
/* which fields to match against? */
__u16 match_flags;
/*用于产品的匹配*/
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/*用于设备类别的匹配*/
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/*用于接口类别的匹配*/
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* Used for vendor-specific interface matches */
__u8 bInterfaceNumber;
/* not matched against */
kernel_ulong_t driver_info
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
hub_id_table
而hub_id_table
分别初始化了三个usb_device_id结构体:
static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_GENESYS_LOGIC,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_CLASS_HUB},
{ } /* Terminating entry */
};
第1个结构体成员
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS,
//表示需匹配的字段
.idVendor = USB_VENDOR_GENESYS_LOGIC,
//匹配的字段
.bInterfaceClass = USB_CLASS_HUB
//匹配的字段
第2个结构体成员
.match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
//表示需匹配的字段
.bDeviceClass = USB_CLASS_HUB
//匹配的字段
第3个结构体成员
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
//表示需匹配的字段
.bInterfaceClass = USB_CLASS_HUB
//匹配的字段
综上所述,match_flags 表示哪些字段匹配,而对应匹配的字段就是idVendor
、bInterfaceClass
,bDeviceClass
,bInterfaceClass
,这里在下面会分析如何使用。
usb_register
现在我们继续回到hub驱动注册:
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
此时串口一般会打印
[ 1.623189] usbcore: registered new interface driver usbfs
表明此时注册的是一个接口类型的 usbfs
/**
* usb_register_driver - register a USB interface driver
* @new_driver: USB operations for the interface driver
* @owner: module owner of this driver.
* @mod_name: module name string
*
* Registers a USB interface driver with the USB core. The list of
* unattached interfaces will be rescanned whenever a new driver is
* added, allowing the new driver to attach to any recognized interfaces.
*
* Return: A negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
//对drvwrap USB驱动包初始化
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = new_driver->name;//初始化驱动名称为“hub”
new_driver->drvwrap.driver.bus = &usb_bus_type;//绑定总线类型为子系统usb
new_driver->drvwrap.driver.probe = usb_probe_interface;//重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver);//驱动注册
...
retval = usb_create_newid_files(new_driver);
...
pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);//证明此时usbcore创建的新的hub是接口型设备
...
}
EXPORT_SYMBOL_GPL(usb_register_driver);
usb_register_driver()
函数内部主要涉及到两个函数,驱动注册driver_register()
和newid
文件创建usb_create_newid_files()
,接下来将逐个分析:
driver_register()
注意:在内核启动阶段,usb core初始化之前,依然有调用
[ 0.558292] drivers/base/driver.c:driver_register: Driver `syscon` fund by 'platform'
[ 0.606917] drivers/base/driver.c:driver_register: Driver `dummy` fund by 'i2c'
[ 1.257772] drivers/base/driver.c:driver_register: Driver `loongson-gpio` fund by 'platform'
[ 1.314486] drivers/base/driver.c:driver_register: Driver `w25q16dvssig` fund by 'spi'
[ 1.363468] drivers/base/driver.c:driver_register: Driver `ls-spi` fund by 'platform'
[ 1.397259] drivers/base/driver.c:driver_register: Driver `ls-spi-pci` fund by 'pci'
[ 1.438725] drivers/base/driver.c:driver_register: Driver `Generic 10G PHY` fund by 'mdio_bus'
[ 1.474069] drivers/base/driver.c:driver_register: Driver `Generic PHY` fund by 'mdio_bus'
注意:other = driver_find(drv->name, drv->bus);//此时usb总线find的驱动名称是:usbfs
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
if (!drv->bus->p) {
pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
drv->name, drv->bus->name);
return -EINVAL;
}
//检测总线的操作函数和驱动的操作函数是否同时存在
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);//这里查找drv->name="usbfs"驱动是否已经在drv->bus总线上注册,并增加引用计数,若已经注册,则返回提示信息
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);//如果之前没注册,就在此注册
...
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
...
}
EXPORT_SYMBOL_GPL(driver_register);
bus_add_driver()
注意:在内核启动阶段,usb core初始化之前,依然有其他模块调用这个函数进行总线模块加载
[ 0.567343] drivers/base/bus.c:bus_add_driver,bus: 'platform': add driver syscon
[ 0.615467] drivers/base/bus.c:bus_add_driver,bus: 'i2c': add driver dummy
[ 1.267419] drivers/base/bus.c:bus_add_driver,bus: 'platform': add driver loongson-gpio
[ 1.323639] drivers/base/bus.c:bus_add_driver,bus: 'spi': add driver w25q16dvssig
[ 1.372542] drivers/base/bus.c:bus_add_driver,bus: 'platform': add driver ls-spi
[ 1.406237] drivers/base/bus.c:bus_add_driver,bus: 'pci': add driver ls-spi-pci
[ 1.448573] drivers/base/bus.c:bus_add_driver,bus: 'mdio_bus': add driver Generic 10G PHY
[ 1.483567] drivers/base/bus.c:bus_add_driver,bus: 'mdio_bus': add driver Generic PHY
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
//用于增加该bus所属的顶层bus的kobject的引用计数,返回的是其所属的顶层bus的指针。
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配一个驱动私有数据driver_private
...
klist_init(&priv->klist_devices, NULL, NULL);//初始化设备链表
//以下相互绑定
priv->driver = drv;//私有驱动数据绑定drv
drv->p = priv;//drv->p驱动绑定priv
priv->kobj.kset = bus->p->drivers_kset;//将priv->kobj.kset当前内核集合指向bus->p->drivers_kset内核集合(该集合在usb总线注册bus_register()描述)
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
...
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//将当前注册的priv->knode_bus节点加入到全局bus->p->klist_drivers链表中
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {//在usb总线注册时对该变量drivers_autoprobe初始化为1了
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv);
...
}
}
module_add_driver(drv->owner, drv);//驱动模块注册时会用到,此时加载的模块名字是usbcore
error = driver_create_file(drv, &driver_attr_uevent);
...
error = driver_add_groups(drv, bus->drv_groups);
...
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
...
}
kobject_init_and_add
这里重点分析下内核对象初始化的内部细节,
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
其中,driver_ktype
为驱动的内核集合类型,主要用来对内核对象的操作
static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
static const struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct driver_attribute *drv_attr = to_drv_attr(attr);//获取驱动的属性结构体
struct driver_private *drv_priv = to_driver(kobj);//获取驱动的私有数据
ssize_t ret = -EIO;
if (drv_attr->show)//驱动属性文件是否不为NULL
ret = drv_attr->show(drv_priv->driver, buf);//显示驱动
return ret;
}
static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct driver_attribute *drv_attr = to_drv_attr(attr);
struct driver_private *drv_priv = to_driver(kobj);
ssize_t ret = -EIO;
if (drv_attr->store)
ret = drv_attr->store(drv_priv->driver, buf, count);//存储
return ret;
}
分析完了驱动内核对象类型操作,再回到内核对象的初始化
kobject_init_and_add
/**
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
* @parent: pointer to the parent of this kobject.
* @fmt: the name of the kobject.
*
* This function combines the call to kobject_init() and
* kobject_add(). The same type of error handling after a call to
* kobject_add() and kobject lifetime rules are the same here.
*/
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
{
va_list args;
int retval;
kobject_init(kobj, ktype);//初始化内核对象(绑定内核对象kobject的内核对象类型接口为ktype)
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);//内核对象增加,即创建hub目录
va_end(args);
return retval;
}
EXPORT_SYMBOL_GPL(kobject_init_and_add);
kobject_init
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized) {
/* do not error out as sometimes we can recover */
pr_err("kobject (%p): tried to init an initialized object, something is seriously wrong.\n",
kobj);
dump_stack();
}
kobject_init_internal(kobj);
kobj->ktype = ktype;//绑定内核对象的内核类型(内核对象的操作接口)
return;
...
}
EXPORT_SYMBOL(kobject_init);
kobject_init_internal
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);//表示父内核对象下挂接的子内核对象
kobj->state_in_sysfs = 0;//sysfs没有初始化(涉及到sysfs文件系统)
kobj->state_add_uevent_sent = 0;//用户层事件是否发送
kobj->state_remove_uevent_sent = 0;//用户层事件是否移除
kobj->state_initialized = 1;//kobj对象初始化完成标识
}
kobject_init_and_add()->kobject_add_varg
static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
pr_err("kobject: can not set name properly!\n");
return retval;
}
kobj->parent = parent;
return kobject_add_internal(kobj);//内核对象增加,在sys文件系统下创建目录hub,绝对路径/sys/bus/usb/drivers/hub
}
kobject_add_internal
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
...
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {//kset为usb集合(因为kset集合是被内核对象绑定,所以下面可以获取内核对象)
if (!parent)
parent = kobject_get(&kobj->kset->kobj);//即为usb内核对象
kobj_kset_join(kobj);
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "" ,
kobj->kset ? kobject_name(&kobj->kset->kobj) : "" );
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
pr_err("%s failed for %s (error: %d parent: %s)\n",
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : "'none'");
} else
kobj->state_in_sysfs = 1;//表示kobject对象在sysfs中的状态
return error;
}
到这里完成了hub内核对象的初始化和添加,并将该节点添加到了usb总线的bus->p->klist_drivers
驱动链表中,同时创建目录hub,绝对路径为/sys/bus/usb/hub
;接下来将分析driver_attach()
driver_attach()
路径:bus_add_driver()-->driver_attach(drv)
/**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);
/**
* bus_for_each_dev - device iterator.
* @bus: bus type.
* @start: device to start iterating from.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @bus's list of devices, and call @fn for each,
* passing it @data. If @start is not NULL, we use that device to
* begin iterating from.
*
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*
* NOTE: The device that returns a non-zero value is not retained
* in any way, nor is its refcount incremented. If the caller needs
* to retain this data, it should do so, and increment the reference
* count in the supplied callback.
*/
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));//设备通过bus_add_device(...)添加时,最终会将设备加入到bus->p->klist_devices设备链表中
while (!error && (dev = next_device(&i)))
error = fn(dev, data);//回调接口函数__driver_attach
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
bus_for_each_dev()
函数内部主要是遍历usb总线的设备链表(由于本次注册的是hub驱动),需找与本次注册的hub驱动相匹配;
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
int ret;
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/
//当设备和驱动的名字不匹配的时候返回的是0,然后就会调用下面的return 0;
ret = driver_match_device(drv, dev);//驱动和设备是否匹配,不匹配将退出,bus_for_each_dev函数继续下一个设备来匹配-->usb_device_match(dev, drv)
if (ret == 0) {
/* no match */
return 0;
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
} /* ret > 0 means positive match */
if (dev->parent && dev->bus->need_parent_lock)
device_lock(dev->parent);
device_lock(dev);
if (!dev->p->dead && !dev->driver)
driver_probe_device(drv, dev);//调用探测函数进行探测,并且调用platform_driver中的probe函数
device_unlock(dev);
if (dev->parent && dev->bus->need_parent_lock)
device_unlock(dev->parent);
...
}
driver_match_device()
static inline int driver_match_device(struct device_driver *drv, struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;//调用match函数,如果没用则默认返回1 -->usb_device_match(dev, drv)
}
通过上面的usb_register_driver()
函数分析,得知这里的drv
为new_driver->drvwrap.driver
,再次贴上该代码
new_driver->drvwrap.driver.name = (char *) new_driver->name; //初始化驱动名称为“hub”
new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线类型为子系统usb
new_driver->drvwrap.driver.probe = usb_probe_interface; //重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
所以driver_match_device()
函数内部drv->bus=&usb_bus_type
,即会调用 drv->bus->match(dev, drv)
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.need_parent_lock = true,
};
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) { //是否是usb设备
/* interface drivers never match devices */
if (!is_usb_device_driver(drv))
return 0;
/* TODO: Add real matching code */
return 1;
} else if (is_usb_interface(dev)) { //是否是usb接口
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* device drivers never match interfaces */
if (is_usb_device_driver(drv))
...
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table);
...
id = usb_match_dynamic_id(intf, usb_drv);
...
}
return 0;
}
在usb_device_match
函数内部是usb设备或接口将执行不同的操作,我们在usb_register()
函数注册时并未绑定类型,所以这里直接返回0
,也就不会执行相应的probe
探测函数了。
intf->dev.type = &usb_if_device_type
将在usb_set_configuration()
内部初始化,dev->dev.type = &usb_device_type
将在usb_alloc_dev()
内部初始化
module_add_driver()
Hub驱动注册到usb总线上,并且这个时候usb总线上只有hub一个驱动,所以上面调用usb_device_match
函数时将无法在对应的usb总线上匹配到设备,即该函数module_add_driver
将不会被执行!不过为了后续再调用到该函数时不解,这里继续分析
module_add_driver(drv->owner, drv);
void module_add_driver(struct module *mod, struct device_driver *drv)
{
char *driver_name;
int no_warn;
struct module_kobject *mk = NULL;
if (!drv)
return;
if (mod) //mod为真
mk = &mod->mkobj;
else if (drv->mod_name) { //驱动名称,假设是usb主机控制器"ehci_hcd"
struct kobject *mkobj;
/* Lookup built-in module entry in /sys/modules */
mkobj = kset_find_obj(module_kset, drv->mod_name); //根据mod_name,在module_kset内核集合上查找是否有相同的驱动
if (mkobj) {
mk = container_of(mkobj, struct module_kobject, kobj); //通过结构体成员mkobj,获取对应的module_kobject结构体指针
/* remember our module structure */
drv->p->mkobj = mk;
/* kset_find_obj took a reference */
kobject_put(mkobj);
}
}
...
/* Don't check return codes; these calls are idempotent */
no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //创建module符号链接,即/sys/bus/usb/drivers/hub/module
driver_name = make_driver_name(drv); //driver_name ="usb:hub"
if (driver_name) {
module_create_drivers_dir(mk); //创建目录/sys/bus/usb/drivers/hub/module/usb:hub
no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
driver_name);
kfree(driver_name);
}
}
usb_hub_init
usb_hub_init
usb子系统中所有和hub相关的都交由一个内核线程表征, 通过 static struct workqueue_struct *hub_wq
来管理。
int usb_hub_init(void)
{
//1. 注册usb hub驱动
if (usb_register(&hub_driver) < 0) {//注册hub驱动到usb子系统总线上
printk(KERN_ERR "%s: can't register hub driver\n",
usbcore_name);
return -1;
}
/*
* The workqueue needs to be freezable to avoid interfering with
* USB-PERSIST port handover. Otherwise it might see that a full-speed
* device was gone before the EHCI controller had handed its port
* over to the companion full-speed controller.
*/
//
hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);//创建hub内核线程
...
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
...
}
usb_hub_init()
就做两件事:
usb_hub_wq
hub_driver
定义如下:
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.unlocked_ioctl = hub_ioctl,
.id_table = hub_id_table,
.supports_autosuspend = 1,
};
由该定义可知,usb hub驱动是一个接口设备驱动,驱动名称为“hub”,id_table
成员为hub_id_table
,probe函数为hub_prob
e,当一个hub设备添加到内核设备驱动模型中的时候,如果hub设备测参数和hub_id_table
中的参数匹配,就会调用到hub_probe
函数。
hub本身也是个usb设备, 跟普通的U盘使用的都是同样的结构体, 当有hub设备被创建时,hub驱动的probe()
将会match
调用, 那问题来了,一个普通设备是被hub创建的, 那hub设备是谁创建的呢?很显然最初的root hub设备必须是静态创建的, 且这部分代码没放在hub.c
, 而是放到了hcd.c
, 可以看出一个Host必然有一个root hub, 是绑定的!
usb_hub_init
–>usb_register
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
注意:retval = driver_register(&new_driver->drvwrap.driver);//此时usb总线find的驱动名称是:hub
/**
* usb_register_driver - register a USB interface driver
* @new_driver: USB operations for the interface driver
* @owner: module owner of this driver.
* @mod_name: module name string
*
* Registers a USB interface driver with the USB core. The list of
* unattached interfaces will be rescanned whenever a new driver is
* added, allowing the new driver to attach to any recognized interfaces.
*
* Return: A negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
//对drvwrap USB驱动包初始化
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = new_driver->name;//初始化驱动名称为“hub”
new_driver->drvwrap.driver.bus = &usb_bus_type;//绑定总线类型为子系统usb
new_driver->drvwrap.driver.probe = usb_probe_interface;//重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver);//此时usb总线find的驱动名称是:hub
...
retval = usb_create_newid_files(new_driver);
...
...
...
}
EXPORT_SYMBOL_GPL(usb_register_driver);
usb_register_driver()
函数内部主要涉及到两个函数,驱动注册driver_register()
和newid
文件创建usb_create_newid_files()
。
usb_register_driver
–>driver_register
此时串口一般会打印
[ 1.715461] usbcore: registered new interface driver hub
表明此时注册的是一个接口类型的 hub
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
...
//检测总线的操作函数和驱动的操作函数是否同时存在
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
...
other = driver_find(drv->name, drv->bus);//这里查找drv->name="hub"驱动是否已经在drv->bus总线上注册,并增加引用计数,若已经注册,则返回提示信息
...
ret = bus_add_driver(drv);//如果之前没注册,就在此注册
...
ret = driver_add_groups(drv, drv->groups);
...
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
....
}
EXPORT_SYMBOL_GPL(driver_register);
driver_register
–>bus_add_driver()
usb总线上添加hub驱动
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
//用于增加该bus所属的顶层bus的kobject的引用计数,返回的是其所属的顶层bus的指针。
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配一个驱动私有数据driver_private
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);//初始化设备链表
//以下相互绑定
priv->driver = drv;//私有驱动数据绑定drv
drv->p = priv;//drv->p驱动绑定priv
priv->kobj.kset = bus->p->drivers_kset;//将priv->kobj.kset当前内核集合指向bus->p->drivers_kset内核集合(该集合在usb总线注册bus_register()描述)
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//将当前注册的priv->knode_bus节点加入到全局bus->p->klist_drivers链表中
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {//在usb总线注册时对该变量drivers_autoprobe初始化为1了
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv);//
if (error)
goto out_unregister;
}
}
module_add_driver(drv->owner, drv);//驱动模块注册时会用到,此时加载的模块名字是usbcore
error = driver_create_file(drv, &driver_attr_uevent);
...
error = driver_add_groups(drv, bus->drv_groups);
...
...
...
}
bus_add_driver
–>kobject_init_and_add
hub内核对象初始化,这里重点分析下内核对象初始化的内部细节,
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
其中,driver_ktype
为驱动的内核集合类型,主要用来对内核对象的操作
static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
static const struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct driver_attribute *drv_attr = to_drv_attr(attr);//获取驱动的属性结构体
struct driver_private *drv_priv = to_driver(kobj);//获取驱动的私有数据
ssize_t ret = -EIO;
if (drv_attr->show)//驱动属性文件是否不为NULL
ret = drv_attr->show(drv_priv->driver, buf);//显示驱动
return ret;
}
static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct driver_attribute *drv_attr = to_drv_attr(attr);
struct driver_private *drv_priv = to_driver(kobj);
ssize_t ret = -EIO;
if (drv_attr->store)
ret = drv_attr->store(drv_priv->driver, buf, count);//存储
return ret;
}
分析完了驱动内核对象类型操作,再回到内核对象的初始化
/**
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
* @parent: pointer to the parent of this kobject.
* @fmt: the name of the kobject.
*
* This function combines the call to kobject_init() and
* kobject_add(). The same type of error handling after a call to
* kobject_add() and kobject lifetime rules are the same here.
*/
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
{
va_list args;
int retval;
kobject_init(kobj, ktype);//初始化内核对象(绑定内核对象kobject的内核对象类型接口为ktype)
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);//内核对象增加,即创建hub目录
va_end(args);
return retval;
}
EXPORT_SYMBOL_GPL(kobject_init_and_add);
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized) {
/* do not error out as sometimes we can recover */
pr_err("kobject (%p): tried to init an initialized object, something is seriously wrong.\n",
kobj);
dump_stack();
}
kobject_init_internal(kobj);
kobj->ktype = ktype;//绑定内核对象的内核类型(内核对象的操作接口)
return;
error:
pr_err("kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
EXPORT_SYMBOL(kobject_init);
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);//表示父内核对象下挂接的子内核对象
kobj->state_in_sysfs = 0;//sysfs没有初始化(涉及到sysfs文件系统)
kobj->state_add_uevent_sent = 0;//用户层事件是否发送
kobj->state_remove_uevent_sent = 0;//用户层事件是否移除
kobj->state_initialized = 1;//kobj对象初始化完成标识
}
kobject_init_and_add()->kobject_add_varg
static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
pr_err("kobject: can not set name properly!\n");
return retval;
}
kobj->parent = parent;
return kobject_add_internal(kobj);//内核对象增加,在sys文件系统下创建目录hub,绝对路径/sys/bus/usb/drivers/hub
}
kobject_add_varg
–>kobject_add_internal
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
...
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {//kset为usb集合(因为kset集合是被内核对象绑定,所以下面可以获取内核对象)
if (!parent)
parent = kobject_get(&kobj->kset->kobj);//即为usb内核对象
kobj_kset_join(kobj);
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "" ,
kobj->kset ? kobject_name(&kobj->kset->kobj) : "" );
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
pr_err("%s failed for %s (error: %d parent: %s)\n",
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : "'none'");
} else
kobj->state_in_sysfs = 1;//表示kobject对象在sysfs中的状态
return error;
}
到这里完成了hub内核对象的初始化和添加,并将该节点添加到了usb总线的bus->p->klist_drivers
驱动链表中,同时创建目录hub,绝对路径为/sys/bus/usb/hub
;
module_add_driver()
Hub驱动注册到usb总线上,并且这个时候usb总线上只有hub一个驱动,所以上面调用usb_device_match
函数时将无法在对应的usb总线上匹配到设备,即该函数module_add_driver
将不会被执行!不过为了后续再调用到该函数时不解,这里继续分析
module_add_driver(drv->owner, drv);
void module_add_driver(struct module *mod, struct device_driver *drv)
{
char *driver_name;
int no_warn;
struct module_kobject *mk = NULL;
if (!drv)
return;
if (mod) //mod为真
mk = &mod->mkobj;
else if (drv->mod_name) { //驱动名称,假设是usb主机控制器"ehci_hcd"
struct kobject *mkobj;
/* Lookup built-in module entry in /sys/modules */
mkobj = kset_find_obj(module_kset, drv->mod_name); //根据mod_name,在module_kset内核集合上查找是否有相同的驱动
if (mkobj) {
mk = container_of(mkobj, struct module_kobject, kobj); //通过结构体成员mkobj,获取对应的module_kobject结构体指针
/* remember our module structure */
drv->p->mkobj = mk;
/* kset_find_obj took a reference */
kobject_put(mkobj);
}
}
...
/* Don't check return codes; these calls are idempotent */
no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //创建module符号链接,即/sys/bus/usb/drivers/hub/module
driver_name = make_driver_name(drv); //driver_name ="usb:hub"
if (driver_name) {
module_create_drivers_dir(mk); //创建目录/sys/bus/usb/drivers/hub/module/usb:hub
no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
driver_name);
kfree(driver_name);
}
}
注册了hub_driver之后,申请hub工作队列。
hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);
在hub的中断轮询的时候,在回调函数hub_irq
中就会向hub_wq
中添加任务。在该任务中再去做hub端口检查,新设备枚举等工作。
usb_init
–>usb_register_device_driver
注意:retval = driver_register(&new_udriver->drvwrap.driver);//此时usb总线find的驱动名称是:usb
/**
* usb_register_device_driver - register a USB device (not interface) driver
* @new_udriver: USB operations for the device driver
* @owner: module owner of this driver.
*
* Registers a USB device driver with the USB core. The list of
* unattached devices will be rescanned whenever a new driver is
* added, allowing the new driver to attach to any recognized devices.
*
* Return: A negative error code on failure and 0 on success.
*/
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
{
int retval = 0;
if (usb_disabled())
...
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;
retval = driver_register(&new_udriver->drvwrap.driver);//此时usb总线find的驱动名称是:usb
//klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
...
}
EXPORT_SYMBOL_GPL(usb_register_device_driver);
初始化usb_generic_driver
中drvwrap
中driver
的name
, bus类型,以及probe
函数,并注册到usb总线klist_drivers
链表上(driver_register
–>bus_add_driver
–>klist_add_tail
)。
driver_register()
注意:other = driver_find(drv->name, drv->bus);//此时usb总线find的驱动名称是:usb
此时串口一般会打印
[ 1.793300] usbcore: registered new device driver usb
表明此时注册的是一个设备类型的 usb
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
...
//检测总线的操作函数和驱动的操作函数是否同时存在
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);//这里查找drv->name="usb"驱动是否已经在drv->bus总线上注册,并增加引用计数,若已经注册,则返回提示信息
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);//如果之前没注册,就在此注册
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
bus_add_driver()
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
//用于增加该bus所属的顶层bus的kobject的引用计数,返回的是其所属的顶层bus的指针。
bus = bus_get(drv->bus);
...
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配一个驱动私有数据driver_private
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);//初始化设备链表
//以下相互绑定
priv->driver = drv;//私有驱动数据绑定drv
drv->p = priv;//drv->p驱动绑定priv
priv->kobj.kset = bus->p->drivers_kset;//将priv->kobj.kset当前内核集合指向bus->p->drivers_kset内核集合(该集合在usb总线注册bus_register()描述)
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
...
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//将当前注册的priv->knode_bus节点加入到全局bus->p->klist_drivers链表中
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {//在usb总线注册时对该变量drivers_autoprobe初始化为1了
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv);
...
}
}
module_add_driver(drv->owner, drv);//**从该函数这开始,本次hub驱动将不会执行下面的函数了**
error = driver_create_file(drv, &driver_attr_uevent);
...
error = driver_add_groups(drv, bus->drv_groups);
...
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
...
}
kobject_init_and_add
这里重点分析下内核对象初始化的内部细节,
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
其中,driver_ktype
为驱动的内核集合类型,主要用来对内核对象的操作
static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
static const struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct driver_attribute *drv_attr = to_drv_attr(attr);//获取驱动的属性结构体
struct driver_private *drv_priv = to_driver(kobj);//获取驱动的私有数据
ssize_t ret = -EIO;
if (drv_attr->show)//驱动属性文件是否不为NULL
ret = drv_attr->show(drv_priv->driver, buf);//显示驱动
return ret;
}
static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct driver_attribute *drv_attr = to_drv_attr(attr);
struct driver_private *drv_priv = to_driver(kobj);
ssize_t ret = -EIO;
if (drv_attr->store)
ret = drv_attr->store(drv_priv->driver, buf, count);//存储
return ret;
}
分析完了驱动内核对象类型操作,再回到内核对象的初始化
kobject_init_and_add
/**
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
* @parent: pointer to the parent of this kobject.
* @fmt: the name of the kobject.
*
* This function combines the call to kobject_init() and
* kobject_add(). The same type of error handling after a call to
* kobject_add() and kobject lifetime rules are the same here.
*/
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
{
va_list args;
int retval;
kobject_init(kobj, ktype);//初始化内核对象(绑定内核对象kobject的内核对象类型接口为ktype)
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);//内核对象增加,即创建hub目录
va_end(args);
return retval;
}
EXPORT_SYMBOL_GPL(kobject_init_and_add);
kobject_init
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
...
kobject_init_internal(kobj);
kobj->ktype = ktype;//绑定内核对象的内核类型(内核对象的操作接口)
return;
...
}
EXPORT_SYMBOL(kobject_init);
kobject_init_internal
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);//表示父内核对象下挂接的子内核对象
kobj->state_in_sysfs = 0;//sysfs没有初始化(涉及到sysfs文件系统)
kobj->state_add_uevent_sent = 0;//用户层事件是否发送
kobj->state_remove_uevent_sent = 0;//用户层事件是否移除
kobj->state_initialized = 1;//kobj对象初始化完成标识
}
kobject_init_and_add()->kobject_add_varg
static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
pr_err("kobject: can not set name properly!\n");
return retval;
}
kobj->parent = parent;
return kobject_add_internal(kobj);//内核对象增加,在sys文件系统下创建目录hub,绝对路径/sys/bus/usb/drivers/hub
}
kobject_add_internal
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
...
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {//kset为usb集合(因为kset集合是被内核对象绑定,所以下面可以获取内核对象)
if (!parent)
parent = kobject_get(&kobj->kset->kobj);//即为usb内核对象
kobj_kset_join(kobj);
kobj->parent = parent;
}
...
error = create_dir(kobj);
if (error) {
...
} else
kobj->state_in_sysfs = 1;//表示kobject对象在sysfs中的状态
return error;
}
到这里完成了hub内核对象的初始化和添加,并将该节点添加到了usb总线的bus->p->klist_drivers
驱动链表中,同时创建目录hub,绝对路径为/sys/bus/usb/hub
;接下来将分析driver_attach()
driver_attach()
路径:bus_add_driver()-->driver_attach(drv)
/**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);
/**
* bus_for_each_dev - device iterator.
* @bus: bus type.
* @start: device to start iterating from.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @bus's list of devices, and call @fn for each,
* passing it @data. If @start is not NULL, we use that device to
* begin iterating from.
*
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*
* NOTE: The device that returns a non-zero value is not retained
* in any way, nor is its refcount incremented. If the caller needs
* to retain this data, it should do so, and increment the reference
* count in the supplied callback.
*/
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));//设备通过bus_add_device(...)添加时,最终会将设备加入到bus->p->klist_devices设备链表中
while (!error && (dev = next_device(&i)))
error = fn(dev, data);//回调接口函数__driver_attach
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
bus_for_each_dev()
函数内部主要是遍历usb总线的设备链表(由于本次注册的是hub驱动),需找与本次注册的hub驱动相匹配;
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
int ret;
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/
//当设备和驱动的名字不匹配的时候返回的是0,然后就会调用下面的return 0;
ret = driver_match_device(drv, dev);//驱动和设备是否匹配,不匹配将退出,bus_for_each_dev函数继续下一个设备来匹配-->usb_device_match(dev, drv)
if (ret == 0) {
/* no match */
return 0;
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
} /* ret > 0 means positive match */
if (dev->parent && dev->bus->need_parent_lock)
device_lock(dev->parent);
device_lock(dev);
if (!dev->p->dead && !dev->driver)
driver_probe_device(drv, dev);//调用探测函数进行探测,并且调用platform_driver中的probe函数
device_unlock(dev);
if (dev->parent && dev->bus->need_parent_lock)
device_unlock(dev->parent);
return 0;
}
driver_match_device()
static inline int driver_match_device(struct device_driver *drv, struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;//调用match函数,如果没用则默认返回1 -->usb_device_match(dev, drv)
}
通过上面的usb_register_driver()
函数分析,得知这里的drv
为new_driver->drvwrap.driver
,再次贴上该代码
new_driver->drvwrap.driver.name = (char *) new_driver->name; //初始化驱动名称为“hub”
new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线类型为子系统usb
new_driver->drvwrap.driver.probe = usb_probe_interface; //重要,是接口的探针函数!!!该函数内部会调用usb_serial_probe()
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
所以driver_match_device()
函数内部drv->bus=&usb_bus_type
,即会调用 drv->bus->match(dev, drv)
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.need_parent_lock = true,
};
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) { //是否是usb设备
/* interface drivers never match devices */
if (!is_usb_device_driver(drv))
return 0;
/* TODO: Add real matching code */
return 1;
} else if (is_usb_interface(dev)) { //是否是usb接口
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* device drivers never match interfaces */
if (is_usb_device_driver(drv))
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table);
...
id = usb_match_dynamic_id(intf, usb_drv);
...
}
return 0;
}
在usb_device_match
函数内部是usb设备或接口将执行不同的操作,我们在usb_register()
函数注册时并未绑定类型,所以这里直接返回0
,也就不会执行相应的probe
探测函数了。
intf->dev.type = &usb_if_device_type
将在usb_set_configuration()
内部初始化,dev->dev.type = &usb_device_type
将在usb_alloc_dev()
内部初始化
usb_write
device
(usb SD
卡驱动)要构造urb
,并且填充要写的data
到urb
,然后usb_submit_urb(skel->write_urb);
启动写数据usb_read
: 驱动从device
读数据到driver
(输入设备,比如鼠标),读要分为两种:
read
动作的触发起源于硬件设备,比如鼠标移动就会自动read
数据到driver
;read
动作的触发起源于驱动代码本身,驱动要读数据才去读,这种情况不需要使用urb
,可使用函数usb_bulk_msg(...)
进行单次的读数据;usb driver
需要自己构造urb
,并且填充,并且提交urb
;usb driver
可以使用函数usb_bulk_msg()
来读写数据;urb
,读分为两种:实时数据要构造urb
,非实时调用函数usb_bulk_msg(...)
进行读;urb
可以重复填充,也可以重复提交usb
读与usb
写的最大不同是读跟写的端点不同,端点里包含的端点的具体地址也不同,具体表现为:
struct usb_endpoint_descriptor *bulk_in, *bulk_out;
//输入端口,输出端口usb_find_common_endpoints(interface->cur_altsetting,&bulk_in, &bulk_out, NULL, NULL);
//分别获取输入,输出端点。bulk_in->bEndpointAddress
不同于bulk_out->bEndpointAddress
,导致填充各自的urb
时产生差异得以区分读写过程。in_urb
:创建一次,反复填充;out_urb
:每写一次创建一次并且填充一次且提交一次,即时创建即时销毁;linux
内核提供的usb
设备驱动编写(包括读写过程)的框架为:drivers\usb\usb-skeleton.c
usb
摄像头(视频,音频)是一个实时传输data
的usb
设备,跟鼠标类似->单向实时usb
输入设备,u
盘属于非实时usb
存贮设备(有读有写)。usb
设备分为两种
usb
鼠标,usb
键盘;usb
磁盘;urb
将数据从设备传输回来之后,要驱动程序处理完数据了,才可以再次提交urb
,这个提交的动作可以发生在回掉函数里,也可以发生在回掉函数之外;反正就是要再次提交才可以再次运输新的数据回来;drivers\usb\usb-skeleton.c
,这个是写usb
磁盘的参考资料,但有很多细节可以参考; usb
总线每传输完一次数据就会产生一次回调中断,这里面可以做数据处理,也可以重新提交urb
;usb_fill_int_urb
u
盘,usb-lcd
屏幕等,这类可以用块usb_fill_bulk_urb
fill
的时候会配置dev->speed
,中断型的传输速率会要求比较高;测试usb键盘驱动
Device Drivers >
HID support >
USB HID support >
< > USB HID transport layer//取消选中这个,
//要不然就会编译linux内核自带的键盘驱动,轮不到自己写的键盘驱动进行控制键盘;
对于tty(输入输出)设备的理解
tty0表示当前使用的控制终端
tty1对应/dev/input/event0(输入设备0)
tty2对应/dev/input/event1(输入设备1)
tty3对应/dev/input/event2(输入设备2)
所以要确定自己注册的输入设备是event*
几;
简单测试
cat /dev/tty1
//这个测试按下了对应的字母按键之后,要再次按下enter键才可以显示之前按下的按键;
正式测试
exec 0</dev/tty1
//将开发板的控制台改为自己的键盘以及自己开发的驱动,这样可以正确测试键盘的输入以及直接用控制台测试;
对exec测试命令的解释:
对于做驱动经常会使用exec来试验驱动,通过exec将-sh进程下的描述符指向我们的驱动,来实现调试
-sh进程常用描述符号:
0:标准输入
1:标准输出
2:错误信息
5:中断服务
exec命令使用:
挂载: exec [描述符号]<[设备节点路径]
卸载: exec [描述符号]<&-
实例:
exec 0</dev/tty1 //将本开发板的第1个输入设备(第一个注册的input_device,就是键盘驱动)挂接到-sh下的0号描述符,也就是标准输入来自/dev/tty1,也就是将标准输入从默认改为我们自己写的输入设备;
exec 0<&- //调用/dev/tty1驱动的卸载函数,系统的标准输入不要用我们自己注册的输入设备;
问2. USB
设备种类非常多,为什么一接入电脑,就能识别出来?
答2. PC
和USB
设备都得遵守一些规范。
比如:
USB
设备接入电脑后,PC
机会发出"你是什么"?
USB
设备就必须回答"我是xxx", 并且回答的语言必须是中文
USB
总线驱动程序会发出某些命令想获取设备信息(描述符),
USB
设备必须返回"描述符"给PC
问3. PC
机上接有非常多的USB
设备,怎么分辨它们?
USB
接口只有4
条线: 5V
,GND
,D-
,D+
答3. 每一个USB
设备接入PC
时,USB总线驱动程序都会给它分配一个编号
接在USB
总线上的每一个USB
设备都有自己的编号(地址)
PC
机想访问某个USB
设备时,发出的命令都含有对应的编号(地址)
问4. USB
设备刚接入PC
时,还没有编号;那么PC
怎么把"分配的编号"告诉它?
答4. 新接入的USB
设备的默认编号是0
,在未分配新编号前,PC
使用0
编号和它通信。
问5. 为什么一接入USB
设备,PC
机就能发现它?
答5. PC
的USB
口内部,D-
和D+
接有15K
的下拉电阻,未接USB
设备时为低电平
USB
设备的USB
口内部,D-
或D+
接有1.5K
的上拉电阻;它一接入PC
,就会把PC USB
口的D-
或D+
拉高,从硬件的角度通知PC
有新设备接入
其他概念:
USB
是主从结构的
所有的USB
传输,都是从USB
主机这方发起;USB
设备没有"主动"通知USB
主机的能力。
例子:USB
鼠标滑动一下立刻产生数据,但是它没有能力通知PC
机来读数据,只能被动地等得PC
机来读。
USB
的传输类型:
a. 控制传输:可靠,时间有保证,比如:USB
设备的识别过程
b. 批量传输: 可靠, 时间没有保证, 比如:U
盘
c. 中断传输:可靠,实时,比如:USB
鼠标
d. 实时传输:不可靠,实时,比如:USB
摄像头
USB
传输的对象:端点(endpoint
)
我们说"读U盘"、“写U盘”,可以细化为:把数据写到U盘
的端点1
,从U
盘的端点2
里读出数据
除了端点0
外,每一个端点只支持一个方向的数据传输
端点0
用于控制传输,既能输出也能输入
每一个端点都有传输类型,传输方向
术语里、程序里说的输入(IN)、输出(OUT) “都是” 基于USB
主机的立场说的。
比如鼠标的数据是从鼠标传到PC
机, 对应的端点称为"输入端点"
USB总线驱动程序的作用
a. 识别USB
设备
b. 查找并安装对应的设备驱动程序
c. 提供USB
读写函数
USB
总线驱动程序负责:识别USB
设备, 给USB
设备找到对应的驱动程序USB驱动程序框架:
app:
-------------------------------------------
USB设备驱动程序 // 知道数据含义
内核 --------------------------------------
USB总线驱动程序 // 1. 识别,
// 2. 找到匹配的设备驱动,
// 3. 提供USB读写函数 (它不知道数据含义)
-------------------------------------------
USB主机控制器
UHCI OHCI EHCI
硬件 -----------
USB设备
UHCI: intel, 低速(1.5Mbps)/全速(12Mbps)
OHCI: microsoft 低速/全速
EHCI: 高速(480Mbps)
USB总线驱动程序的作用
识别USB
设备
1.1 分配地址
1.2 并告诉USB
设备(set address
)
1.3 发出命令获取描述符
描述符的信息可以在include\linux\usb\Ch9.h
看到
查找并安装对应的设备驱动程序
提供USB
读写函数
hub_probe
INIT_WORK(&hub->events, hub_event);
hub_configure
hub_activate
kick_hub_wq
queue_work(hub_wq, &hub->events)
hub_event
port_event
hub_port_connect_change
hub_port_connect
hub_port_init
if (udev->speed < USB_SPEED_SUPER)
dev_info(&udev->dev,"%s %s USB device number %d using %s\n",(udev->config) ? "reset" : "new", speed,devnum, driver_name);
USB设备驱动的核心有两点
1.设备驱动的框架
usb_device
: usb
总线驱动根据插入的usb
设备,1:从这个设备中读取设备描述符(包括设备类型是鼠标还是键盘,还有存贮芯片的大小,厂家id
,设备id
等等),
2:并且总线驱动给插入的usb
设备分配编号(slave id
),
总线驱动根据1
,2
两点信息为该设备构造了一个usb_device
并且挂到usb_bus_type
总线的dev
链表上。
当我们驱动开发人员编写好usb_driver
并且挂到usb_bus_type
的drv
链表上时,两者匹配成功会调用drv
的probe
函数。
usb_driver
: 这个由设备开发人员编写,主要作用是处理:芯片的usb_controller
传给usb_bus
的数据再传给usb_driver
的数据
2.处理usb
总线驱动传给设备驱动的数据:
usb_controller -> usb_bus_driver -> usb_driver(处理硬件通过usb总线传上来的数据)
最重要的是处理数据,这也是USB
设备驱动的核心工作。
usb
设备是单向给usb_controller
传输数据的,当usb
设备插上接口,内核会自动识别此设备获取设备描述符,并且自动根据设备描述符创建一个usb_device
,当操作usb
设备时会产生各种数据(比如位移数据,坐标数据),并且将这些数据传输给usb
总线驱动,usb
总线驱动会有一个函数不断查询usb
设备的接口是否传来数据,如果有就会将这些数据提取进总线并且传递给对应的设备驱动进行数据处理。
usb
设备不可以产生中断,但是usb controller
会根据设备驱动传给它的数据产生中断,中断到cpu
。
usb
总线将来自usb
设备的数据写到buf
之后会产生一个中断,每刷新一次buf
就产生一个中断,这个中断是usb controller
产生的;
usb
设备驱动使用usb
总线提供的读写函数读写usb
设备的核心是:端点描述符;
usb device
传输过来的数据要先放在buf
里面,然后再从buf
里面提取出来填充urb
,urb
作为数据通讯的个单元(两岸通讯的小船:drv
和dev
通讯的小船);
urb
必须通过buf
来填充;
usb_alloc_urb
:申请urb
;
usb_fill_int_urb
(少量数据用中断)/usb_fill_bulk_urb
(大量数据)/usb_fill_control_urb
:填充urb
(include\linux\usb.h
)
这些urb
被填充之后需要提交给一个usb_device
;
dev->umk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //这点很重要
写鼠标驱动时,填充URB
时,
usb_fill_int_urb(dev->umk_urb, udev,
usb_rcvintpipe(udev,endpoint->bEndpointAddress),
dev->umk_urb_data, dev->buflen,
usb_mouse_key_irq_trackpad, dev,endpoint->bInterval);
//因为忘记添加这两句话,白忙活两天
dev->umk_urb->transfer_dma = dev->buf_phy_addr;
dev->umk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //这点很重要
总结:USB
子系统初始化完后,分别在总线上注册了名为"usb"和“hub"的两个驱动,分别对应着usb_register_device_driver
中的usb_probe_device
和 usb_register
–>usb_register_driver
中注册的usb_probe_interface
的probe
函数.
Linux USB驱动分析(一)
usb设备的probe全过程
Linux内核usb子系统
Documentation\driver-api\usb\writing_usb_driver.rst
drivers\usb\usb-skeleton.c(usb设备驱动标准框架,这是一个usb磁盘驱动程序,用户app通过open,wrire,read读写磁盘(u盘))