USB学习之一:USB总线驱动程序

USB总线驱动程序的作用
1. 识别USB设备
1.1 分配地址
1.2 并告诉USB设备(set address)
1.3 发出命令获取描述符
描述符的信息可以在include\linux\usb\Ch9.h看到


2. 查找并安装对应的设备驱动程序

3. 提供USB读写函数

将一个USB设备接到开发板上,看输出信息:
usb 1-1: new full speed USB device using s3c2410-ohci and address 2
usb 1-1: configuration #1 chosen from 1 choi     ce
scsi0 : SCSI emulation for USB Mass Storage devices
scsi 0:0:0:0: Direct-Access     HTC      Android Phone    0100 PQ: 0 ANSI: 2
sd 0:0:0:0: [sda] Attached SCSI removable disk
拔掉
usb 1-1: USB disconnect, address 2

再接上:
usb 1-1: new full speed USB device using s3c2410-ohci and address 3
usb 1-1: configuration #1 chosen from 1 choice
scsi1 : SCSI emulation for USB Mass Storage devices
scsi 1:0:0:0: Direct-Access     HTC      Android Phone    0100 PQ: 0 ANSI: 2
sd 1:0:0:0: [sda] Attached SCSI removable disk

全局搜索  grep "USB device using" * -nR   在2.6的内核中可以搜到相关信息。

我用的是3.0的内核,USB设备插入后,会有如下信息打印出来

[  465.520759] usb 1-2.3: new high speed USB device number 22 using s5p-ehci

因此可以搜索:grep "USB device number" -nr .

找到在linux-3.0.86/drivers/usb/core/hub.c  中hub_port_init函数中,因此我们可以通过hub_port_init函数找出USB总线驱动程序的调用关系。先上一张图。

USB学习之一:USB总线驱动程序_第1张图片

接着从代码的角度做一些分析:

drivers/usb/core/usb.c

struct bus_type usb_bus_type = {
	.name =		"usb",
	.match =	usb_device_match,
	.uevent =	usb_uevent,
};
 
 
static int __init usb_init(void)
{
 
	retval = bus_register(&usb_bus_type); //注册USB总线,USB总线和平台总线及其他总线是类似的
 
     ........  //省略了很多初始化的工作
	retval = usb_hub_init(); //usb hub初始化
}
static struct usb_driver hub_driver = {
	.name =		"hub",
	.probe =	hub_probe,
	.disconnect =	hub_disconnect,
	.suspend =	hub_suspend,
	.resume =	hub_resume,
	.reset_resume =	hub_reset_resume,
	.pre_reset =	hub_pre_reset,
	.post_reset =	hub_post_reset,
	.unlocked_ioctl = hub_ioctl,
	.id_table =	hub_id_table,
	.supports_autosuspend =	1,
};
int usb_hub_init(void)
{
	if (usb_register(&hub_driver) < 0) { //注册usb hub driver,在hub_driver中提供了一系列hub相关的操作函数
 
	}
 
	khubd_task = kthread_run(hub_thread, NULL, "khubd");//初始化一个hub 线程,这个线程在usb设备插入后会跑,后面会分析到。
}
 
//接着分析usb_register函数
usb_register(&hub_driver)
    usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
        driver_register(&new_driver->drvwrap.driver)
            bus_add_driver(drv)
                driver_attach(drv)
                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
                        __driver_attach
                                driver_match_device(drv, dev)
                                  return drv->bus->match ? drv->bus->match(dev, drv) : 1; 
                                  //因此最后是调用的是上文中提到的usb_bus_type中提供的
                         usb_device_match(struct device *dev, struct device_driver *drv)函数。该函数是通过比较usb_driver中的id_table来确定的是否匹配并调用probe函数。
这些是跟内核的总线设备框架有关。      
 
 

设备和驱动匹配到之后就会调用probe函数,即hub_probe

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *desc;
    .......//省略一些初始化工作
 
	hub = kzalloc(sizeof(*hub), GFP_KERNEL); //分配一个hub结构体
    .......
	if (hub_configure(hub, endpoint) >= 0) {
 
}
 
 
hub_configure(hub, endpoint)
    hub->urb = usb_alloc_urb(0, GFP_KERNEL); //分配hub->urb
    usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
		hub, endpoint->bInterval);//注册hub中断 hub_irq,当usb设备被插入时,hub_irq会被调用

