先看一下有关usb的介绍和接入usb的流程
驱动和app 和usb的连接
在usb设备总线里,把device放入usb_bus_type的dev列表
从ubs_bus_type的driver链表里取出usb_driver
把usb_interface和usb_driver的id_table比较
如果能匹配调用driver的probe
怎么写usb_driver usb 设备驱动程序
如果我们使用鼠标,那就像是输入子系统
所以我们再匹配成功时候调用的probe实现我们的输入子系统函数
先写出入口和出口函数,并且加入协议
分配设置一个 usb_driver 结构体
打开别人写的usb鼠标文件进行参考
别人的id_table 是一个宏
所以推断出 usb鼠标设备 接口描述符是 USB_INTERFACE_CLASS_HID
子类是 USB_INTERFACE_SUBCLASS_BOOT
遵守协议是 USB_INTERFACE_PROTOCOL_MOUSE
写出probe函数
先看看现成的probe函数
里面有一个interface接口 ,interface表示着逻辑上的设备,比如一个usb音箱,逻辑上有两个(录音,放音),就对应着两个驱动程序
通过接口得到usb_device结构体
先让鼠标变成一个键盘,可以输入LS 那么就用到输入子系统
在probe函数里面实现输入子系统
a.分配一个input_dev结构体
b.设置
1能产生什么事件
set_bit(EV_KEY, uk_dev->evbit); // 产生按键事件
set_bit(EV_REP, uk_dev->evbit); // 产生持续事件,比如按下不放开就一直输入
2能产生这些事件里面的什么事件
按键事件里面,键盘的L,S,回车事件
c注册
往输入子系统里面注册
d硬件操作
数据传输三要素: 源,长度,目的
源 有usb设备插上去的地址和端点,usb_rcvintpipe()中断类型端点
长度 在端点描述符里找到长度
让长度等于端点描述符的最大长度
目的 usb_buffer_alloc()
这个函数返回一个虚拟地址 参数里面需要一个物理地址
建立一个usb_buf 来存放返回的虚拟地址 这个地址里面调用函数
建立一个usb_buf_phys 作为物理地址
使用三要素
分配一个urb —>usb请求块
用刚刚的三要素进行urb的设置
最后使用urb
触发中断
usb控制器会不停扫描usb 当有数据时候 会给cpu发出中断
写出中断函数
%02X,在输出一个小于2位的数值时,前面补0,使该数总宽度为2位;%x按变量的数据类型的数据长度输出; 16进制的
写到这先进入烧到开发版上面看看有什么东西
所以说 我们只有usb_buf[0]发生了变化 一个 char类型的纸质指正指针是4字节32为位的
用pre_val 保存之前的值 判断是否有按键发生
有的话触发按键中断 ,上报事件
测试
重新建立一个内核
由于之前的内核改的太多,现在重新用之前的
tar -xvf ./linux-2.6.22.6.tar.bz2
book@www.100ask.org:/work/system$ cd ./linux-2.6.22.6/
patch -p1 < ../linux-2.6.22.6_jz2440_v2v3.patch
cp config_ok .config
make menuconfig //去掉原来的usb驱动程序
->driver
->HID
去掉
insmod 自己的驱动 就可以愉快的玩耍了
玩耍
先不插鼠标 安装驱动
ls dev/event*
这时候插入鼠标,就会有 event1
cat /dev/tty1
按下鼠标shell上面就有所产生的按键
/*
* drivers\hid\usbhid\usbmouse.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 struct input_dev *uk_dev;
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) },
//{USB_DEVICE(0x1234,0x5678)},
{ } /* Terminating entry */
};
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
static int cnt = 0;
printk("data cnt %d: ", ++cnt);
printk("%02x ", usb_buf[0]);
printk("%02x\n",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(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);
}
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_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. 硬件相关操作 */
/* 数据传输3要素: 源,目的,长度 */
/* 源: USB设备的某个端点 */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/* 长度: */
len = endpoint->wMaxPacketSize;
/* 目的: */
usb_buf = usb_buffer_alloc(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("disconnect usbmouse!\n");
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);
}
/* 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_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");