详解Linux输入子系统

Linux 的输入子系统又叫 input 子系统,其构建非常灵活,不仅支持鼠标、键盘等常规输入设备,而且还支持蜂鸣器、触摸屏等设备。下面为大家详细讲解一下 Linux输入子系统。

驱动层

将底层的硬件输入转化为统一事件形式,想输入核心(Input Core)汇报。

输入子系统核心层

它承上启下为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息。

事件处理层

主要是和用户空间交互(Linux中在用户空间将所有的设备都当作文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,这些操作在输入子系统中由事件处理层完成)。

设备描述

input_dev结构是实现设备驱动核心工作:向系统报告按键、触摸屏等输入事件(event,通过input_event结构描述),不再需要关心文件操作接口。驱动报告事件经过inputCore和Eventhandler到达用户空间。

注册输入设备函数:

int input_register_device(struct input_dev *dev)

注销输入设备函数:

void input_unregister_device(struct input_dev *dev)

驱动实现——初始化(事件支持)set_bit()告诉input输入子系统支持哪些事件,哪些按键。例如:

set_bit(EV_KEY,button_dev.evbit)  (其中button_dev是struct input_dev类型)

**struct input_dev**中有两个成员为: **1)**evbit事件类型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)。 **2)**keybit按键类型(当事件类型为EV_KEY时包括BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等)。

驱动实现——报告事件用于报告EV_KEY,EV_REL,EV_ABS事件的函数分别为:

void input_report_key(struct input_dev *dev,unsigned int code,int value)
void input_report_rel(struct input_dev *dev,unsigned int code,int value)
void input_report_abs(struct input_dev *dev,unsigned int code,int value)

驱动实现——报告结束input_sync()同步用于告诉input core子系统报告结束,触摸屏设备驱动中,一次点击的整个报告过程如下:

input_reprot_abs(input_dev,ABS_X,x);   //x坐标
input_reprot_abs(input_dev,ABS_Y,y);   // y坐标
input_reprot_abs(input_dev,ABS_PRESSURE,1);
input_sync(input_dev);//同步结束

实例分析(按键中断程序):

//按键初始化
static int __init button_init(void)
{//申请中断
   if(request_irq(BUTTON_IRQ,button_interrupt,0,”button”,NUll))
       return –EBUSY;
   set_bit(EV_KEY,button_dev.evbit); //支持EV_KEY事件
   set_bit(BTN_0,button_dev.keybit); //支持设备两个键
   set_bit(BTN_1,button_dev.keybit); //
   input_register_device(&button_dev);//注册input设备
}
/*在按键中断中报告事件*/
Static void button_interrupt(int irq,void *dummy,struct pt_regs *fp)
{
   input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));//读取寄存器BUTTON_PORT0的值
   input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT1));
   input_sync(&button_dev);
}

总结:input子系统仍然是字符设备驱动程序,但是代码量减少很多,*input子系统只需要完成两个工作:初始化和事件报告(这里在linux中是通过中断来实现的)。*

实例

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  

struct input_dev *button_dev;
struct button_irq_desc {
   int irq;
   int pin;
   int pin_setting;
   int number;
   char *name;
};

