博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
韦东山视频实验之USB鼠标驱动
阅读量:2447 次
发布时间:2019-05-10

本文共 5222 字,大约阅读时间需要 17 分钟。

原理简单阐述:

usb 设备主要涉及配置-》接口-》端点,基本上是包含关系,usb设备主要使用接口提供的配置信息,可以当做操作的逻辑设备和传输通道,传输数据采用urb结构。

如何测试:

1. make menuconfig去掉原来的USB鼠标驱动

-> Device Drivers
  -> HID Devices
  <> USB Human Interface Device (full HID) support

2. make uImage 并使用新的内核启动

3. insmod usbmouse_as_key.ko

4. 在开发板上接入、拔出USB鼠标

调试出现的问题:

1. 启动系统在插上usb时,就弹出

usb 1-1: USB disconnect, address 2

usb 1-1: new low speed USB device using s3c2410-ohci and address 3
usb 1-1: configuration #1 chosen from 1 choice
usb 1-1: USB disconnect, address 3
usb 1-1: new low speed USB device using s3c2410-ohci and address 4
usb 1-1: configuration #1 chosen from 1 choice
usb 1-1: USB disconnect, address 4

使用ohci hcd support,可以自动断开和连接,在关闭时不能探测usb鼠标。估计驱动设计的不是很到位

2. 测试中出现oops,出现这种原因总结在代码中:一处为usb_buff没有初始化;另一处为usb_buffer_free的第一个参数使用了uk_urb,而这个参数在前面已经释放,故产生oops,而且调用这个函数的参数也使用错误。

3. usb插上去并不能触发,后来发现在urb处理完毕,并不能调用结束前的回调函数,而是使用了中断回调函数,而且参数也错误

4. 在鼠标插上去的时候,其实移动鼠标也能触发回调函数usbmouse_callback,开启里面的printk就可以看到自己可以测试

5. 最初的时候传输数据采用的是批量IN端口,导致传输方向不对,鼠标触发应该采用OUT端口,后来改为中断OUT端口可以使用;而且usb_rcvintpipe的第二个参数也使用错误,以为只是使用endpoint即可,其实这里使用的endpoint的传输地址。

源代码:

#include 
#include
#include
#include
#include
#include
static struct usb_device_id usbmouse_id_table [] = { //{ USB_DEVICE(0x1404, 0xcddc) }, { USB_INTERFACE_INFO( USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE)}, { }};static struct urb* uk_urb;static struct input_dev *uk_dev;static char *usb_buff;static dma_addr_t usb_dma_buff_phys_addr;static int len; //数据传输的长度static unsigned int mouse_event[] = {KEY_L,KEY_R,KEY_ENTER};//urb被成功传输到usb设备(或者发生了中断),这个函数将被usb核心调用#if 0static irqreturn_t usbmouse_callback(int irq, void *dev_id)//第一次采用的是中断函数,理解错误#elsestatic void usbmouse_callback(struct urb *urb )#endif{ static unsigned char pre_val; int i; //printk("hello test!\n");#if 0 static int cnt = 0; printk("data cnt %d: " ++cnt); for(i = 0; i < len; i++) { printk("%02x ", usb_buff[i]); } printk("\n"); if ((pre_val & (1<<0)) != (usb_buff[0] & (1<<0))) { /* 左键发生了变化 */ printk("hello test no use array !\n"); input_event(uk_dev, EV_KEY, KEY_L, (usb_buff[0] & (1<<0)) ? 1 : 0); input_sync(uk_dev); }#endif#if 1 char tmp; for(i = 0; i< 3; i++) { tmp = usb_buff[0] & (1 << i); if( (pre_val & (1 << i)) != tmp) { printk("hello test event%d ...\n", i); input_event(uk_dev, EV_KEY, mouse_event[i], tmp ? 1 : 0); input_sync(uk_dev); } }#endif pre_val = usb_buff[0]; //重新提交urb usb_submit_urb(uk_urb, GFP_KERNEL);}/*设置操作函数 *input就不用说了 *urb 先要申请urb空间,分配缓冲空间->初始化urb->提交urb数据->完成后调用结束前的回调函数 */static int usbmouse_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *usbdev = interface_to_usbdev(intf); //得到usb_devive struct usb_host_interface* host_intf; struct usb_endpoint_descriptor endpoint; //设备信息 printk("probe drviver for usb device ...\n"); printk("bcdusb = 0x%x\n", usbdev->descriptor.bcdUSB); printk("VID = 0x%x\n", usbdev->descriptor.idVendor); printk("PID = 0x%x\n", usbdev->descriptor.idProduct); int pipe; host_intf = intf->cur_altsetting; endpoint = host_intf->endpoint[0].desc; //alloc input_dev uk_dev = input_allocate_device(); uk_dev->name = "usb_mouse"; //input_dev ops: set event set_bit(EV_KEY, uk_dev->evbit); set_bit(EV_REP, uk_dev->evbit); set_bit(KEY_L, uk_dev->keybit); set_bit(KEY_S, uk_dev->keybit); set_bit(KEY_ENTER, uk_dev->keybit); //register input_dev input_register_device(uk_dev); //使用urb发送数据 /* 分配usb request block */ uk_urb = usb_alloc_urb(0, GFP_KERNEL); //分配urb空间 /* 数据传输3要素: 源,目的,长度 */ pipe = usb_rcvintpipe(usbdev, endpoint.bEndpointAddress);//把usb设备端口设置为中断out端点 //pipe = usb_rcvintpipe(usbdev, endpoint);//把usb设备端口设置为中断out端点 len = endpoint.wMaxPacketSize; #if 0 usb_buffer_alloc(usbdev, len, GFP_ATOMIC, &usb_dma_buff_phys_addr) //初开始没有给bus_buff赋值,导致内核引用出现错误#else usb_buff = usb_buffer_alloc(usbdev, len, GFP_ATOMIC, &usb_dma_buff_phys_addr); //分配缓冲空间 用来返回dma缓冲地址#endif // 初始化urb结构体 usb_fill_int_urb(uk_urb, usbdev, pipe, usb_buff, len, usbmouse_callback, NULL, endpoint.bInterval); uk_urb->transfer_dma = usb_dma_buff_phys_addr; uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; // 提交urb数据 usb_submit_urb(uk_urb, GFP_KERNEL); return 0;}static void usbmouse_disconnect(struct usb_interface *iface){ printk("disconnect usb mouse as key\n"); struct usb_device *dev = interface_to_usbdev(iface); usb_kill_urb(uk_urb); usb_free_urb(uk_urb);#if 0 usb_buffer_free(uk_urb, len, usb_buff, usb_dma_buff_phys_addr); //这里使用参数错误,导致卸载出现ops#else usb_buffer_free(dev, len, usb_buff, usb_dma_buff_phys_addr);#endif input_unregister_device(uk_dev); input_free_device(uk_dev); printk("disconnect usb mouse as key\n");}// 1 设置usb_drviverstatic struct usb_driver my_usb_mouse_drv = { .name = "usb_mouse", .probe = usbmouse_probe, .disconnect = usbmouse_disconnect, .id_table = usbmouse_id_table, //.no_dynamic_id = 1,};// 2 注册static int input_init(void){ printk ("init usb mouse as key\n"); usb_register(&my_usb_mouse_drv); return 0;}static void input_exit(void){ printk ("free usb mouse as key\n"); //注销设备,释放所占用空间 usb_deregister(&my_usb_mouse_drv); }module_init(input_init);module_exit(input_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("LCL");

 

 注意:代码中if 0 的部分是之前错误的部分,为1的部分是调试正确后的部分。

转载地址:http://obtqb.baihongyu.com/

你可能感兴趣的文章
facebook人脸照片_如何阻止Facebook在别人的照片中建议您的名字
查看>>
如何在离开时自动检测巢穴
查看>>
ubuntu显示管理器_如何在Ubuntu的文件管理器中显示导航栏而不显示面包屑
查看>>
关于极客
查看>>
谷歌地图位置偏移_如何使用Google地图与他人临时分享您的位置
查看>>
自定义日历_如何在网络上自定义Google日历的通知
查看>>
hue功能_Philips Hue的“新实验室”部分中的最佳实验功能
查看>>
微软office在线文档_如何使用Microsoft Office密码保护文档和PDF
查看>>
如何在SHIELD Android TV上调整过扫描
查看>>
outlook 禁用不安全_如何在Outlook中禁用删除确认对话框
查看>>
应用程序白名单实现_如何在Windows 10上仅允许商店中的应用程序(和白名单桌面应用程序)...
查看>>
找到丢失的磁贴跟踪器后如何获取通知
查看>>
PlayStation 4 Pro上的“升压模式”是什么?
查看>>
android 更改软键盘_如何在Android上更改Google键盘的主题
查看>>
kodi 缓存文件夹_如何将Kodi图稿与视频存储在同一文件夹中
查看>>
windows隐藏磁盘_如何在Windows的磁盘清理工具中启用隐藏选项
查看>>
如何在Linux或macOS终端中使用Bash历史记录
查看>>
photos设置成中文_如何在OS X的Photos中设置和使用扩展程序
查看>>
大剧院自助签证_如果您的项目是《剧院》,请使用演员
查看>>
qnx 开发十步_十步实现应用程序本地化
查看>>