鼠标是一个标准的输入型设备,USB鼠标分为两部分,USB部分和输入设备部分,内核提供了USB鼠标的支持,
定义在drivers/hid/usbhid/usbmouse.c
一、USB鼠标驱动的结构
-
static struct usb_driver usb_mouse_driver = {
-
.name = "usbmouse",//驱动名
-
.probe = usb_mouse_probe,//探测方法
-
.disconnect = usb_mouse_disconnect,//断开连接
-
.id_table = usb_mouse_id_table,//支持的设备ID列表
-
};
二、驱动支持的设备ID
-
static struct usb_device_id usb_mouse_id_table [] = {
-
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
-
USB_INTERFACE_PROTOCOL_MOUSE) },
-
{ } /* Terminating entry */
-
};
-
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
三、驱动的注册和注销
-
//驱动加载方法
-
static int __init usb_mouse_init(void)
-
{
-
//注册USB驱动
-
int retval = usb_register(&usb_mouse_driver);
-
if (retval == 0)
-
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-
DRIVER_DESC "\n");
-
return retval;
-
}
-
//驱动卸载方法
-
static void __exit usb_mouse_exit(void)
-
{
-
//注销USB驱动
-
usb_deregister(&usb_mouse_driver);
-
}
四、探测方法
-
//探测方法,当USB鼠标插入时,USB核心获得鼠标的属性并通过设备ID匹配相应的驱动,调用用驱动的探测方法
-
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
-
{
-
//通过接口获得USB设备结构
-
struct usb_device *dev = interface_to_usbdev(intf);
-
struct usb_host_interface *interface;
-
struct usb_endpoint_descriptor *endpoint;
-
struct usb_mouse *mouse;
-
struct input_dev *input_dev;
-
int pipe, maxp;
-
int error = -ENOMEM;
-
//获得当前激活的接口
-
interface = intf->cur_altsetting;
-
//判断接口的端点数是否为1
-
if (interface->desc.bNumEndpoints != 1)
-
return -ENODEV;
-
//获得端点
-
endpoint = &interface->endpoint[0].desc;
-
if (!usb_endpoint_is_int_in(endpoint))
-
return -ENODEV;
-
//创建管道
-
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-
//获得端点传输的最大数据包大小
-
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
//分配usb_mouse私有数据空间
-
mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
-
//分配input_dev结构体
-
input_dev = input_allocate_device();
-
if (!mouse || !input_dev)
-
goto fail1;
-
//分配DMA空间
-
mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
-
if (!mouse->data)
-
goto fail1;
-
//分配URB
-
mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
-
if (!mouse->irq)
-
goto fail2;
-
-
mouse->usbdev = dev;
-
mouse->dev = input_dev;
-
-
if (dev->manufacturer)
-
strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
-
-
if (dev->product) {
-
if (dev->manufacturer)
-
strlcat(mouse->name, " ", sizeof(mouse->name));
-
strlcat(mouse->name, dev->product, sizeof(mouse->name));
-
}
-
-
if (!strlen(mouse->name))
-
snprintf(mouse->name, sizeof(mouse->name),
-
"USB HIDBP Mouse %04x:%04x",
-
le16_to_cpu(dev->descriptor.idVendor),
-
le16_to_cpu(dev->descriptor.idProduct));
-
-
usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
-
strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
-
//初始化input_dev结构
-
input_dev->name = mouse->name;
-
input_dev->phys = mouse->phys;
-
usb_to_input_id(dev, &input_dev->id);
-
input_dev->dev.parent = &intf->dev;
-
-
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
-
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
-
input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-
input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
-
BIT_MASK(BTN_EXTRA);
-
input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
-
-
input_set_drvdata(input_dev, mouse);
-
-
input_dev->open = usb_mouse_open;
-
input_dev->close = usb_mouse_close;
-
//初始化中断urb
-
usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
-
(maxp > 8 ? 8 : maxp),
-
usb_mouse_irq, mouse, endpoint->bInterval);
-
mouse->irq->transfer_dma = mouse->data_dma;
-
mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
//注册input_dev设备
-
error = input_register_device(mouse->dev);
-
if (error)
-
goto fail3;
-
-
usb_set_intfdata(intf, mouse);
-
return 0;
-
-
fail3:
-
usb_free_urb(mouse->irq);
-
fail2:
-
usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
-
fail1:
-
input_free_device(input_dev);
-
kfree(mouse);
-
return error;
-
}
探测方法主要完成的工作是分配input_dev结构,并初始化input_dev结构成员,分配URB结构,中断初始化URB,
注册输入设备。
五、断开连接方法
-
static void usb_mouse_disconnect(struct usb_interface *intf)
-
{
-
struct usb_mouse *mouse = usb_get_intfdata (intf);
-
-
usb_set_intfdata(intf, NULL);
-
if (mouse) {
-
//取消URB的发送
-
usb_kill_urb(mouse->irq);
-
//注销输入设备
-
input_unregister_device(mouse->dev);
-
//释放URB
-
usb_free_urb(mouse->irq);
-
//释放USBDMA空间
-
usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
-
kfree(mouse);
-
}
-
}
断开连接的方法是探测方法的逆操作
六、输入设备的打开方法
-
static int usb_mouse_open(struct input_dev *dev)
-
{
-
struct usb_mouse *mouse = input_get_drvdata(dev);
-
-
mouse->irq->dev = mouse->usbdev;
-
//向USB核心提交URB
-
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
-
return -EIO;
-
-
return 0;
-
}
七、输入设备的关闭方法
-
static void usb_mouse_close(struct input_dev *dev)
-
{
-
struct usb_mouse *mouse = input_get_drvdata(dev);
-
//取消提交的URB
-
usb_kill_urb(mouse->irq);
-
}
八、中断URB回调方法
-
static void usb_mouse_irq(struct urb *urb)
-
{
-
struct usb_mouse *mouse = urb->context;
-
signed char *data = mouse->data;
-
struct input_dev *dev = mouse->dev;
-
int status;
-
//判断URB状态
-
switch (urb->status) {
-
case 0: /* success */
-
break;
-
case -ECONNRESET: /* unlink */
-
case -ENOENT:
-
case -ESHUTDOWN:
-
return;
-
/* -EPIPE: should clear the halt */
-
default: /* error */
-
goto resubmit;
-
}
-
//当URB传递成功后,向输入子系统核心提交事件
-
input_report_key(dev, BTN_LEFT, data[0] & 0x01);
-
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
-
input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
-
input_report_key(dev, BTN_SIDE, data[0] & 0x08);
-
input_report_key(dev, BTN_EXTRA, data[0] & 0x10);
-
//向输入子系统核心提交设备移动方向
-
input_report_rel(dev, REL_X, data[1]);
-
input_report_rel(dev, REL_Y, data[2]);
-
input_report_rel(dev, REL_WHEEL, data[3]);
-
-
input_sync(dev);
-
resubmit:
-
//重新想USB核心提交URB请求
-
status = usb_submit_urb (urb, GFP_ATOMIC);
-
if (status)
-
err ("can't resubmit intr, %s-%s/input0, status %d",
-
mouse->usbdev->bus->bus_name,
-
mouse->usbdev->devpath, status);
-
}
九、总结
USB鼠标驱动的编写步骤
1、申明USB驱动结构
2、注册USB驱动
3、在探测方法中分配input_dev结构并初始化,分配URB并中断初始化URB,注册input驱动
4、在中断URB回调方法中判断URB状态,获得URB传递的值,根据URB值向输入子系统传递事件
5、在注销方法中完成和探测方法中相反的操作
阅读(2034) | 评论(0) | 转发(0) |