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

2014年(14)

我的朋友

分类: LINUX

2014-06-26 14:22:56

键盘是一种输入型的设备,基于USB接口,内核提供了USB键盘的驱动,定义在drivers/hid/usbhid/usbkhd.c

一、USB键盘驱动的结构
定义了USB键盘的usb_driver的实例

点击(此处)折叠或打开

  1. static struct usb_driver usb_kbd_driver = {
  2.     .name =        "usbkbd",//驱动名
  3.     .probe =    usb_kbd_probe,//探测方法
  4.     .disconnect =    usb_kbd_disconnect,//断开连接方法
  5.     .id_table =    usb_kbd_id_table,//支持的设备ID
  6. };
驱动支持的设备ID列表,定义了驱动支持的设备ID

点击(此处)折叠或打开

  1. static struct usb_device_id usb_kbd_id_table [] = {
  2.     { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
  3.         USB_INTERFACE_PROTOCOL_KEYBOARD) },
  4.     { }                        /* Terminating entry */
  5. };
  6. MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
二、驱动的加载和卸载方法

点击(此处)折叠或打开

  1. //驱动加载方法
  2. static int __init usb_kbd_init(void)
  3. {
  4.     //注册USB驱动
  5.     int result = usb_register(&usb_kbd_driver);
  6.     if (result == 0)
  7.         printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
  8.                 DRIVER_DESC "\n");
  9.     return result;
  10. }
  11. //驱动卸载方法
  12. static void __exit usb_kbd_exit(void)
  13. {
  14.     //注销USB驱动
  15.     usb_deregister(&usb_kbd_driver);
  16. }
三、探测方法
当USB键盘插入USB接口,USB核心通过USB键盘的属性匹配对应的驱动,找到对应的驱动后会调用驱动的探测方法

点击(此处)折叠或打开

  1. static int usb_kbd_probe(struct usb_interface *iface,
  2.              const struct usb_device_id *id)
  3. {
  4.     //通过接口得到USB设备结构
  5.     struct usb_device *dev = interface_to_usbdev(iface);
  6.     struct usb_host_interface *interface;
  7.     struct usb_endpoint_descriptor *endpoint;
  8.     struct usb_kbd *kbd;
  9.     struct input_dev *input_dev;
  10.     int i, pipe, maxp;
  11.     int error = -ENOMEM;
  12.     //获得当前激活的接口
  13.     interface = iface->cur_altsetting;
  14.     //判断当前接口的端点数是否为1
  15.     if (interface->desc.bNumEndpoints != 1)
  16.         return -ENODEV;
  17.     //获得端点的描述
  18.     endpoint = &interface->endpoint[0].desc;
  19.     //判断端点是否为中断端点
  20.     if (!usb_endpoint_is_int_in(endpoint))
  21.         return -ENODEV;
  22.     //创建一个管道
  23.     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
  24.     //获得端点传输的最大数据包大小
  25.     maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));

  26.     kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
  27.     //创建input_dev结构
  28.     input_dev = input_allocate_device();
  29.     if (!kbd || !input_dev)
  30.         goto fail1;
  31.     //分配usb_kbd内存空间
  32.     if (usb_kbd_alloc_mem(dev, kbd))
  33.         goto fail2;
  34.     //为usb_kbd结构赋值
  35.     kbd->usbdev = dev;
  36.     kbd->dev = input_dev;
  37.     //获得制造商
  38.     if (dev->manufacturer)
  39.         strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
  40.     //获得产品名
  41.     if (dev->product) {
  42.         if (dev->manufacturer)
  43.             strlcat(kbd->name, " ", sizeof(kbd->name));
  44.         strlcat(kbd->name, dev->product, sizeof(kbd->name));
  45.     }

  46.     if (!strlen(kbd->name))
  47.         snprintf(kbd->name, sizeof(kbd->name),
  48.              "USB HIDBP Keyboard %04x:%04x",
  49.              le16_to_cpu(dev->descriptor.idVendor),
  50.              le16_to_cpu(dev->descriptor.idProduct));

  51.     usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
  52.     strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
  53.     //为input_dev结构赋值
  54.     input_dev->name = kbd->name;
  55.     input_dev->phys = kbd->phys;
  56.     usb_to_input_id(dev, &input_dev->id);
  57.     input_dev->dev.parent = &iface->dev;

  58.     input_set_drvdata(input_dev, kbd);

  59.     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
  60.         BIT_MASK(EV_REP);
  61.     input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
  62.         BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
  63.         BIT_MASK(LED_KANA);
  64.     //设置键编码
  65.     for (i = 0; i < 255; i++)
  66.         set_bit(usb_kbd_keycode[i], input_dev->keybit);
  67.     clear_bit(0, input_dev->keybit);

  68.     input_dev->event = usb_kbd_event;
  69.     input_dev->open = usb_kbd_open;
  70.     input_dev->close = usb_kbd_close;
  71.     //中断urb初始化
  72.     usb_fill_int_urb(kbd->irq, dev, pipe,
  73.              kbd->new, (maxp > 8 ? 8 : maxp),
  74.              usb_kbd_irq, kbd, endpoint->bInterval);
  75.     kbd->irq->transfer_dma = kbd->new_dma;
  76.     kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

  77.     kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
  78.     kbd->cr->bRequest = 0x09;
  79.     kbd->cr->wValue = cpu_to_le16(0x200);
  80.     kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
  81.     kbd->cr->wLength = cpu_to_le16(1);
  82.     //控制urb初始化
  83.     usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
  84.              (void *) kbd->cr, kbd->leds, 1,
  85.              usb_kbd_led, kbd);
  86.     kbd->led->transfer_dma = kbd->leds_dma;
  87.     kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  88.     //注册输入设备
  89.     error = input_register_device(kbd->dev);
  90.     if (error)
  91.         goto fail2;

  92.     usb_set_intfdata(iface, kbd);
  93.     device_set_wakeup_enable(&dev->dev, 1);
  94.     return 0;

  95. fail2:    
  96.     usb_kbd_free_mem(dev, kbd);
  97. fail1:    
  98.     input_free_device(input_dev);
  99.     kfree(kbd);
  100.     return error;
  101. }
