25.3.2 USB键盘驱动

25.3.2  USB键盘驱动

USB键盘驱动与串口驱动结构类似,不同的是,使用USB设备核心提供的usb_keyboard_driver结构作为设备核心结构。下面讲解USB键盘驱动的重点部分。

1.驱动初始和注销

USB键盘驱动初始化和注销函数定义如下:

 

static int _ _init usb_kbd_init(void)

{

  int result = usb_register(&usb_keyboard);     //注册USB设备驱动

  if (result == 0)

     info(DRIVER_VERSION ":" DRIVER_DESC);

  return result;

}

 

static void _ _exit usb_kbd_exit(void)

{

  usb_deregister(&usb_keyboard);                    //注销USB设备驱动

}

 

usb_kbd_init()函数在驱动加载的时候调用,该函数使用usb_register()函数向内核注册一个USB设备驱动;usb_kbd_exit()函数在卸载驱动程序的时候调用,该函数使用usb_deregister()函数注销USB设备。初始化和注销函数使用了usb_keyboard结构变量,用于描述USB键盘驱动程序,定义如下:

 

//usb_driver结构体

static struct usb_driver usb_keyboard = 

{

  .name = "usbkbd",                 // 驱动名称

  .probe = usb_kbd_probe,           // 检测设备函数

  .disconnect = usb_kbd_disconnect, // 断开连接函数

  .id_table = usb_kbd_id_table,     // 设备ID

};

 

usb_keyboard结构定义看出,usb_kbd_probe()函数是设备检测函数;usb_kbd_disconnect()函数是断开设备连接函数。在usb_keyboard结构中还用了一个usb_kbd_id_table结构变量描述设备ID,定义如下:

 

static struct usb_device_id usb_kbd_id_table [] = {

{ USB_INTERFACE_INFO(3, 1, 1) },

{ }

};

MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);

 

2.设备检测函数

设备检测函数在插入USB设备的时候被USB文件系统调用,负责检测设备类型是否与驱动相符。如果设备类型与驱动匹配,则向USB核心注册设备。函数定义如下:

 

static int usb_kbd_probe(struct usb_interface *iface, const struct usb_device_id *id)

{

  struct usb_device *dev = interface_to_usbdev(iface);

  struct usb_host_interface *interface;

  struct usb_endpoint_descriptor *endpoint;

  struct usb_kbd *kbd;

  struct input_dev *input_dev;

  int i, pipe, maxp;

 

  interface = iface->cur_altsetting;

  if (interface->desc.bNumEndpoints != 1)               // 检查设备是否符合

      return  - ENODEV;

 

  endpoint = &interface->endpoint[0].desc;

  if (!(endpoint->bEndpointAddress &USB_DIR_IN))

      return  - ENODEV;

  if ((endpoint->bmAttributes &USB_ENDPOINT_XFERTYPE_MASK) !=

      USB_ENDPOINT_XFER_INT)

      return  - ENODEV;

 

  pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);   //创建端点的管道

  maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));

 

  kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);

  input_dev = input_allocate_device();                                                                                      //分配input_dev结构体

  if (!kbd || !input_dev)

      goto fail1;

 

  if (usb_kbd_alloc_mem(dev, kbd))                  // 分配设备结构占用的内存

      goto fail2;

 

  kbd->usbdev = dev;

  kbd->dev = input_dev;

 

  if (dev->manufacturer)                        // 检查制造商名称

    strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));

 

  if (dev->product)                                 // 检查产品名称

  {

    if (dev->manufacturer)

      strlcat(kbd->name, " ", sizeof(kbd->name));

    strlcat(kbd->name, dev->product, sizeof(kbd->name));

  }

 

  if (!strlen(kbd->name))

    snprintf(kbd->name, sizeof(kbd->name), "USB HIDBP Keyboard

      %04x:%04x",le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev

      ->descriptor.idProduct));

 

  usb_make_path(dev, kbd->phys, sizeof(kbd->phys));

  strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));

 

  /* 初始化输入设备 */

  input_dev->name = kbd->name;              // 输入设备名称

  input_dev->phys = kbd->phys;              // 输入设备物理地址

  usb_to_input_id(dev, &input_dev->id);     // 输入设备ID

  input_dev->cdev.dev = &iface->dev;

  input_dev->private = kbd;

 

  input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);

  input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) |

    BIT(LED_SCROLLL) |BIT(LED_COMPOSE) | BIT(LED_KANA);

 

  for (i = 0; i < 255; i++)

    set_bit(usb_kbd_keycode[i], input_dev->keybit);

  clear_bit(0, input_dev->keybit);

 

  input_dev->event = usb_kbd_event;

  input_dev->open = usb_kbd_open;

  input_dev->close = usb_kbd_close;

 

  /* 初始化中断urb */

  usb_fill_int_urb(kbd->irq, dev, pipe, kbd->new, (maxp > 8 ? 8 : maxp),

    usb_kbd_irq, kbd, endpoint->bInterval);

  kbd->irq->transfer_dma = kbd->new_dma;

  kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

 

  kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;

  kbd->cr->bRequest = 0x09;

  kbd->cr->wValue = cpu_to_le16(0x200);

  kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);

  kbd->cr->wLength = cpu_to_le16(1);

 

  /* 初始化控制urb */

  usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), (void*)

  kbd->cr,

    kbd->leds, 1, usb_kbd_led, kbd);

  kbd->led->setup_dma = kbd->cr_dma;

  kbd->led->transfer_dma = kbd->leds_dma;

  kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP |

   URB_NO_SETUP_DMA_MAP);

  input_register_device(kbd->dev);      //注册输入设备

 

  usb_set_intfdata(iface, kbd);     //设置接口私有数据

  return 0;

 

  fail2: usb_kbd_free_mem(dev, kbd);

  fail1: input_free_device(input_dev);

  kfree(kbd);

  return  - ENOMEM;

}

 

函数一开始检测设备类型,如果与驱动程序匹配,则创建USB设备端点,分配设备驱动结构占用的内存。分配好设备驱动使用的结构后,申请一个键盘设备驱动节点,然后设置键盘驱动,最后设置USB设备的中断URB和控制URB,供USB设备核心使用。

3.设备断开连接函数

在设备断开连接的时候,USB文件系统会调用usb_kbd_disconnect()函数,释放设备占用的资源。函数定义如下:

 

static void usb_kbd_disconnect(struct usb_interface *intf)

{

  struct usb_kbd *kbd = usb_get_intfdata(intf);

 

  usb_set_intfdata(intf, NULL);         //设置接口私有数据为NULL

  if (kbd)

  {

    usb_kill_urb(kbd->irq);              //终止URB

    input_unregister_device(kbd->dev);   //注销输入设备

    usb_kbd_free_mem(interface_to_usbdev(intf), kbd);                                                            // 释放设备驱动占用的内存

    kfree(kbd);

  }

}

 

usb_kbd_disconnect()函数释放USB键盘设备占用的URB资源,然后注销设备,最后调用usb_kbd_free_mem()函数,释放设备驱动结构变量占用的内存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值