Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3808057
  • 博文数量: 197
  • 博客积分: 10086
  • 博客等级: 上将
  • 技术积分: 5145
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-13 10:50
文章分类

全部博文(197)

文章存档

2011年(2)

2009年(30)

2008年(165)

我的朋友

分类: LINUX

2008-05-05 09:50:55

USB键盘驱动

在Linux系统中,键盘被认定为标准输入设备,对于一个USB键盘而言,其驱动主要由两部分组成:usb_driver的成员函数和输入设备的打开、关闭、中断处理等函数。

在USB键盘设备驱动的模块加载和卸载函数中,将分别注册和注销对应于USB键盘的usb_driver结构体usb_kbd_driver,代码清单20.33所示为模块加载与卸载函数以及usb_kbd_driver结构体的定义。

代码清单20.33  USB键盘设备驱动的模块加载与卸载函数及usb_driver结构体

1  static int _ _init usb_kbd_init(void)
2 {
3 int result = usb_register(&usb_kbd_driver); //注册USB设备驱动
4 if (result == 0)
5 info(DRIVER_VERSION ":" DRIVER_DESC);
6 return result;
7 }
8
9 static void _ _exit usb_kbd_exit(void)
10 {
11 usb_deregister(&usb_kbd_driver); //注销USB设备驱动
12 }
13
14 //usb_driver结构体
15 static struct usb_driver usb_kbd_driver =
16 {
17 .name = "usbkbd",
18 .probe = usb_kbd_probe,
19 .disconnect = usb_kbd_disconnect,
20 .id_table = usb_kbd_id_table,
21 };
22
23 //支持的设备列表
24 static struct usb_device_id usb_kbd_id_table [] = {
25 { USB_INTERFACE_INFO(3, 1, 1) },
26 { }
27 };
28 MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);

在usb_driver的探测函数中,将进行input设备的初始化和注册,USB键盘要使用的中断urb和控制urb的初始化,并设置接口的私有数据,如代码清单20.34所示。

代码清单20.34  USB键盘设备驱动的探测函数

1  static int usb_kbd_probe(struct usb_interface *iface, const struct
2 usb_device_id *id)
3 {
4 struct usb_device *dev = interface_to_usbdev(iface);
5 struct usb_host_interface *interface;
6 struct usb_endpoint_descriptor *endpoint;
7 struct usb_kbd *kbd;
8 struct input_dev *input_dev;
9 int i, pipe, maxp;
10
11 interface = iface->cur_altsetting;
12 /* 设备是否适合本驱动?*/
13 if (interface->desc.bNumEndpoints != 1)
14 return - ENODEV;
15
16 endpoint = &interface->endpoint[0].desc;
17 if (!(endpoint->bEndpointAddress &USB_DIR_IN))
18 return - ENODEV;
19 if ((endpoint->bmAttributes &USB_ENDPOINT_XFERTYPE_MASK) !=
20 USB_ENDPOINT_XFER_INT)
21 return - ENODEV;
22
23 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);//创建端点的管道
24 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
25
26 kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
27 input_dev = input_allocate_device();//分配input_dev结构体
28 if (!kbd || !input_dev) //分配
29 goto fail1;
30
31 if (usb_kbd_alloc_mem(dev, kbd))
32 goto fail2;
33
34 kbd->usbdev = dev;
35 kbd->dev = input_dev;
36
37 if (dev->manufacturer)//制造商名非空
38 strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
39
40 if (dev->product)//产品名非空
41 {
42 if (dev->manufacturer)
43 strlcat(kbd->name, " ", sizeof(kbd->name));
44 strlcat(kbd->name, dev->product, sizeof(kbd->name));
45 }
46
47 if (!strlen(kbd->name))
48 snprintf(kbd->name, sizeof(kbd->name), "USB HIDBP Keyboard
49 %04x:%04x",le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev
50 ->descriptor.idProduct));
51
52 usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
53 strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
54 /* 输入设备初始化 */
55 input_dev->name = kbd->name;
56 input_dev->phys = kbd->phys;
57 usb_to_input_id(dev, &input_dev->id);
58 input_dev->cdev.dev = &iface->dev;
59 input_dev->private = kbd;
60
61 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
62 input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) |
63 BIT(LED_SCROLLL) |BIT(LED_COMPOSE) | BIT(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
69 input_dev->event = usb_kbd_event;
70 input_dev->open = usb_kbd_open;
71 input_dev->close = usb_kbd_close;
72 /* 初始化中断urb */
73 usb_fill_int_urb(kbd->irq, dev, pipe, 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
78 kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
79 kbd->cr->bRequest = 0x09;
80 kbd->cr->wValue = cpu_to_le16(0x200);
81 kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
82 kbd->cr->wLength = cpu_to_le16(1);
83 /* 初始化控制urb */
84 usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), (void*)kbd->cr,
85 kbd->leds, 1, usb_kbd_led, kbd);
86 kbd->led->setup_dma = kbd->cr_dma;
87 kbd->led->transfer_dma = kbd->leds_dma;
88 kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP |
89 URB_NO_SETUP_DMA_MAP);
90 input_register_device(kbd->dev); //注册输入设备
91
92 usb_set_intfdata(iface, kbd); //设置接口私有数据
93 return 0;
94
95 fail2: usb_kbd_free_mem(dev, kbd);
96 fail1: input_free_device(input_dev);
97 kfree(kbd);
98 return - ENOMEM;
99 }

