usb键盘驱动 带usb接口的键盘

* @hardware:
* @author: Jaguar.Yuan
* @E-mail: Jaguar.Yuan@139.com
* @version: 1.0
* @kernel: 2.6.33.2
* @arm-linux-gcc -v: gcc version 4.3.3 (Sourcery G++ Lite2009q1-203)
* @date: 2010-8-30
* @function: a usb keyboard driver
*/
#include //内核头文件,包含一些常用函数原型的定义
#include //定义内存分配函数
#include //编译模块必须的函数
#include //输入设备相关函数
#include //linux初始函数
#include //usb设备相关函数
#include

//设备的名称:生产商,产品类别等信息(无具体设备,待测试)
#defineTEST_VENDOR0xfff0
#defineTEST_PRODUCT0xfff0

//定义一个关于usb键盘的设备结构体
struct usb_kbd{
struct input_dev *dev;//内嵌输入设备结构体
struct usb_device *usbdev;//内嵌usb结构体
struct urb *irq;//usb键盘中断请求块
struct urb *led;//usb键盘指示灯请求块
unsigned char old[8];//按键离开时所用数据缓冲区
unsigned char newleds;//指示灯状态
char name[128];//设备名
char phys[64];//设备节点

unsigned char *new;//按键按下时所用数据缓冲区
struct usb_ctrlrequest *cr;//控制请求结构
unsigned char *leds;//当前指示灯状态
dma_addr_t cr_dma;//控制请求dma缓冲地址
dma_addr_t new_dma;//中断urb使用的dma缓冲区
dma_addr_t leds_dma;//指示灯dma缓冲区
};

//键盘扫描码
static unsigned char usb_kbd_keycode[256] = {
0, 0, 0, 0,30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21,44, 2, 3,
4, 5, 6,7, 8, 9, 10, 11,28, 1, 14, 15, 57, 12, 13, 26,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63,64,
65, 66, 67, 68, 87, 88, 99,70,119,110,102,104,111,107,109,106,
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77,71,
72, 73, 82, 83,86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114, 0,0, 0,121, 0, 89, 93,124, 92,94, 95, 0, 0,0,
122,123, 90, 91, 85, 0,0, 0, 0,0, 0, 0,0, 0, 0,0,
0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0,
0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0,
0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0,
0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,0,
29, 42, 56,125, 97,54,100,126,164,166,165,163,161,115,114,113,
150,158,159,128,136,177,178,176,142,152,173,140
};

//设备名传递函数
static void usb_to_input_id(const struct usb_device *dev, structinput_id *id)
{
id->bustype = BUS_USB;
id->vendor = le16_to_cpu(dev->descriptor.idVendor);
id->product = le16_to_cpu(dev->descriptor.idProduct);
id->version = le16_to_cpu(dev->descriptor.bcdDevice);
}

//中断请求处理函数
static void usb_kbd_irq(struct urb *urb)
{
struct usb_kbd *kbd = urb->context;
int i;

switch(urb->status){
case 0:
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
return ;
default:
goto resubmit;
}
//获取键盘扫描码,并报告按键事件
for(i = 0; i < 8; i++)
input_report_key(kbd->dev, usb_kbd_keycode[i + 224],(kbd->new[0] >> i) & 1);
//若同时只按下1个按键则在第[2]个字节,若同时有两个按键则第二个在第[3]字节
for(i = 2; i < 8; i++){
//获取键盘离开的中断

//检测是否有1 个,2 个,3个……6个同时离开,即检测是否有按键离开
if(kbd->old[i] > 3&& memscan(kbd->new + 2, kbd->old[i], 6) ==kbd->new + 8){
if(usb_kbd_keycode[kbd->old[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]],0);
else
printk("unknown key %#x", kbd->old[i]);
}
//其中memscan(void *addr,int c,size_tsize)的作用是在一段区域内寻找字符c,addr是区域的首地址,size是寻找长度,当找到c时,返回区域内首个c的地址,若未能找到C,则返回此区域的下一个字节地址。
if(kbd->new[i] > 3 && memscan(kbd->old + 2,kbd->new[i], 6) == kbd->old + 8){
if(usb_kbd_keycode[kbd->new[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]],1);
else
printk("unknown key %#x", kbd->new[i]);
}
}

input_sync(kbd->dev);//报告同步事件
memcpy(kbd->old, kbd->new, 8);//防止未松开时被当成新的按键处理

resubmit:
i = usb_submit_urb(urb, GFP_ATOMIC);//发送USB请求块
if(i)
printk("can't resubmit intr, %s-%s/input0, status %d",kbd->usbdev->bus->bus_name, kbd->usbdev->devpath,i);
}

