Chinaunix首页 | 论坛 | 博客
  • 博客访问: 131673
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 633
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-05 11:44
文章存档

2014年(14)

我的朋友

分类: LINUX

2014-06-26 13:57:03

鼠标是一个标准的输入型设备,USB鼠标分为两部分,USB部分和输入设备部分,内核提供了USB鼠标的支持,
定义在drivers/hid/usbhid/usbmouse.c

一、USB鼠标驱动的结构

点击(此处)折叠或打开

  1. static struct usb_driver usb_mouse_driver = {
  2.     .name        = "usbmouse",//驱动名
  3.     .probe        = usb_mouse_probe,//探测方法
  4.     .disconnect    = usb_mouse_disconnect,//断开连接
  5.     .id_table    = usb_mouse_id_table,//支持的设备ID列表
  6. };
二、驱动支持的设备ID

点击(此处)折叠或打开

  1. static struct usb_device_id usb_mouse_id_table [] = {
  2.     { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
  3.         USB_INTERFACE_PROTOCOL_MOUSE) },
  4.     { }    /* Terminating entry */
  5. };
  6. MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
三、驱动的注册和注销

点击(此处)折叠或打开

  1. //驱动加载方法
  2. static int __init usb_mouse_init(void)
  3. {
  4.     //注册USB驱动
  5.     int retval = usb_register(&usb_mouse_driver);
  6.     if (retval == 0)
  7.         printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
  8.                 DRIVER_DESC "\n");
  9.     return retval;
  10. }
  11. //驱动卸载方法
  12. static void __exit usb_mouse_exit(void)
  13. {
  14.     //注销USB驱动
  15.     usb_deregister(&usb_mouse_driver);
  16. }
四、探测方法

点击(此处)折叠或打开

  1. //探测方法,当USB鼠标插入时,USB核心获得鼠标的属性并通过设备ID匹配相应的驱动,调用用驱动的探测方法
  2. static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
  3. {
  4.     //通过接口获得USB设备结构
  5.     struct usb_device *dev = interface_to_usbdev(intf);
  6.     struct usb_host_interface *interface;
  7.     struct usb_endpoint_descriptor *endpoint;
  8.     struct usb_mouse *mouse;
  9.     struct input_dev *input_dev;
  10.     int pipe, maxp;
  11.     int error = -ENOMEM;
  12.     //获得当前激活的接口
  13.     interface = intf->cur_altsetting;
  14.     //判断接口的端点数是否为1
  15.     if (interface->desc.bNumEndpoints != 1)
  16.         return -ENODEV;
  17.     //获得端点
  18.     endpoint = &interface->endpoint[0].desc;
  19.     if (!usb_endpoint_is_int_in(endpoint))
  20.         return -ENODEV;
  21.     //创建管道
  22.     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
  23.     //获得端点传输的最大数据包大小
  24.     maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
  25.     //分配usb_mouse私有数据空间
  26.     mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
  27.     //分配input_dev结构体
  28.     input_dev = input_allocate_device();
  29.     if (!mouse || !input_dev)
  30.         goto fail1;
  31.     //分配DMA空间
  32.     mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
  33.     if (!mouse->data)
  34.         goto fail1;
  35.     //分配URB
  36.     mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
  37.     if (!mouse->irq)
  38.         goto fail2;

  39.     mouse->usbdev = dev;
  40.     mouse->dev = input_dev;

  41.     if (dev->manufacturer)
  42.         strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));

  43.     if (dev->product) {
  44.         if (dev->manufacturer)
  45.             strlcat(mouse->name, " ", sizeof(mouse->name));
  46.         strlcat(mouse->name, dev->product, sizeof(mouse->name));
  47.     }

  48.     if (!strlen(mouse->name))
  49.         snprintf(mouse->name, sizeof(mouse->name),
  50.              "USB HIDBP Mouse %04x:%04x",
  51.              le16_to_cpu(dev->descriptor.idVendor),
  52.              le16_to_cpu(dev->descriptor.idProduct));

  53.     usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
  54.     strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
  55.     //初始化input_dev结构
  56.     input_dev->name = mouse->name;
  57.     input_dev->phys = mouse->phys;
  58.     usb_to_input_id(dev, &input_dev->id);
  59.     input_dev->dev.parent = &intf->dev;

  60.     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
  61.     input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
  62.         BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
  63.     input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
  64.     input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
  65.         BIT_MASK(BTN_EXTRA);
  66.     input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);

  67.     input_set_drvdata(input_dev, mouse);

  68.     input_dev->open = usb_mouse_open;
  69.     input_dev->close = usb_mouse_close;
  70.     //初始化中断urb
  71.     usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
  72.              (maxp > 8 ? 8 : maxp),
  73.              usb_mouse_irq, mouse, endpoint->bInterval);
  74.     mouse->irq->transfer_dma = mouse->data_dma;
  75.     mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  76.     //注册input_dev设备
  77.     error = input_register_device(mouse->dev);
  78.     if (error)
  79.         goto fail3;

  80.     usb_set_intfdata(intf, mouse);
  81.     return 0;

  82. fail3:    
  83.     usb_free_urb(mouse->irq);
  84. fail2:    
  85.     usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
  86. fail1:    
  87.     input_free_device(input_dev);
  88.     kfree(mouse);
  89.     return error;
  90. }
