Linux input设备驱动.docx

上传人:b****6 文档编号:8505046 上传时间:2023-01-31 格式:DOCX 页数:18 大小:134.85KB
下载 相关 举报
Linux input设备驱动.docx_第1页
第1页 / 共18页
Linux input设备驱动.docx_第2页
第2页 / 共18页
Linux input设备驱动.docx_第3页
第3页 / 共18页
Linux input设备驱动.docx_第4页
第4页 / 共18页
Linux input设备驱动.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

Linux input设备驱动.docx

《Linux input设备驱动.docx》由会员分享,可在线阅读,更多相关《Linux input设备驱动.docx(18页珍藏版)》请在冰豆网上搜索。

Linux input设备驱动.docx

Linuxinput设备驱动

Linuxinput设备驱动

一.输入设备结构体

1.input_dev输入设备

structinput_dev{

 constchar*name; //设备名

 constchar*phys; //设备系统层的物理路径

 constchar*uniq; //

 structinput_idid; //输入设备id总线类型;厂商编号,产品id,产品版本

 unsignedlongevbit[BITS_TO_LONGS(EV_CNT)]; //事件类型标志位

 unsignedlongkeybit[BITS_TO_LONGS(KEY_CNT)]; //键盘事件标志位

 unsignedlongrelbit[BITS_TO_LONGS(REL_CNT)]; //相对位移事件标志位

 unsignedlongabsbit[BITS_TO_LONGS(ABS_CNT)]; //绝对位移事件标志位

 unsignedlongmscbit[BITS_TO_LONGS(MSC_CNT)]; //杂项事件标志位

 unsignedlongledbit[BITS_TO_LONGS(LED_CNT)]; //led指示灯标志位

 unsignedlongsndbit[BITS_TO_LONGS(SND_CNT)]; //声音事件

 unsignedlongffbit[BITS_TO_LONGS(FF_CNT)]; //强制反馈事件

 unsignedlongswbit[BITS_TO_LONGS(SW_CNT)]; //开关事件标志位

 unsignedinthint_events_per_packet;

 unsignedintkeycodemax; //键盘码表大小

 unsignedintkeycodesize; //键盘码大小

 void*keycode;  //键盘码表指针

 int(*setkeycode)(structinput_dev*dev,unsignedintscancode,unsignedintkeycode); //设置键盘码

 int(*getkeycode)(structinput_dev*dev,unsignedintscancode,unsignedint*keycode); //获取键盘码

 int(*setkeycode_new)(structinput_dev*dev,conststructinput_keymap_entry*ke,unsignedint*old_keycode); 

 int(*getkeycode_new)(structinput_dev*dev,structinput_keymap_entry*ke);

 structff_device*ff; //强制反馈设备

 unsignedintrepeat_key; //重复按键标志位

 structtimer_listtimer; //定时器

 intrep[REP_CNT]; //重复次数

 structinput_mt_slot*mt;

 intmtsize;

 intslot;

 structinput_absinfo*absinfo;

 unsignedlongkey[BITS_TO_LONGS(KEY_CNT)]; //

 unsignedlongled[BITS_TO_LONGS(LED_CNT)]; //

 unsignedlongsnd[BITS_TO_LONGS(SND_CNT)]; //

 unsignedlongsw[BITS_TO_LONGS(SW_CNT)]; //

 int(*open)(structinput_dev*dev); //open方法

 void(*close)(structinput_dev*dev); //close方法

 int(*flush)(structinput_dev*dev,structfile*file);

 int(*event)(structinput_dev*dev,unsignedinttype,unsignedintcode,intvalue);

 structinput_handle__rcu*grab;

 spinlock_tevent_lock;

 structmutexmutex;

 unsignedintusers;

 boolgoing_away;

 boolsync;

 structdevicedev; //设备文件

 structlist_head h_list; //input_handler处理器链表头

 structlist_head node; //input_device设备链表头

};

2.input_handler输入处理器

structinput_handler{

 void*private; //私有数据

 void(*event)(structinput_handle*handle,unsignedinttype,unsignedintcode,intvalue); //事件处理

 bool(*filter)(structinput_handle*handle,unsignedinttype,unsignedintcode,intvalue); //过滤器

 bool(*match)(structinput_handler*handler,structinput_dev*dev); //设备匹配

 int(*connect)(structinput_handler*handler,structinput_dev*dev,conststructinput_device_id*id); //设备连接

 void(*disconnect)(structinput_handle*handle); //设备断开连接

 void(*start)(structinput_handle*handle);

 conststructfile_operations*fops; //输入操作函数集

 intminor; //次设备号

 constchar*name; //设备名

 conststructinput_device_id*id_table; //输入设备id表

 structlist_head h_list; //input_handler处理器链表头

 structlist_head node; //input_device设备链表头

};

二.输入系统初始化

