linux设备驱动(30)usb驱动-usb鼠标驱动详解
内核自带的USB鼠标驱动位于:/drivers/hid/usbhid/usbmouse.c
1 usb mouse driver
1 static struct usb_driver usb_mouse_driver = { 2 .name = "usbmouse", 3 .probe = usb_mouse_probe, 4 .disconnect = usb_mouse_disconnect, 5 .id_table = usb_mouse_id_table, 6 }; 7 8 static struct usb_device_id usb_mouse_id_table [] = { 9 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 10 USB_INTERFACE_PROTOCOL_MOUSE) }, 11 { } /* Terminating entry */ 12 };
USB_INTERFACE_INFO()设置usb_driver驱动的id_table成员
USB_INTERFACE_CLASS_HID:接口类,我们USB鼠标为HID类,所以填入0X03
USB_INTERFACE_SUBCLASS_BOOT:接口子类为启动设备
USB_INTERFACE_PROTOCOL_MOUSE :接口协议为鼠标协议,填入
2 usb mouse probe函数
1 static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) 2 { 3 struct usb_device *dev = interface_to_usbdev(intf); 4 struct usb_host_interface *interface; 5 struct usb_endpoint_descriptor *endpoint; 6 struct usb_mouse *mouse; 7 struct input_dev *input_dev; 8 int pipe, maxp; 9 int error = -ENOMEM; 10 11 interface = intf->cur_altsetting; 12 13 if (interface->desc.bNumEndpoints != 1) 14 return -ENODEV; 15 16 endpoint = &interface->endpoint[0].desc; 17 if (!usb_endpoint_is_int_in(endpoint)) 18 return -ENODEV; 19 20 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 21 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); 22 23 mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL); 24 input_dev = input_allocate_device();//分配input设备 25 if (!mouse || !input_dev) 26 goto fail1; 27 28 mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma); 29 if (!mouse->data) 30 goto fail1; 31 32 mouse->irq = usb_alloc_urb(0, GFP_KERNEL); 33 if (!mouse->irq) 34 goto fail2; 35 36 mouse->usbdev = dev; 37 mouse->dev = input_dev; 38 39 if (dev->manufacturer) 40 strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); 41 42 if (dev->product) { 43 if (dev->manufacturer) 44 strlcat(mouse->name, " ", sizeof(mouse->name)); 45 strlcat(mouse->name, dev->product, sizeof(mouse->name)); 46 } 47 48 if (!strlen(mouse->name)) 49 snprintf(mouse->name, sizeof(mouse->name), 50 "USB HIDBP Mouse %04x:%04x", 51 le16_to_cpu(dev->descriptor.idVendor), 52 le16_to_cpu(dev->descriptor.idProduct)); 53 54 usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); 55 strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); 56 57 input_dev->name = mouse->name; 58 input_dev->phys = mouse->phys; 59 usb_to_input_id(dev, &input_dev->id); 60 input_dev->dev.parent = &intf->dev; 61 /*设置input支持的按键*/ 62 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 63 input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | 64 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); 65 input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); 66 input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | 67 BIT_MASK(BTN_EXTRA); 68 input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); 69 70 input_set_drvdata(input_dev, mouse); 71 72 input_dev->open = usb_mouse_open; 73 input_dev->close = usb_mouse_close; 74 /*设置usb数据传输*/ 75 usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,//初始化urb,对于中断 urb,使用usb_fill_int_urb()函数来初始化 urb。 76 (maxp > 8 ? 8 : maxp), 77 usb_mouse_irq, mouse, endpoint->bInterval); 78 mouse->irq->transfer_dma = mouse->data_dma; 79 mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 80 81 error = input_register_device(mouse->dev);//注册input设备 82 if (error) 83 goto fail3; 84 85 usb_set_intfdata(intf, mouse); 86 return 0; 87 88 fail3: 89 usb_free_urb(mouse->irq); 90 fail2: 91 usb_free_coherent(dev, 8, mouse->data, mouse->data_dma); 92 fail1: 93 input_free_device(input_dev); 94 kfree(mouse); 95 return error; 96 }
2.1 函数usb_fill_int_urb
对于中断 urb,使用usb_fill_int_urb()函数来初始化 urb。
urb完成时被调用的完成处理函数complete :usb_mouse_irq
2.2 函数 usb_mouse_irq
1 static void usb_mouse_irq(struct urb *urb) 2 { 3 struct usb_mouse *mouse = urb->context; 4 signed char *data = mouse->data; 5 struct input_dev *dev = mouse->dev; 6 int status; 7 8 switch (urb->status) { 9 case 0: /* success */ 10 break; 11 case -ECONNRESET: /* unlink */ 12 case -ENOENT: 13 case -ESHUTDOWN: 14 return; 15 /* -EPIPE: should clear the halt */ 16 default: /* error */ 17 goto resubmit; 18 } 19 20 input_report_key(dev, BTN_LEFT, data[0] & 0x01); 21 input_report_key(dev, BTN_RIGHT, data[0] & 0x02); 22 input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); 23 input_report_key(dev, BTN_SIDE, data[0] & 0x08); 24 input_report_key(dev, BTN_EXTRA, data[0] & 0x10); 25 26 input_report_rel(dev, REL_X, data[1]); 27 input_report_rel(dev, REL_Y, data[2]); 28 input_report_rel(dev, REL_WHEEL, data[3]); 29 30 input_sync(dev); 31 resubmit: 32 status = usb_submit_urb (urb, GFP_ATOMIC); 33 if (status) 34 dev_err(&mouse->usbdev->dev, 35 "can't resubmit intr, %s-%s/input0, status %d\n", 36 mouse->usbdev->bus->bus_name, 37 mouse->usbdev->devpath, status); 38 }
3 usb鼠标驱动总结:
首先先定义全局变量:usb_driver结构体,input_dev指针结构体 ,虚拟地址缓存区,DMA地址缓存区
(1) 入口函数中
1)通过usb_register()函数注册usb_driver结构体
(2) 在usb_driver的probe函数中
1)分配一个input_dev结构体
2)设置input_dev支持L、S、回车、3个按键事件
3)注册input_dev结构体
4)设置USB数据传输:
4.1)通过usb_rcvintpipe()创建一个接收中断类型的端点管道,用来端点和数据缓冲区之间的连接
4.2)通过usb_buffer_alloc()申请USB缓冲区
4.3)申请并初始化urb结构体,urb:用来传输数据
4.4) 因为我们2440支持DMA,所以要告诉urb结构体,使用DMA缓冲区地址
4.5)使用usb_submit_urb()提交urb
(3) 在鼠标中断函数中
1)判断缓存区数据是否改变,若改变则上传鼠标事件
2)使用usb_submit_urb()提交urb
(4)在usb_driver的disconnect函数中
1)通过usb_kill_urb()杀掉提交到内核中的urb
2)释放urb
3)释放USB缓存区
4)注销input_device,释放input_device
(5)出口函数
1)通过usb_deregister ()函数注销usb_driver结构体
4 usb鼠标示例
将USB鼠标的左键当作L按键,将USB鼠标的右键当作S按键,中键当作回车按键。
1 #include <linux/kernel.h> 2 #include <linux/slab.h> 3 #include <linux/module.h> 4 #include <linux/init.h> 5 #include <linux/usb/input.h> 6 #include <linux/hid.h> 7 8 static struct input_dev *myusb_mouse_dev; //input_dev 9 static char *myusb_mouse_buf; //虚拟地址缓存区 10 static dma_addr_t myusb_mouse_phyc; //DMA缓存区; 11 12 static __le16 myusb_mouse_size; //数据包长度 13 14 static struct urb *myusb_mouse_urb; //urb 15 16 17 static void myusb_mouse_irq(struct urb *urb) //鼠标中断函数 18 { 19 static char buf1=0; 20 //for(i=0;i<myusb_mouse_size;i++) 21 // printk("%02x ",myusb_mouse_buf[i]); 22 // printk("\n"); 23 24 25 /*bit 1-左右中键 0X01:左键 0X02:右键 0x04:中键 */ 26 if((buf1&(0X01)) != (myusb_mouse_buf[1]&(0X01))) 27 { 28 input_report_key(myusb_mouse_dev, KEY_L, buf1&(0X01)? 1:0); 29 input_sync(myusb_mouse_dev); 30 } 31 if((buf1&(0X02)) != (myusb_mouse_buf[1]&(0X02))) 32 { 33 input_report_key(myusb_mouse_dev, KEY_S, buf1&(0X02)? 1:0); 34 input_sync(myusb_mouse_dev); 35 } 36 if((buf1&(0X04)) != (myusb_mouse_buf[1]&(0X04)) ) 37 { 38 input_report_key(myusb_mouse_dev, KEY_ENTER, buf1&(0X04)? 1:0); 39 input_sync(myusb_mouse_dev); 40 } 41 42 buf1=myusb_mouse_buf[1]; //更新数据 43 44 usb_submit_urb(myusb_mouse_urb, GFP_KERNEL); 45 } 46 47 48 static int myusb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) 49 { 50 struct usb_device *dev = interface_to_usbdev(intf); //设备 51 struct usb_endpoint_descriptor *endpoint; 52 struct usb_host_interface *interface; //当前接口 53 int pipe; //端点管道 54 55 interface=intf->cur_altsetting; 56 endpoint = &interface->endpoint[0].desc; //当前接口下的端点描述符 57 58 59 printk("VID=%x,PID=%x\n",dev->descriptor.idVendor,dev->descriptor.idProduct); //打印VID,PID 60 61 62 /* 1)分配一个input_dev结构体 */ 63 myusb_mouse_dev=input_allocate_device(); 64 65 66 /* 2)设置input_dev支持L、S,回车、3个按键事件*/ 67 set_bit(EV_KEY, myusb_mouse_dev->evbit); 68 set_bit(EV_REP, myusb_mouse_dev->evbit); //支持重复按功能 69 set_bit(KEY_L, myusb_mouse_dev->keybit); 70 set_bit(KEY_S, myusb_mouse_dev->keybit); 71 set_bit(KEY_ENTER, myusb_mouse_dev->keybit); 72 73 /* 3)注册input_dev结构体*/ 74 input_register_device(myusb_mouse_dev); 75 76 77 /* 4)设置USB数据传输 */ 78 /*->4.1)通过usb_rcvintpipe()创建一个端点管道*/ 79 pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress); 80 81 /*->4.2)通过usb_buffer_alloc()申请USB缓冲区*/ 82 myusb_mouse_size=endpoint->wMaxPacketSize; 83 myusb_mouse_buf=usb_buffer_alloc(dev,myusb_mouse_size,GFP_ATOMIC,&myusb_mouse_phyc); 84 85 /*->4.3)通过usb_alloc_urb()和usb_fill_int_urb()申请并初始化urb结构体 */ 86 myusb_mouse_urb=usb_alloc_urb(0,GFP_KERNEL); 87 usb_fill_int_urb (myusb_mouse_urb, //urb结构体 88 dev, //usb设备 89 pipe, //端点管道 90 myusb_mouse_buf, //缓存区地址 91 myusb_mouse_size, //数据长度 92 myusb_mouse_irq, //中断函数 93 0, 94 endpoint->bInterval); //中断间隔时间 95 96 97 /*->4.4) 因为我们2440支持DMA,所以要告诉urb结构体,使用DMA缓冲区地址*/ 98 myusb_mouse_urb->transfer_dma =myusb_mouse_phyc; //设置DMA地址 99 myusb_mouse_urb->transfer_flags =URB_NO_TRANSFER_DMA_MAP; //设置使用DMA地址 100 101 /*->4.5)使用usb_submit_urb()提交urb*/ 102 usb_submit_urb(myusb_mouse_urb, GFP_KERNEL); 103 return 0; 104 } 105 106 static void myusb_mouse_disconnect(struct usb_interface *intf) 107 { 108 struct usb_device *dev = interface_to_usbdev(intf); //设备 109 110 usb_kill_urb(myusb_mouse_urb); 111 usb_free_urb(myusb_mouse_urb); 112 usb_buffer_free(dev, myusb_mouse_size, myusb_mouse_buf,myusb_mouse_phyc); 113 114 input_unregister_device(myusb_mouse_dev); //注销内核中的input_dev 115 input_free_device(myusb_mouse_dev); //释放input_dev 116 } 117 118 static struct usb_device_id myusb_mouse_id_table [] = { 119 { USB_INTERFACE_INFO( 120 USB_INTERFACE_CLASS_HID, //接口类:hid类 121 USB_INTERFACE_SUBCLASS_BOOT, //子类:启动设备类 122 USB_INTERFACE_PROTOCOL_MOUSE) }, //USB协议:鼠标协议 123 }; 124 125 126 static struct usb_driver myusb_mouse_drv = { 127 .name = "myusb_mouse", 128 .probe = myusb_mouse_probe, 129 .disconnect = myusb_mouse_disconnect, 130 .id_table = myusb_mouse_id_table, 131 }; 132 133 module_usb_driver(usb_mouse_driver);