驱动程序之_1_字符设备_13_USB设备_3_鼠标驱动
从上一篇文章知道,当我们接入一个USB设备,USB总线驱动会为我们构建一个device并注册,编写驱动程序时只需要构造driver并注册到总线即可,其中driver中有一个id_table[],用来示意所支持的设备;probe函数用于,完成初始化,(probe函数在总线驱动匹配设备);disconnect函数,切断联系;等等
编写一个简单的USB驱动程序:将鼠标用作键盘,按下左键相当于按下’l‘,按下右键相当于按下’s‘,按下滚轮相当于按下"enter"
以前写键盘类驱动程序(使用input子系统)流程:
一、入口函数
1、分配input_dev
2、设置input_dev
3、注册input_dev
4、硬件初始化(中断等)
二、出口函数,完成与入口函数相反的工作
三、使用input子系统提供的事件函数,完善功能函数
写USB驱动程序的流程:
一、入口函数
1、分配usb_driver
2、设置usb_driver
3、注册usb_driver,(会调用到probe函数,在probe中同样要设置一个input_dev)
4、硬件初始化(中断等)
二、出口函数,完成与入口函数相反的工作
三、使用usb总线驱动提供的读写函数,完善功能函数
分析:
定义、设置usb_driver,在入口函数中注册
static struct usb_driver mouse = {
.name = "mouse",
.probe = mouse_probe,
.disconnect = mouse_disconnect,
.id_table = mouse_id_table,
};
static int mouse_init(void)
{
int error;
error = usb_register(&mouse);
return 0;
}
在probe函数中
1、获取描述符
2、分配、设置、注册input_dev
3、获得数据源、数据包大小、分配数据缓存
4、分配、填充urb(usb请求块)
5、提交urb
static int mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
endpoint = &interface->endpoint[0].desc;
/**********************************************/
input_mouse = input_allocate_device();
set_bit(EV_KEY,input_mouse->evbit);
set_bit(EV_REP,input_mouse->evbit);
set_bit(KEY_L,input_mouse->keybit);
set_bit(KEY_S,input_mouse->keybit);
set_bit(KEY_ENTER,input_mouse->keybit);
input_register_device(input_mouse);
/**********************************************/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = endpoint->wMaxPacketSize;
mouse_buf = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse_buf_phys);
/**********************************************/
mouse_urb = usb_alloc_urb(0, GFP_KERNEL);
usb_fill_int_urb(mouse_urb, dev, pipe, mouse_buf, maxp, mouse_irq, 0, endpoint->bInterval);
mouse_urb->transfer_dma = mouse_buf_phys;
mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/**********************************************/
usb_submit_urb(mouse_urb, GFP_KERNEL);
/**********************************************/
}
在disconnect函数中
1、注销、释放urb
2、释放数据缓存
3、注销释放input_dev
static void mouse_disconnect(struct usb_interface *intf)
{
/**********************************************/
usb_kill_urb(mouse_urb);
usb_free_urb(mouse_urb);
/**********************************************/
usb_buffer_free(interface_to_usbdev(intf),maxp, mouse_buf, mouse_buf_phys);
/**********************************************/
input_unregister_device(input_mouse);
input_free_device(input_mouse);
/**********************************************/
}
在irq中断函数中
1、上报数据
2、提交urb
static void mouse_irq(struct urb *urb)
{
int error;
#ifdef DEBUG
int i;
printk("usb_buf : ");
for(i = 0;i < maxp;i++)
printk("%02x ",mouse_buf[i]);
printk("\r\n");
#else
input_report_key(input_mouse, KEY_L, mouse_buf[0] & 0x01);
input_report_key(input_mouse, KEY_S, mouse_buf[0] & 0x02);
input_report_key(input_mouse, KEY_ENTER, mouse_buf[0] & 0x04);
input_sync(input_mouse);
#endif
error = usb_submit_urb(urb, GFP_ATOMIC);
}
测试方法:
重新编译内核(反选USB驱动),用新内核启动
一、定义宏DEBUG,加载驱动,插上鼠标,按下按键后串口即有输出
二、注释宏DEBUG,测试方法与input子系统相同
附上完整代码
#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>
//#define DEBUG
static struct input_dev *input_mouse;
static dma_addr_t mouse_buf_phys;
static char *mouse_buf;
static struct urb *mouse_urb;
static int maxp;
static void mouse_irq(struct urb *urb)
{
int error;
#ifdef DEBUG
int i;
printk("usb_buf : ");
for(i = 0;i < maxp;i++)
printk("%02x ",mouse_buf[i]);
printk("\r\n");
#else
input_report_key(input_mouse, KEY_L, mouse_buf[0] & 0x01);
input_report_key(input_mouse, KEY_S, mouse_buf[0] & 0x02);
input_report_key(input_mouse, KEY_ENTER, mouse_buf[0] & 0x04);
input_sync(input_mouse);
#endif
error = usb_submit_urb(urb, GFP_ATOMIC);
}
static int mouse_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;
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
endpoint = &interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
printk("found mouse\r\n");
printk("bcdUSB %x\r\n",dev->descriptor.bcdUSB);
printk("Vid %x\r\n",dev->descriptor.idVendor);
printk("Pid %x\r\n",dev->descriptor.idProduct);
input_mouse = input_allocate_device();
set_bit(EV_KEY,input_mouse->evbit);
set_bit(EV_REP,input_mouse->evbit);
set_bit(KEY_L,input_mouse->keybit);
set_bit(KEY_S,input_mouse->keybit);
set_bit(KEY_ENTER,input_mouse->keybit);
input_register_device(input_mouse);
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = endpoint->wMaxPacketSize;
mouse_buf = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse_buf_phys);
mouse_urb = usb_alloc_urb(0, GFP_KERNEL);
usb_fill_int_urb(mouse_urb, dev, pipe, mouse_buf, maxp, mouse_irq, 0, endpoint->bInterval);
mouse_urb->transfer_dma = mouse_buf_phys;
mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(mouse_urb, GFP_KERNEL);
return 0;
}
static void mouse_disconnect(struct usb_interface *intf)
{
printk("disconnect mouse\r\n");
usb_kill_urb(mouse_urb);
usb_free_urb(mouse_urb);
usb_buffer_free(interface_to_usbdev(intf),maxp, mouse_buf, mouse_buf_phys);
input_unregister_device(input_mouse);
input_free_device(input_mouse);
}
static struct usb_device_id mouse_id_table[] = {
{
USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE)
}
};
static struct usb_driver mouse = {
.name = "mouse",
.probe = mouse_probe,
.disconnect = mouse_disconnect,
.id_table = mouse_id_table,
};
static int mouse_init(void)
{
int error;
error = usb_register(&mouse);
return 0;
}
static void mouse_exit(void)
{
usb_deregister(&mouse);
}
module_init(mouse_init);
module_exit(mouse_exit);
MODULE_LICENSE("GPL");
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)