首先分析usb_mouse_init,通过usb_register(&usb_mouse_driver)注册驱动程序,probe函数调用1.先插设备后安装驱动,USB core会遍历所有系统中已存在的USB设备,然后看usb_mouse_id_table, /* 所能支持设备列表 */有无系统支持的设备如果有则调用probe函数,2.先装驱动后装鼠标,USB core发现新的设备进来,会寻找有无能处理设备的驱动,找到后调用probe()。
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};//驱动支持USB鼠标这一类设备。
注册分析完后,分析probe函数(驱动找到USB鼠标后做的事情),
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
先interface = intf->cur_altsetting;/* 获取当前接口设置 */
然后检测接口描述符有多少endpoint if (interface->desc.bNumEndpoints != 1)
通过检测取出端点描述符,endpoint = &interface->endpoint[0].desc;
判断端点是不是为输入型的中断端点(访问鼠标希望从鼠标中读到数据)
if (!usb_endpoint_is_int_in(endpoint))
产生中断管道,驱动程序buffer和端点之间虚拟通道
usb_rcvintpipe(dev, endpoint->bEndpointAddress);
创建输入型设备,因为USB驱动从总线描述设备,从功能上有输入型、网络型、字符等设备,总线驱动包含功能驱动,鼠标是输入设备,所以要创建输入型设备。
input_dev = input_allocate_device();
分配数组buffer,从鼠标端点获取数据,存放进buffer
/* 申请内存空间用于数据传输,data 为指向该空间的地址*/
mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
准备工作完成后,开始围绕urb工作。
mouse->irq = usb_alloc_urb(0, GFP_KERNEL); /* 分配URB */
第一个参数为0,表明中断传输,不设置等时包
获取USB在Sysfs文件系统名字,然后添加上名字"/input0"。
usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
输入型设备初始化时需要指明设备支持哪些操作,例如按键、绝对坐标、左右键………
所支持的操作信息。
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
BIT_MASK(BTN_EXTRA);
input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
制定打开、关闭函数
input_dev->open = usb_mouse_open;
input_dev->close = usb_mouse_close;
接下来有回到URB下来了,使用usb_fill_int_urb初始化URB,endpoint->bInterval表示每个多长时间提交一次URB,
usb_fill_int_urb (mouse->irq, dev, pipe, mouse->data,
(maxp > 8 ? 8 : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);
urb初始化结束后,将URB提交给USB CORE,但是这里并没有提交过程,它在打开时候提交。因为不打开设备,就不用设备,不提交就不会有数据传输,只有当使用才要求提交URB至USB CORE,然后交给HOST_DRIVER,从USB鼠标拿到数据,在pipe拿到数据放在mouse->data,过程结束后调用usb_mouse_irq函数。
static int usb_mouse_open(struct input_dev *dev)
{
struct usb_mouse *mouse = input_get_drvdata(dev);
mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
return -EIO;
return 0;
}
通过urb->status判断URB传输是否成功,0正确继续执行,错误时不会执行。
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
}
正确时报告鼠标按键情况,使用input_report_key()报告信息,使用input_sync表明报告完毕
input_report_key(dev, BTN_LEFT, data[0] & 0x01);
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
input_report_key(dev, BTN_SIDE, data[0] & 0x08);
input_report_key(dev, BTN_EXTRA, data[0] & 0x10);
input_report_rel(dev, REL_X, data[1]);
input_report_rel(dev, REL_Y, data[2]);
input_report_rel(dev, REL_WHEEL, data[3]);
input_sync(dev);
结束之后还要继续传输,又一次提交URB
status = usb_submit_urb (urb, GFP_ATOMIC);
关闭设备时usb_kill_urb
程序由两部分组成,一部分是USB部分,一部分是input部分,USB部分体现总线,围绕urb分析创建、分配、初始化、提交、后续处理,input体现功能部分。