本文主要分析usb框架的主要数据结构,usb驱动框架的初始化,usb系统模型的建立过程。先贴一张网上找来的图,很清晰很详细。
上图浓缩了usb设备模型的建立流程,再次感谢网上前辈的经验总结。下面以文字总结这个过程:
(1). usb主机控制器驱动的probe过程,分配usb_hcd,然后添加到系统中,一个主控制器对应一条usb总线,一个主控制器绑定着一个root hub,一个root hub对应于一个usb_device,然后注册此root hub,主要是调用usb_new_device。每个usb设备(usb_device)有一种或多种配置,每种配置有一个或多个接口,一个接口有一种或多种设置,一种设置有一个或多个端点。为了获取并解析这些描述符,usb_new_device调用usb_configure_device,然后将设备添加到内核。每个usb设备都有一个控制端点。它通常用于配置设备,获取设备信息,发送命令到设备,或者获取设备的状态报告,usb_new_device中调用了函数usb_create_ep_devs。
(2). 当root hub这个usb_device添加到系统中时,系统中也有一个usb_device_driver(注意,不是usb_driver),一个是对应usb设备,一个对应usb接口。匹配上之后就会调用generic_probe,在这个函数里面调用usb_choose_configuration为设备选择一个合理的配置,到此就可以用选定配置下的所有描述符进行设备配置了。函数usb_set_configuration就是完成此项功能。在函数usb_set_configuration中将设备的所有接口都添加到内核device_add(&intf->dev)。这些接口设备的总线类型也是usb_bus_type,不过设备类型为usb_if_device_type。
(3). 接口添加到系统中了,当然要匹配接口驱动。恰好系统中有一个usb_driver为hub_driver,它是为hub接口准备的。接口又分为hub的接口和usb设备的接口。如果是设备的接口,如果匹配上了后就调用probe函数,做相应的初始化、设备模型建立等工作,例如usb storage驱动,后面会有介绍。如果是hub的接口,就调用hub_probe。
- usb驱动框架的数据结构
[cpp] view plain copy
struct usb_device {
int devnum; //usb设备在一条usb总线上的编号
char devpath[16]; //路径字符串
u32 route;
enum usb_device_state state; //状态
enum usb_device_speed speed; //速度
struct usb_tt *tt; //高低速之间的数据转换
int ttport;
unsigned int toggle[2]; //每一位表示每个端点当前发送或接受的是DATA0还是DATA1
struct usb_device *parent; //父usb设备
struct usb_bus *bus; //设备所在的那条总线
struct usb_host_endpoint ep0; //端点0,比较特殊
struct device dev; //内嵌的device结构
struct usb_device_descriptor descriptor; //设备描述符
struct usb_host_config *config; //usb设备的配置数组
struct usb_host_config *actconfig; //usb设备的当前激活配置
struct usb_host_endpoint *ep_in[16]; //16个in端点
struct usb_host_endpoint *ep_out[16]; //16个out端点
char **rawdescriptors; //指针数组,指向GET_DESCRIPTOR请求获得的配置描述符的结果
unsigned short bus_mA;
u8 portnum; //端口号
u8 level; //层次
unsigned can_submit:1;
unsigned persist_enabled:1;
unsigned have_langid:1;
unsigned authorized:1;
unsigned authenticated:1;
unsigned wusb:1;
int string_langid;
/* static strings from the device */
char *product;
char *manufacturer;
char *serial;
struct list_head filelist;
#ifdef CONFIG_USB_DEVICE_CLASS
struct device *usb_classdev; //类设备
#endif
#ifdef CONFIG_USB_DEVICEFS
struct dentry *usbfs_dentry; //usbfs相关的目录项
#endif
int maxchild; //Hub的端口数
struct usb_device *children[USB_MAXCHILDREN]; //子usb设备
u32 quirks;
atomic_t urbnum;
unsigned long active_duration;
#ifdef CONFIG_PM
unsigned long connect_time;
unsigned do_remote_wakeup:1;
unsigned reset_resume:1;
#endif
struct wusb_dev *wusb_dev;
int slot_id;
};
struct usb_device {
int devnum; //usb设备在一条usb总线上的编号
char devpath[16]; //路径字符串
u32 route;
enum usb_device_state state; //状态
enum usb_device_speed speed; //速度
struct usb_tt *tt; //高低速之间的数据转换
int ttport;
unsigned int toggle[2]; //每一位表示每个端点当前发送或接受的是DATA0还是DATA1
struct usb_device *parent; //父usb设备
struct usb_bus *bus; //设备所在的那条总线
struct usb_host_endpoint ep0; //端点0,比较特殊
struct device dev; //内嵌的device结构
struct usb_device_descriptor descriptor; //设备描述符
struct usb_host_config *config; //usb设备的配置数组
struct usb_host_config *actconfig; //usb设备的当前激活配置
struct usb_host_endpoint *ep_in[16]; //16个in端点
struct usb_host_endpoint *ep_out[16]; //16个out端点
char **rawdescriptors; //指针数组,指向GET_DESCRIPTOR请求获得的配置描述符的结果
unsigned short bus_mA;
u8 portnum; //端口号
u8 level; //层次
unsigned can_submit:1;
unsigned persist_enabled:1;
unsigned have_langid:1;
unsigned authorized:1;
unsigned authenticated:1;
unsigned wusb:1;
int string_langid;
/* static strings from the device */
char *product;
char *manufacturer;
char *serial;
struct list_head filelist;
#ifdef CONFIG_USB_DEVICE_CLASS
struct device *usb_classdev; //类设备
#endif
#ifdef CONFIG_USB_DEVICEFS
struct dentry *usbfs_dentry; //usbfs相关的目录项
#endif
int maxchild; //Hub的端口数
struct usb_device *children[USB_MAXCHILDREN]; //子usb设备
u32 quirks;
atomic_t urbnum;
unsigned long active_duration;
#ifdef CONFIG_PM
unsigned long connect_time;
unsigned do_remote_wakeup:1;
unsigned reset_resume:1;
#endif
struct wusb_dev *wusb_dev;
int slot_id;
};
再来看下usb_device_descriptor
[cpp] view plain copy
struct usb_device_descriptor {
__u8 bLength; //长度
__u8 bDescriptorType; //描述符类型
__le16 bcdUSB; //usb spec 的版本号
__u8 bDeviceClass; //设备的类
__u8 bDeviceSubClass; //设备的子类
__u8 bDeviceProtocol; //设备的协议
__u8 bMaxPacketSize0; //端口0一次可以处理的最大字节数
__le16 idVendor; //厂商ID
__le16 idProduct; //产品ID
__le16 bcdDevice; //设备的版本号
__u8 iManufacturer; //厂商字符串对应的索引
__u8 iProduct; //产品字符串对应的索引
__u8 iSerialNumber; //产品序列号对应的索引
__u8 bNumConfigurations; //当前速度下的配置个数
} attribute ((packed));
struct usb_device_descriptor {
__u8 bLength; //长度
__u8 bDescriptorType; //描述符类型
__le16 bcdUSB; //usb spec 的版本号
__u8 bDeviceClass; //设备的类
__u8 bDeviceSubClass; //设备的子类
__u8 bDeviceProtocol; //设备的协议
__u8 bMaxPacketSize0; //端口0一次可以处理的最大字节数
__le16 idVendor; //厂商ID
__le16 idProduct; //产品ID
__le16 bcdDevice; //设备的版本号
__u8 iManufacturer; //厂商字符串对应的索引
__u8 iProduct; //产品字符串对应的索引
__u8 iSerialNumber; //产品序列号对应的索引
__u8 bNumConfigurations; //当前速度下的配置个数
} attribute ((packed));
[cpp] view plain copy
struct usb_host_config {
struct usb_config_descriptor desc; //usb配置描述符
char *string; /* iConfiguration string, if present */
/* List of any Interface Association Descriptors in this
* configuration. */
struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES]; //该配置包含的接口
/* Interface information available even when this is not the
* active configuration */
struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
unsigned char *extra; /* Extra descriptors */
int extralen;
};
struct usb_host_config {
struct usb_config_descriptor desc; //usb配置描述符
char *string; /* iConfiguration string, if present */
/* List of any Interface Association Descriptors in this
* configuration. */
struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES]; //该配置包含的接口
/* Interface information available even when this is not the
* active configuration */
struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
unsigned char *extra; /* Extra descriptors */
int extralen;
};
[cpp] view plain copy
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} attribute ((packed));
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} attribute ((packed));
[cpp] view plain copy
struct usb_interface {
/* array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface *altsetting; //该接口的设置数组
struct usb_host_interface *cur_altsetting; /* the currently
* active alternate setting */ //该接口的当前设置
unsigned num_altsetting; /* number of alternate settings */
/* If there is an interface association descriptor then it will list
* the associated interfaces */
struct usb_interface_assoc_descriptor *intf_assoc;
int minor; /* minor number this interface is
* bound to */
enum usb_interface_condition condition; /* state of binding */
unsigned sysfs_files_created:1; /* the sysfs attributes exist */
unsigned ep_devs_created:1; /* endpoint "devices" exist */
unsigned unregistering:1; /* unregistration is in progress */
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
unsigned needs_binding:1; /* needs delayed unbind/rebind */
unsigned reset_running:1;
unsigned resetting_device:1; /* true: bandwidth alloc after reset */
struct device dev; /* interface specific device info */
struct device *usb_dev;
atomic_t pm_usage_cnt; /* usage counter for autosuspend */
struct work_struct reset_ws; /* for resets in atomic context */
};
struct usb_interface {
/* array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface *altsetting; //该接口的设置数组
struct usb_host_interface *cur_altsetting; /* the currently
* active alternate setting */ //该接口的当前设置
unsigned num_altsetting; /* number of alternate settings */
/* If there is an interface association descriptor then it will list
* the associated interfaces */
struct usb_interface_assoc_descriptor *intf_assoc;
int minor; /* minor number this interface is
* bound to */
enum usb_interface_condition condition; /* state of binding */
unsigned sysfs_files_created:1; /* the sysfs attributes exist */
unsigned ep_devs_created:1; /* endpoint "devices" exist */
unsigned unregistering:1; /* unregistration is in progress */
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
unsigned needs_binding:1; /* needs delayed unbind/rebind */
unsigned reset_running:1;
unsigned resetting_device:1; /* true: bandwidth alloc after reset */
struct device dev; /* interface specific device info */
struct device *usb_dev;
atomic_t pm_usage_cnt; /* usage counter for autosuspend */
struct work_struct reset_ws; /* for resets in atomic context */
};
[cpp] view plain copy
struct usb_host_interface {
struct usb_interface_descriptor desc; //接口描述符
/* array of desc.bNumEndpoint endpoints associated with this
* interface setting. these will be in no particular order.
*/
struct usb_host_endpoint *endpoint; //该设置用到的端点数组
char *string; /* iInterface string, if present */
unsigned char *extra; /* Extra descriptors */
int extralen;
};
struct usb_host_interface {
struct usb_interface_descriptor desc; //接口描述符
/* array of desc.bNumEndpoint endpoints associated with this
* interface setting. these will be in no particular order.
*/
struct usb_host_endpoint *endpoint; //该设置用到的端点数组
char *string; /* iInterface string, if present */
unsigned char *extra; /* Extra descriptors */
int extralen;
};
[cpp] view plain copy
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} attribute ((packed));
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} attribute ((packed));
[cpp] view plain copy
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc; //端点描述符
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list; //该端点的urb链表
void *hcpriv;
struct ep_device ep_dev; / For sysfs info */ //端点设备
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc; //端点描述符
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list; //该端点的urb链表
void *hcpriv;
struct ep_device ep_dev; / For sysfs info */ //端点设备
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
[cpp] view plain copy
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} attribute ((packed));
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} attribute ((packed));
总结:
一个struct usb_device包含一个设备描述符(usb_device_descriptor)和配置结构数组(struct usb_host_config *)。
一个struct usb_host_config包含一个配置描述符(usb_config_descriptor)和接口结构数组(struct usb_interface)
一个usb_interface包含设置结构数组(struct usb_host_interface *),因为一个接口可以有多个设置
一个usb_host_interface包含一个接口描述符和端点结构数组(struct usb_host_endpoint *)
一个usb_host_endpoint包含一个端点描述符。
[cpp] view plain copy
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; //动态id
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
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;
};
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; //动态id
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
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_driver是面向接口的,系统中有好多接口驱动,如hub_driver,usb_storage_driver。usb_device_driver是面向设备的,只有一个usb_generic_driver。
[cpp] view plain copy
struct usb_hcd {
/*
* housekeeping
*/
struct usb_bus self; /* hcd is-a bus */ //hcd是一个usb总线
struct kref kref; /* reference counter */ //引用计数
const char *product_desc; /* product/vendor string */ //产品描述
int speed; /* Speed for this roothub.
* May be different from
* hcd->driver->flags & HCD_MASK
*/
char irq_descr[24]; /* driver + bus # */
struct timer_list rh_timer; /* drives root-hub polling */ //root hub轮询定时器
struct urb *status_urb; /* the current status urb */
#ifdef CONFIG_USB_SUSPEND
struct work_struct wakeup_work; /* for remote wakeup */
#endif
/*
* hardware info/state
*/
const struct hc_driver *driver; /* hw-specific hooks */ //hc驱动
/* Flags that need to be manipulated atomically because they can
* change while the host controller is running. Always use
* set_bit() or clear_bit() to change their values.
*/
unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0 /* at full power /
#define HCD_FLAG_SAW_IRQ 1
#define HCD_FLAG_POLL_RH 2 / poll for rh status? /
#define HCD_FLAG_POLL_PENDING 3 / status has changed? /
#define HCD_FLAG_WAKEUP_PENDING 4 / root hub is resuming? /
#define HCD_FLAG_RH_RUNNING 5 / root hub is running? /
#define HCD_FLAG_DEAD 6 / controller has died? */
/* The flags can be tested using these macros; they are likely to
* be slightly faster than test_bit().
*/
#define HCD_HW_ACCESSIBLE(hcd) ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))
#define HCD_SAW_IRQ(hcd) ((hcd)->flags & (1U << HCD_FLAG_SAW_IRQ))
#define HCD_POLL_RH(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_RH))
#define HCD_POLL_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))
#define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
#define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
#define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))
/* Flags that get set only during HCD registration or removal. */
unsigned rh_registered:1;/* is root hub registered? */
unsigned rh_pollable:1; /* may we poll the root hub? */
unsigned msix_enabled:1; /* driver has MSI-X enabled? */
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
unsigned uses_new_polling:1;
unsigned wireless:1; /* Wireless USB HCD */
unsigned authorized_default:1;
unsigned has_tt:1; /* Integrated TT in root hub */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
u64 rsrc_start; /* memory/io resource start */
u64 rsrc_len; /* memory/io resource length */
unsigned power_budget; /* in mA, 0 = no limit */
/* bandwidth_mutex should be taken before adding or removing
* any new bus bandwidth constraints:
* 1. Before adding a configuration for a new device.
* 2. Before removing the configuration to put the device into
* the addressed state.
* 3. Before selecting a different configuration.
* 4. Before selecting an alternate interface setting.
*
* bandwidth_mutex should be dropped after a successful control message
* to the device, or resetting the bandwidth after a failed attempt.
*/
struct mutex *bandwidth_mutex;
struct usb_hcd *shared_hcd;
struct usb_hcd *primary_hcd;
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool[HCD_BUFFER_POOLS];
int state;
define __ACTIVE 0x01
define __SUSPEND 0x04
define __TRANSIENT 0x80
define HC_STATE_HALT 0
define HC_STATE_RUNNING (__ACTIVE)
define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
define HC_STATE_SUSPENDED (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
/* more shared queuing code would be good; it should support
* smarter scheduling, handle transaction translators, etc;
* input size of periodic table to an interrupt scheduler.
* (ohci 32, uhci 1024, ehci 256/512/1024).
*/
/* The HC driver's private data is stored at the end of
* this structure.
*/
unsigned long hcd_priv[0]
__attribute__ ((aligned(sizeof(unsigned long))));
};
struct usb_hcd {
/*
* housekeeping
*/
struct usb_bus self; /* hcd is-a bus */ //hcd是一个usb总线
struct kref kref; /* reference counter */ //引用计数
const char *product_desc; /* product/vendor string */ //产品描述
int speed; /* Speed for this roothub.
* May be different from
* hcd->driver->flags & HCD_MASK
*/
char irq_descr[24]; /* driver + bus # */
struct timer_list rh_timer; /* drives root-hub polling */ //root hub轮询定时器
struct urb *status_urb; /* the current status urb */
#ifdef CONFIG_USB_SUSPEND
struct work_struct wakeup_work; /* for remote wakeup */
#endif
/*
* hardware info/state
*/
const struct hc_driver *driver; /* hw-specific hooks */ //hc驱动
/* Flags that need to be manipulated atomically because they can
* change while the host controller is running. Always use
* set_bit() or clear_bit() to change their values.
*/
unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0 /* at full power /
#define HCD_FLAG_SAW_IRQ 1
#define HCD_FLAG_POLL_RH 2 / poll for rh status? /
#define HCD_FLAG_POLL_PENDING 3 / status has changed? /
#define HCD_FLAG_WAKEUP_PENDING 4 / root hub is resuming? /
#define HCD_FLAG_RH_RUNNING 5 / root hub is running? /
#define HCD_FLAG_DEAD 6 / controller has died? */
/* The flags can be tested using these macros; they are likely to
* be slightly faster than test_bit().
*/
#define HCD_HW_ACCESSIBLE(hcd) ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))
#define HCD_SAW_IRQ(hcd) ((hcd)->flags & (1U << HCD_FLAG_SAW_IRQ))
#define HCD_POLL_RH(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_RH))
#define HCD_POLL_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))
#define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
#define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
#define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))
/* Flags that get set only during HCD registration or removal. */
unsigned rh_registered:1;/* is root hub registered? */
unsigned rh_pollable:1; /* may we poll the root hub? */
unsigned msix_enabled:1; /* driver has MSI-X enabled? */
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
unsigned uses_new_polling:1;
unsigned wireless:1; /* Wireless USB HCD */
unsigned authorized_default:1;
unsigned has_tt:1; /* Integrated TT in root hub */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
u64 rsrc_start; /* memory/io resource start */
u64 rsrc_len; /* memory/io resource length */
unsigned power_budget; /* in mA, 0 = no limit */
/* bandwidth_mutex should be taken before adding or removing
* any new bus bandwidth constraints:
* 1. Before adding a configuration for a new device.
* 2. Before removing the configuration to put the device into
* the addressed state.
* 3. Before selecting a different configuration.
* 4. Before selecting an alternate interface setting.
*
* bandwidth_mutex should be dropped after a successful control message
* to the device, or resetting the bandwidth after a failed attempt.
*/
struct mutex *bandwidth_mutex;
struct usb_hcd *shared_hcd;
struct usb_hcd *primary_hcd;
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool[HCD_BUFFER_POOLS];
int state;
define __ACTIVE 0x01
define __SUSPEND 0x04
define __TRANSIENT 0x80
define HC_STATE_HALT 0
define HC_STATE_RUNNING (__ACTIVE)
define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
define HC_STATE_SUSPENDED (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
/* more shared queuing code would be good; it should support
* smarter scheduling, handle transaction translators, etc;
* input size of periodic table to an interrupt scheduler.
* (ohci 32, uhci 1024, ehci 256/512/1024).
*/
/* The HC driver's private data is stored at the end of
* this structure.
*/
unsigned long hcd_priv[0]
__attribute__ ((aligned(sizeof(unsigned long))));
};
[cpp] view plain copy
struct hc_driver {
const char description; / “ehci-hcd” etc */
const char product_desc; / product/vendor string /
size_t hcd_priv_size; / size of private data */
/* irq handler */
irqreturn_t (*irq) (struct usb_hcd *hcd);
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) /
#define HCD_LOCAL_MEM 0x0002 / HC needs local memory /
#define HCD_SHARED 0x0004 / Two (or more) usb_hcds share HW /
#define HCD_USB11 0x0010 / USB 1.1 /
#define HCD_USB2 0x0020 / USB 2.0 /
#define HCD_USB3 0x0040 / USB 3.0 */
#define HCD_MASK 0x0070
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd);
int (*start) (struct usb_hcd *hcd);
/* NOTE: these suspend/resume calls relate to the HC as
* a whole, not just the root hub; they're for PCI bus glue.
*/
/* called after suspending the hub, before entering D3 etc */
int (*pci_suspend)(struct usb_hcd *hcd, bool do_wakeup);
/* called after entering D0 (etc), before resuming the hub */
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
/* shutdown HCD */
void (*shutdown) (struct usb_hcd *hcd);
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/*
* (optional) these hooks allow an HCD to override the default DMA
* mapping and unmapping routines. In general, they shouldn't be
* necessary unless the host controller has special DMA requirements,
* such as alignment contraints. If these are not specified, the
* general usb_hcd_(un)?map_urb_for_dma functions will be used instead
* (and it may be a good idea to call these functions in your HCD
* implementation)
*/
int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags);
void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
/* (optional) reset any endpoint state such as sequence number
and current window */
void (*endpoint_reset)(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
/* root hub support */
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
int (*hub_control) (struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int (*bus_suspend)(struct usb_hcd *);
int (*bus_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
/* force handover of high-speed port to full-speed companion */
void (*relinquish_port)(struct usb_hcd *, int);
/* has a port been handed over to a companion? */
int (*port_handed_over)(struct usb_hcd *, int);
/* CLEAR_TT_BUFFER completion callback */
void (*clear_tt_buffer_complete)(struct usb_hcd *,
struct usb_host_endpoint *);
/* xHCI specific functions */
/* Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
/* Called by usb_disconnect to free HC device structures */
void (*free_dev)(struct usb_hcd *, struct usb_device *);
/* Change a group of bulk endpoints to support multiple stream IDs */
int (*alloc_streams)(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
unsigned int num_streams, gfp_t mem_flags);
/* Reverts a group of bulk endpoints back to not using stream IDs.
* Can fail if we run out of memory.
*/
int (*free_streams)(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
gfp_t mem_flags);
/* Bandwidth computation functions */
/* Note that add_endpoint() can only be called once per endpoint before
* check_bandwidth() or reset_bandwidth() must be called.
* drop_endpoint() can only be called once per endpoint also.
* A call to xhci_drop_endpoint() followed by a call to
* xhci_add_endpoint() will add the endpoint to the schedule with
* possibly new parameters denoted by a different endpoint descriptor
* in usb_host_endpoint. A call to xhci_add_endpoint() followed by a
* call to xhci_drop_endpoint() is not allowed.
*/
/* Allocate endpoint resources and add them to a new schedule */
int (*add_endpoint)(struct usb_hcd *, struct usb_device *,
struct usb_host_endpoint *);
/* Drop an endpoint from a new schedule */
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *,
struct usb_host_endpoint *);
/* Check that a new hardware configuration, set using
* endpoint_enable and endpoint_disable, does not exceed bus
* bandwidth. This must be called before any set configuration
* or set interface requests are sent to the device.
*/
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Reset the device schedule to the last known good schedule,
* which was set from a previous successful call to
* check_bandwidth(). This reverts any add_endpoint() and
* drop_endpoint() calls since that last successful call.
* Used for when a check_bandwidth() call fails due to resource
* or bandwidth constraints.
*/
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Returns the hardware-chosen device address */
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
/* Notifies the HCD after a hub descriptor is fetched.
* Will block.
*/
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
int (*reset_device)(struct usb_hcd *, struct usb_device *);
/* Notifies the HCD after a device is connected and its
* address is set
*/
int (*update_device)(struct usb_hcd *, struct usb_device *);
};
struct hc_driver {
const char description; / “ehci-hcd” etc */
const char product_desc; / product/vendor string /
size_t hcd_priv_size; / size of private data */
/* irq handler */
irqreturn_t (*irq) (struct usb_hcd *hcd);
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) /
#define HCD_LOCAL_MEM 0x0002 / HC needs local memory /
#define HCD_SHARED 0x0004 / Two (or more) usb_hcds share HW /
#define HCD_USB11 0x0010 / USB 1.1 /
#define HCD_USB2 0x0020 / USB 2.0 /
#define HCD_USB3 0x0040 / USB 3.0 */
#define HCD_MASK 0x0070
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd);
int (*start) (struct usb_hcd *hcd);
/* NOTE: these suspend/resume calls relate to the HC as
* a whole, not just the root hub; they're for PCI bus glue.
*/
/* called after suspending the hub, before entering D3 etc */
int (*pci_suspend)(struct usb_hcd *hcd, bool do_wakeup);
/* called after entering D0 (etc), before resuming the hub */
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
/* shutdown HCD */
void (*shutdown) (struct usb_hcd *hcd);
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/*
* (optional) these hooks allow an HCD to override the default DMA
* mapping and unmapping routines. In general, they shouldn't be
* necessary unless the host controller has special DMA requirements,
* such as alignment contraints. If these are not specified, the
* general usb_hcd_(un)?map_urb_for_dma functions will be used instead
* (and it may be a good idea to call these functions in your HCD
* implementation)
*/
int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags);
void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
/* (optional) reset any endpoint state such as sequence number
and current window */
void (*endpoint_reset)(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
/* root hub support */
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
int (*hub_control) (struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int (*bus_suspend)(struct usb_hcd *);
int (*bus_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
/* force handover of high-speed port to full-speed companion */
void (*relinquish_port)(struct usb_hcd *, int);
/* has a port been handed over to a companion? */
int (*port_handed_over)(struct usb_hcd *, int);
/* CLEAR_TT_BUFFER completion callback */
void (*clear_tt_buffer_complete)(struct usb_hcd *,
struct usb_host_endpoint *);
/* xHCI specific functions */
/* Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
/* Called by usb_disconnect to free HC device structures */
void (*free_dev)(struct usb_hcd *, struct usb_device *);
/* Change a group of bulk endpoints to support multiple stream IDs */
int (*alloc_streams)(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
unsigned int num_streams, gfp_t mem_flags);
/* Reverts a group of bulk endpoints back to not using stream IDs.
* Can fail if we run out of memory.
*/
int (*free_streams)(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
gfp_t mem_flags);
/* Bandwidth computation functions */
/* Note that add_endpoint() can only be called once per endpoint before
* check_bandwidth() or reset_bandwidth() must be called.
* drop_endpoint() can only be called once per endpoint also.
* A call to xhci_drop_endpoint() followed by a call to
* xhci_add_endpoint() will add the endpoint to the schedule with
* possibly new parameters denoted by a different endpoint descriptor
* in usb_host_endpoint. A call to xhci_add_endpoint() followed by a
* call to xhci_drop_endpoint() is not allowed.
*/
/* Allocate endpoint resources and add them to a new schedule */
int (*add_endpoint)(struct usb_hcd *, struct usb_device *,
struct usb_host_endpoint *);
/* Drop an endpoint from a new schedule */
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *,
struct usb_host_endpoint *);
/* Check that a new hardware configuration, set using
* endpoint_enable and endpoint_disable, does not exceed bus
* bandwidth. This must be called before any set configuration
* or set interface requests are sent to the device.
*/
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Reset the device schedule to the last known good schedule,
* which was set from a previous successful call to
* check_bandwidth(). This reverts any add_endpoint() and
* drop_endpoint() calls since that last successful call.
* Used for when a check_bandwidth() call fails due to resource
* or bandwidth constraints.
*/
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Returns the hardware-chosen device address */
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
/* Notifies the HCD after a hub descriptor is fetched.
* Will block.
*/
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
int (*reset_device)(struct usb_hcd *, struct usb_device *);
/* Notifies the HCD after a device is connected and its
* address is set
*/
int (*update_device)(struct usb_hcd *, struct usb_device *);
};
[cpp] view plain copy
struct usb_bus {
struct device controller; / host/master side hardware / //主机控制器端的device结构
int busnum; / Bus number (in order of reg) */ //总线编号
const char bus_name; / stable id (PCI slot_name etc) / //总线名字
u8 uses_dma; / Does the host controller use DMA? /
u8 uses_pio_for_control; /
* Does the host controller use PIO
* for control transfers?
/
u8 otg_port; / 0, or number of OTG/HNP port /
unsigned is_b_host:1; / true during some HNP roleswitches /
unsigned b_hnp_enable:1; / OTG: did A-Host enable HNP? /
unsigned sg_tablesize; / 0 or largest number of sg list entries */
int devnum_next; /* Next open device number in
* round-robin allocation */
struct usb_devmap devmap; /* device address allocation map */
struct usb_device *root_hub; /* Root hub */ //指向根hub
struct usb_bus *hs_companion; /* Companion EHCI bus, if any */
struct list_head bus_list; /* list of busses */ //链接到所有的ub总线的连接件
int bandwidth_allocated; /* on this bus: how much of the time
* reserved for periodic (intr/iso)
* requests is used, on average?
* Units: microseconds/frame.
* Limits: Full/low speed reserve 90%,
* while high speed reserves 80%.
*/
int bandwidth_int_reqs; /* number of Interrupt requests */ //中断传输的数量
int bandwidth_isoc_reqs; /* number of Isoc. requests */ //等时传输的数量
#ifdef CONFIG_USB_DEVICEFS
struct dentry usbfs_dentry; / usbfs dentry entry for the bus */
#endif
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
struct mon_bus mon_bus; / non-null when associated /
int monitored; / non-zero when monitored */
#endif
};
struct usb_bus {
struct device controller; / host/master side hardware / //主机控制器端的device结构
int busnum; / Bus number (in order of reg) */ //总线编号
const char bus_name; / stable id (PCI slot_name etc) / //总线名字
u8 uses_dma; / Does the host controller use DMA? /
u8 uses_pio_for_control; /
* Does the host controller use PIO
* for control transfers?
/
u8 otg_port; / 0, or number of OTG/HNP port /
unsigned is_b_host:1; / true during some HNP roleswitches /
unsigned b_hnp_enable:1; / OTG: did A-Host enable HNP? /
unsigned sg_tablesize; / 0 or largest number of sg list entries */
int devnum_next; /* Next open device number in
* round-robin allocation */
struct usb_devmap devmap; /* device address allocation map */
struct usb_device *root_hub; /* Root hub */ //指向根hub
struct usb_bus *hs_companion; /* Companion EHCI bus, if any */
struct list_head bus_list; /* list of busses */ //链接到所有的ub总线的连接件
int bandwidth_allocated; /* on this bus: how much of the time
* reserved for periodic (intr/iso)
* requests is used, on average?
* Units: microseconds/frame.
* Limits: Full/low speed reserve 90%,
* while high speed reserves 80%.
*/
int bandwidth_int_reqs; /* number of Interrupt requests */ //中断传输的数量
int bandwidth_isoc_reqs; /* number of Isoc. requests */ //等时传输的数量
#ifdef CONFIG_USB_DEVICEFS
struct dentry usbfs_dentry; / usbfs dentry entry for the bus */
#endif
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
struct mon_bus mon_bus; / non-null when associated /
int monitored; / non-zero when monitored */
#endif
};
2. usb框架的初始化
[cpp] view plain copy
static int __init usb_init(void)
{
int retval;
if (nousb) {
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
retval = usb_debugfs_init(); //usb debugfs初始化
if (retval)
goto out;
retval = bus_register(&usb_bus_type); //注册usb 总线
if (retval)
goto bus_register_failed;
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); //注册usb总线的通知块
if (retval)
goto bus_notifier_failed;
retval = usb_major_init(); //注册主设备号为180的usb字符设备
if (retval)
goto major_init_failed;
retval = usb_register(&usbfs_driver); //注册一个usb_driver usbfs_driver
if (retval)
goto driver_register_failed;
retval = usb_devio_init(); //注册主设备号为189,次设备数为64*128
if (retval)
goto usb_devio_init_failed;
retval = usbfs_init(); //注册usb_fs_type文件系统
if (retval)
goto fs_init_failed;
retval = usb_hub_init(); //注册hub_driver,创建khub内核线程
if (retval)
goto hub_init_failed;
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //注册usb系统唯一的usb_device_driver usb_generic_driver
if (!retval)
goto out;
usb_hub_cleanup();
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
major_init_failed:
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
usb_debugfs_cleanup();
out:
return retval;
}
static int __init usb_init(void)
{
int retval;
if (nousb) {
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
retval = usb_debugfs_init(); //usb debugfs初始化
if (retval)
goto out;
retval = bus_register(&usb_bus_type); //注册usb 总线
if (retval)
goto bus_register_failed;
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); //注册usb总线的通知块
if (retval)
goto bus_notifier_failed;
retval = usb_major_init(); //注册主设备号为180的usb字符设备
if (retval)
goto major_init_failed;
retval = usb_register(&usbfs_driver); //注册一个usb_driver usbfs_driver
if (retval)
goto driver_register_failed;
retval = usb_devio_init(); //注册主设备号为189,次设备数为64*128
if (retval)
goto usb_devio_init_failed;
retval = usbfs_init(); //注册usb_fs_type文件系统
if (retval)
goto fs_init_failed;
retval = usb_hub_init(); //注册hub_driver,创建khub内核线程
if (retval)
goto hub_init_failed;
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //注册usb系统唯一的usb_device_driver usb_generic_driver
if (!retval)
goto out;
usb_hub_cleanup();
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
major_init_failed:
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
usb_debugfs_cleanup();
out:
return retval;
}
[cpp] view plain copy
static int usb_debugfs_init(void)
{
usb_debug_root = debugfs_create_dir(“usb”, NULL);
if (!usb_debug_root)
return -ENOENT;
usb_debug_devices = debugfs_create_file("devices", 0444,
usb_debug_root, NULL,
&usbfs_devices_fops);
if (!usb_debug_devices) {
debugfs_remove(usb_debug_root);
usb_debug_root = NULL;
return -ENOENT;
}
return 0;
}
static int usb_debugfs_init(void)
{
usb_debug_root = debugfs_create_dir(“usb”, NULL);
if (!usb_debug_root)
return -ENOENT;
usb_debug_devices = debugfs_create_file("devices", 0444,
usb_debug_root, NULL,
&usbfs_devices_fops);
if (!usb_debug_devices) {
debugfs_remove(usb_debug_root);
usb_debug_root = NULL;
return -ENOENT;
}
return 0;
}
[cpp] view plain copy
int usb_major_init(void)
{
int error;
error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
if (error)
printk(KERN_ERR "Unable to get major %d for usb devices\n",
USB_MAJOR);
return error;
}
int usb_major_init(void)
{
int error;
error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
if (error)
printk(KERN_ERR "Unable to get major %d for usb devices\n",
USB_MAJOR);
return error;
}
[cpp] view plain copy
int __init usb_devio_init(void)
{
int retval;
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device");
if (retval) {
printk(KERN_ERR "Unable to register minors for usb_device\n");
goto out;
}
cdev_init(&usb_device_cdev, &usbdev_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) {
printk(KERN_ERR "Unable to get usb_device major %d\n",
USB_DEVICE_MAJOR);
goto error_cdev;
}
#ifdef CONFIG_USB_DEVICE_CLASS
usb_classdev_class = class_create(THIS_MODULE, “usb_device”);
if (IS_ERR(usb_classdev_class)) {
printk(KERN_ERR “Unable to register usb_device class\n”);
retval = PTR_ERR(usb_classdev_class);
cdev_del(&usb_device_cdev);
usb_classdev_class = NULL;
goto out;
}
/* devices of this class shadow the major:minor of their parent
* device, so clear ->dev_kobj to prevent adding duplicate entries
* to /sys/dev
*/
usb_classdev_class->dev_kobj = NULL;
#endif
usb_register_notify(&usbdev_nb);
out:
return retval;
error_cdev:
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
}
int __init usb_devio_init(void)
{
int retval;
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device");
if (retval) {
printk(KERN_ERR "Unable to register minors for usb_device\n");
goto out;
}
cdev_init(&usb_device_cdev, &usbdev_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) {
printk(KERN_ERR "Unable to get usb_device major %d\n",
USB_DEVICE_MAJOR);
goto error_cdev;
}
#ifdef CONFIG_USB_DEVICE_CLASS
usb_classdev_class = class_create(THIS_MODULE, “usb_device”);
if (IS_ERR(usb_classdev_class)) {
printk(KERN_ERR “Unable to register usb_device class\n”);
retval = PTR_ERR(usb_classdev_class);
cdev_del(&usb_device_cdev);
usb_classdev_class = NULL;
goto out;
}
/* devices of this class shadow the major:minor of their parent
* device, so clear ->dev_kobj to prevent adding duplicate entries
* to /sys/dev
*/
usb_classdev_class->dev_kobj = NULL;
#endif
usb_register_notify(&usbdev_nb);
out:
return retval;
error_cdev:
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
}
[cpp] view plain copy
int usb_hub_init(void)
{
if (usb_register(&hub_driver) < 0) {
printk(KERN_ERR “%s: can’t register hub driver\n”,
usbcore_name);
return -1;
}
khubd_task = kthread_run(hub_thread, NULL, "khubd");
if (!IS_ERR(khubd_task))
return 0;
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
return -1;
}
int usb_hub_init(void)
{
if (usb_register(&hub_driver) < 0) {
printk(KERN_ERR “%s: can’t register hub driver\n”,
usbcore_name);
return -1;
}
khubd_task = kthread_run(hub_thread, NULL, "khubd");
if (!IS_ERR(khubd_task))
return 0;
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
return -1;
}
[cpp] view plain copy
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = (char *) 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);
if (!retval) {
pr_info("%s: registered new device driver %s\n",
usbcore_name, new_udriver->name);
usbfs_update_special();
} else {
printk(KERN_ERR "%s: error %d registering device "
" driver %s\n",
usbcore_name, retval, new_udriver->name);
}
return retval;
}
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = (char *) 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);
if (!retval) {
pr_info("%s: registered new device driver %s\n",
usbcore_name, new_udriver->name);
usbfs_update_special();
} else {
printk(KERN_ERR "%s: error %d registering device "
" driver %s\n",
usbcore_name, retval, new_udriver->name);
}
return retval;
}
原文地址:
https://blog.csdn.net/duan_xiaosu/article/details/68487314