USB鼠标驱动

25 篇文章 0 订阅
1 篇文章 0 订阅

仿照drivers/hid/usbhid/usbmouse.c系统自带的USB鼠标驱动实现的USB鼠标驱动。

一、usb/usbmouse_as_key.c

#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 int len;
static char *usb_buf;
static dma_addr_t usb_buf_phys;
struct urb *uk_urb;
struct input_dev *uk_dev;

static void usbmouse_as_key_irq(struct urb *urb)
{
#if 0
    int i;
    static int cnt = 0;

    printk("date cnt %d: ", ++cnt);

    for(i = 0; i < len; i++)
    {
        printk("%02x ", usb_buf[i]);
    }
    printk("\n");
    //加载驱动之后可通过 hexdump dev/input/event0 查看鼠标数据
#endif
    static char per_val;

    /*鼠标数据格式:
    data[0]:    bit0 - 左键,1 - 按下,0 - 松开
                bit1 - 右键,1 - 按下,0 - 松开
                bit2 = 中键,1 - 按下,0 - 松开
    data[6]:    = 0x01 滚轮前进
                = 0xff 滚轮后进
    */
    if((per_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((per_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((per_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);
    }

    per_val = usb_buf[0];
    /* 重新提交urb */
    usb_submit_urb(uk_urb, GFP_KERNEL);
}

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_endpoint_descriptor *endpoint;
    struct usb_host_interface *interface;
    int pipe;
    

    printk("bcdUSB = %x\nVID = 0x%x\nPID = 0x%x\n", dev->descriptor.bcdUSB, dev->descriptor.idVendor, dev->descriptor.idProduct);
    printk("run %s, %d\n", __FUNCTION__, __LINE__);

	interface = intf->cur_altsetting;
	endpoint = &interface->endpoint[0].desc;

    /* a. 分配一个input_dev */
    uk_dev = input_allocate_device();
    uk_dev->name = "usbmouse";

	/* 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. 硬件相关操作 */
	/* 数据传输3要素: 源,目的,长度 */
	/* 源: USB设备的某个端点 */
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);    
	/* 长度: */
    len = endpoint->wMaxPacketSize;
	/* 目的: */
    usb_buf = usb_alloc_coherent(dev, len, 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);
    uk_urb->transfer_dma = usb_buf_phys;
	uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	/* 使用URB */
    usb_submit_urb(uk_urb, GFP_KERNEL);
    return 0;
}

static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
    struct usb_device *dev = interface_to_usbdev(intf);

    printk("run %s, %d\n", __FUNCTION__, __LINE__);  
    
    usb_kill_urb(uk_urb);
    usb_free_urb(uk_urb);

    usb_free_coherent(dev, len, usb_buf, usb_buf_phys);
	input_unregister_device(uk_dev);
	input_free_device(uk_dev);
}


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) },
	{ }	/* Terminating entry */
};

static struct usb_driver usbmouse_as_key_driver = {
	.name		= "usbmouse",
	.probe		= usbmouse_as_key_probe,
	.disconnect	= usbmouse_as_key_disconnect,
	.id_table	= usbmouse_as_key_id_table,
};

static int usbmouse_as_key_init(void)
{
    usb_register(&usbmouse_as_key_driver);
    return 0;
}

static void usbmouse_as_key_exit(void)
{
    usb_deregister(&usbmouse_as_key_driver);
}

module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);
MODULE_LICENSE("GPL");

二、测试

1、说明

KEY_L = 38 = 0x0026
KEY_S = 31 = 0x001f
KEY_ENTER = 28 = 0x001c
因为鼠标中间坏了,就不验证了。

2、内核处理

内核需要把系统自带的USB鼠标驱动移除
在这里插入图片描述

insmod usbmouse_as_key.ko
bcdUSB = 200
VID = 0x46d
PID = 0xc52f
run usbmouse_as_key_probe, 71
input: usbmouse as /devices/virtual/input/input4
usbcore: registered new interface driver usbmouse
/ #
/ # hexdump dev/input/event0
0000000 0878 0000 c7fa 000b 0001 0026 0001 0000
0000010 0878 0000 c7fa 000b 0000 0000 0000 0000
0000020 0878 0000 8d09 000d 0001 0026 0000 0000
0000030 0878 0000 8d09 000d 0000 0000 0000 0000
0000040 0879 0000 3d1c 000c 0001 001f 0001 0000
0000050 0879 0000 3d1c 000c 0000 0000 0000 0000

三、问题排查

1、接上鼠标打印device descriptor read/64, error -62

经分析是USB D+、D-接反导致。

/ # usb 4-1: new full-speed USB device number 2 using ohci-platform
usb 4-1: device descriptor read/64, error -62
usb 4-1: device descriptor read/64, error -62
usb 4-1: new full-speed USB device number 3 using ohci-platform
usb 4-1: device descriptor read/64, error -62
usb 4-1: device descriptor read/64, error -62
usb 4-1: new full-speed USB device number 4 using ohci-platform
usb 4-1: device not accepting address 4, error -62
usb 4-1: new full-speed USB device number 5 using ohci-platform
usb 4-1: device not accepting address 5, error -62
usb usb4-port1: unable to enumerate USB device

2、打印USB disconnect, device number 2

采用有线鼠标测试的时候,出现过加载驱动后打印显示成功加载,但过了一会儿就显示断开了 USB disconnect,采用无线鼠标则没有此类情况。可能是单板USB口采用飞线引出,信号有影响导致。

/ # insmod usbmouse_as_key.ko
bcdUSB = 200
VID = 0x17ef
PID = 0x608d
run usbmouse_as_key_probe, 40
input: usbmouse as /devices/virtual/input/input0
usbcore: registered new interface driver usbmouse
/ # usb 4-1: USB disconnect, device number 2
run usbmouse_as_key_disconnect, 83
usb 4-1: new low-speed USB device number 3 using ohci-platform
bcdUSB = 200
VID = 0x17ef
PID = 0x608d
run usbmouse_as_key_probe, 40
input: usbmouse as /devices/virtual/input/input1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值