探测方法的功能为分配一个input_dev结构并初始化input_dev结构;分配中断URB,中断初始化URB;分配控制URB,
控制初始化URB;注册输入设备

四、断开连接的方法

点击(此处)折叠或打开

  1. static void usb_kbd_disconnect(struct usb_interface *intf)
  2. {
  3.     struct usb_kbd *kbd = usb_get_intfdata (intf);

  4.     usb_set_intfdata(intf, NULL);
  5.     if (kbd) {
  6.         //取消urb传递
  7.         usb_kill_urb(kbd->irq);
  8.         //注销input设备
  9.         input_unregister_device(kbd->dev);
  10.         //释放USB DMA空间
  11.         usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
  12.         kfree(kbd);
  13.     }
  14. }
五、中断URB回调方法

点击(此处)折叠或打开

  1. static void usb_kbd_irq(struct urb *urb)
  2. {
  3.     struct usb_kbd *kbd = urb->context;
  4.     int i;
  5.     //判断URB状态
  6.     switch (urb->status) {
  7.     case 0:            /* success */
  8.         break;
  9.     case -ECONNRESET:    /* unlink */
  10.     case -ENOENT:
  11.     case -ESHUTDOWN:
  12.         return;
  13.     /* -EPIPE: should clear the halt */
  14.     default:        /* error */
  15.         goto resubmit;
  16.     }
  17.     //向输入子系统核心提交事件
  18.     for (i = 0; i < 8; i++)
  19.         input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);

  20.     for (i = 2; i < 8; i++) {

  21.         if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
  22.             if (usb_kbd_keycode[kbd->old[i]])
  23.                 input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
  24.             else
  25.                 hid_info(urb->dev,
  26.                      "Unknown key (scancode %#x) released.\n",
  27.                      kbd->old[i]);
  28.         }

  29.         if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
  30.             if (usb_kbd_keycode[kbd->new[i]])
  31.                 input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
  32.             else
  33.                 hid_info(urb->dev,
  34.                      "Unknown key (scancode %#x) released.\n",
  35.                      kbd->new[i]);
  36.         }
  37.     }
  38.     //同步事件
  39.     input_sync(kbd->dev);

  40.     memcpy(kbd->old, kbd->new, 8);

  41. resubmit:
  42.     //重新提交事件
  43.     i = usb_submit_urb (urb, GFP_ATOMIC);
  44.     if (i)
  45.         hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
  46.             kbd->usbdev->bus->bus_name,
  47.             kbd->usbdev->devpath, i);
  48. }
六、控制URB回调方法

点击(此处)折叠或打开

  1. static void usb_kbd_led(struct urb *urb)
  2. {
  3.     struct usb_kbd *kbd = urb->context;
  4.     //判断URB状态
  5.     if (urb->status)
  6.         hid_warn(urb->dev, "led urb status %d received\n",
  7.              urb->status);

  8.     if (*(kbd->leds) == kbd->newleds)
  9.         return;

  10.     *(kbd->leds) = kbd->newleds;
  11.     kbd->led->dev = kbd->usbdev;
  12.     if (usb_submit_urb(kbd->led, GFP_ATOMIC))
  13.         hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
  14. }
七、输入设备的事件处理方法

点击(此处)折叠或打开

  1. static int usb_kbd_event(struct input_dev *dev, unsigned int type,
  2.              unsigned int code, int value)
  3. {
  4.     struct usb_kbd *kbd = input_get_drvdata(dev);

  5.     if (type != EV_LED)
  6.         return -1;

  7.     kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
  8.          (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
  9.          (!!test_bit(LED_NUML, dev->led));

  10.     if (kbd->led->status == -EINPROGRESS)
  11.         return 0;

  12.     if (*(kbd->leds) == kbd->newleds)
  13.         return 0;

  14.     *(kbd->leds) = kbd->newleds;
  15.     kbd->led->dev = kbd->usbdev;
  16.     if (usb_submit_urb(kbd->led, GFP_ATOMIC))
  17.         pr_err("usb_submit_urb(leds) failed\n");

  18.     return 0;
  19. }
USB键盘驱动使用了中断URB和控制URB







阅读(1908) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~