1input_init

staticint__initinput_init(void)

{

 interr;

 err=class_register(&input_class); //注册类创建"/sys/input" 

 if(err){

 printk(KERN_ERR"input:

unabletoregisterinput_devclass\n");

 returnerr;

 }

 err=input_proc_init(); //初始化"/proc/bus/input"接口

 if(err)

 gotofail1;

 err=register_chrdev(INPUT_MAJOR,"input",&input_fops); //注册所有输入字符设备,并捆绑input_fops

 if(err){

 printk(KERN_ERR"input:

unabletoregistercharmajor%d",INPUT_MAJOR);

 gotofail2;

 }

 return0;

 fail2:

 input_proc_exit();

 fail1:

 class_unregister(&input_class);

 returnerr;

}

2./proc接口

2.1创建/proc/bus/input下的文件

staticint__initinput_proc_init(void)

{

 structproc_dir_entry*entry;

 proc_bus_input_dir=proc_mkdir("bus/input",NULL); //创建"/proc/bus/input"

 if(!

proc_bus_input_dir)

 return-ENOMEM;

 entry=proc_create("devices",0,proc_bus_input_dir,&input_devices_fileops); //创建"/proc/bus/input/devices"

 if(!

entry)

 gotofail1;

 entry=proc_create("handlers",0,proc_bus_input_dir,&input_handlers_fileops); //创建"/proc/bus/input/handlers"

 if(!

entry)

 gotofail2;

 return0;

 fail2:

 remove_proc_entry("devices",proc_bus_input_dir);

 fail1:

remove_proc_entry("bus/input",NULL);

 return-ENOMEM;

}

2.2devices文件

staticconststructfile_operationsinput_devices_fileops={

 .owner =THIS_MODULE,

 .open =input_proc_devices_open,

 .poll =input_proc_devices_poll,

 .read =seq_read,

 .llseek =seq_lseek,

 .release =seq_release,

};

2.2.1限于篇幅及省略啰嗦

这里当我们去cat/proc/bus/input/devices时候,会调用input_proc_devices_open函数,接着调用seq_open(file,&input_devices_seq_ops),捆绑了input_devices_seq_ops操作函数集,

其seq_operations函数集中声明了.show方法为input_devices_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,

接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

2.2.2input_devices_seq_show

staticintinput_devices_seq_show(structseq_file*seq,void*v)

{

 structinput_dev*dev=container_of(v,structinput_dev,node); //获取到输入设备结构体

 constchar*path=kobject_get_path(&dev->dev.kobj,GFP_KERNEL); //获取在/sys下的路径

 structinput_handle*handle;

 seq_printf(seq,"I:

Bus=%04xVendor=%04xProduct=%04xVersion=%04x\n",dev->id.bustype,dev->id.vendor,dev->id.product,dev->id.version);

 //打印I:

总线类型,厂商id,产品id,版本号 

 seq_printf(seq,"N:

Name=\"%s\"\n",dev->name?

dev->name:

""); //打印N:

输入设备名

 seq_printf(seq,"P:

Phys=%s\n",dev->phys?

dev->phys:

""); //打印P:

phys

 seq_printf(seq,"S:

Sysfs=%s\n",path?

path:

""); //打印S:

sysfs文件系统下的路径

 seq_printf(seq,"U:

Uniq=%s\n",dev->uniq?

dev->uniq:

""); //打印U:

uniq

 seq_printf(seq,"H:

Handlers="); //打印H:

input_handler处理器名

 list_for_each_entry(handle,&dev->h_list,d_node) //遍历处理器链表

 seq_printf(seq,"%s",handle->name);

 seq_putc(seq,'\n');

 input_seq_print_bitmap(seq,"EV",dev->evbit,EV_MAX); //打印EV:

事件类型位图

 if(test_bit(EV_KEY,dev->evbit))   //打印各种具体事件的事件位图

 input_seq_print_bitmap(seq,"KEY",dev->keybit,KEY_MAX); 

 if(test_bit(EV_REL,dev->evbit))

 input_seq_print_bitmap(seq,"REL",dev->relbit,REL_MAX);

 if(test_bit(EV_ABS,dev->evbit))

 input_seq_print_bitmap(seq,"ABS",dev->absbit,ABS_MAX);

 if(test_bit(EV_MSC,dev->evbit))

 input_seq_print_bitmap(seq,"MSC",dev->mscbit,MSC_MAX);

 if(test_bit(EV_LED,dev->evbit))

 input_seq_print_bitmap(seq,"LED",dev->ledbit,LED_MAX);

 if(test_bit(EV_SND,dev->evbit))

 input_seq_print_bitmap(seq,"SND",dev->sndbit,SND_MAX);

 if(test_bit(EV_FF,dev->evbit))

 input_seq_print_bitmap(seq,"FF",dev->ffbit,FF_MAX);

 if(test_bit(EV_SW,dev->evbit))

 input_seq_print_bitmap(seq,"SW",dev->swbit,SW_MAX);

 seq_putc(seq,'\n');

 kfree(path);

 return0;

}

打印效果大致如下:

因设备不同而异

catdevices 

I:

Bus=0019Vendor=0000Product=0001Version=0000

N:

Name="PowerButton"  

P:

Phys=LNXPWRBN/button/input0

S:

Sysfs=/devices/LNXSYSTM:

00/LNXPWRBN:

00/input/input0

U:

Uniq=

H:

Handlers=kbdevent0 

B:

EV=3

B:

KEY=100000000

I:

Bus=0017Vendor=0001Product=0001Version=0100

N:

Name="Macintoshmousebuttonemulation"

P:

Phys=

S:

Sysfs=/devices/virtual/input/input1

U:

Uniq=

H:

Handlers=mouse0event1 

B:

EV=7

B:

KEY=7000000000000

B:

REL=3

这里可以根据Bus值得知该输入设备是基于什么总线的

#defineBUS_PCI 0x01

#defineBUS_ISAPNP 0x02

#defineBUS_USB 0x03

#defineBUS_HIL 0x04

#defineBUS_BLUETOOTH 0x05

#defineBUS_VIRTUAL 0x06

#defineBUS_ISA 0x10

#defineBUS_I8042 0x11

#defineBUS_XTKBD 0x12

#defineBUS_RS232 0x13

#defineBUS_GAMEPORT 0x14

#defineBUS_PARPORT 0x15

#defineBUS_AMIGA 0x16

#defineBUS_ADB 0x17

#defineBUS_I2C 0x18

#defineBUS_HOST 0x19

#defineBUS_GSC 0x1A

#defineBUS_ATARI 0x1B

#defineBUS_SPI 0x1C

2.3handlers文件

staticconststructfile_operationsinput_handlers_fileops={

 .owner =THIS_MODULE,

 .open =input_proc_handlers_open,

 .read =seq_read,

 .llseek =seq_lseek,

 .release =seq_release,

};

2.3.1

这里当我们去cat/proc/bus/input/handlers时候,会调用input_proc_handlers_open函数,接着调用seq_open(file,&input_handlers_seq_ops),捆绑了input_handlers_seq_ops操作函数集,

其seq_operations函数集中声明了.show方法为input_handlers_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,

接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

staticintinput_handlers_seq_show(structseq_file*seq,void*v)

{

 structinput_handler*handler=container_of(v,structinput_handler,node); //获得输入处理器

 unioninput_seq_state*state=(unioninput_seq_state*)&seq->private;

 seq_printf(seq,"N:

Number=%uName=%s",state->pos,handler->name); //打印N:

Number=序号name=设备名

 if(handler->filter)

 seq_puts(seq,"(filter)");

 if(handler->fops)

 seq_printf(seq,"Minor=%d",handler->minor); //打印Minor=次设备号

 seq_putc(seq,'\n');

 return0;

}

我的打印是

cathandlers 

N:

Number=0Name=rfkill

N:

Number=1Name=kbd

N:

Number=2Name=mousedevMinor=32

N:

Number=3Name=evdevMinor=64

3.字符设备接口

3.1主设备号

#defineINPUT_MAJOR 13

3.2input_fops

staticconststructfile_operationsinput_fops={

 .owner=THIS_MODULE,

 .open=input_open_file, //打开方法

 .llseek=noop_llseek, 

};

3.2.1input_open_file

staticintinput_open_file(structinode*inode,structfile*file)

{

 structinput_handler*handler;

 conststructfile_operations*old_fops,*new_fops=NULL;

 interr;

 err=mutex_lock_interruptible(&input_mutex);

 if(err)

 returnerr;

 /*Noload-on-demandhere?

*/

 handler=input_table[iminor(inode)>>5]; //根据节点算出次设备号,并在全局input_table找到输入处理器

 if(handler)

 new_fops=fops_get(handler->fops); //获取输入操作函数集指针

 mutex_unlock(&input_mutex);

 /*

 *That's_really_odd.UsuallyNULL->openmeans"nothingspecial",

 *not"nodevice".Oh,well...

 */

 if(!

new_fops||!

new_fops->open){ //判断输入操作函数集的存在且存在open方法

 fops_put(new_fops); 

 err=-ENODEV;

 gotoout;

 }

 old_fops=file->f_op; //获取文件的操作函数集指针

 file->f_op=new_fops; //替换为输入操作函数集指针

 err=new_fops->open(inode,file); //调用输入操作函数集的open方法

 if(err){

 fops_put(file->f_op);

 file->f_op=fops_get(old_fops);

 }

 fops_put(old_fops);

out:

 returnerr;

}

三.分配i

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1