USB驱动框架分析2
2015-06-17 10:11
309 查看
本文先分析OHCI的usb主机驱动控制器驱动,root hub这个usb_device的创建过程,读取配置描述符过程,设置配置,然后添加接口到系统。
1. 先看下数据结构
(1)分配urb结构
(2)填充此urb结构
(3)将urb结构提交到主机控制器。
usb_start_wait_urb
usb_submit_urb
usb_pipe_endpoint
usb_hcd_submit_urb
rh_urb_enqueue(hcd, urb) //root hub的urb处理
rh_call_control
hcd->driver->hub_control
ohci_s3c2410_hub_control
hcd->driver->urb_enqueue(hcd, urb, mem_flags)
//非root hub的urb处理
wait_for_completion_timeout
获取到设备描述符后,就调用usb_new_device函数,此函数读取并解析设备描述符后就调用device_add添加到linux设备模型中,会触发设备的匹配(usb_device_match)。因为它是usb_device会匹配到唯一的usb_device_driver。generic_probe会被调用。
1. 先看下数据结构
struct ohci_hcd { spinlock_t lock; /* * I/O memory used to communicate with the HC (dma-consistent) */ struct ohci_regs __iomem *regs; //与主机控制器通信的IO内存 /* * main memory used to communicate with the HC (dma-consistent). * hcd adds to schedule for a live hc any time, but removals finish * only at the start of the next frame. */ struct ohci_hcca *hcca; dma_addr_t hcca_dma; struct ed *ed_rm_list; /* to be removed */ //指向被移除的OHCI端点 struct ed *ed_bulktail; /* last in bulk list */ //批量队列尾 struct ed *ed_controltail; /* last in ctrl list */ //控制队列尾 struct ed *periodic [NUM_INTS]; /* shadow int_table */ /* * OTG controllers and transceivers need software interaction; * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; void (*start_hnp)(struct ohci_hcd *ohci); /* * memory management for queue data structures */ struct dma_pool *td_cache; struct dma_pool *ed_cache; struct td *td_hash [TD_HASH_SIZE]; struct list_head pending; /* * driver state */ int num_ports; int load [NUM_INTS]; u32 hc_control; /* copy of hc control reg */ unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ unsigned autostop:1; /* rh auto stopping/stopped */ unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ #define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ #define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ #define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ #define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ /* Needed for ZF Micro quirk */ struct timer_list unlink_watchdog; unsigned eds_scheduled; struct ed *ed_to_check; unsigned zf_delay; #ifdef DEBUG struct dentry *debug_dir; struct dentry *debug_async; struct dentry *debug_periodic; struct dentry *debug_registers; #endif };直接看ohci_hcd_s3c2410_drv_probe
static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, struct platform_device *dev) { struct usb_hcd *hcd = NULL; int retval; s3c2410_usb_set_power(dev->dev.platform_data, 1, 1); //配置端口1电源 s3c2410_usb_set_power(dev->dev.platform_data, 2, 1); //配置端口2电源 hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx"); //创建主机控制器 if (hcd == NULL) return -ENOMEM; hcd->rsrc_start = dev->resource[0].start; //io资源的开始地址 hcd->rsrc_len = resource_size(&dev->resource[0]); //io资源的长度 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_err(&dev->dev, "request_mem_region failed\n"); retval = -EBUSY; goto err_put; } clk = clk_get(&dev->dev, "usb-host"); //获取时钟信息 if (IS_ERR(clk)) { dev_err(&dev->dev, "cannot get usb-host clock\n"); retval = PTR_ERR(clk); goto err_mem; } usb_clk = clk_get(&dev->dev, "usb-bus-host"); if (IS_ERR(usb_clk)) { dev_err(&dev->dev, "cannot get usb-bus-host clock\n"); retval = PTR_ERR(usb_clk); goto err_clk; } s3c2410_start_hc(dev, hcd); //将IO地址空间映射到内存的虚拟地址空间 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&dev->dev, "ioremap failed\n"); retval = -ENOMEM; goto err_ioremap; } ohci_hcd_init(hcd_to_ohci(hcd)); //初始化主机控制器 retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED); //主机控制器的注册 if (retval != 0) goto err_ioremap; return 0; err_ioremap: s3c2410_stop_hc(dev); iounmap(hcd->regs); clk_put(usb_clk); err_clk: clk_put(clk); err_mem: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put: usb_put_hcd(hcd); return retval; }可以看到主要有两个core层的api接口usb_create_hcd和usb_add_hcd
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name, struct usb_hcd *primary_hcd) { struct usb_hcd *hcd; hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); if (!hcd) { dev_dbg (dev, "hcd alloc failed\n"); return NULL; } if (primary_hcd == NULL) { hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex), GFP_KERNEL); if (!hcd->bandwidth_mutex) { kfree(hcd); dev_dbg(dev, "hcd bandwidth mutex alloc failed\n"); return NULL; } mutex_init(hcd->bandwidth_mutex); dev_set_drvdata(dev, hcd); } else { hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; hcd->primary_hcd = primary_hcd; primary_hcd->primary_hcd = primary_hcd; hcd->shared_hcd = primary_hcd; primary_hcd->shared_hcd = hcd; } kref_init(&hcd->kref); usb_bus_init(&hcd->self); hcd->self.controller = dev; hcd->self.bus_name = bus_name; hcd->self.uses_dma = (dev->dma_mask != NULL); init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; #ifdef CONFIG_USB_SUSPEND INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif hcd->driver = driver; hcd->speed = driver->flags & HCD_MASK; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; return hcd; }
int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { int retval; struct usb_device *rhdev; dev_info(hcd->self.controller, "%s\n", hcd->product_desc); /* Keep old behaviour if authorized_default is not in [0, 1]. */ if (authorized_default < 0 || authorized_default > 1) hcd->authorized_default = hcd->wireless? 0 : 1; else hcd->authorized_default = authorized_default; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* HC is in reset state, but accessible. Now do the one-time init, * bottom up so that hcds can customize the root hubs before khubd * starts talking to them. (Note, bus id is assigned early too.) */ if ((retval = hcd_buffer_create(hcd)) != 0) { //初始化一个buffer池 dev_dbg(hcd->self.controller, "pool alloc failed\n"); return retval; } if ((retval = usb_register_bus(&hcd->self)) < 0) //注册此总线 goto err_register_bus; if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { //分配usb_device结构 dev_err(hcd->self.controller, "unable to allocate root hub\n"); retval = -ENOMEM; goto err_allocate_root_hub; } hcd->self.root_hub = rhdev; switch (hcd->speed) { case HCD_USB11: rhdev->speed = USB_SPEED_FULL; break; case HCD_USB2: rhdev->speed = USB_SPEED_HIGH; break; case HCD_USB3: rhdev->speed = USB_SPEED_SUPER; break; default: retval = -EINVAL; goto err_set_rh_speed; } /* wakeup flag init defaults to "everything works" for root hubs, * but drivers can override it in reset() if needed, along with * recording the overall controller's system wakeup capability. */ device_init_wakeup(&rhdev->dev, 1); /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is * registered. But since the controller can die at any time, * let's initialize the flag before touching the hardware. */ set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); /* "reset" is misnamed; its role is now one-time init. the controller * should already have been reset (and boot firmware kicked off etc). */ //如果有reset函数就调用 if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { dev_err(hcd->self.controller, "can't setup\n"); goto err_hcd_driver_setup; } hcd->rh_pollable = 1; /* NOTE: root hub and controller capabilities may not be the same */ if (device_can_wakeup(hcd->self.controller) && device_can_wakeup(&hcd->self.root_hub->dev)) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); /* enable irqs just before we start the controller */ if (usb_hcd_is_primary_hcd(hcd)) { retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); if (retval) goto err_request_irq; } hcd->state = HC_STATE_RUNNING; retval = hcd->driver->start(hcd); if (retval < 0) { dev_err(hcd->self.controller, "startup error %d\n", retval); goto err_hcd_driver_start; } /* starting here, usbcore will pay attention to this root hub */ rhdev->bus_mA = min(500u, hcd->power_budget); if ((retval = register_root_hub(hcd)) != 0) //注册此root hub goto err_register_root_hub; retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); if (retval < 0) { printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", retval); goto error_create_attr_group; } if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) usb_hcd_poll_rh_status(hcd); return retval; error_create_attr_group: clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); if (HC_IS_RUNNING(hcd->state)) hcd->state = HC_STATE_QUIESCING; spin_lock_irq(&hcd_root_hub_lock); hcd->rh_registered = 0; spin_unlock_irq(&hcd_root_hub_lock); #ifdef CONFIG_USB_SUSPEND cancel_work_sync(&hcd->wakeup_work); #endif mutex_lock(&usb_bus_list_lock); usb_disconnect(&rhdev); /* Sets rhdev to NULL */ mutex_unlock(&usb_bus_list_lock); err_register_root_hub: hcd->rh_pollable = 0; clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); del_timer_sync(&hcd->rh_timer); hcd->driver->stop(hcd); hcd->state = HC_STATE_HALT; clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); del_timer_sync(&hcd->rh_timer); err_hcd_driver_start: if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0) free_irq(irqnum, hcd); err_request_irq: err_hcd_driver_setup: err_set_rh_speed: usb_put_dev(hcd->self.root_hub); err_allocate_root_hub: usb_deregister_bus(&hcd->self); err_register_bus: hcd_buffer_destroy(hcd); return retval; }
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; usb_dev->devnum = devnum; usb_dev->bus->devnum_next = devnum + 1; memset (&usb_dev->bus->devmap.devicemap, 0, sizeof usb_dev->bus->devmap.devicemap); set_bit (devnum, usb_dev->bus->devmap.devicemap); usb_set_device_state(usb_dev, USB_STATE_ADDRESS); //设置usb_device的状态 mutex_lock(&usb_bus_list_lock); usb_dev->ep0.desc.wMaxPacketSize = 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", dev_name(&usb_dev->dev), retval); return (retval < 0) ? retval : -EMSGSIZE; } retval = usb_new_device (usb_dev); //注册此usb_device if (retval) { dev_err (parent_dev, "can't register root hub for %s, %d\n", dev_name(&usb_dev->dev), retval); } mutex_unlock(&usb_bus_list_lock); if (retval == 0) { spin_lock_irq (&hcd_root_hub_lock); hcd->rh_registered = 1; spin_unlock_irq (&hcd_root_hub_lock); /* Did the HC die before the root hub was registered? */ if (HCD_DEAD(hcd)) usb_hc_died (hcd); /* This time clean up */ } return retval; }
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) memcpy(&dev->descriptor, desc, size); kfree(desc); return ret; } int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { int i; int result; memset(buf, 0, size); /* Make sure we parse really received data */ 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 = -ENODATA; continue; } break; } return result; }再来看下如何才能获取设备描述符
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; dr->bRequestType = requesttype; dr->bRequest = request; dr->wValue = cpu_to_le16(value); dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(size); /* dbg("usb_control_msg"); */ ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); kfree(dr); return ret; } 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 = usb_alloc_urb(0, GFP_NOIO); if (!urb) return -ENOMEM; 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_internal_control_msg是一个比较重要的函数,此函数主要有3个过程
(1)分配urb结构
(2)填充此urb结构
(3)将urb结构提交到主机控制器。
usb_start_wait_urb
usb_submit_urb
usb_pipe_endpoint
usb_hcd_submit_urb
rh_urb_enqueue(hcd, urb) //root hub的urb处理
rh_call_control
hcd->driver->hub_control
ohci_s3c2410_hub_control
hcd->driver->urb_enqueue(hcd, urb, mem_flags)
//非root hub的urb处理
wait_for_completion_timeout
获取到设备描述符后,就调用usb_new_device函数,此函数读取并解析设备描述符后就调用device_add添加到linux设备模型中,会触发设备的匹配(usb_device_match)。因为它是usb_device会匹配到唯一的usb_device_driver。generic_probe会被调用。
int usb_new_device(struct usb_device *udev) { int err; if (udev->parent) { /* Initialize non-root-hub device wakeup to disabled; * device (un)configuration controls wakeup capable * sysfs power/wakeup controls wakeup enabled/disabled */ device_init_wakeup(&udev->dev, 0); } /* Tell the runtime-PM framework the device is active */ pm_runtime_set_active(&udev->dev); pm_runtime_get_noresume(&udev->dev); pm_runtime_use_autosuspend(&udev->dev); pm_runtime_enable(&udev->dev); /* By default, forbid autosuspend for all devices. It will be * allowed for hubs during binding. */ usb_disable_autosuspend(udev); err = usb_enumerate_device(udev); /* Read descriptors */ //读取并解析设备描述符 if (err < 0) goto fail; dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n", udev->devnum, udev->bus->busnum, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); /* Tell the world! */ announce_device(udev); //把此usb_device结构的信息打印出来 device_enable_async_suspend(&udev->dev); /* Register the device. The device driver is responsible * for configuring the device and invoking the add-device * notifier chain (used by usbfs and possibly others). */ err = device_add(&udev->dev); //添加到linux设备模型,会触发匹配usb_device_match if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); goto fail; } (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); //创建端点设备 usb_mark_last_busy(udev); pm_runtime_put_sync_autosuspend(&udev->dev); return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); pm_runtime_disable(&udev->dev); pm_runtime_set_suspended(&udev->dev); return err; }
static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { //针对usb设备 /* interface drivers never match devices */ if (!is_usb_device_driver(drv)) return 0; /* TODO: Add real matching code */ return 1; } else if (is_usb_interface(dev)) { //针对usb接口 struct usb_interface *intf; struct usb_driver *usb_drv; const struct usb_device_id *id; /* device drivers never match interfaces */ if (is_usb_device_driver(drv)) return 0; intf = to_usb_interface(dev); usb_drv = to_usb_driver(drv); id = usb_match_id(intf, usb_drv->id_table); if (id) return 1; id = usb_match_dynamic_id(intf, usb_drv); if (id) return 1; } return 0; }
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 (usb_device_is_owned(udev)) ; /* Don't configure if the device is owned */ else 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); //设置配置,并注册interfrace 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; }
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; struct usb_hcd *hcd = bus_to_hcd(dev->bus); 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]; //取得索引号为configuration的配置结构体 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; if (cp) { //分配bNumInterfaces个接口结构 nintf = cp->desc.bNumInterfaces; new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_NOIO); if (!new_interfaces) { dev_err(&dev->dev, "Out of memory\n"); return -ENOMEM; } for (; n < nintf; ++n) { new_interfaces = kzalloc( sizeof(struct usb_interface), GFP_NOIO); if (!new_interfaces ) { dev_err(&dev->dev, "Out of memory\n"); ret = -ENOMEM; free_interfaces: while (--n >= 0) kfree(new_interfaces ); 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. */ mutex_lock(hcd->bandwidth_mutex); if (dev->state != USB_STATE_ADDRESS) usb_disable_device(dev, 1); /* Skip ep0 */ /* Get rid of pending async Set-Config requests for this device */ cancel_async_set_config(dev); /* Make sure we have bandwidth (and available HCD resources) for this * configuration. Remove endpoints from the schedule if we're dropping * this configuration to set configuration 0. After this point, the * host controller will not allow submissions to dropped endpoints. If * this call fails, the device state is unchanged. */ ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); if (ret < 0) { mutex_unlock(hcd->bandwidth_mutex); usb_autosuspend_device(dev); goto free_interfaces; } //发送USB_REQ_SET_CONFIGURATION的urb信息来设置设备的配置 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; } dev->actconfig = cp; if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); mutex_unlock(hcd->bandwidth_mutex); usb_autosuspend_device(dev); goto free_interfaces; } mutex_unlock(hcd->bandwidth_mutex); usb_set_device_state(dev, USB_STATE_CONFIGURED); /* Initialize the new interface structures and the * hc/hcd/usbcore interface/endpoint state. */ //初始化各个usb_interface 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); 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; usb_enable_interface(dev, intf, true); 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; INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); intf->minor = -1; device_initialize(&intf->dev); pm_runtime_no_callbacks(&intf->dev); dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, alt->desc.bInterfaceNumber); } kfree(new_interfaces); if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) 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", dev_name(&intf->dev), configuration, intf->cur_altsetting->desc.bInterfaceNumber); device_enable_async_suspend(&intf->dev); ret = device_add(&intf->dev); //将接口的dev添加到系统,将触发接口设备和接口驱动的match if (ret != 0) { dev_err(&dev->dev, "device_add(%s) --> %d\n", dev_name(&intf->dev), ret); continue; } create_intf_ep_devs(intf); } usb_autosuspend_device(dev); return 0; }
相关文章推荐
- cocos2d 2.2.6 win7下的配置
- C#中4种深拷贝方法介绍
- 黑马程序员——Java语言基础
- 自定义ProgressBar
- 磁盘信息处理概述
- epoll的使用方法
- 编程学习的七个阶段
- TLD视觉跟踪算法
- DIV+CSS定位position
- Perl按修改日期排序文件
- Redis学习第三课:Redis Hash类型及操作
- Objective-C Json 使用
- 数据库字符集修改
- 如何获取跟系统相关的时间(oracle)
- USB驱动框架分析1
- 【译】VisionMobile:2015 IOT大趋势(五)每人都是开发者
- MVC架构设计参考
- IdeasToComeTrue
- Redhat6.5 + oracle 11gR2 设置数据库开机自启动
- MySQL查看用户权限