文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>LINUX下USB1.1设备学习小记(4)_uhci(6)

LINUX下USB1.1设备学习小记(4)_uhci(6)

时间:2009-03-14  来源:superfight

现在到usb_new_device,到了这里,就要注册usb设备了,详细的注册过程我就不分析了,还记得之前注册的usb_bus_type和usb_device_type么, usb_bus_type指明了驱动在usb总线上搜索,现在usb总线上有3个驱动,分别为usb_generic_driver, usbfs_driver和hub_driver 现在进入到usb总线的匹配函数usb_device_match  
usb_device_match在/drivers/usb/core/driver.c中

static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
 //判断注册的设备为usb设备还是usb接口设备
 if (is_usb_device(dev))
 {
  /* interface drivers never match devices */
  //检测驱动的for_devices标志
  //为1则是usb设备驱动,为0则为usb接口驱动
  if (!is_usb_device_driver(drv))
   return 0;
  /* TODO: Add real matching code */
  return 1;
 }
 else
 {
  struct usb_interface *intf;
  struct usb_driver *usb_drv;
  const struct usb_device_id *id;
  /* device drivers never match interfaces */
  //检测驱动的for_devices标志
  //为1则是usb设备驱动,为0则为usb接口驱动
  if (is_usb_device_driver(drv))
   return 0;
  //取得接口结构
  intf = to_usb_interface(dev);
  //取得usb驱动结构
  usb_drv = to_usb_driver(drv);
  //匹配ID
  id = usb_match_id(intf, usb_drv->id_table);
  if (id)
   return 1;
  //匹配动态ID
  id = usb_match_dynamic_id(intf, usb_drv);
  if (id)
   return 1;
 }
 return 0;
}

  is_usb_device判断为usb接口设备还是usb设备,这里为usb_device_type,当然是进入if了,然后判断驱动的for_devices标志,在3个驱动中,只有usb_generic_driver为1,所以现在进入usb_generic_driver的初始化函数generic_probe     generic_probe在/drivers/usb/core/generic.c中  

static int generic_probe(struct usb_device *udev)
{
 int err, c;
 /* 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负责选一个最佳的配置  
usb_choose_configuration在/drivers/usb/core/generic.c中
 

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! */
  //判断配置中的接口数是否大于0
  if (c->desc.bNumInterfaces > 0)
   //取得接口描述符
   desc = &c->intf_cache[0]->altsetting->desc;
  /*
   * 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;
  }
  /* 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
  }
  /* 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;
  }
  /* If all the remaining configs are vendor-specific,
   * choose the first one. */
   //如果所有的配置都为厂商特定
   //则使用第一个
  else if (!best)
   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;
  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_choose_configuration会返回选中的配置描述符中的配置值,这个值的作用会在下面介绍
现在到usb_set_configuration,这个函数负责按照传递进来的配置值匹配对应的配置结构,并历遍该配置下所有的接口,为所有的接口抽象为接口设备匹配对应的接口驱动,如果有接口号一样的接口,会有接口联合描述符,在这个描述符中有如何使用接口的信息,这里不考虑(其实是我没有这样的多接口的设备进行测试....... = 3=)
    usb_set_configuration在/drivers/usb/core/generic.c中

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;
 else
 {
  //历遍配置描述符
  for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
  {
   //匹配配置描述符中的配置值与要求值
   if (dev->config[i].desc.bConfigurationValue == configuration)
   {
    //取得相应的配置结构
    cp = &dev->config[i];
    break;
   }
  }
 }
 //匹配值不为0且相应的结构不存在则返回错误
 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.
  */
 //弹出警告,匹配值为0可以接受,-1则要求卸载设备
 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;
 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.
  */
  //状态不为USB_STATE_ADDRESS则重置1号端点开始的所有端点
 if (dev->state != USB_STATE_ADDRESS)
  usb_disable_device(dev, 1); /* Skip ep0 */
 //发送设置配置消息
 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
         USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
         NULL, 0, USB_CTRL_SET_TIMEOUT);
 if (ret < 0)
 {
  /* All the old state is gone, so what else can we do?
   * The device is probably useless now anyway.
   */
  cp = NULL;
 }
 //连接当前配置到usb_device
 dev->actconfig = cp;
 //当前配置不存在则设置设备的状态为寻址
 //及悬挂设备
 if (!cp)
 {
  usb_set_device_state(dev, USB_STATE_ADDRESS);
  usb_autosuspend_device(dev);
  goto free_interfaces;
 }
 //设置设备状态为配置
 usb_set_device_state(dev, 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);
  //取得0号接口配置
  alt = usb_altnum_to_altsetting(intf, 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];
  //设置接口设备当前所使用的接口
  intf->cur_altsetting = alt;
  //使能该接口下的所有端点,这里会使能uhci的1号输入端点
  usb_enable_interface(dev, intf);
  //设置接口设备信息
  intf->dev.parent = &dev->dev;
  intf->dev.driver = NULL;
  intf->dev.bus = &usb_bus_type;
  intf->dev.type = &usb_if_device_type;
  intf->dev.groups = usb_interface_groups;
  intf->dev.dma_mask = dev->dev.dma_mask;
  //初始化设备
  device_initialize(&intf->dev);
  //设置接口为等待
  mark_quiesced(intf);
  //设置接口设备名称
  sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",dev->bus->busnum, dev->devpath,
   configuration, alt->desc.bInterfaceNumber);
 }
 kfree(new_interfaces);
 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];
  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);
  if (ret != 0)
  {
   dev_err(&dev->dev, "device_add(%s) --> %d\n",intf->dev.bus_id, ret);
   continue;
  }
  usb_create_sysfs_intf_files(intf);
 }
 usb_autosuspend_device(dev);
 return 0;
}


ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
         USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
         NULL, 0, USB_CTRL_SET_TIMEOUT);
