频 道 直 达 - 新闻 - 培训 - 软件 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 读书 - 博客 - BBS
51CTO.COM_中国最大的网络技术网站
找资料:

20.4.2 USB键盘驱动

作者: 宋宝华 编著 出处:人民邮电出版社  2008-03-11 12:07    砖    好    评论   进入论坛
阅读提示:《Linux设备驱动开发详解》本书全面而详细地讲解了Linux设备驱动开发中涉及的理论以及多种设备驱动的框架。第20章主要讲解从主机侧角度看到的USB主机控制器驱动和设备驱动。本文写的是USB键盘驱动。

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 }

【责任编辑:董书 TEL:(010)68476606】

回书目   上一节   下一节
专题
Linux——从菜鸟到高手
Linux/Solaris服务器的安全配置
Linux 集群技术专题
Linux中文环境
Linux防火墙
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 最 大 的 网 络 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
RAID——磁盘阵列基础
RAID——磁盘阵列基础
华为员工自杀频频拷问企业文化
华为员工自杀频频拷问企业文化
Linux——从菜鸟到高手
Linux——从菜鸟到高手
· Linux——从菜鸟到高手
· 微软Forefront企业安全..
· 如何优化IT 控制能耗
· 国际文档格式标准开战
· CISSP认证成长之路
· 珊瑚虫QQ作者侵权案开庭
· 微软出价446亿美元收购..
· Windows Server 2008专..
· 隐私保护技术探讨
· 贝恩资本携手华为22亿..
· 802.11n:下一代的无线..
· 体验Visual Studio 200..
· 运营商封堵非法ADSL共享
· ADSL应用面面俱到
· 龙芯要做中国的“奔腾”
· 华为七千人主动辞职规..
清除流氓软件——51CTO特别专题
清除流氓软件——51CTO特别专..
ARP攻击防范与解决方案
ARP攻击防范与解决方案
VPN技术
VPN技术
· VPN技术
· SQL Server 2008/2005..
· SOA 面向服务架构
· 子网掩码教程
· SQL Server 2008/2005..
· RAID——磁盘阵列基础
· 中间件应用技术专题
· 深入了解PGP加密技术
· MySQL数据库备份
· 病毒查杀专题
· VPN技术
· Solaris 10 配置管理
· SSL VPN详细知识
· Linux防火墙
· 打造安全服务器
· Sniffer安全技术从入门..
服务器选型与选购
服务器选型与选购
ARP攻击防范与解决方案
ARP攻击防范与解决方案
VPN技术
VPN技术
· VPN技术
· SQL Server 2008/2005..
· 中间件应用技术专题
· SQL Server 2008/2005..
· SOA 面向服务架构
· 子网掩码教程
· MySQL数据库备份
· RAID——磁盘阵列基础
· 身份认证技术
· 病毒查杀专题
· 清除流氓软件——51CTO..
· SSL VPN详细知识
· Sniffer安全技术从入门..
· VPN技术
· SOA 面向服务架构
· 了解统一威胁管理(UTM)..