在usb_driver的断开函数中,将设置接口私有数据为NULL、终止已提交的urb并注销输入设备,如代码清单20.35所示。

代码清单20.35  USB键盘设备驱动的断开函数

1  static void usb_kbd_disconnect(struct usb_interface *intf)
2 {
3 struct usb_kbd *kbd = usb_get_intfdata(intf);
4
5 usb_set_intfdata(intf, NULL);//设置接口私有数据为NULL
6 if (kbd)
7 {
8 usb_kill_urb(kbd->irq);//终止urb
9 input_unregister_device(kbd->dev); //注销输入设备
10 usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
11 kfree(kbd);
12 }
13 }

在键盘中断处理函数,也就是中断urb的完成函数中,将会通过input_report_key()报告按键事件,通过input_sync()报告同步事件,并发起一次新的控制urb传输,如代码清单20.36所示。

代码清单20.36  USB键盘设备驱动的中断urb完成函数

1  static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)
2 {
3 struct usb_kbd *kbd = urb->context;
4 int i;
5
6 switch (urb->status)
7 {
8 case 0: /* 成功 */
9 break;
10 case - ECONNRESET: /* unlink */
11 case - ENOENT:
12 case - ESHUTDOWN:
13 return ;
14 default: /* 错误 */
15 goto resubmit;
16 }
17 /*获得键盘扫描码并报告按键事件*/
18 input_regs(kbd->dev, regs);
19
20 for (i = 0; i < 8; i++)
21 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) &1);
22
23 for (i = 2; i < 8; i++)
24 {
25 if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) ==
26 kbd->new +8)
27 {
28 if (usb_kbd_keycode[kbd->old[i]])
29 input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
30 else
31 info("Unknown key (scancode %#x) released.", kbd->old[i]);
32 }
33
34 if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) ==
35 kbd->old +8)
36 {
37 if (usb_kbd_keycode[kbd->new[i]])
38 input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
39 else
40 info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
41 }
42 }
43
44 input_sync(kbd->dev);报告同步事件
45
46 memcpy(kbd->old, kbd->new, 8);
47
48 resubmit: i = usb_submit_urb(urb, SLAB_ATOMIC);
49 if (i)
50 err("can't resubmit intr, %s-%s/input0, status %d", kbd->usbdev->bus
51 ->bus_name, kbd->usbdev->devpath, i);
52 }
阅读(1423) | 评论(0) | 转发(0) |
0

上一篇:USB串口驱动(zz)

下一篇:wget (zz)

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