linux下控制usb设备,LINUX下USB1.1设备学习小记(4)_uhci(4)

本文详细介绍了USB设备在主机控制器上注册的过程,包括启动根集线器、注册根集线器、获取设备描述符等步骤。通过对驱动源代码的分析,揭示了USB设备如何通过一系列内核函数交互,最终完成设备描述符的获取。这一过程涉及到如`usb_get_device_descriptor`、`usb_submit_urb`等关键函数,以及urb、DMA缓存映射和设备状态管理等多个环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

启动主机控制器和根集线器之后,现在来注册根集线器

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=  请大家略过

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值