简单的usb鼠标驱动分析
2012-09-19 19:53
375 查看
如果没有看过 :
驱动usb鼠标识别 建议先看看
下面主要是分析了usb识别后的操作
驱动usb鼠标识别 建议先看看
下面主要是分析了usb识别后的操作
#include<linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/init.h> #include <linux/usb/input.h> #include <linux/hid.h> #define DRIVER_LICENSE "GPL" #define DRIVER_AUTHOR "zhutoubenben" #define DRIVER_DESC "u s b ..." MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE(DRIVER_LICENSE); #define USB_MOUSE_VENDOR_ID 0x1c4f #define USB_MOUSE_PRODUCT_ID 0x03 struct usb_device_id my_usb_table[] = { #if 0 { USB_DEVICE(USB_MOUSE_VENDOR_ID,USB_MOUSE_PRODUCT_ID), }, // 已经注释 无效 #else { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) }, #endif {} }; struct my_mouse_dev { struct usb_device* usb_dev; struct input_dev* input_dev; struct urb * urb; signed char * data; dma_addr_t data_dma; }; int my_usb_mouse_open(struct input_dev *dev){ struct my_mouse_dev* mouse_dev = input_get_drvdata( dev); mouse_dev->urb->dev = mouse_dev->usb_dev; if(usb_submit_urb(mouse_dev->urb,GFP_ATOMIC)){ return -EIO; } return 0; } void my_usb_mouse_close(struct input_dev *dev){ struct my_mouse_dev *mouse = input_get_drvdata(dev); usb_kill_urb(mouse->urb); } /******* 鼠标事件发生 调用的函数 由下方的probe中的 usb_fill_int_urb()决定 ******/ static void usb_mouse_irq(struct urb *urb){ struct my_mouse_dev* mouse = urb->context; struct input_dev* dev = mouse->input_dev; signed char * data = mouse->data; //printk("irq now ..... \n"); switch(urb->status){ case 0: break; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: return; default: /* error */ goto resubmit; } input_report_key(dev, BTN_LEFT, data[0] & 0x01);//data[0]: bit0-左键, 1-按下, 0-松开 input_report_key(dev, BTN_RIGHT, data[0] & 0x02);// bit1-右键, 1-按下, 0-松开 input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);// bit2-中键, 1-按下, 0-松开 input_report_key(dev, BTN_SIDE, data[0] & 0x08);// 鼠标的side 键 input_report_key(dev, BTN_EXTRA, data[0] & 0x10);// 鼠标的extra键 input_report_rel(dev, REL_X, data[1]); // 表示鼠标的水平位移 input_report_rel(dev, REL_Y, data[2]); // 表示鼠标的垂直位移 input_report_rel(dev, REL_WHEEL, data[3]); // REL_WHEEL滚轮位移 input_sync(dev); resubmit: usb_submit_urb (urb, GFP_ATOMIC);// 提交 /* URB处理流程 (1)USB设备驱动程序创建并初始化一个访问特定USB设备特定端点的urb,并提交给USB core (2)USR core提交该urb到到USB主控制器驱动程序。 (3)USB主控制器驱动程序根据该urb描述的信息,来访问usb设备 (4)当设备访问结束后,USB主的控制器驱动程序通知USB设备驱动程序。 */ // 此次应加上判断返回的状态是否成功.... } static int my_usb_probe(struct usb_interface *intf,const struct usb_device_id *id){ int retval = -ENOMEM; struct my_mouse_dev *mouse; struct input_dev *input_dev; struct usb_endpoint_descriptor *endpoint; /* 端点描述符 */ struct usb_host_interface *host_intf; /* 接口设置描述 */ struct usb_device *dev = interface_to_usbdev(intf); /* 设备描述 usb_device */ int pipe; // 管道 int maxp; host_intf = intf->cur_altsetting;// 获取当前的接口配置 if(1!=host_intf->desc.bNumEndpoints){ return -ENODEV; } endpoint = &host_intf->endpoint[0].desc; if (!usb_endpoint_is_int_in(endpoint)){ return -ENODEV;/* 根据HID规范,鼠标唯一的端点应为中断端点 */ } pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);/* 生成中断接收管道 */ /* 返回该端点能够传输的最大的包长度,鼠标的返回的最大数据包为4个字节。*/ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); mouse = kzalloc(sizeof(struct my_mouse_dev),GFP_KERNEL); input_dev = input_allocate_device(); if(!mouse || !input_dev){ goto fail0; } mouse->data = usb_buffer_alloc(dev,8,GFP_ATOMIC,&mouse->data_dma); if(!mouse->data){ printk("usb_buffer_alloc error \n "); goto fail1; } mouse->urb = usb_alloc_urb(0,GFP_KERNEL);//0表示不适用iso等时传输,GFP_KERNEL申请内存的一种方式 if(!mouse->urb){ printk("usb_alloc_urb error \n "); goto fail2; } mouse->usb_dev= dev; mouse->input_dev = input_dev; usb_fill_int_urb(mouse->urb,dev,pipe,mouse->data,(maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval); mouse->urb->transfer_dma = mouse->data_dma; mouse->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;// 当不使用DMA /* input 子系统部分 */ input_dev->dev.parent = &intf->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); //EV_REL 相对坐标(轨迹球) ; EV_ABS 绝对坐标 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_set_drvdata(input_dev,mouse); // 设置私有数据 input_dev->open = my_usb_mouse_open; input_dev->close = my_usb_mouse_close; retval = input_register_device(mouse->input_dev); if (retval){ printk("input_register_device error \n "); goto fail3; } usb_set_intfdata(intf, mouse);// 设置私有数据 return 0; fail3: usb_free_urb(mouse->urb); fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); fail1: input_free_device(input_dev); fail0: kfree(mouse); return retval; } /* 对于probe函数中的设置有两部分, 一部分是usb的,一部分是input子系统的 对于usb部分: 1.获得usb_host_interface即当前接口配置描述的指针,目的是 2.为了获取端点配置(可能有多个) 3.生成中断接收管道 4.设置包最大长度 5.分配usb_buffer这个用来存放获取的数据data 6.申请并设置urb 7.调用usb_fill_int_urb来填充中断 8.在适当的时机调用usb_submit_urb开始工作(这里是在open的时候调用的) 至于input子系统主要就是申请input_dev,设置其支持的事件和键,注册*/ static void my_usb_disconnect (struct usb_interface *intf){ struct my_mouse_dev* mouse = usb_get_intfdata (intf); usb_set_intfdata(intf, NULL); if (mouse) { usb_kill_urb(mouse->urb); /* 结束 urb 生命周期 */ input_unregister_device(mouse->input_dev); /* 将鼠标设备从输入子系统中注销 */ input_free_device(mouse->input_dev); /* 释放存放鼠标事件的存储空间 */ usb_free_urb(mouse->urb); /* 释放 urb 存储空间 */ usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);/* 释放存放鼠标事件的 data 存储空间 */ kfree(mouse); } printk("device %x disconnect ... \n",interface_to_usbdev(intf)->descriptor.idVendor); } static struct usb_driver my_usb_driver = { .name = "my_usb_driver", .probe = my_usb_probe, .disconnect = my_usb_disconnect, .id_table = my_usb_table, }; static int __init my_usb_mouse_init(void){ int result; result = usb_register(&my_usb_driver); if (result) err("usb_register failed. Error number %d", result); return result; } static void __exit my_usb_mouse_exit(void){ usb_deregister(&my_usb_driver); } module_init(my_usb_mouse_init); module_exit(my_usb_mouse_exit); insmod驱动后, 使用cat /dev/event? 然后移动鼠标或者按下鼠标就会有提示输出, 但是都是乱码, 主要的原因是他所提交的都是基于input子系统的结构体, 故这里是乱码, 如果要打印出具体的信息那么就需要我们去写一个input子系统的应用程序, 把具体的数据打印出来...
相关文章推荐
- USB驱动简单分析一
- 慢慢学Linux驱动开发,第四篇,USB工作原理简单分析
- 基于Linux内核的USB鼠标驱动的简单实现
- linux驱动由浅入深系列:usb子系统之四(android平台鼠标驱动代码分析)
- USB鼠标设备简单驱动设计
- 简单的USB鼠标驱动(1)
- usb键鼠标驱动分析
- usb鼠标驱动分析
- 慢慢学Linux驱动开发,第四篇,USB工作原理简单分析
- 简单的USB鼠标驱动(2)
- 从USB设备插上到驱动probe调用流程分析
- WinCE 5.0下鼠标键盘驱动分析
- Linux-USB总线驱动分析
- 简单usb驱动代码记录
- 第十三篇:无征不信,不信民弗从--USB-IF官方驱动BSOD案例分析
- 通用USB设备驱动源码分析
- linux设备驱动之USB数据传输分析(之五)
- USB驱动框架分析1
- Linux下USB驱动框架分析
- Omap4470 USB驱动分析之注册过程