USB学习综述--usb基础知识,设备配置接口端点
USB类型与速度
usb1.0 low-speed 1.5Mbps
usb1.1 full-speed 12Mbps
usb2.0 high-speed 480Mbps
usb3.0 super-speed 4.8Gbps
USB组成
综述
可以在/sys/bus/usb/device路径查看usb信息
lsusb也可以快速查询
设备》配置》接口》端点
手机是一个设备,将其配置为摄像,接口就是摄像的不同功能,端点就是调整焦距的通道
USB 描述符主要有四种:设备描述符、配置描述符、接口描述符和端点描述符,都放在USB 设备中的EEPROM
wc –l ./* 可以显示每一个文件的行数,方便查看代码量
)
其中2-1:1.0表示2号总线,也就是2号 Root Hub,1就是这里我们说的usb_device的 devpath,1 表示配置为 1 号, 0 表示接口号为 0。
USBcore
)
lsmod中可以查询到ehci_hcd 或 uhci_hcd就是usb主机控制器,OHCI/UHCI,这都是在 USB spec 1.0 时, 2.0 时代推出了 EHCI,高速设备应运而生
在usbcore目录下,config USB_DEVICEFS开启关于 usbfs 文件系统的。 usbfs 文件系统挂载在/proc/bus/usb 上。
在/driver/usb/core/usb.c中初始化usb,如下:
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();
usb_acpi_register();
retval = bus_register(&usb_bus_type);
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
retval = usb_major_init();
retval = usb_register(&usbfs_driver);
retval = usb_devio_init();
retval = usb_hub_init();
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
}
USB设备
Linux 设备模型中的 device 落实在 USB 子系统,成了两个结构:一个是 struct usb_device,一个是 struct usb_interface
USB的设备号
//USB的设备号
#define USB_MAJOR 180
#define USB_DEVICE_MAJOR 189
struct usb_device {
int devnum;
char devpath[16];
u32 route;
enum usb_device_state state;
enum usb_device_speed speed;
unsigned int rx_lanes;
unsigned int tx_lanes;
enum usb_ssp_rate ssp_rate;
struct usb_tt *tt;
int ttport;
unsigned int toggle[2];
struct usb_device *parent;
struct usb_bus *bus;
struct usb_host_endpoint ep0;
struct device dev;
struct usb_device_descriptor descriptor;
struct usb_host_bos *bos;
struct usb_host_config *config;
struct usb_host_config *actconfig;
struct usb_host_endpoint *ep_in[16];
struct usb_host_endpoint *ep_out[16];
char **rawdescriptors;
unsigned short bus_mA;
u8 portnum;
u8 level;
u8 devaddr;
unsigned can_submit:1;
unsigned persist_enabled:1;
unsigned reset_in_progress:1;
unsigned have_langid:1;
unsigned authorized:1;
unsigned authenticated:1;
unsigned wusb:1;
unsigned lpm_capable:1;
unsigned lpm_devinit_allow:1;
unsigned usb2_hw_lpm_capable:1;
unsigned usb2_hw_lpm_besl_capable:1;
unsigned usb2_hw_lpm_enabled:1;
unsigned usb2_hw_lpm_allowed:1;
unsigned usb3_lpm_u1_enabled:1;
unsigned usb3_lpm_u2_enabled:1;
int string_langid;
/* static strings from the device */
char *product;
char *manufacturer;
char *serial;
struct list_head filelist;
int maxchild;
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;
unsigned port_is_suspended:1;
#endif
struct wusb_dev *wusb_dev;
int slot_id;
struct usb2_lpm_parameters l1_params;
struct usb3_lpm_parameters u1_params;
struct usb3_lpm_parameters u2_params;
unsigned lpm_disable_count;
u16 hub_delay;
unsigned use_generic_driver:1;
};
USB设备描述符
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} __attribute__ ((packed));
USB的接口
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 resetting_device:1; /* true: bandwidth alloc after reset */
unsigned authorized:1; /* used for interface authorization */
struct device dev; /* interface specific device info */
struct device *usb_dev;
struct work_struct reset_ws; /* for resets in atomic context */
};
USB配置
USB设备的配置
struct usb_host_config {
struct usb_config_descriptor desc;
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;
};
USB配置描述符
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
USB接口
设备可以有多个接口,每个接口代表一个功能,每个接口对应着一个驱动。
接口的设置如下
/* host-side wrapper for one interface setting's parsed descriptors */
struct usb_host_interface {
struct usb_interface_descriptor desc;
int extralen;
unsigned char *extra; /* Extra descriptors */
/* array of desc.bNumEndpoints endpoints associated with this
* interface setting. these will be in no particular order.
*/
struct usb_host_endpoint *endpoint;
char *string; /* iInterface string, if present */
};
接口描述符如下
/* 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));
bInterfaceClass与bInterfaceSubClass是对usb设备的分类,比如Mass Storage 的 Class 就是 0x08, Hub的 Class 就是 0x09。
USB端点
端点0
端点0可以是in端点也可以是out端点,用来实现默认的控制管道来控制设备
传输方式
控制传输:用来传送控制信息,端点0
中断传输:USB键盘鼠标
批量传输:U盘
等时传输:视频
PIPE_ISOCHRONOUS 就是标志等时通道, PIPE_INTERRUPT 就是中断通道, PIPE_CONTROL 就是控制通道, PIPE_BULK 就是批量通道
端点是 USB 数据传输的终点。看一看它在内核中的定义。
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp;
struct list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
int streams;
};
端点描述符
/* 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接口驱动
向接口驱动中添加新的厂商和产品 id ,在/sys/bus/usb/drivers 的new_id 写入id即可,如echo 0557 2008 > /sys/bus/usb/drivers/foo_driver/new_id
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;
const struct attribute_group **dev_groups;
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设备驱动
struct usb_device_driver {
const char *name;
bool (*match) (struct usb_device *udev);
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);
const struct attribute_group **dev_groups;
struct usbdrv_wrap drvwrap;
const struct usb_device_id *id_table;
unsigned int supports_autosuspend:1;
unsigned int generic_subclass:1;
};
USB设备流程
- usb_alloc_dev当有hub检测到新的usb插入时,分配usb_device,调用设备模型提供的接口将设备添加到 USB总线的设备列表里,然后 USB 总线会遍历驱动列表里的每个驱动,调用自己的 match 函数看它们和你的设备或接口是否匹配,就走到 match 函数了。
- 初始化usb_device结构体,包括设备状态,支持速度,设备等级等,设备从powered状态进入Default 状态,再进入Address 状态,需要函数 usb_control_ msg,给设备发送 SET_ADDRESS 请求
- usb_control_ msg调用函数usb_internal_control_ msg,以一个 struct urb 结构体为中心,以 usb_alloc_urb、usb_fill_control_urb、 usb_start_wait_urb 三个函数为基本点。usb_alloc_urb创建一个 urb;usb_fill_control_urb 函数,进行初始化控制 urb;usb_start_wait_urb 函数,将 urb 提交给 USB Core,以便分配给特定的主机控制器驱动进行处理,然后默默地等待处理结果,或者超时;
kref, urb 的引用计数,控制kref就可以控制urb存亡
struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
int unlinked; /* unlink error code */
void *hcpriv; /* private data for host controller */
atomic_t use_count; /* concurrent submissions counter */
atomic_t reject; /* submissions will fail */
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
struct list_head anchor_list; /* the URB may be anchored */
struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
unsigned int stream_id; /* (in) stream ID */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
struct scatterlist *sg; /* (in) scatter gather buffer list */
int num_mapped_sgs; /* (internal) mapped sg entries */
int num_sgs; /* (in) number of entries in the sg list */
u32 transfer_buffer_length; /* (in) data buffer length */
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
int start_frame; /* (modify) start frame (ISO) */
int number_of_packets; /* (in) number of ISO packets */
int interval; /* (modify) transfer interval
* (INT/ISO) */
int error_count; /* (return) number of ISO errors */
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[];
/* (in) ISO ONLY */
};
- urb_list,每个端点都会有的那个 urb 队列; dev,它表示 urb 要去的那个 USB 设备; pipe,urb 到达端点之前,需要经过一个通往端点的管道,就是这个 pipe,端点有四种,又有OUT和IN,就有八种管道;status, urb 的当前状态;transfer_flags,一些标记;
- usb_submit_urb 函数在urb.c中,对 urb 做些前期处理之后扔给 HCD;对于控制/批量/中断传输,实际上很多时候你可以不用创建 urb,不用对它初始化,不用调用 usb_submit_urb 来提交, USB Core 将这个过程分别封装在了 usb_control_ msg、usb_bulk_ msg 和 usb_interrupt_ msg 这三个函数中,不同的是它们的实现是同步的,会去等待传输完全结束。
- HCD最重要的就是drivers/usb/core/hcd.h 中定义的 struct usb_hcd;CONFIG_USB_MON,一个所谓的 USB Monitor,也就是 USB 监视器就会编进内核。这个 Monitor 是用来监视 USB 总线上的底层通信流的,相关的文件都在 drivers/usb/mon 下面。
- struct usb_hcd中的kref, USB 主机控制器的引用计数;
- 设备进入Configured状态,使用函数usb_get_device_descriptor()先获取设备描述符,接下来就要获得各个配置的配置描述符,函数usb_get_configuration
- 数据不管是配置描述符、接口描述符还是端点描述符都挤在一起,所以得想办法将它们给分开,于是用到了 usb_parse_configuration()函数,调用到了usb_parse_configuration、 usb_parse_interface 和 usb_parse_endpoint三个函数。
USB驱动流程
USB状态流程:power>default>address>configured
- usb_register_device_driver开始,将usb_generic_driver 注册给系统,usb_generic_driver 和 USB 设备匹配成功后,调用usb_probe_
device()函数,调用generic_probe()对你的设备进行进一步的审查,从而让设备进入Configured 状态;- Core 配置设备使用的是 message.c 里的 usb_set_configuration 函数
- usb_disable_device 函数处于Configured 状 态 了, 退 回 到 Address状态。
USB字符串描述符
字符串描述符的地位仅次于设备/配置/接口/端点四大描述符,那么四大设备必须支持它。而字符串描述符对设备来说则是可选的。
usb_cache_string获得字符串描述符,调用usb_string()
USB-HUB
hub作用
存在只是为了支持更多设备连接到 USB 总线上来
usb_hub_init()函数初始化hub
第一个函数, usb_alloc_dev(),一个 struct usb_device 结构体指针,申请内存,这个结构体指针可不是为 Hub 准备的,它正是为了 Hub 这个端口所接的设备而申请的,别忘了我们此时此刻的上下文,之所以进入这个循环,是因为我们的 Hub 检测到某个端口有设备连接,所以, Hub驱动就义不容辞地要为该设备做点什么。
第二个函数, usb_set_device_state(),这个函数用来设置设备的状态,在 struct usb_device结构体中,有一个成员 enum usb_device_state state,这一刻会把这个设备的状态设置为USB_STATE_POWERED,即上电状态。
第三个函数, choose_address(),为设备选择一个地址。后面会用实例来查看效果。
第四个函数, hub_port_init(),端口初始化,主要就是前面所讲的获取设备的描述符。
第五个函数, usb_get_status(),这个函数是专门为 Hub 准备的,不是为当前的这个 Hub,而是说当前 Hub 的这个端口上连接的如果又是 Hub,那么和连接普通设备就不一样。
第六个函数, check_highspeed(),不同速度的设备,当然待遇不一样。
第七个函数, usb_new_device()。寻找驱动程序,调用驱动程序的 probe,跟踪这个函数就
能一直到设备驱动程序的 probe()函数的调用。
第八个函数, hub_power_remaining(),电源管理。
查看usb参数/sys/bus/usb/devices/1-1/power,autosuspend 如果设备闲置了 2s,那么它将被自动挂起;level 就是所反映的设备的电源级别,可以为 auto/on/suspend,auto 是最为常见的级别,而 on 就意味着不允许设备进行 autosuspend