当由USB设备插入hub,hub端口的D+或者D-会由原来的低电平被拉高到3V高电平,触发hub中断,hub_irq

static void hub_irq(struct urb *urb)
{
	struct usb_hub *hub = urb->context;
	int status = urb->status;
	unsigned i;
	unsigned long bits;
    .........
 
	/* Something happened, let khubd figure it out */
	kick_khubd(hub);  //唤醒上文中提到的hub_thread
 
}
 
static int hub_thread(void *__unused)
{
	set_freezable();
 
	do {
		hub_events();
		wait_event_freezable(khubd_wait,
				!list_empty(&hub_event_list) ||
				kthread_should_stop());
	} while (!kthread_should_stop() || !list_empty(&hub_event_list));
}
//接着调用到hub_events
hub_events
    hub_port_connect_change(hub, i,
						portstatus, portchange);
        udev = usb_alloc_dev(hdev, hdev->bus, port1);//分配一个USB DEV设备
        choose_devnum(udev);//设置这个dev的编号
        hub_port_init(hub, udev, port1, i);

在hub_port_init中做了很多事情

hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
		int retry_counter)
{
	static DEFINE_MUTEX(usb_address0_mutex);
 
	retval = hub_port_reset(hub, port1, udev, delay);//复位hub
 
	oldspeed = udev->speed; //获取usb设备的速度
 
	switch (udev->speed) { //根据不同速度的设备做一些设置
	case USB_SPEED_SUPER:
	case USB_SPEED_WIRELESS:	/* fixed at 512 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
		break;
	case USB_SPEED_HIGH:		/* fixed at 64 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
		break;
	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
		/* to determine the ep0 maxpacket size, try to read
		 * the device descriptor to get bMaxPacketSize0 and
		 * then correct our initial guess.
		 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
		break;
	case USB_SPEED_LOW:		/* fixed at 8 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
		break;
	}
 
	if (udev->speed != USB_SPEED_SUPER)
		dev_info(&udev->dev,
				"%s %s speed %sUSB device number %d using %s\n", //识别到usb设备后就会打印这句信息
				(udev->config) ? "reset" : "new", speed, type,
				devnum, udev->bus->controller->driver->name);
 
 
	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
		if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
			struct usb_device_descriptor *buf;
			int r = 0;
 
 
#undef GET_DESCRIPTOR_BUFSIZE
		}
 
 		/*
 		 * If device is WUSB, we already assigned an
 		 * unauthorized address in the Connect Ack sequence;
 		 * authorization will assign the final address.
 		 */
		if (udev->wusb == 0) {
			for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
				retval = hub_set_address(udev, devnum); //设置设备的地址
			}
 
			if (udev->speed == USB_SPEED_SUPER) {
				devnum = udev->devnum;
				dev_info(&udev->dev,
						"%s SuperSpeed USB device number %d using %s\n",
						(udev->config) ? "reset" : "new",
						devnum, udev->bus->controller->driver->name);
			}
  		}
 
		retval = usb_get_device_descriptor(udev, 8);//获取设备描述符,第8个字节是设备描述符的最大包长
 
		i = udev->descriptor.bMaxPacketSize0;
	if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
		if (udev->speed == USB_SPEED_LOW ||
	}
 
	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);//在上文中获取到了设备描述符的最大包长,因此这里一次把设备描述符读取
	if (retval < (signed)sizeof(udev->descriptor)) {
		dev_err(&udev->dev, "device descriptor read/all, error %d\n",
			retval);
		if (retval >= 0)
			retval = -ENOMSG;
		goto fail;
	}
}

hub_port_init初始化完成以后调用usb_new_device(udev),将usb设备添加到设备链表中去。

int usb_new_device(struct usb_device *udev)
         device_add(&udev->dev); // 把device放入usb_bus_type的dev链表, 
							            // 从usb_bus_type的driver链表里取出usb_driver,
							            // 把usb_interface和usb_driver的id_table比较
							            // 如果能匹配,调用usb_driver的probe

至此USB总线驱动程序框架已经分析完了。

你可能感兴趣的:(USB)