参考韦东山视频:
-
/* 参考:drivershidusbhidusbmouse.c
-
* 功能描述: 实现在linux 下把usb鼠标的左右和中间滚轮设置为L S ENTER使用
-
*/
-
-
#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 *uk_dev;
-
static char *usb_buf; //虚拟地址
-
static dma_addr_t usb_buf_phys; //dma_addr_t 用来定义一个物理地址 dma_addr_t 实际上是定义一个u32的整数
-
static int len;
-
static struct urb *uk_urb; //urb: usb 请求块
-
static struct usb_device_id usbmouse_as_key_id_table [] = {
-
//{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
-
// USB_INTERFACE_PROTOCOL_MOUSE) },
-
{USB_DEVICE(0x0461, 0x4D80)}, // vend:厂家id prod :设备id
-
{ } /* Terminating entry */
-
};
-
/* usb主机控制器不断去查询鼠标,有数据后会把数据读到自己的缓冲区里并产生一个中断,这个就是中断处理函数 */
-
static void usbmouse_as_key_irq(struct urb *urb)
-
{
-
static char pre_val;
-
#if 0
-
int i;
-
static int cnt = 0;
-
printk("data cnt %d:",++cnt);
-
for(i=0;i<len;i++)
-
{
-
printk("%02x ",usb_buf[i]);
-
}
-
printk("n");
-
#endif
-
/*data[0] : bit0-左键 1-按下 0-松开
-
* bit1-右键 1-按下 0-松开
-
* bit2-中键 1-按下 0-松开
-
*/
-
if((pre_val&(1<<0))!=(usb_buf[0]&(1<<0)))
-
/* 左键发生了变化 */
-
{
-
input_event(uk_dev,EV_KEY,KEY_L,(usb_buf[0]&(1<<0))? 1:0);
-
input_sync(uk_dev);
-
}
-
if((pre_val&(1<<1))!=(usb_buf[0]&(1<<1)))
-
/* 右键发生了变化 */
-
{
-
input_event(uk_dev,EV_KEY,KEY_S,(usb_buf[0]&(1<<1))? 1:0);
-
input_sync(uk_dev);
-
}
-
if((pre_val&(1<<2))!=(usb_buf[0]&(1<<2)))
-
/* 中键发生了变化 */
-
{
-
input_event(uk_dev,EV_KEY,KEY_ENTER,(usb_buf[0]&(1<<2))? 1:0);
-
input_sync(uk_dev);
-
}
-
pre_val = usb_buf[0]; //保存当前值
-
/* 重新提交urb */
-
usb_submit_urb(uk_urb, GFP_ATOMIC);
-
}
-
-
static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
-
{
-
struct usb_device *dev = interface_to_usbdev(intf);
-
struct usb_host_interface *interface;
-
struct usb_endpoint_descriptor *endpoint;
-
int pipe;
-
-
interface = intf->cur_altsetting;
-
endpoint = &interface->endpoint[0].desc;
-
#if 0
-
printk("found usbmouse!n");
-
printk("bcdUSB = %xn",dev->descriptor.bcdUSB); //USB版本号
-
printk("idVendor = 0x%xn",dev->descriptor.idVendor);
-
printk("idProduct = 0x%xn",dev->descriptor.idProduct);
-
#endif
-
/* a. 分配一个input_dev结构体 */
-
uk_dev = input_allocate_device();
-
/* b. 设置 */
-
/* b.1 能产生哪类事件 */
-
set_bit(EV_KEY,uk_dev->evbit);
-
set_bit(EV_REP,uk_dev->evbit);
-
/* b.2 能产生这类事件中的哪些事件 */
-
-
set_bit(KEY_L,uk_dev->keybit);
-
set_bit(KEY_S,uk_dev->keybit);
-
set_bit(KEY_ENTER,uk_dev->keybit);
-
/* c. 注册 */
-
input_register_device(uk_dev);
-
/* d. 硬件相关的操作 */
-
-
/* 区别: 用usb总线驱动程序提供的函数来收发数据和以往操作硬件都是中断,寄存器里读数据不同
-
* 数据传输三要素
-
* a 源 : USB设备的某个端点
-
* b 目的 : 要用usb总线驱动程序里专门的分配空间的函数
-
* c 长度 : 在端点描述符里有描述长度的
-
*/
-
-
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); //源
-
len = endpoint->wMaxPacketSize; //长度: 最大包大小
-
usb_buf = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &usb_buf_phys); //目的 返回一个虚拟地址
-
/* 使用''3 要素'' */
-
/* 分配一个usb request block ( 请求块 )*/
-
uk_urb = usb_alloc_urb(0, GFP_KERNEL);
-
/* 使用'3要素' 设置urb*/
-
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设置查询的频率
-
uk_urb->transfer_dma = usb_buf_phys; //告诉地址并设置相关标志位
-
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
/* 使用urb */
-
usb_submit_urb(uk_urb, GFP_KERNEL); //提交urb
-
return 0;
-
}
-
-
static void usbmouse_as_key_disconnect(struct usb_interface *intf)
-
{
-
-
struct usb_device *dev = interface_to_usbdev(intf);
-
usb_kill_urb(uk_urb);
-
usb_free_urb(uk_urb);
-
usb_free_coherent(dev,len,usb_buf,usb_buf_phys); //注意第四个参数和usb_alloc_coherent不一样
-
input_unregister_device(uk_dev);
-
input_free_device(uk_dev);
-
//printk("distconnect usbmouse!n");
-
}
-
-
/* 1. 分配/设置usb_driver结构体 */
-
static struct usb_driver usbmouse_as_key = {
-
.name = "usbmouse_as_key",
-
.probe = usbmouse_as_key_probe,
-
.disconnect = usbmouse_as_key_disconnect,
-
.id_table = usbmouse_as_key_id_table,
-
};
-
-
static int usbmouse_as_key_init(void)
-
{
-
/*2. 设置*/
-
usb_register(&usbmouse_as_key);
-
return 0;
-
}
-
-
static void usbmouse_as_key_exit(void)
-
{
-
usb_deregister(&usbmouse_as_key);
-
}
-
-
module_init(usbmouse_as_key_init);
-
module_exit(usbmouse_as_key_exit);
-
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
阅读(1515) | 评论(0) | 转发(0) |