参考/drivers/hid/usbhid/usbmouse.c(内核自带的USB鼠标驱动)

1.本节需要用到的宏如下:

struct usb_device_id usbmouse_id_table []=USB_INTERFACE_INFO(cl,sc,pr);          

USB_INTERFACE_INFO()设置usb_driver驱动的id_table成员

cl:接口类,我们USB鼠标为HID类,所以填入0X03,也就是USB_INTERFACE_CLASS_HID

sc:接口子类为启动设备,填入USB_INTERFACE_SUBCLASS_BOOT

pr:接口协议为鼠标协议,填入USB_INTERFACE_PROTOCOL_MOUSE

struct usb_device *dev=interface_to_usbdev(intf);  

通过usb_ interface接口获取usb_device设备,为后面设置USB数据传输用

pipe=usb_rcvintpipe(dev,endpoint);

创建一个接收(rcv)中断(int)类型的端点管道(pipe),用来端点和数据缓冲区之间的连接,鼠标为接收中断型

dev: usb_device设备结构体

endpoint:为端点描述符的成员endpoint->bEndpointAddress   //端点地址

  • 对于控制类型的端点管道使用: usb_sndctrlpipe()/usb_rcvctrlpipe()
  • 对于实时类型的端点管道使用: usb_sndisocpipe()/usb_sndisocpipe()
  • 对于批量类型的端点管道使用: usb_sndbulkpipe()/usb_rcvbulkpipe()

2.本节需要用到的函数如下:

usb_deregister(struct usb_driver *driver);

注册一个usb_driver驱动,然后内核会通过usb_driver的成员.id_table函数匹配一次USB设备,匹配成功就会调用usb_driver的成员.probe函数

usb_deregister(struct usb_driver *driver);

注销一个usb_driver驱动,在出口函数中写

*usb_buffer_alloc(struct usb_device *dev,size_t size,gfp_t mem_flags,dma_addr_t *dma);

分配一个usb缓冲区,该缓存区的物理地址会与虚拟地址的数据一致,分配成功返回一个char型缓冲区虚拟地址

*dev: usb_device设备结构体

size:分配的缓冲区大小,这里填端点描述符的成员endpoint->wMaxPacketSize          //端点最大包长

mem_flags:分配内存的参数,这里填GFP_ATOMIC,表示从不睡眠

dma:分配成功则会返回一个DMA缓冲区物理地址

void usb_buffer_free(struct usb_device *dev,size_t size,void *addr,dma_addr_t dma);

注销分配的usb缓冲区,在usb_driver的disconnect成员函数中使用

addr:要注销的缓冲区虚拟地址

dma: 要注销的DMA缓冲区虚拟地址

struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);

分配一个urb数据结构体, 分配成功返回一个urb结构体

urb全称为usb request block,USB传输数据时,就是打包成urb结构体来传输

iso_packets:表示iso类型的包个数,这里我们不是iso类型包,直接填0

mem_flags:分配内存的参数,这里填入GFP_KERNEL,正常分配

其中urb结构体如下所示:

struct urb
{... ...struct usb_device *dev;             //指向usb设备struct usb_host_endpoint *ep;    //指向端点的数据结构 unsigned int pipe;                  //指向端点管道(pipe), 本节的pipe通过usb_rcvintpipe()宏获取 int status;                                 //状态,当status==0,表示数据被成功地收到/发送
 unsigned int transfer_flags;     //传输状态... ...
/*以下两个缓冲区通过usb_buffer_alloc ()函数获取 */
//urb结构体默认的transfer_flags是URB_NO_SETUP_DMA_MAP ,也就是说没有提供DMA的缓冲区
//就会使用transfer_buffer虚拟地址缓冲区来当缓冲区
//当支持DMA缓冲区时,就需要手动设置transfer_flags =URB_NO_TRANSFER_DMA_MAP,并手动设置transfer_dma等于获取到的DMA物理地址 void *transfer_buffer;                //虚拟缓冲区dma_addr_t transfer_dma;          //DMA物理缓冲区
... ...
};
void usb_free_urb(struct urb *urb);

释放申请的urb,在usb_driver的disconnect成员函数中使用

