在hub.c的hub_port_connect_change中,检测到有USB设备插进来后执行该代码。
1. USB协议中规定,插入设备后,主机要至少等待100ms,让设备完成插入以及上电动作;hub_port_debounce(hub, port1)就是起到这个作用。
2. 接着在hub_port_init函数中,USB协议规定,上电后,HUB要响USB设备发送持续10ms的复位信号(D+、D-都拉低), hub_port_reset(hub, port1, udev, delay)完成该动作。
这样,当信号完成后,端口就有效了,设备处于缺省状态(Default state),并且获得主机提供的100mA的电流;主机可以和设备地址0,端点0(即default pipe)通过控制传输进行通讯,端点0比较特殊,可以写入,可以读出;其他端点都是单向的,比如U盘有两个断电,从端点1写入数据,端点2读出数据。
要注意,USB术语中端点的IN和OUT,是从主机端的立场来看的,比如USB鼠标输入数据到电脑,对应的端点即为输入端点。
3.
#define GET_DESCRIPTOR_BUFSIZE 64 for (j = 0; j < 3; ++j) { buf->bMaxPacketSize0 = 0; r = usb_control_msg(udev, usb_rcvaddr0pipe(), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, 0, buf, GET_DESCRIPTOR_BUFSIZE, initial_descriptor_timeout); switch (buf->bMaxPacketSize0) { case 8: case 16: case 32: case 64: case 255: if (buf->bDescriptorType == USB_DT_DEVICE) { r = 0; break; } /* FALL THROUGH */ default: if (r == 0) r = -EPROTO; break; } if (r == 0) break; }
获取设备描述符(device descriptor),请求的长度是64,虽然一般的设备描述符长度只有18,但主机并不在乎,从switch语句看出,它更在乎的是描述符的总长度信息。
4. 获取完设备描述符后,接着hub_port_reset(hub, port1, udev, delay)再次对设备进行复位(USB协议中并没有这一步的要求),这次复位的目的是使设备进入一个确定的状态。
5. 往下,hub_set_address(udev, devnum)给设备分配一个唯一的新地址,设备处于编址状态(Address state).
6. 有了新地址后,再次获取设备描述符,用usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE)来获得,USB_DT_DEVICE_SIZE 为18。这次,主机会认真解析设备描述符的信息,包括断电0的最大包长度、设备所支持的配置个数、设备类型、VID、PID等。hub_port_init函数就完成了。
7. 回到hub_port_connect_change函数继续往下,usb_new_device(udev)函数:
int usb_new_device(struct usb_device *udev) { 。。。。。。 err = usb_enumerate_device(udev); /* Read descriptors */ 。。。。。。 /* Tell the world! */ announce_device(udev); 。。。。。。 /* 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); 。。。。。。 }
static int usb_enumerate_device(struct usb_device *udev) { int err; if (udev->config == NULL) { err = usb_get_configuration(udev); if (err < 0) { dev_err(&udev->dev, "can't read configurations, error %d\n", err); goto fail; } } if (udev->wusb == 1 && udev->authorized == 0) { udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); } else { /* read the standard strings and cache them if present */ udev->product = usb_cache_string(udev, udev->descriptor.iProduct); udev->manufacturer = usb_cache_string(udev, udev->descriptor.iManufacturer); udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); } err = usb_enumerate_device_otg(udev); fail: return err; }
ncfg = dev->descriptor.bNumConfigurations
struct usb_host_config { struct usb_config_descriptor desc; char *string; /* iConfiguration string, if present */ /* List of any Interface Association Descriptors in this * configuration. */ struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS]; /* the interfaces associated with this configuration, * stored in no particular order */ struct usb_interface *interface[USB_MAXINTERFACES]; /* Interface information available even when this is not the * active configuration */ struct usb_interface_cache *intf_cache[USB_MAXINTERFACES]; unsigned char *extra; /* Extra descriptors */ int extralen; };
device_add(&udev->dev)就把该设备添加到USB总线上了,因为这时候主机已经从设备出获取了足够的信息,USB HUB只能做到这里了,后续的事情就要由具体的设备驱动来完成了。
根据前一篇文章的分析,接着往下走就来到了generic.c的generic_probe方法中:
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; }
usb_choose_configuration(udev)会根据一些条件来选择一个配置,比如判断该配置下描述的电流是否过大,然后LINUX根据自己喜好,选择了一个不是USB_CLASS_VENDOR_SPEC的配置,代码片段如下:
/* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver * than a vendor-specific driver. */ else if (udev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC && (desc && desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC)) { best = c; break; } #define USB_CLASS_VENDOR_SPEC 0xff
其实大多数设备只有一种配置而已,这样就返回了配置编号。
接着usb_set_configuration(udev, c)把选择的配置写入设备。在该函数中完成配置后用 usb_enable_interface(dev, intf, true)使接口生效;创建cp->desc.bNumInterfaces个代表该配置下接口的device并用device_add(&intf->dev)添加到USB核心中去;可见,一个接口对应一个驱动,bNumInterfaces个接口就要bNumInterfaces个驱动了;不过由于一个device_driver可以对应多个device,所以像pl2303就是一个driver,但是可以处理多个接口。
下边通过具体的例子来分析这个接口。
把pl2303线插入平板上,在/sys/bus/usb/devices多出了两个设备
3-1
3-1:1.0
3-1代表的就是usb_device结构体中的device,这是在hub_port_connect_change中创建的,名字的由来如下:
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
3-1:1.0代表的就是pl2303的接口,可见该设备只有一个接口,名字的创建如下:
dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, alt->desc.bInterfaceNumber);用的是1配置,0接口。进入3-1:1.0目录看到如下信息:
bAlternateSetting bInterfaceClass bInterfaceNumber bInterfaceProtocol bInterfaceSubClass bNumEndpoints driver ep_02 ep_81 ep_83 modalias power subsystem supports_autosuspend ttyUSB0 uevent看到有三个端点,再进入端点目录发现ep_02为bulk传输,方向为out;ep_81为Interrupt传输,方向为in;ep_83为Bulk传输,方向为in; bInterfaceClass为ff,表示是厂商自定义的设备。
而进入3-1目录看到如下信息(有设备描述符和配置描述符的信息):
3-1:1.0 authorized avoid_reset_quirk bConfigurationValue bDeviceClass bDeviceProtocol bDeviceSubClass bMaxPacketSize0 bMaxPower bNumConfigurations bNumInterfaces bcdDevice bmAttributes busnum configuration descriptors dev devnum devpath driver ep_00 idProduct idVendor manufacturer maxchild power product quirks removable remove speed subsystem uevent urbnum usb_device version
bNumConfigurations为1,只有一种配置;bNumInterfaces为1,只有一个接口;ep_00代表控制端点0,因为这是每个usb设备都必须有的,作为共性放到了这里。
最后进入pl2303驱动看usb_serial_probe函数的实现。
int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { ......................... type = search_serial_device(interface); ........................ serial = create_serial(dev, interface, type); ......................... for (i = 0; i < num_bulk_in; ++i) { usb_fill_bulk_urb(port->read_urbs[j], dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), port->bulk_in_buffers[j], buffer_size, serial->type->read_bulk_callback, port); } } ............................................ for (i = 0; i < num_bulk_out; ++i) { usb_fill_bulk_urb(port->write_urbs[j], dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress), port->bulk_out_buffers[j], buffer_size, serial->type->write_bulk_callback, port); } ..................................... if (serial->type->read_int_callback) { for (i = 0; i < num_interrupt_in; ++i) { usb_fill_int_urb(port->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), port->interrupt_in_buffer, buffer_size, serial->type->read_int_callback, port, endpoint->bInterval); } ............................................... if (serial->type->write_int_callback) { for (i = 0; i < num_interrupt_out; ++i) { usb_fill_int_urb(port->interrupt_out_urb, dev, usb_sndintpipe(dev, endpoint->bEndpointAddress), port->interrupt_out_buffer, buffer_size, serial->type->write_int_callback, port, endpoint->bInterval); } ................................... }其实就是用usb_fill_bulk_urb或者usb_fill_int_urb函数来注册中断或者批量传输函数,以后有数据到来或者有数据需要发送,调用相应的函数来处理。
不过要注意,这里还用到serial/generic.c中的相应函数,该文件提供了通用的访问接口,比如pl2303.c中没有定义read_bulk_callback函数,但是在usb-serical.c中有:
#define set_to_generic_if_null(type, function) \ do { \ if (!type->function) { \ type->function = usb_serial_generic_##function; \ dbg("Had to override the " #function \ " usb serial operation with the generic one.");\ } \ } while (0) static void fixup_generic(struct usb_serial_driver *device) { set_to_generic_if_null(device, open); set_to_generic_if_null(device, write); set_to_generic_if_null(device, close); set_to_generic_if_null(device, write_room); set_to_generic_if_null(device, chars_in_buffer); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); set_to_generic_if_null(device, disconnect); set_to_generic_if_null(device, release); set_to_generic_if_null(device, process_read_urb); set_to_generic_if_null(device, prepare_write_buffer); }
这样,当串口有数据到来时候,调用read_bulk_callback:
void usb_serial_generic_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; unsigned long flags; int i; for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { if (urb == port->read_urbs[i]) break; } set_bit(i, &port->read_urbs_free); dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, urb->actual_length); if (urb->status) { dbg("%s - non-zero urb status: %d\n", __func__, urb->status); return; } usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); port->serial->type->process_read_urb(urb); /* Throttle the device if requested by tty */ spin_lock_irqsave(&port->lock, flags); port->throttled = port->throttle_req; if (!port->throttled) { spin_unlock_irqrestore(&port->lock, flags); usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); } else spin_unlock_irqrestore(&port->lock, flags); } EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
这时候数据已经在urb结构中了,接着调用pl2303.c的process_read_urb方法:
static void pl2303_process_read_urb(struct urb *urb) { 。。。。。。。。。。 if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); if (port->port.console && port->sysrq) { for (i = 0; i < urb->actual_length; ++i) if (!usb_serial_handle_sysrq_char(port, data[i])) tty_insert_flip_char(tty, data[i], tty_flag); } else { tty_insert_flip_string_fixed_flag(tty, data, tty_flag, urb->actual_length); } tty_flip_buffer_push(tty); tty_kref_put(tty); }