标签: USB协议 UKey分析
资源来自《Linux那些事儿之USB》,本文主要是读书笔记,附加一些自己的分析和相关知识点说明
内核代码版本2.6.24
目录
4. 设备生命线
4.1. Hub监听处理
插到Hub到拔出。当USB设备连接到Hub某端口上时,Hub检测到有设备连接后,会分配一个struct usb_device结构并初始化,调用设备模型提供的接口将设备添加到USB总线的设备列表中,然后USB总线会遍历驱动列表中的每个驱动,调用自己的match函数看是否和设备或接口匹配。
Hub检测过程如下:
其中hub_port_connect_change关键代码如下:
for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *udev;
/* reallocate for each attempt, since references
* to the previous one can escape in various ways
*/
udev = usb_alloc_dev(hdev, hdev->bus, port1);
//Hub检测到端口有设备连接后,会调用core的usb_alloc_dev函数
//为struct usb_device结构的对象申请内容,详见4.1.1
if (!udev) {
dev_err (hub_dev,
"couldn't allocate port %d usb_device\n",
port1);
goto done;
}
usb_set_device_state(udev, USB_STATE_POWERED);
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
//完成struct usb_device结构体创建后,hub会进行后续初始化工作
//将设备状态设置为powered(加电状态)
//将speed暂时设置为USB_SPEED_UNKNOWN,核心就是成员属性设置
//设备level设置为Hub level+1
//为设备能够从Hub那里获得的电流赋值,为了保证通信
/* set the address */
choose_address(udev);
if (udev->devnum <= 0) {
status = -ENOTCONN; /* Don't retry */
goto loop;
}
//Hub会为设备在总线上选择独一无二的地址,设置usb_device->devnum
/* reset and get descriptor */
status = hub_port_init(hub, udev, port1, i);
//复位、设置地址、并获得设备描述符,详见下文
if (status < 0)
goto loop;
/* consecutive bus-powered hubs aren't reliable; they can
* violate the voltage drop budget. if the new child has
* a "powered" LED, users should notice we didn't enable it
* (without reading syslog), even without per-port LEDs
* on the parent.
*/
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
&& udev->bus_mA <= 100) {
//如果设备类型是USB_CLASS_HUB进行的特殊处理,暂不关心
u16 devstat;
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
&devstat);
if (status < 2) {
dev_dbg(&udev->dev, "get status %d ?\n", status);
goto loop_disable;
}
le16_to_cpus(&devstat);
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_err(&udev->dev,
"can't connect bus-powered hub "
"to this port\n");
if (hub->has_indicators) {
hub->indicator[port1-1] =
INDICATOR_AMBER_BLINK;
schedule_delayed_work (&hub->leds, 0);
}
status = -ENOTCONN; /* Don't retry */
goto loop_disable;
}
}
/* check for devices running slower than they could */
if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
&& udev->speed == USB_SPEED_FULL
&& highspeed_hubs != 0)
check_highspeed (hub, udev, port1);
/* Store the parent's children[] pointer. At this point
* udev becomes globally accessible, although presumably
* no one will look at it until hdev is unlocked.
*/
status = 0;
/* We mustn't add new devices if the parent hub has
* been disconnected; we would race with the
* recursively_mark_NOTATTACHED() routine.
*/
spin_lock_irq(&device_state_lock);
if (hdev->state == USB_STATE_NOTATTACHED)
status = -ENOTCONN;
else
hdev->children[port1-1] = udev;
spin_unlock_irq(&device_state_lock);
/* Run it through the hoops (find a driver, etc) */
if (!status) {
status = usb_new_device(udev);
//核心调用,初始化设备配置,详见4.1.4
if (status) {
spin_lock_irq(&device_state_lock);
hdev->children[port1-1] = NULL;
spin_unlock_irq(&device_state_lock);
}
}
if (status)
goto loop_disable;
status = hub_power_remaining(hub);
if (status)
dev_dbg(hub_dev, "%dmA power budget left\n", status);
return;
loop_disable:
hub_port_disable(hub, port1, 1);
loop:
ep0_reinit(udev);
release_address(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
设备要想从Powered状态发展到下一个Default状态,必须收到一个复位信号,并成功复位。Hub会复位设备,成功后,设备进入Default状态。
复位进入Default状态后,Hub也会获得设备真正的速度,依据速度,能过知道端口0一次能够处理的最大数据长度。
下面Hub使用Core中定义的usb_control_msg函数给设备发送SET_ADDRESS请求,设备就进入Address状态了,设备的address就是上表中的Devnum
4.1.1 usb_alloc_dev-USB设备对象创建
下面来分析一下usb_alloc_dev函数的实现
struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
//USB设备的构造函数,parent是设备连接的hub,bus是设备连接的总线,port1是设备连接在Hub上的端口
{
struct usb_device *dev;
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
//申请struct usb_device空间,kzalloc=kmalloc+memset
if (!dev)
return NULL;
if (!usb_get_hcd(bus_to_hcd(bus))) {
//hcd,主机控制器驱动相关的函数,主机控制器对应一条USB总线,用struct usb_hcd结构表示
//一条总线用struct usb_bus结构表示
//函数bus_to_hcd,获得总线对应的主机控制器驱动,也就是struct usb_hcd结构对象
//函数usb_get_hcd将得到的usb_hcd结构对象的引用计数加1,,因为总线上多了一个设备
kfree(dev);
return NULL;
}
device_initialize(&dev->dev);
//设备模型的函数,目的是将struct usb_device结构中嵌入的struct device结构体初始化掉
dev->dev.bus = &usb_bus_type;
//设置总线类型为usb_bus_type
dev->dev.type = &usb_device_type;
//设置设备类型为usb_device_type
/*除了总线类型,还有设备类型,如下
struct device_type usb_device_type = {
.name = "usb_device",
.release = usb_release_dev,
.uevent = usb_dev_uevent,
};
*/
dev->dev.dma_mask = bus->controller->dma_mask;
//DMA传输设备,是否支持DMA要看主机控制器的dma_mask
set_dev_node(&dev->dev, dev_to_node(bus->controller));
//设置内存节点,numa,uma表示一致内存访问,uniform memory access
dev->state = USB_STATE_ATTACHED;
//将USB设备的状态设置为ATTACHED,表示已经连接到USB接口上
atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
//初始化ep0端点的urb_list
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
//初始化ep0的描述符长度和描述符类型
/* ep0 maxpacket comes later, from device descriptor */
usb_enable_endpoint(dev, &dev->ep0);
//设置usb_device,ep_out[0]和ep_in[0]
dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
* string is a path along hub ports, from the root. Each device's
* dev->devpath will be stable until USB is re-cabled, and hubs
* are often labeled with these port numbers. The bus_id isn't
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
if (unlikely(!parent)) {
//告诉编译器条件x发生的可能性不大,这个条件块里的语句目标码可以放在较远位置,保证经常执行的目标更紧凑
//这里parent为空,表示设备直接连载root hub上
//内核觉得USB设置直接连到root hub上可能性很小
dev->devpath[0] = '0';
dev->dev.parent = bus->controller;
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
root_hub = 1;
//如果是连接到root hub,那么需要设置的usb_device的属性
//usb_device->devpath="0"
//usb_device->dev(struct device类型).parent(struct device类型)=主机控制器
//usb_device->dev(struct device类型).bus_id[]="usb1"或者usb2\3\4这样的字符串
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
else
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->dev.parent = &parent->dev;
sprintf(&dev->dev.bus_id[0], "%d-%s",
bus->busnum, dev->devpath);
//如果不是连接到root hub,那么需要设置的usb_device的属性
//如果所在hub在Root Hub上,那么usb_device->devpath=端口号
//否则usb_device->devpath=所在Hub的devpath基础上加一个.再加端口号
//usb_device->dev(struct device类型).parent(struct device类型)=parent->dev
//usb_device->dev(struct device类型).bus_id[]=(bus->busnum)-(dev->devpath)
/* hub driver sets up TT records */
}
dev->portnum = port1;
dev->bus = bus;
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
//初始化一个链表
//下面是电源管理相关
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
if (root_hub) /* Root hub always ok [and always wired] */
dev->authorized = 1;
else {
dev->authorized = usb_hcd->authorized_default;
dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
}
return dev;
}
4.1.2. hub_port_init-设备复位、设备Address、设备描述符获取
代码如下:
static int
hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int retry_counter)
{
static DEFINE_MUTEX(usb_address0_mutex);
struct usb_device *hdev = hub->hdev;
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
*/
if (!hdev->parent) {
delay = HUB_ROOT_RESET_TIME;
if (port1 == hdev->bus->otg_port)
hdev->bus->b_hnp_enable = 0;
}
/* Some low speed devices have problems with the quick delay, so */
/* be a bit pessimistic with those devices. RHbug #23670 */
if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME;
mutex_lock(&usb_address0_mutex);
/* Reset the device; full speed may morph to high speed */
retval = hub_port_reset(hub, port1, udev, delay);
//设备复位,得到真正的设备速度(udev->speed),详见下文
if (retval < 0) /* error or disconnect */
goto fail;
/* success, speed is known */
retval = -ENODEV;
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail;
}
oldspeed = udev->speed;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
//下面依据设备驱动,设置端点0的一次能够处理的最大长度
switch (udev->speed) {
case USB_SPEED_VARIABLE: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
break;
case USB_SPEED_HIGH: /* fixed at 64 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
/* to determine the ep0 maxpacket size, try to read
* the device descriptor to get bMaxPacketSize0 and
* then correct our initial guess.
*/
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
break;
case USB_SPEED_LOW: /* fixed at 8 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8);
break;
default:
goto fail;
}
//下面是printk输出
type = "";
switch (udev->speed) {
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
case USB_SPEED_VARIABLE:
speed = "variable";
type = "Wireless ";
break;
default: speed = "?"; break;
}
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, devnum);
//下面是TT:transaction translator,负责高速和低速/全速的数据转换
/* Set up TT records, if needed */
if (hdev->tt) {
udev->tt = hdev->tt;
udev->ttport = hdev->ttport;
} else if (udev->speed != USB_SPEED_HIGH
&& hdev->speed == USB_SPEED_HIGH) {
udev->tt = &hub->tt;
udev->ttport = port1;
}
/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
* Because device hardware and firmware is sometimes buggy in
* this area, and this is how Linux has done it for ages.
* Change it cautiously.
*
* NOTE: If USE_NEW_SCHEME() is true we will start by issuing
* a 64-byte GET_DESCRIPTOR request. This is what Windows does,
* so it may help with some non-standards-compliant devices.
* Otherwise we start with SET_ADDRESS and then try to read the
* first 8 bytes of the device descriptor to get the ep0 maxpacket
* value.
*/
//从字面意思来说是获取描述符
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
if (USE_NEW_SCHEME(retry_counter)) { //暂时不考虑这个NEW——SCHEME
struct usb_device_descriptor *buf;
int r = 0;
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
if (!buf) {
retval = -ENOMEM;
continue;
}
/* Retry on all errors; some devices are flakey.
* 255 is for WUSB devices, we actually need to use
* 512 (WUSB1.0[4.8.1]).
*/
for (j = 0; j < 3; ++j) {
buf->bMaxPacketSize0 = 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
USB_CTRL_GET_TIMEOUT);
switch (buf->bMaxPacketSize0) {
case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==
USB_DT_DEVICE) {
r = 0;
break;
}
/* FALL THROUGH */
default:
if (r == 0)
r = -EPROTO;
break;
}
if (r == 0)
break;
}
udev->descriptor.bMaxPacketSize0 =
buf->bMaxPacketSize0;
kfree(buf);
retval = hub_port_reset(hub, port1, udev, delay);
if (retval < 0) /* error or disconnect */
goto fail;
if (oldspeed != udev->speed) {
dev_dbg(&udev->dev,
"device reset changed speed!\n");
retval = -ENODEV;
goto fail;
}
if (r) {
dev_err(&udev->dev, "device descriptor "
"read/%s, error %d\n",
"64", r);
retval = -EMSGSIZE;
continue;
}
#undef GET_DESCRIPTOR_BUFSIZE
}
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = hub_set_address(udev, devnum);
//设置usb_device的地址,将当前devnum成员值告诉设备
//就是调用usb_control_msg,展开调用如下:
//usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval >= 0)
break;
msleep(200);
}
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
devnum, retval);
goto fail;
}
/* cope with hardware quirkiness:
* - let SET_ADDRESS settle, some device hardware wants it
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
if (USE_NEW_SCHEME(retry_counter))
break;
retval = usb_get_device_descriptor(udev, 8);
//核心,获取设备描述符,此时size为0,猜测应该没有真正获取,真正的获取应该在下面
//本函数调用usb_get_descriptor,后者调用usb_control_msg(USB_REG_GET_DESCRIPTOR)
//然后将获取到的描述符,赋值给usb_device->descriptor(usb_device_descriptor类型)
if (retval < 8) {
dev_err(&udev->dev, "device descriptor "
"read/%s, error %d\n",
"8", retval);
if (retval >= 0)
retval = -EMSGSIZE;
} else {
retval = 0;
break;
}
}
if (retval)
goto fail;
i = udev->descriptor.bMaxPacketSize0 == 0xff?
512 : udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
dev_err(&udev->dev, "ep0 maxpacket = %d\n", i);
retval = -EMSGSIZE;
goto fail;
}
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
ep0_reinit(udev);
}
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
//核心,获取设备描述符,此时size为USB_DT_DEVICE_SIZE,应该进行了真正获取和赋值
//本函数调用usb_get_descriptor,后者调用usb_control_msg(USB_REG_GET_DESCRIPTOR)
//然后将获取到的描述符,赋值给usb_device->descriptor(usb_device_descriptor类型)
if (retval < (signed)sizeof(udev->descriptor)) {
dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
"all", retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
}
retval = 0;
fail:
if (retval) {
hub_port_disable(hub, port1, 0);
udev->devnum = devnum; /* for disconnect processing */
}
mutex_unlock(&usb_address0_mutex);
return retval;
}
其中hub_port_reset实现如下:
static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay)
{
int i, status;
/* Block EHCI CF initialization during the port reset.
* Some companion controllers don't like it when they mix.
*/
down_read(&ehci_cf_port_reset_rwsem);
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
status = set_port_feature(hub->hdev,
port1, USB_PORT_FEAT_RESET);
//核心调用,调用usb_control_msg,展开如下:
//usb_control_msg(hub->hdev, usb_sndctrlpipe(hub->hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_RESET, port1,
NULL, 0, 1000);
//usb_control_msg详见4.1.3分析
if (status)
dev_err(hub->intfdev,
"cannot reset port %d (err = %d)\n",
port1, status);
else {
status = hub_port_wait_reset(hub, port1, udev, delay);
//等待reset完成,调用hub_port_status获取端口状态,后者调用get_port_status
//最终调用usb_control_msg来完成功能
//依据返回的端口状态,设置udev->speed
if (status && status != -ENOTCONN)
dev_dbg(hub->intfdev,
"port_wait_reset: err = %d\n",
status);
}
/* return on disconnect or reset */
switch (status) {
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
udev->devnum = 0; /* Device now at address 0 */
//设备目前位于地址0
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_C_RESET);
/* FIXME need disconnect() for NOTATTACHED device */
usb_set_device_state(udev, status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
//设置设备状态:正常情况下为USB_STATE_DEFAULT
goto done;
}
dev_dbg (hub->intfdev,
"port %d not enabled, trying reset again...\n",
port1);
delay = HUB_LONG_RESET_TIME;
}
dev_err (hub->intfdev,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
done:
up_read(&ehci_cf_port_reset_rwsem);
return status;
}
4.1.3. usb_control_msg发送urb(端点管道)-TODO
usb_control_msg构建URB发送给设备,drivers/usb/core/message.c,接口定义如下:
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
这里暂时不展开分析,只说明一下管道,管道有两端,一端是主机上的缓冲区,一端是设备上的断点,端点有四种类型,每种都有in和out两个方向。确定一条管道需要知道管道两端的地址、方向和类型,主机端是确定的,需要确定的是另一端的设备地址和端点地址。
管道bit7表示方向,bit8-bit14表示设备地址(7位),bit15-bit18表示端点号(16位),bit30-bit31表示管道类型,创建管道的宏定义如下:
include/linux/usb.h
//bit30-bit31:管道类型
#define PIPE_ISOCHRONOUS 0
#define PIPE_INTERRUPT 1
#define PIPE_CONTROL 2
#define PIPE_BULK 3
//bit8-bit14:设备地址,bit15-bit18:端点号
static inline unsigned int __create_pipe(struct usb_device *dev,
unsigned int endpoint)
{
return (dev->devnum << 8) | (endpoint << 15);
}
//bit7:方向
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
/* Create various pipes... */
#define usb_sndctrlpipe(dev,endpoint) \
((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
#define usb_rcvctrlpipe(dev,endpoint) \
((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev,endpoint) \
((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
#define usb_rcvisocpipe(dev,endpoint) \
((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev,endpoint) \
((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
#define usb_rcvbulkpipe(dev,endpoint) \
((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev,endpoint) \
((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
#define usb_rcvintpipe(dev,endpoint) \
((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
4.1.4. usb_new_device-配置设备、设备注册、驱动匹配
/**
* usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
* It will return if the device is configured properly or not. Zero if
* the interface was registered with the driver core; else a negative
* errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
*/
int usb_new_device(struct usb_device *udev)
{
int err;
usb_detect_quirks(udev); /* Determine quirks */
//预定义了一个usb_device_id数组,按照设备描述符信息进行匹配
//本质是一个黑名单,匹配成功会进行输出提示
err = usb_configure_device(udev); /* detect & probe dev/intfs */
//核心调用,配置设备,detect & probe 设备或接口,详见下文
if (err < 0)
goto fail;
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
//usb_device->dev(struct device类型).devt(dev_t类型)dev_t赋值
//主设备号是USB_DEVICE_MAJOR,按照前面的描述,说的是usbfs
//次设备号是(udev->bus->busnum-1) * 128) + (udev->devnum-1)
/* Increment the parent's count of unsuspended children */
if (udev->parent)
usb_autoresume_device(udev->parent);
/* Register the device. The device driver is responsible
* for adding the device files to sysfs and for configuring
* the device.
*/
err = device_add(&udev->dev);
//注册设备,将设备添加到设备树中,详见下文
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
/* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
"SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
show_string(udev, "Product", udev->product);
show_string(udev, "Manufacturer", udev->manufacturer);
show_string(udev, "SerialNumber", udev->serial);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
return err;
}
quirk黑名单如下所示
static const struct usb_device_id usb_quirk_list[] = {
/* CBM - Flash disk */
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
/* SKYMEDI USB_DRIVE */
{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */
};
void usb_detect_quirks(struct usb_device *udev)
{
const struct usb_device_id *id = usb_quirk_list;
id = find_id(udev);
//会调用usb_match_device,按照match_flags进行匹配
if (id)
udev->quirks = (u32)(id->driver_info);
if (udev->quirks)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
//如果存在,就进行调试输出,USB支持该设备有问题
/* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
udev->autosuspend_disabled = 1;
#endif
}
4.1.4.1 usb_configure_device
usb_configure_device函数实现如下:
static int usb_configure_device(struct usb_device *udev)
{
int err;
if (udev->config == NULL) {
err = usb_get_configuration(udev);
//如果usb_device的配置为空usb_host_config类型,那么首先获取所有配置,详见下文
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
}
if (udev->wusb == 1 && udev->authorized == 0) {
udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
}
else {
/* read the standard strings and cache them if present */
udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
udev->manufacturer = usb_cache_string(udev,
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
//获取字符串描述符的字符串值,usb_device设备描述符中包含了字符串的位置
//还是通过usb_control_msg来获取字符串描述符的值
}
err = usb_configure_device_otg(udev);
fail:
return err;
}
usb_get_configuration实现如下:
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;//设备描述符中包含配置数
int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
cfgno = 0;
if (dev->authorized == 0) /* Not really an error */
goto out_not_authorized;
result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
if (ncfg < 1) {
dev_err(ddev, "no configurations\n");
return -EINVAL;
}
//给usb_device->config创建对应数量的结构体struct usb_host_config空间
length = ncfg * sizeof(struct usb_host_config);
dev->config = kzalloc(length, GFP_KERNEL);
if (!dev->config)
goto err2;
//给usb_device->rawdescriptors创建对应数量的字符串char *空间
//这是一个字符指针数组,里面的每一项都指向一个使用GET_DESCRIPTOR请求去获取配置描述符时的结果
length = ncfg * sizeof(char *);
dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
if (!dev->rawdescriptors)
goto err2;
//开辟配置描述符空间,长度为9
buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
if (!buffer)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
result = 0;
for (; cfgno < ncfg; cfgno++) { //按照配置数进行循环
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
//调用usb_control_msg(usb_device,usb_rcvctrlpipe(dev,0),USB_REQ_GET_DESCRIPTOR,USB_DIR_IN,USB_DT_CONFIG<<8+cfgno,buffer,USB_DT_CONFIG_SIZE)
//发送urb,获取配置描述符
//但是是用一个for 3次循环进行调用的:
//一些设备厂商生产设备不守规矩,一次请求还一定能成功
//但是获取不到无法继续,只能多试几次
if (result < 0) { //获取失败
dev_err(ddev, "unable to read config index %d "
"descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
} else if (result < 4) { //如果小于4,表示数据太少
//配置描述符中,第三个字节wTotalLength表示嵌套包含的各类描述符的总大小,
//第四个字节bNuminterfaces表示接口数量,只要获得了前4个字节,就能得到总长度
dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno,
USB_DT_CONFIG_SIZE, result);
result = -EINVAL;
goto err;
}
length = max((int) le16_to_cpu(desc->wTotalLength),
USB_DT_CONFIG_SIZE);
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
result = -ENOMEM;
goto err;
}
//按照返回的wTotalLength开辟空间,重新调用usb_get_descriptor
//获取嵌套的各级配置描述符
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "all");
kfree(bigbuffer);
goto err;
}
if (result < length) {
dev_warn(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, length, result);
length = result;
}
dev->rawdescriptors[cfgno] = bigbuffer;
//赋值给usb_device->rawdescriptors[i]
result = usb_parse_configuration(&dev->dev, cfgno,
&dev->config[cfgno], bigbuffer, length);
//配置信息的解析,就是从前面获取的所有数据中解析出各个描述符,详见下文
if (result < 0) {
++cfgno;
goto err;
}
}
result = 0;
err:
kfree(buffer);
out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
dev_err(ddev, "out of memory\n");
return result;
}
GET_DESCRIPTOR请求说明如下:
GET_DESCRIPTOR得到的数据并不是杂乱无序的,是有规律的,一般来说,配置描述符后面跟的就是第一个接口的接口描述符,接着就是这个接口里第一个端点的端点描述符,如果有class-和vendor-specific描述符的话,会紧跟在对应的标准描述符后面,不管接口有多少个端点都是按照这个规律顺序排列。总的来说,肯定先是配置描述符,然后是其包含的接口描述符,然后是该接口包含的端点描述符,例如config1+interface1+ep1+ep2+interface2+ep1+ep2+interface3。
usb_parse_configuration函数实现如下:
static int usb_parse_configuration(struct device *ddev, int cfgidx,
struct usb_host_config *config, unsigned char *buffer, int size)
{
unsigned char *buffer0 = buffer;
int cfgno;
int nintf, nintf_orig;
int i, j, n;
struct usb_interface_cache *intfc;
unsigned char *buffer2;
int size2;
struct usb_descriptor_header *header;
int len, retval;
u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
unsigned iad_num = 0;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
//buffer的前USB_DT_CONFIG_SIZE长度一定是配置描述符,直接拷贝
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
config->desc.bLength < USB_DT_CONFIG_SIZE) {
//里面做一个校验判断
dev_err(ddev, "invalid descriptor for config index %d: "
"type = 0x%X, length = %d\n", cfgidx,
config->desc.bDescriptorType, config->desc.bLength);
return -EINVAL;
}
cfgno = config->desc.bConfigurationValue;
//指明了将要激活哪个配置
buffer += config->desc.bLength;
size -= config->desc.bLength;
//buffer指针位置和size修正
nintf = nintf_orig = config->desc.bNumInterfaces;
//配置数量
if (nintf > USB_MAXINTERFACES) {
dev_warn(ddev, "config %d has too many interfaces: %d, "
"using maximum allowed: %d\n",
cfgno, nintf, USB_MAXINTERFACES);
nintf = USB_MAXINTERFACES;
}
/* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */
n = 0;
for ((buffer2 = buffer, size2 = size);
size2 > 0;
(buffer2 += header->bLength, size2 -= header->bLength)) {
//循环得到每个接口长度和可选设置
if (size2 < sizeof(struct usb_descriptor_header)) {
dev_warn(ddev, "config %d descriptor has %d excess "
"byte%s, ignoring\n",
cfgno, size2, plural(size2));
break;
}
header = (struct usb_descriptor_header *) buffer2;
/*描述符头,便于通用分析
struct usb_descriptor_header {
__u8 bLength;
__u8 bDescriptorType;
} __attribute__ ((packed));
*/
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
break;
}
if (header->bDescriptorType == USB_DT_INTERFACE) { //如果类型是接口描述符
//一个接口描述符就代表了接口拥有某个一个设置,没有什么所谓的设置描述符
struct usb_interface_descriptor *d;
int inum;
d = (struct usb_interface_descriptor *) header;
if (d->bLength < USB_DT_INTERFACE_SIZE) {
dev_warn(ddev, "config %d has an invalid "
"interface descriptor of length %d, "
"skipping\n", cfgno, d->bLength);
continue;
}
inum = d->bInterfaceNumber;
//表明当前接口描述符(多个设置中的一个)属于哪个接口
if (inum >= nintf_orig)
dev_warn(ddev, "config %d has an invalid "
"interface number: %d but max is %d\n",
cfgno, inum, nintf_orig - 1);
/* Have we already encountered this interface?
* Count its altsettings */
for (i = 0; i < n; ++i) {
if (inums[i] == inum)
break;
}
if (i < n) {
if (nalts[i] < 255)
++nalts[i];
} else if (n < USB_MAXINTERFACES) {
inums[n] = inum;
nalts[n] = 1;
++n;
}
//使用inums和nalts数组来记录接口号及其可选设置数量,n表示接口数量
} else if (header->bDescriptorType ==
USB_DT_INTERFACE_ASSOCIATION) { //针对复合设备的的描述符
if (iad_num == USB_MAXIADS) {
dev_warn(ddev, "found more Interface "
"Association Descriptors "
"than allocated for in "
"configuration %d\n", cfgno);
} else {
config->intf_assoc[iad_num] =
(struct usb_interface_assoc_descriptor
*)header;
iad_num++;
}
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
dev_warn(ddev, "config %d contains an unexpected "
"descriptor of type 0x%X, skipping\n",
cfgno, header->bDescriptorType);
} /* for ((buffer2 = buffer, size2 = size); ...) */
size = buffer2 - buffer;
config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);
//数组修正,buffer中可能会包含一些无效内容,这里只记录有效内容
if (n != nintf)
dev_warn(ddev, "config %d has %d interface%s, different from "
"the descriptor's value: %d\n",
cfgno, n, plural(n), nintf_orig);
else if (n == 0)
dev_warn(ddev, "config %d has no interfaces?\n", cfgno);
config->desc.bNumInterfaces = nintf = n;
//如果解析出来的接口数量有异常,要进行警告
/* Check for missing interface numbers */
for (i = 0; i < nintf; ++i) {
for (j = 0; j < nintf; ++j) {
if (inums[j] == i)
break;
}
if (j >= nintf)
dev_warn(ddev, "config %d has no interface number "
"%d\n", cfgno, i);
}
//查看是否遗漏了哪个接口号,进行警告
/* Allocate the usb_interface_caches and altsetting arrays */
for (i = 0; i < nintf; ++i) {
//遍历每个接口号
j = nalts[i];
if (j > USB_MAXALTSETTING) {
dev_warn(ddev, "too many alternate settings for "
"config %d interface %d: %d, "
"using maximum allowed: %d\n",
cfgno, inums[i], j, USB_MAXALTSETTING);
nalts[i] = j = USB_MAXALTSETTING;
}
//获取每个接口的可选设置数
len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
//为usb_host_config->intf_cache[i](struct usb_interface_cache *类型)开辟可选设置的接口空间
/*usb_interface_cache内容如下
struct usb_interface_cache {
unsigned num_altsetting; /* number of alternate settings
struct kref ref; /* reference counter
/* variable-length array of alternate settings for this interface,
* stored in no particular order
struct usb_host_interface altsetting[0];
};
*/
if (!intfc)
return -ENOMEM;
kref_init(&intfc->ref);
}
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first interface descriptor */
config->extra = buffer;
//配置描述符后面还可能接class-和vendor-specific描述符,夹在配置描述符和接口描述符之间
//不管有没有,先把buffer地址赋给extra,如果没有则下一行返回的i等于0,extralen为0
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
USB_DT_INTERFACE, &n);
//在buffer中寻找配置描述赋予后面跟着的第一个接口描述符
config->extralen = i;
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, plural(n), "configuration");
buffer += i;
size -= i;
//进行buffer指针和size的修正,如果中间存在class-和vendor-specific描述符会被忽略掉
//此时buffer第一个肯定是接口描述符
/* Parse all the interface/altsetting descriptors */
while (size > 0) {
retval = usb_parse_interface(ddev, cfgno, config,
buffer, size, inums, nalts);
//解析所有的接口/可选设置,详见下文
if (retval < 0)
return retval;
buffer += retval;
size -= retval;
}
/* Check for missing altsettings */
for (i = 0; i < nintf; ++i) {
intfc = config->intf_cache[i];
for (j = 0; j < intfc->num_altsetting; ++j) {
for (n = 0; n < intfc->num_altsetting; ++n) {
if (intfc->altsetting[n].desc.
bAlternateSetting == j)
break;
}
if (n >= intfc->num_altsetting)
dev_warn(ddev, "config %d interface %d has no "
"altsetting %d\n", cfgno, inums[i], j);
}
}
//警告有没有哪个设置被遗漏了
return 0;
}
其中usb_parse_interface实现如下:
static int usb_parse_interface(struct device *ddev, int cfgno,
struct usb_host_config *config, unsigned char *buffer, int size,
u8 inums[], u8 nalts[])
{
unsigned char *buffer0 = buffer;
struct usb_interface_descriptor *d;
int inum, asnum;
struct usb_interface_cache *intfc;
struct usb_host_interface *alt;
int i, n;
int len, retval;
int num_ep, num_ep_orig;
d = (struct usb_interface_descriptor *) buffer;
//将接口描述符
buffer += d->bLength;
size -= d->bLength;
//buffer位置前移
if (d->bLength < USB_DT_INTERFACE_SIZE)
goto skip_to_next_interface_descriptor;
/* Which interface entry is this? */
intfc = NULL;
inum = d->bInterfaceNumber;
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
if (inums[i] == inum) {
intfc = config->intf_cache[i];
//获取接口号对应的intf_cache(struct usb_interface_cache *类型)
break;
}
}
if (!intfc || intfc->num_altsetting >= nalts[i])
goto skip_to_next_interface_descriptor;
/* Check for duplicate altsetting entries */
asnum = d->bAlternateSetting;
for ((i = 0, alt = &intfc->altsetting[0]);
i < intfc->num_altsetting;
(++i, ++alt)) {
if (alt->desc.bAlternateSetting == asnum) {
dev_warn(ddev, "Duplicate descriptor for config %d "
"interface %d altsetting %d, skipping\n",
cfgno, inum, asnum);
goto skip_to_next_interface_descriptor;
}
}
//查看该接口的设置是否存在过(设置编号是否一样)
++intfc->num_altsetting;
memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);
//进行intf_cache的数据赋值
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first endpoint or interface descriptor */
alt->extra = buffer;
//接口描述符后面还可能跟着class-或者vendor-specific描述符,先赋值给extra
//如果没有下面find_next_descriptor会返回0
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
//找到下一个端点或者接口描述符,因为有可能一个接口只有端点0,那么接口描述符后面可能不会跟着端点描述符
alt->extralen = i;
//extralen设置,如果没有class-或者vendor-specific,那么该值就是0
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, plural(n), "interface");
buffer += i;
size -= i;
//buffer指针和size位置修改,略过class-或者vendor-specifi描述符
/* Allocate space for the right(?) number of endpoints */
num_ep = num_ep_orig = alt->desc.bNumEndpoints;
//获取可选设置的端点数量
alt->desc.bNumEndpoints = 0; // Use as a counter
if (num_ep > USB_MAXENDPOINTS) {
dev_warn(ddev, "too many endpoints for config %d interface %d "
"altsetting %d: %d, using maximum allowed: %d\n",
cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);
num_ep = USB_MAXENDPOINTS;
}
if (num_ep > 0) { /* Can't allocate 0 bytes */
len = sizeof(struct usb_host_endpoint) * num_ep;
alt->endpoint = kzalloc(len, GFP_KERNEL);
if (!alt->endpoint)
return -ENOMEM;
}
//开辟端点数量的struct usb_host_endpoint控件
//为可选设置usb_host_interface->endpoint(usb_host_endpoint *类型)赋值
/* Parse all the endpoint descriptors */
n = 0;
while (size > 0) {
if (((struct usb_descriptor_header *) buffer)->bDescriptorType
== USB_DT_INTERFACE)
break;
retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,
num_ep, buffer, size);
//解析端点描述符,不再展开,就是构建struct usb_endpoint_descriptor
//给alt(usb_host_interface *)->endpoint[ep->desc.bNumEndpoints]赋值
if (retval < 0)
return retval;
++n;
buffer += retval;
size -= retval;
}
if (n != num_ep_orig)
dev_warn(ddev, "config %d interface %d altsetting %d has %d "
"endpoint descriptor%s, different from the interface "
"descriptor's value: %d\n",
cfgno, inum, asnum, n, plural(n), num_ep_orig);
return buffer - buffer0;
skip_to_next_interface_descriptor:
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
USB_DT_INTERFACE, NULL);
return buffer - buffer0 + i;
}
4.1.4.1 device_register->device_add
device_add是device_register函数的Part2,首先从device_register进行分析,实现如下:
/**
* device_register - register a device with the system.
* @dev: pointer to the device structure
*
* This happens in two clean steps - initialize the device
* and add it to the system. The two steps can be called
* separately, but this is the easiest and most common.
* I.e. you should only call the two helpers separately if
* have a clearly defined need to use and refcount the device
* before it is added to the hierarchy.
*/
int device_register(struct device *dev)
{
device_initialize(dev);
//设备初始化
return device_add(dev);
//设备添加到系统中
}
void device_initialize(struct device *dev)
{
kobj_set_kset_s(dev, devices_subsys);
//设置struct device->kobj(kobject类型).kset(kset类型)为预定义的devices_subsys
//应该就是/sys/devices
kobject_init(&dev->kobj);
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
set_dev_node(dev, -1);
//初始化struct device的各个成员
}
/**
* device_add - add device to device hierarchy.
* @dev: device.
*
* This is part 2 of device_register(), though may be called
* separately _iff_ device_initialize() has been called separately.
*
* This adds it to the kobject hierarchy via kobject_add(), adds it
* to the global and sibling lists for the device, then
* adds it to the other relevant subsystems of the driver model.
*/
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
//增加引用计数
if (!dev || !strlen(dev->bus_id))
goto Error;
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
parent = get_device(dev->parent);
//获取parent,顺便增加parent的引用计数
error = setup_parent(dev, parent);
//设置struct device->kobj.parent,有可能是所属class的kobj
if (error)
goto Error;
/* first, register with generic layer. */
kobject_set_name(&dev->kobj, "%s", dev->bus_id);
//设置device->kobj.k_name为struct device->bus_id
//按照前文描述,就是usb1、usb2或者1-1、1-1.1
error = kobject_add(&dev->kobj);
//kobject_add:
//如果kobject->kset存在:
//将kobject->entry(list_head类型)添加到kobject->kset->list中
//如果kobject->parent不存在,设置parent就是kobject->kset->kobject
//这里就是预定义的devices_subsys
//create_dir(kobject)->sysfs_create_dir(kobject)
//创建sysfs目录,如果存在parent就在该parent目录下创建,如果不存在就在sys根下创建
//这里就是在bus_subsys下创建
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
/* notify clients of device entry (new way) */
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
error = device_create_file(dev, &uevent_attr);
//sysfs操作:创建属性文件uevent
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
//sysfs操作:创建属性文件devt
if (error)
goto ueventattrError;
}
error = device_add_class_symlinks(dev);
//sysfs操作:创建符号链接subsystem、device
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
//sysfs操作:device->class(struct class类型)->dev_attrs
//sysfs操作:device->type(device_type类型)->groups
//sysfs操作:device->groups
if (error)
goto AttrsError;
error = dpm_sysfs_add(dev);
//电源管理
if (error)
goto PMError;
device_pm_add(dev);
//电源管理
error = bus_add_device(dev);
//sysfs操作:为device创建device->bus_type->dev_attrs[]属性文件
//sysfs操作:为device创建链接文件device->bus_id,值为usb1、usb2或者1-1、1-1.1
//sysfs操作:为device创建链接文件"subsystem",值为device->bus_type->subsys,kobj
//sysfs操作:为device创建链接文件"bus",值为device->bus_type->subsys,kobj
if (error)
goto BusError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
//向用户空间报告uevent事件
bus_attach_device(dev);
//向总线添加设备,详见下文
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
//将该struct device添加到parent->klist_children中
if (dev->class) { //如果存在所属class,也进行class相关链表添加,及其他操作
down(&dev->class->sem);
/* tie the class to the device */
list_add_tail(&dev->node, &dev->class->devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
Done:
put_device(dev);
return error;
BusError:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
PMError:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
if (dev->class) {
sysfs_remove_link(&dev->kobj, "subsystem");
/* If this is not a "fake" compatible device, remove the
* symlink from the class to the device. */
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_remove_link(&dev->class->subsys.kobj,
dev->bus_id);
if (parent) {
#ifdef CONFIG_SYSFS_DEPRECATED
char *class_name = make_class_name(dev->class->name,
&dev->kobj);
if (class_name)
sysfs_remove_link(&dev->parent->kobj,
class_name);
kfree(class_name);
#endif
sysfs_remove_link(&dev->kobj, "device");
}
}
ueventattrError:
device_remove_file(dev, &uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
if (parent)
put_device(parent);
goto Done;
}
bus_attach_device实现如下:
void bus_attach_device(struct device * dev)
{
struct bus_type *bus = dev->bus;
int ret = 0;
if (bus) {
dev->is_registered = 1;
if (bus->drivers_autoprobe)
ret = device_attach(dev);
//将设备attach到驱动上,实现见下文
WARN_ON(ret < 0);
if (ret >= 0)
klist_add_tail(&dev->knode_bus, &bus->klist_devices);
//将设备添加到总线的设备链表中
else
dev->is_registered = 0;
}
}
int device_attach(struct device * dev)
{
int ret = 0;
down(&dev->sem);
if (dev->driver) {
ret = device_bind_driver(dev);
//如果已经存在驱动,那么就直接调用device_bind_driver
//sysfs操作
//将device->knode_driver添加到driver的klist_devices链表中
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
//如果没有存在驱动,调用bus_for_each_drv
//遍历bus_type->klist_drivers中每一个驱动对象,调用__device_attach函数,见下文
}
up(&dev->sem);
return ret;
}
static int __device_attach(struct device_driver * drv, void * data)
{
struct device * dev = data;
return driver_probe_device(drv, dev);
//实现见下
}
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done;
//如果总线存在match函数,调用总线的match函数,就是之前分析的usb_device_match函数
pr_debug("%s: Matched Device %s with Driver %s\n",
drv->bus->name, dev->bus_id, drv->name);
ret = really_probe(dev, drv);
//如果总线存在probe函数,那么就调用总线的probe函数,usb_bus_type没有probe函数
//否则,如果驱动存在probe函数,那么就调用驱动的probe函数
done:
return ret;
}
4.2. 设备与驱动的match与probe
4.2.1. 设备驱动usb_generic_driver & usb_bus_type->match
前面分析过usb_generic_driver和usb_bus_type如下
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 bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.suspend = usb_suspend,
.resume = usb_resume,
};
//没有probe指针,如果设备和驱动匹配,就需要调用驱动的probe函数,这里调用的是device_driver->probe函数
usb_bus_type的match函数usb_device_match前面分析过,基本来说就是,如果是USB设备,那么只要驱动是USB 设备类型的即可,如下:
struct device_type usb_device_type = {
.name = "usb_device",
.release = usb_release_dev,
.uevent = usb_dev_uevent,
};
如果是USB接口,那么就需要遍历接口驱动usb_driver中的id_table和dynids,针对每一个usb_device_id的match_flags,和usb_device中设备描述符及usb_interface当前设置usb_host_interface中接口描述符信息进行匹配
所以当一个USB设备注册到总线后,肯定会匹配到usb_generic_driver,然后调用usb_generic_driver(usb_device_driver类型)->drvwrap(usbdrv_wrap类型)->driver(device_driver类型)->probe函数,在usb_register_device_driver时进行过设置,该probe函数为usb_probe_device
同样当一个USB接口注册到总线后,匹配到对应的接口驱动(调用usb_register进行注册,该函数调用usb_register_driver,会设置device_driver->probe为usb_probe_interface),然后调用usb_driver->drvwrap(usbdrv_wrap类型)->driver(device_driver类型)->probe函数,也就是usb_probe_interface
4.2.2. 设备驱动usb_generic_driver中device_driver->probe(usb_probe_device)
usb_probe_device实现如下:
static int usb_probe_device(struct device *dev)
{
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
//获取所属usb_device_driver,也就是usb_generic_driver
struct usb_device *udev;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __FUNCTION__);
if (!is_usb_device(dev)) /* Sanity check */
//确保是设备类型,而不是接口类型
return error;
udev = to_usb_device(dev);
//获取所在的usb_device
/* TODO: Add real matching code */
/* The device should always appear to be in use
* unless the driver suports autosuspend.
*/
udev->pm_usage_cnt = !(udriver->supports_autosuspend);
error = udriver->probe(udev);
//调用usb_device_driver->probe函数
//也就是usb_generic_driver的probe函数generic_probe
return error;
}
4.2.3. 设备驱动usb_generic_driver->probe(generic_probe)
static int generic_probe(struct usb_device *udev)
{
int err, c;
/* put device-specific files into sysfs */
usb_create_sysfs_dev_files(udev);
//sysfs操作
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
if (udev->authorized == 0)
dev_err(&udev->dev, "Device is not authorized for usage\n");
else {
c = usb_choose_configuration(udev);
//核心操作,选择配置,详见下文
if (c >= 0) {
err = usb_set_configuration(udev, c);
//核心操作,设置配置,详见下文
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
return 0;
}
usb_choose_configuration实现如下:
int usb_choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
int insufficient_power = 0;
struct usb_host_config *c, *best;
best = NULL;
c = udev->config;
//所有可选配置指针
num_configs = udev->descriptor.bNumConfigurations;
//可选配置数
for (i = 0; i < num_configs; (i++, c++)) {
//循环遍历,获得最优配置
struct usb_interface_descriptor *desc = NULL;
/* It's possible that a config has no interfaces! */
if (c->desc.bNumInterfaces > 0)
desc = &c->intf_cache[0]->altsetting->desc;
//获取intf_cache接口缓存中第一个接口的第一个可选设置的接口描述符
/*
* HP's USB bus-powered keyboard has only one configuration
* and it claims to be self-powered; other devices may have
* similar errors in their descriptors. If the next test
* were allowed to execute, such configurations would always
* be rejected and the devices would not work as expected.
* In the meantime, we run the risk of selecting a config
* that requires external power at a time when that power
* isn't available. It seems to be the lesser of two evils.
*
* Bugzilla #6448 reports a device that appears to crash
* when it receives a GET_DEVICE_STATUS request! We don't
* have any other way to tell whether a device is self-powered,
* but since we don't use that information anywhere but here,
* the call has been removed.
*
* Maybe the GET_DEVICE_STATUS call and the test below can
* be reinstated when device firmwares become more reliable.
* Don't hold your breath.
*/
#if 0 //忽略
/* Rule out self-powered configs for a bus-powered device */
if (bus_powered && (c->desc.bmAttributes &
USB_CONFIG_ATT_SELFPOWER))
continue;
#endif
/*
* The next test may not be as effective as it should be.
* Some hubs have errors in their descriptor, claiming
* to be self-powered when they are really bus-powered.
* We will overestimate the amount of current such hubs
* make available for each port.
*
* This is a fairly benign sort of failure. It won't
* cause us to reject configurations that we should have
* accepted.
*/
/* Rule out configs that draw too much bus current */
if (c->desc.bMaxPower * 2 > udev->bus_mA) {
insufficient_power++;
continue;
}
//如果配置所需电流超出hub可提供电流,则略过
/* When the first config's first interface is one of Microsoft's
* pet nonstandard Ethernet-over-USB protocols, ignore it unless
* this kernel has enabled the necessary host side driver.
*/
if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else
best = c;
#endif
}
//配置选择规则1:第一个配置的第一个接口是一个微软pet nonstandard Ethernet-over-USB protocols,如果kernel中做了设置,则优先选择
/* From the remaining configs, choose the first one whose
* first interface is for a non-vendor-specific class.
* Reason: Linux is more likely to have a class driver
* than a vendor-specific driver. */
else if (udev->descriptor.bDeviceClass !=
USB_CLASS_VENDOR_SPEC &&
(!desc || desc->bInterfaceClass !=
USB_CLASS_VENDOR_SPEC)) {
best = c;
break;
}
//配置选择规则2:设备描述符中的non-vendor-specific类
/* If all the remaining configs are vendor-specific,
* choose the first one. */
else if (!best)
//如果剩下的全是vendor-specific的,则选择第一个
best = c;
}
if (insufficient_power > 0)
dev_info(&udev->dev, "rejected %d configuration%s "
"due to insufficient available bus power\n",
insufficient_power, plural(insufficient_power));
if (best) {
i = best->desc.bConfigurationValue;
//最终返回选择最好配置的描述符中的bConfigurationValue
dev_info(&udev->dev,
"configuration #%d chosen from %d choice%s\n",
i, num_configs, plural(num_configs));
} else {
i = -1;
dev_warn(&udev->dev,
"no configuration chosen from %d choice%s\n",
num_configs, plural(num_configs));
}
return i;
}
usb_set_configuration实现如下:
int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_host_config *cp = NULL;
struct usb_interface **new_interfaces = NULL;
int n, nintf;
if (dev->authorized == 0 || configuration == -1)
configuration = 0;
//如果没有可选配置,则设置配置号为0
//规范中描述,配置号必须为0或者配置描述符中bConfigurationValue的值
//如果配置号为0,则SET_CONFIGURATION后,设备还处于Address状态
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue ==
configuration) {
cp = &dev->config[i];
//依据配置描述符的bConfigurationValue获取usb_host_config结构
break;
}
}
}
if ((!cp && configuration != 0))
return -EINVAL;
/* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0,
* we will accept it as a correctly configured state.
* Use -1 if you really want to unconfigure the device.
*/
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
/* Allocate memory for new interfaces before doing anything else,
* so that if we run out then nothing will have changed. */
n = nintf = 0;
//开辟usb_interface指针数组
if (cp) {
nintf = cp->desc.bNumInterfaces;
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
GFP_KERNEL);
//开辟指针数组
if (!new_interfaces) {
dev_err(&dev->dev, "Out of memory\n");
return -ENOMEM;
}
for (; n < nintf; ++n) {
new_interfaces[n] = kzalloc(
sizeof(struct usb_interface),
GFP_KERNEL);
//开辟数组中的每一项
if (!new_interfaces[n]) {
dev_err(&dev->dev, "Out of memory\n");
ret = -ENOMEM;
free_interfaces:
while (--n >= 0)
kfree(new_interfaces[n]);
kfree(new_interfaces);
return ret;
}
}
i = dev->bus_mA - cp->desc.bMaxPower * 2;
if (i < 0)
dev_warn(&dev->dev, "new config #%d exceeds power "
"limit by %dmA\n",
configuration, -i);
}
/* Wake up the device so we can send it the Set-Config request */
ret = usb_autoresume_device(dev);
if (ret)
goto free_interfaces;
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
if (dev->state != USB_STATE_ADDRESS)
usb_disable_device (dev, 1); // Skip ep0
//如果已经处于配置状态,则退回Address状态
//首先将设备中所有端点都删除掉,然后将设备当前配置使用的每个接口都从系统中unregister掉
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
//向设备发送请求,SET_CONFIGURATION
/* All the old state is gone, so what else can we do?
* The device is probably useless now anyway.
*/
cp = NULL;
}
dev->actconfig = cp;
//将激活的配置,赋值给usb_device->actconfig
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_autosuspend_device(dev);
goto free_interfaces;
//如果目标配置为空,则将设备重置为Address状态,并释放相关结构
}
usb_set_device_state(dev, USB_STATE_CONFIGURED);
//设置usb_device的状态为USB_STATE_CONFIGURED
/* Initialize the new interface structures and the
* hc/hcd/usbcore interface/endpoint state.
*/
for (i = 0; i < nintf; ++i) {
//对配置中的每个接口进行处理
struct usb_interface_cache *intfc;
struct usb_interface *intf;
struct usb_host_interface *alt;
cp->interface[i] = intf = new_interfaces[i];
intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting;
intf->intf_assoc = find_iad(dev, cp, i);
kref_get(&intfc->ref);
//为usb_host_config->interface数组赋值,使用intf_cache缓存数组中的数据来填充它
alt = usb_altnum_to_altsetting(intf, 0);
//获取0号可选设置
//规范中说明,接口的默认设置总是0号设置,所以这里的目的就是获得接口的默认设置
/* No altsetting 0? We'll assume the first altsetting.
* We could use a GetInterface call, but if a device is
* so non-compliant that it doesn't have altsetting 0
* then I wouldn't trust its reply anyway.
*/
if (!alt)
alt = &intf->altsetting[0];
//如果没有拿到0号设置,就拿之前缓存的可选设置中第一项来充数
intf->cur_altsetting = alt;
//指定刚才拿到的设置为当前使用的设置
usb_enable_interface(dev, intf);
//enable接口:enable每个endpoint,分别获取端点地址、端点号、是否是控制断点
//根据端点方向来初始化usb_device的ep_in和ep_out数组
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.dma_mask = dev->dev.dma_mask;
//接口的struct device设置
//parent为usb_device->dev(struct device类型)
//设备类型为usb_if_device_type,总线类型为usb_bus_type
device_initialize (&intf->dev);
//初始化接口的struct device,之前分析过
mark_quiesced(intf);
//将接口的is_active标志初始化为0,表示还没有和任何驱动绑定
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
}
kfree(new_interfaces);
//释放指针数组,并不释放每一个数组项,已经赋值给了usb_host_config->interface[]
if (cp->string == NULL)
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
//获取配置的字符串描述符,不展开分析
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
* claim() any interfaces not yet bound. Many class drivers
* need that: CDC, audio, video, etc.
*/
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
//遍历每个usb_interface
dev_dbg (&dev->dev,
"adding %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
ret = device_add (&intf->dev);
//调用device_add,前面分析过,该函数最终会调用bus_attach_device(dev)向总线添加设备,后者首先调用device_attach(dev)将设备attach到驱动上,最后将设备添加到总线的设备链表中
//device_attach函数会遍历总线usb_bus_type上的每个device_driver,调用其match函数,匹配成功的调用驱动(usb_register_driver注册的)中struct device_driver->probe函数
//也就是usb_probe_interface函数
if (ret != 0) {
dev_err(&dev->dev, "device_add(%s) --> %d\n",
intf->dev.bus_id, ret);
continue;
}
usb_create_sysfs_intf_files(intf);
//sysfs操作
}
usb_autosuspend_device(dev);
return 0;
}
4.2.4. 接口驱动中struct device_driver->probe(usb_probe_interface)
static int usb_probe_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
//获取所在的usb_driver
struct usb_interface *intf;
struct usb_device *udev;
const struct usb_device_id *id;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __FUNCTION__);
if (is_usb_device(dev)) /* Sanity check */
return error;
//如果是usb设备,不是接口设备,直接返回错误
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
//获取usb_interface和所在usb_device
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return -ENODEV;
}
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
//获取匹配的usb_device_id
if (id) {
dev_dbg(dev, "%s - got id\n", __FUNCTION__);
error = usb_autoresume_device(udev);
//立即autoresume一个USB设备和它的接口
if (error)
return error;
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
//设置struct usb_interface->is_active为1,表示驱动匹配成功
intf->condition = USB_INTERFACE_BINDING;
//修改绑定状态
/* The interface should always appear to be in use
* unless the driver suports autosuspend.
*/
intf->pm_usage_cnt = !(driver->supports_autosuspend);
error = driver->probe(intf, id);
//驱动usb_driver的probe函数,这个函数就是每个定义为usb_driver自己的probe函数
if (error) {
mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
} else
intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev);
//delayed autosuspend 一个USB设备和它的接口
}
return error;
}
最终会调用usb_driver->probe函数,就是各个接口驱动自己的定义了,需要针对不同驱动进行特例分析