本文先分析OHCI的usb主機驅動控制器驅動,root hub這個usb_device的創建過程,讀取配置描述符過程,設置配置,然後添加接口到系統。
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
- };
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;
- }
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;
- }
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;
- }
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;
- }
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_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;
- }
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;
- }
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 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;
- }
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[n] = kzalloc(
- sizeof(struct usb_interface),
- GFP_NOIO);
- 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.
- */
- 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;
- }
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[n] = kzalloc(
sizeof(struct usb_interface),
GFP_NOIO);
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.
*/
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;
}