/*定义一个结构体数组*/
static struct button_irq_desc button_irqs [] = {
   {IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"},
   {IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"},
   {IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"},
   {IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"},
   {IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"},
   {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},
};

static int key_values = 0;
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
   struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
   int down;
   udelay(0);
/*获取按键值*/
down = !s3c2410_gpio_getpin(button_irqs->pin); //down: 1(按下),0(弹起)
if (!down) {
   /*报告事件*/
   key_values = button_irqs->number;
   //printk("====>rising key_values=%d\n",key_values);
   if(key_values==0)
       input_report_key(button_dev, KEY_1, 0);
   if(key_values==1)
       input_report_key(button_dev, KEY_2, 0);
   if(key_values==2)
       input_report_key(button_dev, KEY_3, 0);
   if(key_values==3)
       input_report_key(button_dev, KEY_4, 0);
   if(key_values==4)
       input_report_key(button_dev, KEY_5, 0);
   if(key_values==5)
       input_report_key(button_dev, KEY_6, 0);
   /*报告结束*/
   input_sync(button_dev);
   }
else {
   key_values = button_irqs->number;
   //printk("====>falling key_values=%d\n",key_values);
   if(key_values==0)
       input_report_key(button_dev, KEY_1, 1);
   if(key_values==1)
       input_report_key(button_dev, KEY_2, 1);
   if(key_values==2)
       input_report_key(button_dev, KEY_3, 1);
   if(key_values==3)
       input_report_key(button_dev, KEY_4, 1);
   if(key_values==4)
       input_report_key(button_dev, KEY_5, 1);
   if(key_values==5)
       input_report_key(button_dev, KEY_6, 1);
   input_sync(button_dev);
   }
   return IRQ_RETVAL(IRQ_HANDLED);
}
static int s3c24xx_request_irq(void)
{
   int i;
   int err = 0;
   for (i = 0; i if (button_irqs[i].irq continue;
       }
       /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */
       err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
       button_irqs[i].name, (void *)&button_irqs[i]);
       if (err)
           break;
   }
   /*错误处理*/
   if (err) {
       i--;
       for (; i >= 0; i--) {
           if (button_irqs[i].irq continue;
           }
           disable_irq(button_irqs[i].irq);
         free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
       }
       return -EBUSY;
   }
   return 0;
}
static int __init dev_init(void)
{
   /*request irq*/
   s3c24xx_request_irq();
   /* Initialise input stuff */
   button_dev = input_allocate_device();
   if (!button_dev) {
       printk(KERN_ERR "Unable to allocate the input device !!\n");
       return -ENOMEM;
   }
   button_dev->name = "s3c2440_button";
   button_dev->id.bustype = BUS_RS232;
   button_dev->id.vendor = 0xDEAD;
   button_dev->id.product = 0xBEEF;
   button_dev->id.version = 0x0100;

   button_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT(EV_SYN);
   //set_bit(EV_KEY, button_dev->evbit)//支持EV_KEY事件
   /*设置支持哪些按键*/
   set_bit(KEY_1, button_dev->keybit);
   set_bit(KEY_2, button_dev->keybit);
   set_bit(KEY_3, button_dev->keybit);
   set_bit(KEY_4, button_dev->keybit);
   set_bit(KEY_5, button_dev->keybit);
   set_bit(KEY_6, button_dev->keybit);
   //printk("KEY_RESERVED=%d ,KEY_1=%d",KEY_RESERVED,KEY_1);
   input_register_device(button_dev); //注册input设备

   printk ("initialized\n");

   return 0;
}

static void __exit dev_exit(void)
{
   int i;

   for (i = 0; i if (button_irqs[i].irq continue;
       }
       free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
   }

   input_unregister_device(button_dev);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");

原创文章,作者:晴川运维,如若转载,请注明出处:https://baike.qcidc.com/9823.html

(0)
晴川运维晴川运维
上一篇 1天前
下一篇 1天前

相关推荐

  • Linux中nmcli命令使用方法

    nmcli命令是redhat7或者centos7之后的命令,该命令可以完成网卡上所有的配置工作,并且可以写入配置文件,永久生效,下面为大家讲解一下nmcli命令使用方法。 基本用法…

    Linux系统 2025年6月8日
  • 面向系统管理员的网络管理指南

    一个使管理服务器和网络更轻松的 linux 工具和命令的参考列表。 如果你是一位系统管理员,那么你的日常工作应该包括管理服务器和数据中心的网络。以下的 Linux 实用工具和命令 …

    Linux系统 2025年6月8日
  • Ubuntu下查看路由表具体方法

    路由表的主要作用是供路由器查找目标网络,进而确定转发接口及下一跳路由,完成数据包的转发功能,在本篇文章中将为大家讲解一下如何在Ubuntu中查看网络路由表的具体方法。 什么是Lin…

    Linux系统 2025年6月4日
  • 如何备份一个磁盘分区

    通常你可能会把数据放在一个分区上,有时候可能需要对该设备或者上面的一个分区进行备份。树莓派用户为了可引导 SD 卡当然有这个需求。其它小体积计算机的用户也会发现这非常有用。有时候设…

    Linux系统 2025年6月8日
  • Linux下安装和使用Dokuwiki

    Dokuwiki作为一个wiki引擎,软件主体十分小巧但功能非常强大而又灵活。它语法简单,为易写性、易读性提供保障。它提供权限管理和安全策略,能够保证信息库的安全性。 需求 Dok…

    Linux系统 2025年6月8日
  • Linux lsblk命令实例

    lsblk命令用来查看block设备的信息.主要应用场景: 获取wwnid,获取块设备列表,获取块设备类型(ssd,hdd),获取块设备的size等信息。 系统环境 Centos7…

    Linux系统 2025年6月11日
  • Linux下使用 Docker托管 .NET Core

    .NET Core是适用于 Windows、Linux 和 macOS 的免费、开源托管的计算机软件框架,是微软开发的第一个官方版本,具有跨平台能力的应用程序开发框架 (Appli…

    Linux系统 2025年6月13日
  • 详解Vim插件:Python-mode

    Python-mode 是一个 vim 插件,允许你在 vim 编辑器中使用工具:pylint, rope, pydoc, pyflakes, pep8, mccabe ,用来对 …

    Linux系统 2025年6月10日
  • Linux中搭建 Docker私有仓库

    私有镜像仓库是指部署在公司或组织内部,用于自身应用Docker镜像存储、分发的镜像仓库。在构建公司内部使用的自动化发布系统的过程中,从安全的角度出发,应用的打包镜像一般情况下只会被…

    Linux系统 4天前
  • Python中实现线程同步

    python中如何实现线程同步?所谓的线程同步机制其实就是锁的使用,下面为大家详细讲解一下python中实现线程同步具体方法。 使用 Thread 对象的 Lock 和 Rlock…

    Linux系统 2025年6月13日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注