您的位置:首页 > 其它

USB驱动框架分析2

2015-06-17 10:11 309 查看
本文先分析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
};
直接看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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: