启动主机控制器和根集线器之后,现在来注册根集线器
register_root_hub负责根集线器的注册
register_root_hub在/drivers/usb/core/hcd.c中
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
struct usb_device *usb_dev = hcd->self.root_hub;
const int devnum = 1;
int retval;
//设置设备的设备号为1
usb_dev->devnum = devnum;
//uhci总线的设备计数器+1
usb_dev->bus->devnum_next = devnum + 1;
//初始化设备位表
memset (&usb_dev->bus->devmap.devicemap, 0,sizeof usb_dev->bus->devmap.devicemap);
//占用设备表的第1位
set_bit (devnum, usb_dev->bus->devmap.devicemap);
//设置设备状态为USB_STATE_ADDRESS
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
mutex_lock(&usb_bus_list_lock);
//设置端点0包的最大值
usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
//取得设备描述符
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
//检测返回的描述符大小和设备描述符的大小是否一致
if (retval != sizeof usb_dev->descriptor)
{
mutex_unlock(&usb_bus_list_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
usb_dev->dev.bus_id, retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
//建立设备
retval = usb_new_device (usb_dev);
if (retval)
{
dev_err (parent_dev, "can't register root hub for %s, %d\n",usb_dev->dev.bus_id, retval);
}
mutex_unlock(&usb_bus_list_lock);
if (retval == 0)
{
spin_lock_irq (&hcd_root_hub_lock);
//设置注册标识为1
hcd->rh_registered = 1;
spin_unlock_irq (&hcd_root_hub_lock);
/* Did the HC die before the root hub was registered? */
if (hcd->state == HC_STATE_HALT)
usb_hc_died (hcd); /* This time clean up */
}
return retval;
}
usb_get_device_descriptor负责取得设备的设备描述符,设备描述符的结构如下
struct usb_device_descriptor {
__u8 bLength; //描述符的长度
__u8 bDescriptorType; //描述符的类型
__le16 bcdUSB; //表示usb设备所遵循的usb规范
__u8 bDeviceClass; //表示usb设备所属的标准设备类
__u8 bDeviceSubClass; //表示usb设备所属的标准设备子类
__u8 bDeviceProtocol; //表示usb设备所使用的设备类协议
__u8 bMaxPacketSize0; //表示0号端点包的最大大小
__le16 idVendor; //表示usb设备的生厂商id
__le16 idProduct; //表示usb设备的产品id
__le16 bcdDevice; //表示usb设备的版本号
__u8 iManufacturer; //表示生产商字符串描述符的索引值
__u8 iProduct; //表示产品字符串描述符的索引值
__u8 iSerialNumber; //表示设备序列号字符串描述符的索引值
__u8 bNumConfigurations; //表示usb设备的配置数
} __attribute__ ((packed));
usb_get_device_descriptor在/drivers/usb/core/messgae.c中
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
{
struct usb_device_descriptor *desc;
int ret;
if (size > sizeof(*desc))
return -EINVAL;
//分配设备描述符所需要的空间
desc = kmalloc(sizeof(*desc), GFP_NOIO);
if (!desc)
return -ENOMEM;
//取得描述符,类型为设备
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
if (ret >= 0)
//拷贝设备描述符到usb_device中
memcpy(&dev->descriptor, desc, size);
kfree(desc);
return ret;
}
usb_get_descripto的用途为取得描述符
usb_get_descriptor在/drivers/usb/core/messgae.c中
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
unsigned char index, void *buf, int size)
{
int i;
int result;
//buf清0
memset(buf, 0, size); /* Make sure we parse really received data */
//重试3次
for (i = 0; i < 3; ++i)
{
/* retry on length 0 or error; some devices are flakey */
//发送控制消息
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(type << 8) + index, 0, buf, size,
USB_CTRL_GET_TIMEOUT);
if (result <= 0 && result != -ETIMEDOUT)
continue;
if (result > 1 && ((u8 *)buf)[1] != type)
{
result = -EPROTO;
continue;
}
break;
}
return result;
}
usb_control_msg的用途为发送控制消息
usb_control_msg在/drivers/usb/core/messgae.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)
{
struct usb_ctrlrequest *dr;
int ret;
//为控制请求结构分配空间
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
//组建8字节的控制请求字段
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
dr->wIndex = cpu_to_le16p(&index);
dr->wLength = cpu_to_le16p(&size);
/* dbg("usb_control_msg"); */
//发送控制消息
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
这8字节的数据眼熟么?~ 还记得在前面提到的setup事务中的数据包的内容么? 正是这8字节的数据,眼泪啊,到了这里,终于接触到传输了
usb_internal_control_msg的用途为组建一个urb结构并发送他,urb这个结构在usb设备插入前都不会讲解,因为在host自己对自己的访问中,urb只起到了一个花瓶的作用,走走过场,并没有真正发送出去
usb_internal_control_msg在/drivers/usb/core/messgae.c中
static int usb_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe,
struct usb_ctrlrequest *cmd,
void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
//取得一个初始化好的URB结构
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
//填充该URB结构
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
//发送它
retv = usb_start_wait_urb(urb, timeout, &length);
//检测错误标识
if (retv < 0)
//返回错误标识
return retv;
else
//返回传输的数据长度
return length;
}
这里需要注意的是usb_api_blocking_completion这个参数,他注册到urb的complete中,之后会再提起
usb_start_wait_urb的用途才是真正的发送并完成urb........真麻烦...........
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
struct api_context ctx;
unsigned long expire;
int retval;
init_completion(&ctx.done);
urb->context = &ctx;
urb->actual_length = 0;
//发送URB
retval = usb_submit_urb(urb, GFP_NOIO);
//检测错误标识
if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
//等待urb的完成
if (!wait_for_completion_timeout(&ctx.done, expire))
{
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
}
else
retval = ctx.status;
out:
if (actual_length)
//取得实际传输数据的大小
*actual_length = urb->actual_length;
//释放urb结构
usb_free_urb(urb);
return retval;
}
在这里先放下usb_submit_urb,先说说wait_for_completion_timeout,其实这等于一个异步传输,异步传输,也就是urb完成之后会报告我完成任务了,而不需要一直询问urb,你完成任务了嘛? 你完成任务了嘛?,呢用什么报告完成呢?就是前面的usb_api_blocking_completion,urb执行这个函数之后,线程才会继续执行下面的代码
好,现在回头看usb_submit_urb
usb_submit_urb在/drivers/usb/core/urb.c中
又臭又长........抱怨一下 Orz
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int xfertype, max;
struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out;
//判断urb是否存在
//hcpriv私有数据是否存在
//完成函数是否存在
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
//取得urb所关联的usb设备
dev = urb->dev;
//检测usb设备是否存在并且状态低于默认
if ((!dev) || (dev->state < USB_STATE_DEFAULT))
return -ENODEV;
/* For now, get the endpoint from the pipe. Eventually drivers
* will be required to set urb->ep directly and we will eliminate
* urb->pipe.
*/
//通过管道计算需要使用的usb设备端点号
ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)[usb_pipeendpoint(urb->pipe)];
if (!ep)
return -ENOENT;
//关联urb与端点
urb->ep = ep;
//设置urb的状态
urb->status = -EINPROGRESS;
//初始化实际传送的空间大小
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
//取得端点的传输类型
xfertype = usb_endpoint_type(&ep->desc);
//传输类型为控制信息
if (xfertype == USB_ENDPOINT_XFER_CONTROL)
{
//取得控制请求结构
struct usb_ctrlrequest *setup = (struct usb_ctrlrequest *) urb->setup_packet;
//检测控制请求是否为空
if (!setup)
return -ENOEXEC;
//检测请求类型的要求是否为传入
is_out = !(setup->bRequestType & USB_DIR_IN) || !setup->wLength;
}
else
{
//检测端点的传输方向
is_out = usb_endpoint_dir_out(&ep->desc);
}
/* Cache the direction for later use */
urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | (is_out ? URB_DIR_OUT : URB_DIR_IN);
//端点的传输类型不为控制,且设备的状态小于设置则返回出错
if (xfertype != USB_ENDPOINT_XFER_CONTROL && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
//取得包的最大长度
max = le16_to_cpu(ep->desc.wMaxPacketSize);
//包的长度小于0则返回出错
if (max <= 0)
{
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__func__, max);
return -EMSGSIZE;
}
/* periodic transfers limit size per frame/uframe,
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
//判断传输类型是否为等时
if (xfertype == USB_ENDPOINT_XFER_ISOC)
{
int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH)
{
int mult = 1 + ((max >> 11) & 0x03);
max &= 0x07ff;
max *= mult;
}
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++)
{
len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
}
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */
//检测需要传输的数据要求的大小,小于0则返回出错
if (urb->transfer_buffer_length < 0)
return -EMSGSIZE;
/*
* Force periodic transfer intervals to be legal values that are
* a power of two (so HCDs don't need to).
*
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
//判断传输类型
switch (xfertype)
{
//等时传输
case USB_ENDPOINT_XFER_ISOC:
//中断传输
case USB_ENDPOINT_XFER_INT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
/* too big? */
//判断传输速度
switch (dev->speed)
{
//高速
case USB_SPEED_HIGH: /* units are microframes */
/* NOTE usb handles 2^15 */
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
max = 1024 * 8;
break;
//全速
case USB_SPEED_FULL: /* units are frames/msec */
//低速
case USB_SPEED_LOW:
if (xfertype == USB_ENDPOINT_XFER_INT)
{
if (urb->interval > 255)
return -EINVAL;
/* NOTE ohci only handles up to 32 */
max = 128;
}
else
{
if (urb->interval > 1024)
urb->interval = 1024;
/* NOTE usb and ohci handle up to 2^15 */
max = 1024;
}
break;
default:
return -EINVAL;
}
/* Round down to a power of 2, no more than max */
urb->interval = min(max, 1 << ilog2(urb->interval));
}
//发送urb
return usb_hcd_submit_urb(urb, mem_flags);
}
走完这堆代码之后终于到了usb_hcd_submit_urb,一看还是submit....... 还没发送出去啊?倒~
usb_hcd_submit_urb在/drivers/usb/core/hcd.c中
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
//取得host控制器驱动
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
/* increment urb's reference count as part of giving it to the HCD
* (which will control it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
usb_get_urb(urb);
atomic_inc(&urb->use_count);
atomic_inc(&urb->dev->urbnum);
//usbmon_urb_submit(&hcd->self, urb);
/* NOTE requirements on root-hub callers (usbfs and the hub
* driver, for now): URBs' urb->transfer_buffer must be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data. Also, control
* URBs must be submitted in process context with interrupts
* enabled.
*/
//为urb建立DMA缓存
status = map_urb_for_dma(hcd, urb, mem_flags);
//检测映射是否成功
if (unlikely(status))
{
usbmon_urb_submit_error(&hcd->self, urb, status);
goto error;
}
//判断接收设备是否为根集线器
if (is_root_hub(urb->dev))
status = rh_urb_enqueue(hcd, urb);
else
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
//判断传输是否成功
if (unlikely(status))
{
usbmon_urb_submit_error(&hcd->self, urb, status);
unmap_urb_for_dma(hcd, urb);
error:
urb->hcpriv = NULL;
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
atomic_dec(&urb->dev->urbnum);
if (urb->reject)
wake_up(&usb_kill_urb_queue);
usb_put_urb(urb);
}
//返回错误标识
return status;
}
按fudan_abc的说法,带usbmon的都是usb监控相关的,既然和架构无关,我就无视这些函数好了 = 3=
我们的发送目标为根集线器,呢么调用的当然是rh_urb_enqueue了
rh_urb_enqueue在/drivers/usb/core/hcd.c中
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
//传输类型为中断
if (usb_endpoint_xfer_int(&urb->ep->desc))
return rh_queue_status (hcd, urb);
//传输类型为控制
if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
return -EINVAL;
}
这里为控制传输,呢么调用的就是rh_call_control了
rh_call_control在/drivers/usb/core/hcd.c中
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
{
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
u8 tbuf [sizeof (struct usb_hub_descriptor)]
__attribute__((aligned(4)));
const u8 *bufp = tbuf;
int len = 0;
int status;
int n;
u8 patch_wakeup = 0;
u8 patch_protocol = 0;
might_sleep();
spin_lock_irq(&hcd_root_hub_lock);
//添加URB进端点队列
status = usb_hcd_link_urb_to_ep(hcd, urb);
spin_unlock_irq(&hcd_root_hub_lock);
if (status)
return status;
//设置URB的私有信息为usb_hcd
urb->hcpriv = hcd; /* Indicate it's queued */
//取得控制请求结构
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
wIndex = le16_to_cpu (cmd->wIndex);
wLength = le16_to_cpu (cmd->wLength);
if (wLength > urb->transfer_buffer_length)
goto error;
urb->actual_length = 0;
//判断请求类型
switch (typeReq)
{
/* DEVICE REQUESTS */
/* The root hub's remote wakeup enable bit is implemented using
* driver model wakeup flags. If this system supports wakeup
* through USB, userspace may change the default "allow wakeup"
* policy through sysfs or these calls.
*
* Most root hubs support wakeup from downstream devices, for
* runtime power management (disabling USB clocks and reducing
* VBUS power usage). However, not all of them do so; silicon,
* board, and BIOS bugs here are not uncommon, so these can't
* be treated quite like external hubs.
*
* Likewise, not all root hubs will pass wakeup events upstream,
* to wake up the whole system. So don't assume root hub and
* controller capabilities are identical.
*/
//请求设备信息| 标准类型| 接收为设备,信息为取得状态
case DeviceRequest | USB_REQ_GET_STATUS:
tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)
<< USB_DEVICE_REMOTE_WAKEUP)
| (1 << USB_DEVICE_SELF_POWERED);
tbuf [1] = 0;
len = 2;
break;
//设置设备信息| 标准类型| 接收为设备,信息为清除特征
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (wValue == USB_DEVICE_REMOTE_WAKEUP)
device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
else
goto error;
break;
//设置设备信息| 标准类型| 接收为设备,信息为设置特征
case DeviceOutRequest | USB_REQ_SET_FEATURE:
if (device_can_wakeup(&hcd->self.root_hub->dev) && wValue == USB_DEVICE_REMOTE_WAKEUP)
device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
else
goto error;
break;
//请求设备信息| 标准类型| 接收为设备,信息为取得配置
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
tbuf [0] = 1;
len = 1;
/* FALLTHROUGH */
//设置设备信息| 标准类型| 接收为设备,信息为设置配置
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
break;
//请求设备信息| 标准类型| 接收为设备,信息为取得描述符
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch (wValue & 0xff00)
{
//设备描述符
case USB_DT_DEVICE << 8:
if (hcd->driver->flags & HCD_USB2)
bufp = usb2_rh_dev_descriptor;
else if (hcd->driver->flags & HCD_USB11)
bufp = usb11_rh_dev_descriptor;
else
goto error;
len = 18;
if (hcd->has_tt)
patch_protocol = 1;
break;
//设置描述符
case USB_DT_CONFIG << 8:
if (hcd->driver->flags & HCD_USB2)
{
bufp = hs_rh_config_descriptor;
len = sizeof hs_rh_config_descriptor;
}
else
{
bufp = fs_rh_config_descriptor;
len = sizeof fs_rh_config_descriptor;
}
if (device_can_wakeup(&hcd->self.root_hub->dev))
patch_wakeup = 1;
break;
//字符描述符
case USB_DT_STRING << 8:
n = rh_string (wValue & 0xff, hcd, ubuf, wLength);
if (n < 0)
goto error;
urb->actual_length = n;
break;
default:
goto error;
}
break;
//请求设备信息| 标准类型| 接收为设备,信息为取得接口
case DeviceRequest | USB_REQ_GET_INTERFACE:
tbuf [0] = 0;
len = 1;
/* FALLTHROUGH */
//设置设备信息| 标准类型| 接收为设备,信息为设置接口
case DeviceOutRequest | USB_REQ_SET_INTERFACE:
break;
//设置设备信息| 标准类型| 接收为设备,信息为设置地址
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
//wValue == urb->dev->devaddr
dev_dbg (hcd->self.controller, "root hub device address %d\n",wValue);
break;
/* INTERFACE REQUESTS (no defined feature/status flags) */
/* ENDPOINT REQUESTS */
//请求端点信息| 标准类型| 接收为接口,信息为设置状态
case EndpointRequest | USB_REQ_GET_STATUS:
// ENDPOINT_HALT flag
tbuf [0] = 0;
tbuf [1] = 0;
len = 2;
/* FALLTHROUGH */
//设置端点信息| 标准类型| 接收为接口,信息为清除特征
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
//设置端点信息| 标准类型| 接收为接口,信息为设置特征
case EndpointOutRequest | USB_REQ_SET_FEATURE:
dev_dbg (hcd->self.controller, "no endpoint features yet\n");
break;
/* CLASS REQUESTS (and errors) */
//默认类型
default:
//非标准的请求
/* non-generic request */
switch (typeReq)
{
//取得集线器状态
case GetHubStatus:
//取得端口状态
case GetPortStatus:
len = 4;
break;
//取得集线器描述符
case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor);
break;
}
//运行host控制器驱动的hub_control函数
status = hcd->driver->hub_control (hcd,typeReq, wValue, wIndex,tbuf, wLength);
break;
error:
/* "protocol stall" on error */
status = -EPIPE;
}
//检测错误描述符
if (status)
{
//设置需要复制的长度为0
len = 0;
if (status != -EPIPE)
{
dev_dbg (hcd->self.controller,
"CTRL: TypeReq=0x%x val=0x%x "
"idx=0x%x len=%d ==> %d\n",
typeReq, wValue, wIndex,
wLength, status);
}
}
//检测需要复制的大小
if (len)
{
//检测需要传输的数据大小,小于len则以要传输的大小为准
if (urb->transfer_buffer_length < len)
len = urb->transfer_buffer_length;
//设置实际传输的数据大小
urb->actual_length = len;
// always USB_DIR_IN, toward host
//复制大小为len的bufp信息到ubuf中
memcpy (ubuf, bufp, len);
/* report whether RH hardware supports remote wakeup */
if (patch_wakeup &&len > offsetof (struct usb_config_descriptor,bmAttributes))
((struct usb_config_descriptor *)ubuf)->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
/* report whether RH hardware has an integrated TT */
if (patch_protocol &&len > offsetof(struct usb_device_descriptor,bDeviceProtocol))
((struct usb_device_descriptor *) ubuf)->bDeviceProtocol = 1;
}
/* any errors get returned through the urb completion */
spin_lock_irq(&hcd_root_hub_lock);
//卸载urb与端点的连接
usb_hcd_unlink_urb_from_ep(hcd, urb);
/* This peculiar use of spinlocks echoes what real HC drivers do.
* Avoiding calls to local_irq_disable/enable makes the code
* RT-friendly.
*/
spin_unlock(&hcd_root_hub_lock);
//返回urb
usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&hcd_root_hub_lock);
spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
我们的目标是取得设备描述符
呢么目标就是DeviceRequest | USB_REQ_GET_DESCRIPTOR中的USB_DT_DEVICE << 8了
uhci为1.1设备,呢么就是HCD_USB11了
千辛万苦,终于拿到了我们的设备描述符usb11_rh_dev_descriptor,结构如下
static const u8 usb11_rh_dev_descriptor [18] = {
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x10, 0x01, /* __le16 bcdUSB; v1.1 */
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
0x01, 0x00, /* __le16 idProduct; device 0x0001 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
说明都在旁边,大家当锻炼一下英文吧 Orz
把usb11_rh_dev_descriptor复制到ubuf中,ubuf也就是urb->transfer_buffer,这样就把设备描述符复制到了urb中
到usb_hcd_giveback_urb,这个函数中有大玄机
usb_hcd_giveback_urb在/drivers/usb/core/hcd.c中
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
//卸载urb的私有数据
urb->hcpriv = NULL;
//检测urb的连接状态
if (unlikely(urb->unlinked))
status = urb->unlinked;
else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length < urb->transfer_buffer_length &&
!status))
status = -EREMOTEIO;
//卸载urb的dma缓存映射
unmap_urb_for_dma(hcd, urb);
//usbmon_urb_complete(&hcd->self, urb, status);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
//设置urb的状态
urb->status = status;
//运行urb的完成函数
urb->complete (urb);
atomic_dec (&urb->use_count);
if (unlikely (urb->reject))
wake_up (&usb_kill_urb_queue);
usb_put_urb (urb);
}
urb->complete (urb);这句看到了么,前面在苦苦等待urb完成的线程终于可以前进了,因为这里调用的正是usb_api_blocking_completion
usb_get_device_descriptor执行完毕之后, usb11_rh_dev_descriptor就在usb_device. descriptor中了
接下来到usb_new_device
usb_new_device在/drivers/usb/core/hub.c中
int usb_new_device(struct usb_device *udev)
{
int err;
//探测怪癖
usb_detect_quirks(udev); /* Determine quirks */
//取得设备设置
err = usb_configure_device(udev); /* detect & probe dev/intfs */
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)));
/* 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.
*/
//注册设备到sysfs中
err = device_add(&udev->dev);
if (err)
{
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
/* put device-specific files into sysfs */
//建立USB设备的属性文件
usb_create_sysfs_dev_files(udev);
/* Tell the world! */
//输出设备信息
announce_device(udev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
return err;
};
usb_detect_quirks的任务根据设备描述符中的数据检测是否为怪癖设备,某些设备要求的复位时间长一点啥之后的不符合usb规范的设置,这个函数就不详细介绍了
usb_configure_device的用途为取得信息描述符(配置描述符,接口描述符和端口描述符的联合体)
usb_configure_device在/drivers/usb/core/hub.c中
static int usb_configure_device(struct usb_device *udev)
{
int err;
if (udev->config == NULL)
{
//取得设置
err = usb_get_configuration(udev);
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);
}
err = usb_configure_device_otg(udev);
fail:
return err;
}
打断一下,最后的usb_configure_device_otg函数是otg内容,也就是On-The-Go,是为了让一些移动设备也能做host而出的规范,关于otg的内容我不做分析 = 3= 请大家略过