Chinaunix首页 | 论坛 | 博客
  • 博客访问: 138420
  • 博文数量: 33
  • 博客积分: 15
  • 博客等级: 民兵
  • 技术积分: 42
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-22 10:23
个人简介

嵌入式带动整个社会!

文章分类
文章存档

2015年(4)

2014年(15)

2013年(8)

2012年(6)

分类: 嵌入式

2013-05-17 13:19:40

参考韦东山视频:

点击(此处)折叠或打开

  1. /* 参考:drivershidusbhidusbmouse.c
  2.   * 功能描述: 实现在linux 下把usb鼠标的左右和中间滚轮设置为L S ENTER使用
  3.   */

  4. #include <linux/kernel.h>
  5. #include <linux/slab.h>
  6. #include <linux/module.h>
  7. #include <linux/init.h>
  8. #include <linux/usb/input.h>
  9. #include <linux/hid.h>

  10. static struct input_dev *uk_dev;
  11. static char *usb_buf; //虚拟地址
  12. static dma_addr_t usb_buf_phys; //dma_addr_t 用来定义一个物理地址 dma_addr_t 实际上是定义一个u32的整数
  13. static int len;
  14. static struct urb *uk_urb; //urb: usb 请求块
  15. static struct usb_device_id usbmouse_as_key_id_table [] = {
  16.     //{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
  17.     //    USB_INTERFACE_PROTOCOL_MOUSE) },
  18.     {USB_DEVICE(0x0461, 0x4D80)}, // vend:厂家id prod :设备id
  19.     { }    /* Terminating entry */
  20. };
  21. /* usb主机控制器不断去查询鼠标,有数据后会把数据读到自己的缓冲区里并产生一个中断,这个就是中断处理函数 */
  22. static void usbmouse_as_key_irq(struct urb *urb)
  23. {
  24.     static char pre_val;
  25. #if 0
  26.     int i;
  27.     static int cnt = 0;
  28.     printk("data cnt %d:",++cnt);
  29.     for(i=0;i<len;i++)
  30.     {
  31.         printk("%02x ",usb_buf[i]);
  32.     }
  33.     printk("n");
  34. #endif    
  35.     /*data[0] : bit0-左键 1-按下 0-松开
  36.      * bit1-右键 1-按下 0-松开
  37.      * bit2-中键 1-按下 0-松开
  38.         */
  39.     if((pre_val&(1<<0))!=(usb_buf[0]&(1<<0)))
  40.         /* 左键发生了变化 */
  41.     {
  42.         input_event(uk_dev,EV_KEY,KEY_L,(usb_buf[0]&(1<<0))? 1:0);
  43.         input_sync(uk_dev);
  44.     }
  45.     if((pre_val&(1<<1))!=(usb_buf[0]&(1<<1)))
  46.         /* 右键发生了变化 */
  47.     {
  48.         input_event(uk_dev,EV_KEY,KEY_S,(usb_buf[0]&(1<<1))? 1:0);
  49.         input_sync(uk_dev);
  50.     }
  51.     if((pre_val&(1<<2))!=(usb_buf[0]&(1<<2)))
  52.         /* 中键发生了变化 */
  53.     {
  54.         input_event(uk_dev,EV_KEY,KEY_ENTER,(usb_buf[0]&(1<<2))? 1:0);
  55.         input_sync(uk_dev);
  56.     }
  57.     pre_val = usb_buf[0]; //保存当前值
  58.     /* 重新提交urb */
  59.     usb_submit_urb(uk_urb, GFP_ATOMIC);
  60. }

  61. static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
  62. {
  63.     struct usb_device *dev = interface_to_usbdev(intf);
  64.     struct usb_host_interface *interface;
  65.     struct usb_endpoint_descriptor *endpoint;
  66.     int pipe;
  67.     
  68.     interface = intf->cur_altsetting;
  69.     endpoint = &interface->endpoint[0].desc;
  70. #if 0    
  71.     printk("found usbmouse!n");
  72.     printk("bcdUSB = %xn",dev->descriptor.bcdUSB); //USB版本号
  73.     printk("idVendor = 0x%xn",dev->descriptor.idVendor);
  74.     printk("idProduct = 0x%xn",dev->descriptor.idProduct);
  75. #endif
  76.     /* a. 分配一个input_dev结构体 */
  77.     uk_dev = input_allocate_device();
  78.     /* b. 设置 */
  79.     /* b.1 能产生哪类事件 */
  80.     set_bit(EV_KEY,uk_dev->evbit);
  81.     set_bit(EV_REP,uk_dev->evbit);
  82.     /* b.2 能产生这类事件中的哪些事件 */
  83.     
  84.     set_bit(KEY_L,uk_dev->keybit);    
  85.     set_bit(KEY_S,uk_dev->keybit);
  86.     set_bit(KEY_ENTER,uk_dev->keybit);
  87.     /* c. 注册 */
  88.     input_register_device(uk_dev);
  89.     /* d. 硬件相关的操作 */

  90.     /* 区别: 用usb总线驱动程序提供的函数来收发数据和以往操作硬件都是中断,寄存器里读数据不同
  91.      * 数据传输三要素
  92.      * a 源 : USB设备的某个端点
  93.      * b 目的 : 要用usb总线驱动程序里专门的分配空间的函数
  94.      * c 长度 : 在端点描述符里有描述长度的
  95.      */
  96.     
  97.     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); //
  98.     len = endpoint->wMaxPacketSize; //长度: 最大包大小
  99.     usb_buf = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &usb_buf_phys); //目的 返回一个虚拟地址
  100.     /* 使用''3 要素'' */
  101.     /* 分配一个usb request block ( 请求块 )*/
  102.     uk_urb = usb_alloc_urb(0, GFP_KERNEL);
  103.     /* 使用'3要素' 设置urb*/
  104.     usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,len,usbmouse_as_key_irq, NULL, endpoint->bInterval); //完成函数并不是usb鼠标 有 数据并不是 中断cpu,它没有中断cpu能力,6410芯片里有usb控制器,它不断查询是否有数据,如果有usb控制器中断6410cpu,bInterval设置查询的频率
  105.     uk_urb->transfer_dma = usb_buf_phys; //告诉地址并设置相关标志位
  106.     uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  107.     /* 使用urb */
  108.     usb_submit_urb(uk_urb, GFP_KERNEL); //提交urb
  109.     return 0;
  110. }

  111. static void usbmouse_as_key_disconnect(struct usb_interface *intf)
  112. {
  113.     
  114.     struct usb_device *dev = interface_to_usbdev(intf);
  115.     usb_kill_urb(uk_urb);
  116.     usb_free_urb(uk_urb);
  117.     usb_free_coherent(dev,len,usb_buf,usb_buf_phys); //注意第四个参数和usb_alloc_coherent不一样
  118.     input_unregister_device(uk_dev);
  119.     input_free_device(uk_dev);
  120.     //printk("distconnect usbmouse!n");
  121. }

  122. /* 1. 分配/设置usb_driver结构体 */
  123. static struct usb_driver usbmouse_as_key = {
  124.     .name        = "usbmouse_as_key",
  125.     .probe        = usbmouse_as_key_probe,
  126.     .disconnect    = usbmouse_as_key_disconnect,
  127.     .id_table    = usbmouse_as_key_id_table,
  128. };

  129. static int usbmouse_as_key_init(void)
  130. {
  131.     /*2. 设置*/
  132.     usb_register(&usbmouse_as_key);
  133.     return 0;
  134. }

  135. static void usbmouse_as_key_exit(void)
  136. {
  137.     usb_deregister(&usbmouse_as_key);
  138. }

  139. module_init(usbmouse_as_key_init);
  140. module_exit(usbmouse_as_key_exit);
  141. MODULE_LICENSE("GPL");