这句代码发送控制消息,还是进入到rh_call_control中,这次的case为DeviceOutRequest | USB_REQ_SET_CONFIGURATION,发现就孤零零的一个break,太好了,啥都不做,直接退出,太感动了
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
总线还是呢个usb总线,但是类型不一样了,这里设置的是接口设备类型usb_if_device_type,不是usb_device_type
device_add, 又看见device_add,还是进入到usb总线的匹配函数usb_device_match中,不过这次到了else中

else
 {
  struct usb_interface *intf;
  struct usb_driver *usb_drv;
  const struct usb_device_id *id;
  /* device drivers never match interfaces */
  //检测驱动的for_devices标志
  //为1则是usb设备驱动,为0则为usb接口驱动
  if (is_usb_device_driver(drv))
   return 0;
  //取得接口结构
  intf = to_usb_interface(dev);
  //取得usb驱动结构
  usb_drv = to_usb_driver(drv);
  //匹配ID
  id = usb_match_id(intf, usb_drv->id_table);
  if (id)
   return 1;
  //匹配动态ID
  id = usb_match_dynamic_id(intf, usb_drv);
  if (id)
   return 1;
 }

这次所要匹配的驱动是for_devices标志,所以有hub_driver和usbfs_driver两个入选,不看ID是否匹配, usbfs_driver中的probe函数也为空,所以不用考虑usbfs_driver,呢么就是hub_driver了(其实我自己也还没看ID匹配 = 3= ) 根集线器是一个usb设备,这个usb设备有一个接口,该接实现集线器的功能 好,现在进入hub_probe中
hub_probe在在/drivers/usb/core/hub.c中

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
 struct usb_host_interface *desc;
 struct usb_endpoint_descriptor *endpoint;
 struct usb_device *hdev;
 struct usb_hub *hub;
 //取得接口
 desc = intf->cur_altsetting;
 //取得usb设备
 hdev = interface_to_usbdev(intf);
#ifdef CONFIG_USB_OTG_BLACKLIST_HUB
 if (hdev->parent)
 {
  dev_warn(&intf->dev, "ignoring external hub\n");
  return -ENODEV;
 }
#endif
 /* Some hubs have a subclass of 1, which AFAICT according to the */
 /* specs is not defined, but it works */
 if ((desc->desc.bInterfaceSubClass != 0) && (desc->desc.bInterfaceSubClass != 1))
 {
descriptor_error:
  dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
  return -EIO;
 }
 /* Multiple endpoints? What kind of mutant ninja-hub is this? */
 //端点数不为1则出错
 if (desc->desc.bNumEndpoints != 1)
  goto descriptor_error;
 //取得端点描述符
 endpoint = &desc->endpoint[0].desc;
 /* If it's not an interrupt in endpoint, we'd better punt! */
 //测试端点的传输类型是否为中断,方向是否为传入
 if (!usb_endpoint_is_int_in(endpoint))
  goto descriptor_error;
 /* We found a hub */
 dev_info (&intf->dev, "USB hub found\n");
 //分配集线器结构所需的空间
 hub = kzalloc(sizeof(*hub), GFP_KERNEL);
 //分配出错则返回
 if (!hub)
 {
  dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
  return -ENOMEM;
 }
 kref_init(&hub->kref);
 INIT_LIST_HEAD(&hub->event_list);
 //连接接口设备到集线器
 hub->intfdev = &intf->dev;
 //连接usb设备到集线器
 hub->hdev = hdev;
 INIT_DELAYED_WORK(&hub->leds, led_work);
 //增加接口设备的计数器
 usb_get_intf(intf);
 //连接集线器到接口设备
 usb_set_intfdata (intf, hub);
 //置驱动需要远程唤醒为真
 intf->needs_remote_wakeup = 1;
 //为高速设备则增加高速设备计数器
 if (hdev->speed == USB_SPEED_HIGH)
  highspeed_hubs++;
 //配置集线器
 if (hub_configure(hub, endpoint) >= 0)
  return 0;
 //配置集线器失败 则卸载连接
 hub_disconnect (intf);
 return -ENODEV;
}