//事件处理函数
static int usb_kbd_event(struct input_dev *dev, unsigned int type,unsigned int code, int value)
{
struct usb_kbd *kbd = input_get_drvdata(dev);
if(type != EV_LED)//如果不支持led事件,则在初始有错,返回 
return -1;
//获取指示灯的目标状态
kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) |(!!test_bit(LED_COMPOSE, dev->led) << 3) |(!!test_bit(LED_SCROLLL, dev->led) << 2) |(!!test_bit(LED_CAPSL, dev->led) << 1) |(!!test_bit(LED_NUML, dev->led));

if(kbd->led->status == -EINPROGRESS)
return 0;
//指示灯状态已经是目标状态则不需要再做任何操作
if(*(kbd->leds) == kbd->newleds)
return 0;
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
//提交urb请求块
if(usb_submit_urb(kbd->led, GFP_ATOMIC))
printk("usb_submit_urb(leds) failed");
return 0;
}

//led事件处理函数
static void usb_kbd_led(struct urb *urb)
{
struct usb_kbd *kbd = urb->context;
//打印指示灯的当前状态
if(urb->status)
printk("led urb status %d received", urb->status);
//指示灯状态已经是目标状态则不需要再做任何操作
if(*(kbd->leds) == kbd->newleds)
return ;
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if(usb_submit_urb(kbd->led, GFP_ATOMIC))
printk("usb_subimt_urb(leds) failed");
}

//打开设备函数
static int usb_kbd_open(struct input_dev *dev)
{
struct usb_kbd *kbd = input_get_drvdata(dev);
kbd->irq->dev = kbd->usbdev;
if(usb_submit_urb(kbd->irq, GFP_KERNEL))
return -EIO;
return 0;
}

//关闭设备函数
static void usb_kbd_close(struct input_dev *dev)
{
struct usb_kbd *kbd = input_get_drvdata(dev);
usb_kill_urb(kbd->irq);
}

//分配内存函数
static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd*kbd)
{
if(!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
return -1;
if(!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
return -1;
if(!*(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC,&kbd->new_dma)))
return -1;
if(!(kbd->cr = usb_buffer_alloc(dev, sizeof(structusb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
return -1;
if(!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC,&kbd->leds_dma)))
return -1;
return 0;
}

//释放内存函数
static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd*kbd)
{
if(kbd->irq)
usb_free_urb(kbd->irq);
if(kbd->led)
usb_free_urb(kbd->led);
if(kbd->new)
usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
if(kbd->cr)
usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr,kbd->cr_dma);
if(kbd->leds)
usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
}

//usb键盘驱动探测函数
static int usb_kbd_probe(struct usb_interface *iface, const structusb_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;//当前的interface
if(interface->desc.bNumEndpoints != 1)//键盘只有一个中断in端点
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;
//将endpoint设置为中断in端点,创建端点管道
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();
if(!kbd || !input_dev)
goto fail1;
//调用分配内存函数,对结构体各相关项分配内存
if(usb_kbd_alloc_mem(dev, kbd))
goto fail2;
//填充usb设备相关结构体
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 keyboardx:x",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);
input_dev->dev.parent = &iface->dev;//父

//配置,以备调用
input_set_drvdata(input_dev, kbd);

//分别为键码事件,LED事件,自动重复数值 
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);

usb键盘驱动 带usb接口的键盘
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);
//指定urb需要传输的DMA缓冲区
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);
//数据传输阶段传输多少个bytes
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;
//如果使用DMA传输则urb中setup_dma指针所指向的缓冲区是DMA缓冲区而不是setup_packet所指向的缓冲区
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;
}