测试过程:
一开始想把内核自带的usb驱动卸掉,可是不是卸多了就是卸不净,主要是还是没理清内核自带的usb层次,于是参照网上的牛人修改内核代码后可以执行自己写的probe函数了

内核自带:
[root@FriendlyARM /]# usb 1-1.3: new low speed USB device using s3c2410-ohci and address 3
usb 1-1.3: New USB device found, idVendor=0461, idProduct=4d80
usb 1-1.3: New USB device strings: Mfr=0, Product=2, SerialNumber=0
usb 1-1.3: Product: USB Optical Mouse
input: USB Optical Mouse as /devices/platform/s3c2410-ohci/usb1/1-1/1-1.3/1-1.3:1.0/input/input1
generic-usb 0003:0461:4D80.0001: input: USB HID v1.11 Mouse [USB Optical Mouse] on usb-s3c24xx-1.3/input0  //hid/usbhid/hid-core.c:1467:     .name = "generic-usb",
usb 1-1.3: USB disconnect, address 3

 

修改后:执行自己写的probe函数

[root@FriendlyARM /mnt]# usb 1-1.3: new low speed USB device using s3c2410-ohci and address 3
usb 1-1.3: New USB device found, idVendor=0461, idProduct=4d80
usb 1-1.3: New USB device strings: Mfr=0, Product=2, SerialNumber=0
usb 1-1.3: Product: USB Optical Mouse
*** Device ignored ***/nVendorID = 0461, ProductID = 4D80/n(null)/nUSB Optical Mouse/n**********************/n
found usbmouse!
bcdUSB = 200
idVendor = 0x461
idProduct = 0x4d80
usb 1-1.3: USB disconnect, address 3         //usb/core/hub.c:1603:    dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
distconnect usbmouse!

 


3th test:

BUG: sleeping function called from invalid context at mm/slub.c:795
in_atomic(): 1, irqs_disabled(): 128, pid: 0, name: swapper
[] (unwind_backtrace+0x0/0xe4) from [] (__kmalloc+0x6c/0xf4)
[] (__kmalloc+0x6c/0xf4) from [] (ohci_urb_enqueue+0x218/0x68c)
[] (ohci_urb_enqueue+0x218/0x68c) from [] (usb_hcd_submit_urb+0x7ac/0x8c4)
[] (usb_hcd_submit_urb+0x7ac/0x8c4) from [] (usbmouse_as_key_irq+0x64/0x88 [usbmouse_as_key])
[] (usbmouse_as_key_irq+0x64/0x88 [usbmouse_as_key]) from [] (usb_hcd_giveback_urb+0x70/0xb8)
[] (usb_hcd_giveback_urb+0x70/0xb8) from [] (finish_urb+0x7c/0xb8)
[] (finish_urb+0x7c/0xb8) from [] (ohci_irq+0x314/0x4e4)
[] (ohci_irq+0x314/0x4e4) from [] (usb_hcd_irq+0x38/0x88)
[] (usb_hcd_irq+0x38/0x88) from [] (handle_IRQ_event+0x24/0xe0)
[] (handle_IRQ_event+0x24/0xe0) from [] (handle_level_irq+0xbc/0x13c)
[] (handle_level_irq+0xbc/0x13c) from [] (asm_do_IRQ+0x70/0x94)
[] (asm_do_IRQ+0x70/0x94) from [] (__irq_svc+0x48/0xa0)
Exception stack(0xc05e3f78 to 0xc05e3fc0)
3f60:                                                       00000000 00000000
3f80: 00000021 f6100000 c05e2000 c05e7274 c061a1c4 c08518c0 50023c68 410fb766
3fa0: 50023c00 00000000 cf8c6044 c05e3fc0 c01728a0 bf00003c 60000013 ffffffff
[] (__irq_svc+0x48/0xa0) from [] (__cpu_pfn_fa+0x3c/0x44 [fa_cpu_pfn])
[] (__cpu_pfn_fa+0x3c/0x44 [fa_cpu_pfn]) from [] (cpu_idle+0x40/0x8c)
[] (cpu_idle+0x40/0x8c) from [] (start_kernel+0x270/0x2c8)
[] (start_kernel+0x270/0x2c8) from [<50008034>] (0x50008034)

解决:
static void usbmouse_as_key_irq(struct urb *urb)函数中
重新提交urb参数设置由 usb_submit_urb(uk_urb, GFP_KERNEL)改成 usb_submit_urb(uk_urb, GFP_ATOMIC);

测试结果:    按键   x方向位移   y方向位移   滚轮  
data cnt  1:  01      00    00    00       00 00  //左键按下

data cnt  2:  00      00    00    00       00 00 //左键松开

data cnt  3:  02      00    00    00       00 00 //右键按下

data cnt  4:  00      00    00    00       00 00 //右键松开

data cnt  5:  04      00    00    00       00 00 //滚轮按下

data cnt  6:  00      00    00    00       00 00 //滚轮松开

data cnt  7:  03      00    00    00       00 00  //左右键同时按下

data cnt  8:  00      00    00    00       00 00  // 左右键同时松开

data cnt  9:  00      fe    0f    00       00 00 //左移

data cnt 10:  00      01    20    00       00 00 //右移

data cnt 11:  00      00    f0    ff       00 00  //上移

data cnt 12:  00      00    10    00       00 00   //下移

data cnt 13:  00      00    00    00       01 00   //滚轮上滑

data cnt 14:  00      00    00    00       ff 00   滚轮下滑

该鼠标用6个字节来表示数据,x方向和y方向各用1个独立字节,且共用一个字节表示位移也有的鼠标用8个或4个字节等来描述

4th test:
[root@FriendlyARM /mnt]#  ls -l /dev/input/event*
crw-rw----    1 root     root       13,  64 Jan  9  2000 /dev/input/event0
crw-rw----    1 root     root       13,  65 Jan  8 19:56 /dev/input/event1   这个是刚安装上去的usb驱动主设备号为13,次设备号为65
[root@FriendlyARM /mnt]# hexdump /dev/input/event1 (hexdump实质是open这个设备,然后read,最后以16进制显示出来)
                              (type)     (code)        (value)
            秒         微秒  按键类     哪个按键        按键值
0000000 1d82 3877 dc29 0000   0001      0026(l)       0001 0000
0000010 1d82 3877 dc45 0000   0000      0000          0000 0000
0000020 1d82 3877 b0d5 0002   0001      0026          0000 0000   同步事件
0000030 1d82 3877 b0ec 0002   0000      0000          0000 0000

 

0000040 1d87 3877 7a51 0006   0001      001f(s)       0001 0000
0000050 1d87 3877 7a6c 0006   0000      0000          0000 0000
0000060 1d87 3877 eb4c 0008   0001      001f          0000 0000
0000070 1d87 3877 eb62 0008   0000      0000          0000 0000

 

 
0000080 1d8a 3877 0644 000f   0001     001c(enter)    0001 0000
0000090 1d8a 3877 065f 000f   0000      0000             0000 0000
00000a0 1d8b 3877 6d7d 0003   0001     001c             0000 0000
00000b0 1d8b 3877 6d91 0003   0000     0000            0000 0000

 

阅读(1529) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~