Linux input设备驱动.docx
- 文档编号:8505046
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:18
- 大小:134.85KB
Linux input设备驱动.docx
《Linux input设备驱动.docx》由会员分享,可在线阅读,更多相关《Linux input设备驱动.docx(18页珍藏版)》请在冰豆网上搜索。
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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux input设备驱动 input 设备 驱动