/*
参考例子:drivers\hid\usbhid\usbmouse.c
* 功能:完整的USB驱动程序
*
* 2016年6月23日21:37:10
*/
#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;//物理地址
static struct urb *uk_urb;
static int len;
static void usbmouse_as_key_irq(struct urb *urb)
{
static unsigned 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
/* USB鼠标数据的含义
* 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_KERNEL);
}
/* 对 USB_DEVICE 宏进行分析
* #define USB_DEVICE(vend,prod) \
* .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
* .idProduct = (prod)
*
* 该宏定义支持的厂家ID,和设备ID
*/
/* 对 USB_INTERFACE_INFO宏分析:
* #define USB_INTERFACE_INFO(cl,sc,pr) \
* .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
* .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
*
*
* match_flags:表示匹配这个设备描述符里面的哪一项,
* USB_DEVICE_ID_MATCH_INT_INFO表示匹配接口信息(接口的信息在接口描述符里),
* 只要接口描述符里面的接口类.bInterfaceClass是cl(什么东西),
* 接口描述符里的接口子类.bInterfaceSubClass是sc(什么东西),
* 接口描述符里的协议.bInterfaceProtocol是pr(什么东西),就能支持
*/
/* 只要usb设备的接口描述符里的类是HID类,子类是BOOT,协议是MOUSE就能支持
*
*/
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设备驱动程序只支持某个厂家生产(0x1234)的某款产品(0x5678)*/
// {USB_DEVICE(0x1234,0x5678)},
{ } /* Terminating entry */
};
/*注册驱动后,usb_bus_type中的match函数把usb_interface和usb_driver的id_table比较
* 若能匹配成功,则调用usb_driver中的usbmouse_as_key_probe函数。
*/
static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
/*通过接口得到usb_device结构体*/
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
/*获取usb接口结构体中的usb_host接口结构体*/
interface = intf->cur_altsetting;
/*获取usb_host接口结构体中的端点描述结构体*/
endpoint = &interface->endpoint[0].desc;
int pipe
/*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设备的某个端点
* 把指定usb设备的指定端口设置为一个控制IN端点
* 创建管道,用于连接驱动程序缓冲区和设备端口
*/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/*长度:
* 是端点描述符里面的最大包大小
*/
len = endpoint->wMaxPacketSize;
/* 目的:
* 这就是驱动程序缓冲区了,usb_buffer_alloc函数同时分配物理地址和虚拟地址,
* 当usb主机控制器查询到有数据时,会将数据存放到usb_buf_phys缓冲区中,
*/
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
/*使用三要素:*/
/* URB处理流程:
* (1)USB设备驱动程序创建并初始化一个访问特定USB设备特定端点的urb,并提交给USB core
* (2)USR core提交该urb到到USB总线驱动程序。
* (3)USB总线驱动程序根据该urb描述的信息,来访问usb设备
* (4)当设备访问结束后,USB总线驱动程序通知USB设备驱动程序。
*
*/
/* 分配usb request block */
uk_urb = usb_alloc_urb(0, GFP_KERNEL);
/* 使用"3要素设置urb"
* 设置urb请求块,可以通过设置它来控制驱动程序与设备端点之间的通信
*
* usb主机控制器不断查询usb设备有无数据,当usb主机控制器查询到有数据时,
* 会将数据存放到usb_buf_phys缓冲区中,
* 会产生一个中断,usb总线驱动程序就会调用usb_fill_int_urb函数中的complete_fn(完成)函数。
* endpoint->bInterval是usb主机控制器查询usb设备的频率。
*/
//中断类型
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,len,usbmouse_as_key_irq, NULL, endpoint->bInterval);
/* usb主机控制器得到数据后,要往哪个物理地址写入数据
* 如果要操作读取的数据的话,则要用虚拟地址
*/
uk_urb->transfer_dma = usb_buf_phys;
/*设置某些标记*/
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 使用urb
* 提交urb给usb总线驱动程序驱动
*/
usb_submit_urb(uk_urb, GFP_KERNEL);
return 0;
}
/*拔掉usb设备后,则执行usbmouse_as_key_disconnect函数*/
static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
// printk("disconnect usbmouse!");
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb);
usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(uk_dev);
input_free_device(uk_dev);
}
}
/*分配/设置usb_driver结构体*/
static struct usb_driver usbmouse_as_key_driver = {
.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)
{
/*注册*/
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");
* 功能:完整的USB驱动程序
*
* 2016年6月23日21:37:10
*/
#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;//物理地址
static struct urb *uk_urb;
static int len;
static void usbmouse_as_key_irq(struct urb *urb)
{
static unsigned 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
/* USB鼠标数据的含义
* 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_KERNEL);
}
/* 对 USB_DEVICE 宏进行分析
* #define USB_DEVICE(vend,prod) \
* .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
* .idProduct = (prod)
*
* 该宏定义支持的厂家ID,和设备ID
*/
/* 对 USB_INTERFACE_INFO宏分析:
* #define USB_INTERFACE_INFO(cl,sc,pr) \
* .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
* .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
*
*
* match_flags:表示匹配这个设备描述符里面的哪一项,
* USB_DEVICE_ID_MATCH_INT_INFO表示匹配接口信息(接口的信息在接口描述符里),
* 只要接口描述符里面的接口类.bInterfaceClass是cl(什么东西),
* 接口描述符里的接口子类.bInterfaceSubClass是sc(什么东西),
* 接口描述符里的协议.bInterfaceProtocol是pr(什么东西),就能支持
*/
/* 只要usb设备的接口描述符里的类是HID类,子类是BOOT,协议是MOUSE就能支持
*
*/
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设备驱动程序只支持某个厂家生产(0x1234)的某款产品(0x5678)*/
// {USB_DEVICE(0x1234,0x5678)},
{ } /* Terminating entry */
};
/*注册驱动后,usb_bus_type中的match函数把usb_interface和usb_driver的id_table比较
* 若能匹配成功,则调用usb_driver中的usbmouse_as_key_probe函数。
*/
static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
/*通过接口得到usb_device结构体*/
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
/*获取usb接口结构体中的usb_host接口结构体*/
interface = intf->cur_altsetting;
/*获取usb_host接口结构体中的端点描述结构体*/
endpoint = &interface->endpoint[0].desc;
int pipe
/*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设备的某个端点
* 把指定usb设备的指定端口设置为一个控制IN端点
* 创建管道,用于连接驱动程序缓冲区和设备端口
*/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/*长度:
* 是端点描述符里面的最大包大小
*/
len = endpoint->wMaxPacketSize;
/* 目的:
* 这就是驱动程序缓冲区了,usb_buffer_alloc函数同时分配物理地址和虚拟地址,
* 当usb主机控制器查询到有数据时,会将数据存放到usb_buf_phys缓冲区中,
*/
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
/*使用三要素:*/
/* URB处理流程:
* (1)USB设备驱动程序创建并初始化一个访问特定USB设备特定端点的urb,并提交给USB core
* (2)USR core提交该urb到到USB总线驱动程序。
* (3)USB总线驱动程序根据该urb描述的信息,来访问usb设备
* (4)当设备访问结束后,USB总线驱动程序通知USB设备驱动程序。
*
*/
/* 分配usb request block */
uk_urb = usb_alloc_urb(0, GFP_KERNEL);
/* 使用"3要素设置urb"
* 设置urb请求块,可以通过设置它来控制驱动程序与设备端点之间的通信
*
* usb主机控制器不断查询usb设备有无数据,当usb主机控制器查询到有数据时,
* 会将数据存放到usb_buf_phys缓冲区中,
* 会产生一个中断,usb总线驱动程序就会调用usb_fill_int_urb函数中的complete_fn(完成)函数。
* endpoint->bInterval是usb主机控制器查询usb设备的频率。
*/
//中断类型
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,len,usbmouse_as_key_irq, NULL, endpoint->bInterval);
/* usb主机控制器得到数据后,要往哪个物理地址写入数据
* 如果要操作读取的数据的话,则要用虚拟地址
*/
uk_urb->transfer_dma = usb_buf_phys;
/*设置某些标记*/
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 使用urb
* 提交urb给usb总线驱动程序驱动
*/
usb_submit_urb(uk_urb, GFP_KERNEL);
return 0;
}
/*拔掉usb设备后,则执行usbmouse_as_key_disconnect函数*/
static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
// printk("disconnect usbmouse!");
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb);
usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(uk_dev);
input_free_device(uk_dev);
}
}
/*分配/设置usb_driver结构体*/
static struct usb_driver usbmouse_as_key_driver = {
.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)
{
/*注册*/
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");