//驱动断开函数
static void usb_kbd_disconnect(struct usb_interface *intf)
{
struct usb_kbd *kbd = usb_get_intfdata(intf);//获取接口的私有数据给kbd
usb_set_intfdata(intf, NULL);//清空接口私有数据
if(kbd){
usb_kill_urb(kbd->irq);//取消中断
input_unregister_device(kbd->dev);//注销设备
usb_kbd_free_mem(interface_to_usbdev(intf), kbd);//释放内存
kfree(kbd);
}
}

//驱动设备id表
static struct usb_device_id usb_kbd_id_table[] = {
{USB_DEVICE(TEST_VENDOR, TEST_PRODUCT)},
{USB_INTERFACE_INFO(3, 1,1)},//3,1,1分别表示接口类,接口子类,接口协议;3,1,1为键盘接口类;鼠标为3,1,2
{ }
};

//将设备注册到系统
MODULE_DEVICE_TABLE(usb, usb_kbd_id_table);

//usb键盘驱动结构体
static struct usb_driver usb_kbd_driver = {
.name ="usbkbd",//设备驱动名
.probe =usb_kbd_probe,//驱动探测函数
.disconnect =usb_kbd_disconnect,//驱动断开函数
.id_table =usb_kbd_id_table,//驱动设备id表,用来指定设备或接口
};

//向usb core注册键盘驱动程序
static int __init usb_kbd_init(void)
{
return usb_register(&usb_kbd_driver);
}

//向usb core注销键盘驱动程序
static void __exit usb_kbd_exit(void)
{
usb_deregister(&usb_kbd_driver);
}

module_init(usb_kbd_init);
module_exit(usb_kbd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jaguar.Yuan");

  

爱华网本文地址 » http://www.413yy.cn/a/25101014/195872.html

更多阅读

OTG连接线与普通USB连接线的区别 otg连接线是什么

?  USB数据线是我们常见的设备,OTG连接线作为近年来随着手机行业的快速发展,逐步进入了我们的日常使用范围。OTG连接线与普通USB连接线的有什么区别??  USB数据线用来连接手机和电脑,可通过电脑访问手机里面的照片、音乐,把手机

dnf带红字的装备怎么净化 dnf红字装备怎么强化

dnf带红字的装备怎么净化——简介DNF如何净化红字。红字装备只能看。却不能戴上、请看以下内容、dnf带红字的装备怎么净化——方法/步骤dnf带红字的装备怎么净化 1、一:DNF净化红字、。首先我们要先找到克伦特。在阿法利亚营地。如

电脑USB接口不能用怎么办 电脑usb接口不识别手机

电脑USB接口不能用怎么办——简介电脑USB接口不能用怎么办_为什么我电脑USB插口没反应,电脑USB接口没反应,电脑USB借口不能用是电脑常见问题。下面小编就为大家讲解一下电脑USB借口不能用的原因以及就解决方法。电脑USB接口不能用怎

电脑usb接口不能用没反应的诊断修复方法 usb接口没反应怎么办

当出现电脑usb接口不能用没反应的时候,我们千万别慌张,不要认为电脑坏了不能修复了,我们现在就为介绍修复方法,我们首先检查一下插入的设备是否正常,如鼠标、U盘等是不是好的,如果在别的机子上也不能读出,就要考虑插入的设备有问题了。如果

声明:《usb键盘驱动 带usb接口的键盘》为网友光一样的少年分享!如侵犯到您的合法权益请联系我们删除