关闭

USB驱动程序之鼠标用做键盘

标签: armusb测试内核编程
84人阅读 评论(1) 收藏 举报
分类:

我们还是接着来看看我们的例子程序 usbmouse.c


这里它接着判断了他是不是鼠标,

得到它的usb_host_interface,interface=intf->cur_alsetting就是当前接口的设置



这里有个接口描述符,我们来看看接口描述符


接口描述符里面有个__u8  bNumEndpoints端点的个数

这个端点的个数是除了端点0之外还有多少个端点


这里首先判断如果除了端点0之外,端点个数不是1的话就返回错误,不是我能够支持的设备

如果只有一个端点,那就把这个端点放到endpoint这个数组里面,这个并不是端点0,而是除了端点0之外第一个端点

得到一个端点描述符

if(!usb_endpoint_is_int_in(endpoint))这个是指如果他不是中断类似的端点,不是输入端点,注意了我们这里输入输出是站在主机的角度说的,站在主机角度,我们的鼠标是输入设备,数据是输入给主机的。如果不是输入类型端点,中断类型端点,就返回一个错误。这个怎么回事呢,怎么知道你是不是中断输入端点呢,端点描述符里面不是有个属性吗,属性里面就是表示它是什么类型的,方向。


我们在我们自己的程序里就不做判断了,我们回到我们的主题,我们就认为就是一个鼠标,



我们硬件相关的操作要用到USB总线驱动程序里面的读写函数

我们只需要记住数据传输3要素,把这个三要素找出就可以实现这一点

1.源   在我们这里是USB设备的某个端点


这个就是源

我们来看看usb_rcvintpipe这个宏


这个源是个整数,pipe_interrupt是指中断类型端点,USB_DIR_IN是端点的方向。我们进入__create_pipe(dev,endpoint)这个宏


devnum是设备的地址,endpoint是端点的地址也是端点编号


2.目的

我们从USB设备里面读数据,读到哪里去,肯定读到缓冲区,但这个缓冲区肯定不能用kmallioc函数,

用这函数

返回一个void* 是个虚拟地址

最后一个参数是指的物理地址


3.长度就是我们的端点描述符最大包大小


使用我们三要素

怎么用呢,看一下我们的例子


分配一个urb urb是什么意思呢,就是USB请求快的意思 usb request block

然后使用这个3要素设置我们的urb  来看我们的例子程序




看看这个函数原型


第一个参数是urb,第二个参数是设备,第三个参数是源,第四个参数是目的,第五个参数是长度 ,第6个参数是完成函数,第7个参数是给那个完成函数用的,我们不需要,第8个参数是查询的频率。

我们前面说过usb设备不能打断主机控制器,只能让主机控制器查询,不断的去查询,等有数据之后才能中断CPU。当它得到数据之后,总线驱动程序就会调用这个complete_fn这个函数,查询多频繁呢就是int interval 。

端点描述符里面有个binterval就是的



我们USB主机控制器,得到数据之后是往某个地方写,但是我们主机控制器没那么聪明,所以我们要告诉它,例子里面


第一句就是告诉物理地址,下面一句是设置某些标记


我们构造了URB 就要使用urb

怎么使用urb


使用usb_submit_urb提交urb



usb鼠标数据含义

我们前面说框架的时候说过,USB设备驱动程序知道数据的含义,USB总线驱动程序提供识别设备,给设备找到驱动,提供读写函数,但是不知道数据的含义。这些数据需要由设备驱动程序来解析,


data[0] bit 0表示左键,1表示按下,0表示松开

     bit 1表示右键,1表示按下,0表示松开

     bit  2表示中键    1表示按下,0表示松开



代码如下

#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 *usb_key;
static char * usb_buf;
static dma_addr_t usb_buf_phys;
static int len;
static struct urb *uk_urb;
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 void usbmouse_as_key_irq(struct urb *urb)
{
static unsigned char pre_val;
/* USB鼠标数据含义
* data[0]: bit0-左键, 1-按下, 0-松开
*          bit1-右键, 1-按下, 0-松开
*          bit2-中键, 1-按下, 0-松开 
*/
if((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
{
//左键发生了变化
input_event(usb_key, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
input_sync(usb_key);
}
if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
{
/* 右键发生了变化 */
input_event(usb_key, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
input_sync(usb_key);
}
if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
{
/* 中键发生了变化 */
input_event(usb_key, EV_KEY, KEY_ENTER, (usb_buf[0]  & (1<<2)) ? 1 : 0);
input_sync(usb_key);
}

pre_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_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int pipe;//源


interface = intf->cur_altsetting;


endpoint = &interface->endpoint[0].desc;
/*a.分配一个input_device结构体*/
usb_key=input_allocate_device();
/*b.设置*/
/*b.1能产生哪类事件*/
//能够产生按键类事件
set_bit(EV_KEY,usb_key->evbit);
set_bit(EV_REP,usb_key->evbit);//能够产生重复类事件,就是只我们按下一个字母不动就会不断的打印出来


/*b.2能产生这类事件的哪些事件*/
set_bit(KEY_L,usb_key->keybit);
set_bit(KEY_S,usb_key->keybit);
set_bit(KEY_ENTER,usb_key->keybit);


/*c.注册*/
input_register_device(usb_key);
/*d.硬件相关的操作*/
/*数据传输3要素 源,目的,长度*/
/*1.源 :USB设备的某个端点*/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);


//长度 等于端点描述符的最大包大小
len=endpoint->wMaxPacketSize;


/*2.目的 */
usb_buf = usb_alloc_coherent(dev,len, GFP_ATOMIC, &usb_buf_phys);


//使用三要素
/*分配一个urb 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);
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb);
usb_free_coherent(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(usb_key);
input_free_device(usb_key);




}
/*1.分配/设置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)
{
/*2.注册usb_driver结构体*/
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");
MODULE_AUTHOR("EIGHT");


测试结构如下图







0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:5473次
    • 积分:751
    • 等级:
    • 排名:千里之外
    • 原创:72篇
    • 转载:0篇
    • 译文:0篇
    • 评论:2条
    最新评论