本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记
新的usb设备的总线是usb_bus_type,类型是usb_device_type。根据前面root hub设备的device和driver的匹配可知,这里的probe函数还是调用的generic_probe。
跟root hub usb设备和驱动的匹配走的流程是一样的:
先选择一个合适的配置,然后调用usb_set_configuration函数去设置;
根据configured可以知道有多少个接口,对每个接口进行初始化,初始化usb 接口设备,初始化它的设置,指定每个接口当前活跃的设置为0号设置;
将每个接口注册成usb接口设备;
不同的是root hub只有一个配置,一个接口,一个设置,一个端口,但是实际的usb设备可能有很多种配置,很多个接口,很多中设置,很多端口,所以实际的usb设备的流程要复杂一些。
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);
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;
int n, nintf;
//configuration是前边儿choose_configuration()那里返回回来的
//当configuration为-1也就是没有发现满意的配置时,设备不能进入Configured,所以要把configuration的值改为0,以便满足SET_CONFIGURATION请求的要求
if (dev->authorized == 0 || configuration == -1)
configuration = 0;
else {
//从设备struct usb_device结构体的config数组里将相应配置的描述信息,也就是struct usb_host_config结构体给取出来
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue ==
configuration) {
cp = &dev->config[i];
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) {
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;
}
//申请每一项new_interfaces[n]的内存
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;
/* 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.
*/
if (cp)
ret = usb_hcd_check_bandwidth(dev, cp, NULL);
else
ret = usb_hcd_check_bandwidth(dev, NULL, NULL);
if (ret < 0) {
usb_autosuspend_device(dev);
goto free_interfaces;
}
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
//不disable ep0
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);
//发送命令,设置configuration
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;
}
//将激活的那个配置的地址赋给actconfig
dev->actconfig = cp;
//如果cp为空,重新设置设备的状态为Address,并将之前准备的那些struct usb_interface结构体和new_interfaces释放掉,然后返回
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_hcd_check_bandwidth(dev, NULL, NULL);
usb_autosuspend_device(dev);
goto free_interfaces;
}
//设置设备的状态为configured
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号设置,接口的默认设置总是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.
*/
//拿altsetting数组里的第一项来充数
if (!alt)
alt = &intf->altsetting[0];
//指定刚刚拿到的设置为当前要使用的设置
intf->cur_altsetting = alt;
//轮询前面获得的那个接口设置使用到的每个端点,将它们统统enable
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);
device_initialize(&intf->dev);
mark_quiesced(intf);
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循环准备好的每个接口送给设备模型
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);
ret = device_add(&intf->dev);
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;
}
文章参考:https://blog.csdn.net/fudan_abc/article/category/325189