接着到hub_configure
 
hub_configure在/drivers/usb/core/hub.c中

static int hub_configure(struct usb_hub *hub,
 struct usb_endpoint_descriptor *endpoint)
{
 struct usb_device *hdev = hub->hdev;
 struct device *hub_dev = hub->intfdev;
 u16 hubstatus, hubchange;
 u16 wHubCharacteristics;
 unsigned int pipe;
 int maxp, ret;
 char *message;
 //分配集线器的缓存
 hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,&hub->buffer_dma);
 //缓存空间分配失败则返回出错
 if (!hub->buffer)
 {
  message = "can't allocate hub irq buffer";
  ret = -ENOMEM;
  goto fail;
 }
 //分配状态报告结构的空间
 hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
 //分配失败则返回
 if (!hub->status)
 {
  message = "can't kmalloc hub status buffer";
  ret = -ENOMEM;
  goto fail;
 }
 mutex_init(&hub->status_mutex);
 //分配集线器描述符空间
 hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 //分配失败则返回错误
 if (!hub->descriptor)
 {
  message = "can't kmalloc hub descriptor";
  ret = -ENOMEM;
  goto fail;
 }
 /* Request the entire hub descriptor.
  * hub->descriptor can handle USB_MAXCHILDREN ports,
  * but the hub can/will return fewer bytes here.
  */
  //取得集线器描述符
 ret = get_hub_descriptor(hdev, hub->descriptor,sizeof(*hub->descriptor));
 if (ret < 0)
 {
  message = "can't read hub descriptor";
  goto fail;
 }
 else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN)
 {
  message = "hub has too many ports!";
  ret = -ENODEV;
  goto fail;
 }
 hdev->maxchild = hub->descriptor->bNbrPorts;
 dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,(hdev->maxchild == 1) ? "" : "s");
 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 //检测是否为复合设备
 if (wHubCharacteristics & HUB_CHAR_COMPOUND)
 {
  int i;
  char portstr [USB_MAXCHILDREN + 1];
  for (i = 0; i < hdev->maxchild; i++)
   portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8))
    ? 'F' : 'R';
  portstr[hdev->maxchild] = 0;
  dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
 }
 else
  dev_dbg(hub_dev, "standalone hub\n");
 switch (wHubCharacteristics & HUB_CHAR_LPSM)
 {
  case 0x00:
   dev_dbg(hub_dev, "ganged power switching\n");
   break;
  case 0x01:
   dev_dbg(hub_dev, "individual port power switching\n");
   break;
  case 0x02:
  case 0x03:
   dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
   break;
 }
 switch (wHubCharacteristics & HUB_CHAR_OCPM)
 {
  case 0x00:
   dev_dbg(hub_dev, "global over-current protection\n");
   break;
  case 0x08:
   dev_dbg(hub_dev, "individual port over-current protection\n");
   break;
  case 0x10:
  case 0x18:
   dev_dbg(hub_dev, "no over-current protection\n");
                        break;
 }
 spin_lock_init (&hub->tt.lock);
 INIT_LIST_HEAD (&hub->tt.clear_list);
 INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
 switch (hdev->descriptor.bDeviceProtocol)
 {
  case 0:
   break;
  case 1:
   dev_dbg(hub_dev, "Single TT\n");
   hub->tt.hub = hdev;
   break;
  case 2:
   ret = usb_set_interface(hdev, 0, 1);
   if (ret == 0)
   {
    dev_dbg(hub_dev, "TT per port\n");
    hub->tt.multi = 1;
   }
   else
    dev_err(hub_dev, "Using single TT (err %d)\n",
     ret);
   hub->tt.hub = hdev;
   break;
  default:
   dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
    hdev->descriptor.bDeviceProtocol);
   break;
 }
 /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
 switch (wHubCharacteristics & HUB_CHAR_TTTT)
 {
  case HUB_TTTT_8_BITS:
   if (hdev->descriptor.bDeviceProtocol != 0)
   {
    hub->tt.think_time = 666;
    dev_dbg(hub_dev, "TT requires at most %d "
      "FS bit times (%d ns)\n",
     8, hub->tt.think_time);
   }
   break;
  case HUB_TTTT_16_BITS:
   hub->tt.think_time = 666 * 2;
   dev_dbg(hub_dev, "TT requires at most %d "
     "FS bit times (%d ns)\n",
    16, hub->tt.think_time);
   break;
  case HUB_TTTT_24_BITS:
   hub->tt.think_time = 666 * 3;
   dev_dbg(hub_dev, "TT requires at most %d "
     "FS bit times (%d ns)\n",
    24, hub->tt.think_time);
   break;
  case HUB_TTTT_32_BITS:
   hub->tt.think_time = 666 * 4;
   dev_dbg(hub_dev, "TT requires at most %d "
     "FS bit times (%d ns)\n",
    32, hub->tt.think_time);
   break;
 }
 /* probe() zeroes hub->indicator[] */
 if (wHubCharacteristics & HUB_CHAR_PORTIND)
 {
  hub->has_indicators = 1;
  dev_dbg(hub_dev, "Port indicators are supported\n");
 }
 dev_dbg(hub_dev, "power on to power good time: %dms\n", hub->descriptor->bPwrOn2PwrGood * 2);
 /* power budgeting mostly matters with bus-powered hubs,
  * and battery-powered root hubs (may provide just 8 mA).
  */
 ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
 if (ret < 2)
 {
  message = "can't get hub status";
  goto fail;
 }
 le16_to_cpus(&hubstatus);
 //检测该集线器是否为根集线器
 if (hdev == hdev->bus->root_hub)
 {
  if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
   hub->mA_per_port = 500;
  else
  {
   hub->mA_per_port = hdev->bus_mA;
   hub->limited_power = 1;
  }
 }
 else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0)
 {
  dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",hub->descriptor->bHubContrCurrent);
  hub->limited_power = 1;
  if (hdev->maxchild > 0)
  {
   int remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
   if (remaining < hdev->maxchild * 100)
    dev_warn(hub_dev,
     "insufficient power available "
     "to use all downstream ports\n");
   hub->mA_per_port = 100; /* 7.2.1.1 */
  }
 }
 else
 { /* Self-powered external hub */
  /* FIXME: What about battery-powered external hubs that
   * provide less current per port? */
  hub->mA_per_port = 500;
 }
 
 if (hub->mA_per_port < 500)
  dev_dbg(hub_dev, "%umA bus power budget for each child\n",
    hub->mA_per_port);
 //取得集线器状态及改变
 ret = hub_hub_status(hub, &hubstatus, &hubchange);
 if (ret < 0)
 {
  message = "can't get hub status";
  goto fail;
 }
 /* local power status reports aren't always correct */
 if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
  dev_dbg(hub_dev, "local power source is %s\n",
   (hubstatus & HUB_STATUS_LOCAL_POWER)
   ? "lost (inactive)" : "good");
 if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)
  dev_dbg(hub_dev, "%sover-current condition exists\n",
   (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 /* set up the interrupt endpoint
  * We use the EP's maxpacket size instead of (PORTS+1+7)/8
  * bytes as USB2.0[11.12.3] says because some hubs are known
  * to send more data (and thus cause overflow). For root hubs,
  * maxpktsize is defined in hcd.c's fake endpoint descriptors
  * to be big enough for at least USB_MAXCHILDREN ports. */
 //设置管道 
 pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
 //取得包的最大值
 maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
 //检测包的最大值是否大于缓存
 if (maxp > sizeof(*hub->buffer))
  maxp = sizeof(*hub->buffer);
 //分配一个urb
 hub->urb = usb_alloc_urb(0, GFP_KERNEL);
 //分配失败则返回错误
 if (!hub->urb)
 {
  message = "couldn't allocate interrupt urb";
  ret = -ENOMEM;
  goto fail;
 }
 //填充urb
 usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,hub, endpoint->bInterval);
 hub->urb->transfer_dma = hub->buffer_dma;
 hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 /* maybe cycle the hub leds */
 if (hub->has_indicators && blinkenlights)
  hub->indicator [0] = INDICATOR_CYCLE;
 hub_power_on(hub);
 hub_activate(hub);
 return 0;
fail:
 dev_err (hub_dev, "config failed, %s (err %d)\n",
   message, ret);
 /* hub_disconnect() frees urb and descriptor */
 return ret;
}


ret = get_hub_descriptor(hdev, hub->descriptor,sizeof(*hub->descriptor));
这句是取得集线器描述符,他调用的是get_hub_descriptor, get_hub_descriptor又调用
ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
  USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
  USB_DT_HUB << 8, 0, data, size,
  USB_CTRL_GET_TIMEOUT);
好~ 我们又来到了rh_call_control中,这次是case,噢~ 不对,这次是到了default中,在default中无论case是什么,最后都会调用hcd->driver->hub_control, hcd->driver->hub_control的真面目是uhci_hub_control
相关阅读 更多 +
排行榜 更多 +
开局一个小兵最新版

开局一个小兵最新版

休闲益智 下载
火柴人联盟2腾讯qq登录版

火柴人联盟2腾讯qq登录版

体育竞技 下载
tsuki odyssey游戏(月兔冒险奥德赛)

tsuki odyssey游戏(月兔冒险奥德赛)

休闲益智 下载