Chinaunix首页 | 论坛 | 博客
  • 博客访问: 218789
  • 博文数量: 112
  • 博客积分: 275
  • 博客等级: 二等列兵
  • 技术积分: 565
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-20 10:52
文章分类

全部博文(112)

文章存档

2014年(3)

2013年(2)

2012年(64)

2011年(43)

分类:

2012-07-17 18:44:58

启动主机控制器和根集线器之后,现在来注册根集线器
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=  请大家略过
阅读(792) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~