探测方法主要完成的工作是分配input_dev结构,并初始化input_dev结构成员,分配URB结构,中断初始化URB,
注册输入设备。

五、断开连接方法

点击(此处)折叠或打开

  1. static void usb_mouse_disconnect(struct usb_interface *intf)
  2. {
  3.     struct usb_mouse *mouse = usb_get_intfdata (intf);

  4.     usb_set_intfdata(intf, NULL);
  5.     if (mouse) {
  6.         //取消URB的发送
  7.         usb_kill_urb(mouse->irq);
  8.         //注销输入设备
  9.         input_unregister_device(mouse->dev);
  10.         //释放URB
  11.         usb_free_urb(mouse->irq);
  12.         //释放USBDMA空间
  13.         usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
  14.         kfree(mouse);
  15.     }
  16. }
断开连接的方法是探测方法的逆操作

六、输入设备的打开方法

点击(此处)折叠或打开

  1. static int usb_mouse_open(struct input_dev *dev)
  2. {
  3.     struct usb_mouse *mouse = input_get_drvdata(dev);

  4.     mouse->irq->dev = mouse->usbdev;
  5.     //向USB核心提交URB
  6.     if (usb_submit_urb(mouse->irq, GFP_KERNEL))
  7.         return -EIO;

  8.     return 0;
  9. }
七、输入设备的关闭方法

点击(此处)折叠或打开

  1. static void usb_mouse_close(struct input_dev *dev)
  2. {
  3.     struct usb_mouse *mouse = input_get_drvdata(dev);
  4.     //取消提交的URB
  5.     usb_kill_urb(mouse->irq);
  6. }
八、中断URB回调方法

点击(此处)折叠或打开

  1. static void usb_mouse_irq(struct urb *urb)
  2. {
  3.     struct usb_mouse *mouse = urb->context;
  4.     signed char *data = mouse->data;
  5.     struct input_dev *dev = mouse->dev;
  6.     int status;
  7.     //判断URB状态
  8.     switch (urb->status) {
  9.     case 0:            /* success */
  10.         break;
  11.     case -ECONNRESET:    /* unlink */
  12.     case -ENOENT:
  13.     case -ESHUTDOWN:
  14.         return;
  15.     /* -EPIPE: should clear the halt */
  16.     default:        /* error */
  17.         goto resubmit;
  18.     }
  19.     //当URB传递成功后,向输入子系统核心提交事件
  20.     input_report_key(dev, BTN_LEFT, data[0] & 0x01);
  21.     input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
  22.     input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
  23.     input_report_key(dev, BTN_SIDE, data[0] & 0x08);
  24.     input_report_key(dev, BTN_EXTRA, data[0] & 0x10);
  25.     //向输入子系统核心提交设备移动方向
  26.     input_report_rel(dev, REL_X, data[1]);
  27.     input_report_rel(dev, REL_Y, data[2]);
  28.     input_report_rel(dev, REL_WHEEL, data[3]);

  29.     input_sync(dev);
  30. resubmit:
  31.     //重新想USB核心提交URB请求
  32.     status = usb_submit_urb (urb, GFP_ATOMIC);
  33.     if (status)
  34.         err ("can't resubmit intr, %s-%s/input0, status %d",
  35.                 mouse->usbdev->bus->bus_name,
  36.                 mouse->usbdev->devpath, status);
  37. }
九、总结
USB鼠标驱动的编写步骤
1、申明USB驱动结构
2、注册USB驱动
3、在探测方法中分配input_dev结构并初始化,分配URB并中断初始化URB,注册input驱动
4、在中断URB回调方法中判断URB状态,获得URB传递的值,根据URB值向输入子系统传递事件
5、在注销方法中完成和探测方法中相反的操作







阅读(1987) | 评论(0) | 转发(0) |
1

上一篇:8X8键盘驱动

下一篇:USB键盘驱动

给主人留下些什么吧!~~