驱动程序之_1_字符设备_13_USB设备_3_鼠标驱动

驱动程序之_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");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值