欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-14 10:56:49
...

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总线驱动程序

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

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