static inline void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,                      void *transfer_buffer,int buffer_length, usb_complete_t complete_fn,void *context,int interval);

初始化中断型端点的urb数据结构体

针对批量型端点的urb使用usb_fill_bulk_urb()
针对控制型端点的urb使用usb_fill_control_urb()
针对等时型端点的urb  需要手动初始化。

urb:指向要初始化的urb

dev:指向要传输的usb设备

pipe:要传输的端点管道, 本节的pipe通过usb_rcvintpipe()宏获取

transfer_buffer:指向要传输数据的虚拟地址缓冲区

buffer_length:数据大小, 这里填端点描述符的成员endpoint->wMaxPacketS //端点最大包长

complete_fn:数据传输完成后产生的中断函数

context:会放在urb->context结构成员中,用来给中断函数用,本节不需要,填NULL即可

interval:间隔时间,表示间隔多少时间读一次数据,填入endpoint-> bInterval即可

int usb_submit_urb(struct urb *urb,gfp_t mem_flags);

提交urb到内核,初始化urb和中断函数退出时,都要重新提交一次,告诉内核初始化内存缓存等

void usb_kill_urb(struct urb *urb);

杀掉urb,在usb_driver的disconnect成员函数中使用

3.步骤如下:

首先先定义全局变量:usb_driver结构体,input_dev指针结构体 ,虚拟地址缓存区,DMA地址缓存区

3.1在入口函数中

1)通过usb_register()函数注册usb_driver结构体

3.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.3在鼠标中断函数中

1)判断缓存区数据是否改变,若改变则上传鼠标事件

2)使用usb_submit_urb()提交urb

3.4.在usb_driver的disconnect函数中

1)通过usb_kill_urb()杀掉提交到内核中的urb

2)释放urb

3)释放USB缓存区

4)注销input_device,释放input_device

3.5在出口函数中

1)通过usb_deregister ()函数注销usb_driver结构体

4.代码如下:

#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>static struct input_dev *myusb_mouse_dev;              //input_dev static char *myusb_mouse_buf;                         //虚拟地址缓存区
static dma_addr_t myusb_mouse_phyc;                     //DMA缓存区;static __le16 myusb_mouse_size;                        //数据包长度static struct urb  *myusb_mouse_urb;                     //urbstatic void myusb_mouse_irq(struct urb *urb)               //鼠标中断函数
{static char buf1=0;//for(i=0;i<myusb_mouse_size;i++)// printk("%02x  ",myusb_mouse_buf[i]);
 //  printk("\n");/*bit 1-左右中键  0X01:左键   0X02:右键     0x04:中键   */if((buf1&(0X01))    !=      (myusb_mouse_buf[1]&(0X01))){         input_report_key(myusb_mouse_dev, KEY_L, buf1&(0X01)? 1:0);input_sync(myusb_mouse_dev);  }if((buf1&(0X02))    !=    (myusb_mouse_buf[1]&(0X02))){input_report_key(myusb_mouse_dev, KEY_S, buf1&(0X02)? 1:0);input_sync(myusb_mouse_dev);  }if((buf1&(0X04))    !=    (myusb_mouse_buf[1]&(0X04))  ){input_report_key(myusb_mouse_dev, KEY_ENTER, buf1&(0X04)? 1:0);input_sync(myusb_mouse_dev);  }buf1=myusb_mouse_buf[1];                                   //更新数据
usb_submit_urb(myusb_mouse_urb, GFP_KERNEL);
}static int myusb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{struct usb_device *dev = interface_to_usbdev(intf);             //设备struct usb_endpoint_descriptor *endpoint;                            struct usb_host_interface *interface;                         //当前接口int pipe;                                                   //端点管道interface=intf->cur_altsetting;                                                                   endpoint = &interface->endpoint[0].desc;                                    //当前接口下的端点描述符
   printk("VID=%x,PID=%x\n",dev->descriptor.idVendor,dev->descriptor.idProduct); //打印VID,PID/*   1)分配一个input_dev结构体  */myusb_mouse_dev=input_allocate_device();/*   2)设置input_dev支持L、S,回车、3个按键事件*/set_bit(EV_KEY, myusb_mouse_dev->evbit);set_bit(EV_REP, myusb_mouse_dev->evbit);        //支持重复按功能
set_bit(KEY_L, myusb_mouse_dev->keybit);       set_bit(KEY_S, myusb_mouse_dev->keybit);set_bit(KEY_ENTER, myusb_mouse_dev->keybit);    /*   3)注册input_dev结构体*/input_register_device(myusb_mouse_dev);/*   4)设置USB数据传输 *//*->4.1)通过usb_rcvintpipe()创建一个端点管道*/pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress); /*->4.2)通过usb_buffer_alloc()申请USB缓冲区*/myusb_mouse_size=endpoint->wMaxPacketSize;myusb_mouse_buf=usb_buffer_alloc(dev,myusb_mouse_size,GFP_ATOMIC,&myusb_mouse_phyc);/*->4.3)通过usb_alloc_urb()和usb_fill_int_urb()申请并初始化urb结构体 */myusb_mouse_urb=usb_alloc_urb(0,GFP_KERNEL);usb_fill_int_urb (myusb_mouse_urb,                       //urb结构体dev,                           //usb设备pipe,                          //端点管道myusb_mouse_buf,               //缓存区地址myusb_mouse_size,              //数据长度myusb_mouse_irq,               //中断函数0,endpoint->bInterval);          //中断间隔时间/*->4.4) 因为我们2440支持DMA,所以要告诉urb结构体,使用DMA缓冲区地址*/myusb_mouse_urb->transfer_dma   =myusb_mouse_phyc;             //设置DMA地址myusb_mouse_urb->transfer_flags   =URB_NO_TRANSFER_DMA_MAP;     //设置使用DMA地址/*->4.5)使用usb_submit_urb()提交urb*/usb_submit_urb(myusb_mouse_urb, GFP_KERNEL);return 0;
}static void myusb_mouse_disconnect(struct usb_interface *intf)
{struct usb_device *dev = interface_to_usbdev(intf);                  //设备
usb_kill_urb(myusb_mouse_urb);usb_free_urb(myusb_mouse_urb);usb_buffer_free(dev, myusb_mouse_size, myusb_mouse_buf,myusb_mouse_phyc);input_unregister_device(myusb_mouse_dev);         //注销内核中的input_devinput_free_device(myusb_mouse_dev);             //释放input_dev
} static struct usb_device_id myusb_mouse_id_table [] = {{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,                 //接口类:hid类USB_INTERFACE_SUBCLASS_BOOT,             //子类:启动设备类USB_INTERFACE_PROTOCOL_MOUSE) },      //USB协议:鼠标协议
};static struct usb_driver myusb_mouse_drv = {.name            = "myusb_mouse",.probe           = myusb_mouse_probe,                           .disconnect     = myusb_mouse_disconnect,.id_table  = myusb_mouse_id_table,
};/*入口函数*/
static int myusb_mouse_init(void)
{usb_register(&myusb_mouse_drv);return 0;
}/*出口函数*/
static void myusb_mouse_exit(void)
{usb_deregister(&myusb_mouse_drv);
}module_init(myusb_mouse_init);
module_exit(myusb_mouse_exit);
MODULE_LICENSE("GPL");

5.测试运行

5.1 重新设置编译内核(去掉默认的hid_USB驱动)

make menuconfig ,进入menu菜单重新设置内核参数:

进入-> Device Drivers -> HID Devices

<> USB Human Interface Device (full HID) support //hid:人机交互的USB驱动,比如鼠标,键盘等

然后make uImage 编译内核

将新的触摸屏驱动模块放入nfs文件系统目录中

5.2然后烧写内核,装载触摸屏驱动模块

如下图,当我们插上USB鼠标时,可以看到该VID和PID,和电脑上的鼠标的参数一样

5.3使用hexdump命令来调试

(hexdump命令调试代码详解地址:http://www.cnblogs.com/lifexy/p/7553550.html)

5.4 使用tty1进程测试

Linux-USB鼠标驱动相关推荐

  1. Linux USB鼠标驱动入门以及处理流程

    1 需要 禁用掉 CONFIG_USB_HID,不然下面的驱动不会被探测. 2 下面的驱动模块代码只打印了鼠标左键是否被按下,左键没有被按下打印0,左键被按下打印1. 3 参考了这里 4 内核版本 4 ...

  2. 十五、Linux驱动之USB鼠标驱动

    1. 如何编写USB鼠标驱动 结合十四.Linux驱动之USB驱动分析中的分析,我们开始写一个USB鼠标驱动.      USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动, ...

  3. Linux下的USB总线驱动(03)——USB鼠标驱动 usbmouse.c

    USB鼠标驱动 usbmouse.c 原文链接:http://www.linuxidc.com/Linux/2012-12/76197p7.htm drivers/hid/usbhid/usbmous ...

  4. Linux USB设备驱动程序设计 和 USB下载线驱动设计

    Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...

  5. 浅谈Linux USB设备驱动

    1.USB基础介绍 1-1.USB硬件接口介绍 USB接口在硬件上总共有四根线组成VCC.D+.D-.GND,通过计算D+和D-的差值来确定数据.USB设备在传输速率上可以分为低速(1.5Mbps). ...

  6. USB鼠标驱动开发流程

    USB驱动开发,针对某一个USB设备的某个功能(接口)构建的驱动程序.USB驱动并不直接和USB设备进行数据交互,而是通过USB总线驱动程序(USB Core和USB HCD)来操作USB设备的.一般 ...

  7. linux usb can驱动开发,linux驱动编写之十 USB初探

    通用串行总线(USB)是主机和外设设备之间的一种连接 USB的关键点在于搞懂那些连成线,连成片的各个数据结构,其实linux系统总的说来,不就是一个个的数据结构加上一些方法函数所组成的庞大的整体吗?w ...

  8. Linux usb设备驱动

    原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316 1.Linux usb设备驱动框架 USB是通用串行总线的总称,Linu ...

  9. 编写Linux usb 键盘驱动的笔记

    编写linux usb 设备驱动参考:    linux-5.8.5\Documentation\driver-api\usb\writing_usb_driver.rst    linux-5.8. ...

  10. linux usb gadget驱动详解(二)

    在上篇<linux usb gadget驱动详解(一)>中,我们了解到gadget的测试方法,但在最后,我们留下一个问题,就是怎样使用新的方法进行usb gadget驱动测试. 我们发现l ...

最新文章

  1. Angular应用提高打包速度
  2. 《Python 学习手册4th》 第十二章 if测试和语法规则
  3. 一个经典的字母排列算法
  4. Pandas中DataFrame的属性及方法大全
  5. Spring+CXF之集成
  6. Spring boot中使用Swagger2
  7. 设计模式——装饰器模式
  8. How is a Batch request handled in the backend
  9. 2011考研数学概率论基础复习必备知识点
  10. [置顶] Z-STACK之OSAL_Nv非易失性存储解读上
  11. linux mint 19界面美化,安装完 LinuxMint 19.3 后必做的10件事
  12. shell 两时间之差
  13. 条件运算符的嵌套问题
  14. 计算机等级考试二级c++2013 南开题库 答案光碟,全国计算机等级考试二级C++上机题库试卷一2013年.pdf...
  15. 平均聚类系数_聚类方法排除CPU用量误报警
  16. 谷歌地图的离线地图下载
  17. python重复import_Python 中循环 import 造成的问题如何解决?
  18. KILE无法软件仿真
  19. 苹果iPhone 7价格差很多,谨慎购买!
  20. 华为OD机试 - 士兵过河

热门文章

  1. typescript 使用jsx语法
  2. 用Rational RequisitePro写用例规约(Use Case Specification)的心得
  3. Canny、Sobel和Prewitt算子python实现
  4. Verilog——双向IO口的FPGA实现
  5. 云开发超多功能工具箱组合微信小程序源码/附带流量主功能介绍
  6. 我可是一个有图的留言板咳咳√
  7. 按字寻址与按字节寻址的区别
  8. 基于SVM的语音情感识别系统设计
  9. html页面禁止滚动条,css如何不让出现滚动条?
  10. C#简单实现成绩管理系统