20.4.2 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 }
|
| 回书目 上一节 下一节 |
|
||||
| · Linux——从菜鸟到高手 · 微软Forefront企业安全.. · 如何优化IT 控制能耗 · 国际文档格式标准开战 · CISSP认证成长之路 · 珊瑚虫QQ作者侵权案开庭 · 微软出价446亿美元收购.. · Windows Server 2008专.. |
· 隐私保护技术探讨 · 贝恩资本携手华为22亿.. · 802.11n:下一代的无线.. · 体验Visual Studio 200.. · 运营商封堵非法ADSL共享 · ADSL应用面面俱到 · 龙芯要做中国的“奔腾” · 华为七千人主动辞职规.. |
|||
|
||||
| · VPN技术 · SQL Server 2008/2005.. · SOA 面向服务架构 · 子网掩码教程 · SQL Server 2008/2005.. · RAID——磁盘阵列基础 · 中间件应用技术专题 · 深入了解PGP加密技术 |
· MySQL数据库备份 · 病毒查杀专题 · VPN技术 · Solaris 10 配置管理 · SSL VPN详细知识 · Linux防火墙 · 打造安全服务器 · Sniffer安全技术从入门.. |
|||
|
||||
| · VPN技术 · SQL Server 2008/2005.. · 中间件应用技术专题 · SQL Server 2008/2005.. · SOA 面向服务架构 · 子网掩码教程 · MySQL数据库备份 · RAID——磁盘阵列基础 |
· 身份认证技术 · 病毒查杀专题 · 清除流氓软件——51CTO.. · SSL VPN详细知识 · Sniffer安全技术从入门.. · VPN技术 · SOA 面向服务架构 · 了解统一威胁管理(UTM).. |
|||