Android 架构解析及驱动 键盘篇

S5PV210 Android 矩阵键盘驱动[基于x210开发板] 矩阵键盘驱动源文件: kernel/drivers/input/touchscreen/keyboard/s3c-keypad.c kernel/drivers/input/touchscreen/keyboard/s3c-keypad.h kernel/arch/arm/mach-s5pv210/mach-smdkc110.c kernel/arch/arm/plat-s5p/devs. 阅读详情

学习网站:http://blog.youkuaiyun.com/sfrysh/archive/2010/07/28/5772158.aspx 里面有很多好用的东东 参考下

--  作者:老树
--  发布时间:2010-6-2 15:01:19
--  Android 架构解析及驱动 键盘篇

一、用户空间      

      ADROID 2.1 架构解析 7 键盘

     以上链接,详细介绍了Android用户空间按键的操作,最终通过不断轮询所有设备,直到读取有POLLIN事件产生的设备状态:if(mFDs[i].revents & POLLIN) { res = read(mFDs[i].fd, &iev, sizeof(iev));......

二、底层驱动

1.设备注册
static struct resource s3c_keypad_resource[] = {
[0] = {
   .start = S3C64XX_PA_KEYPAD,
   .end = S3C64XX_PA_KEYPAD+S3C64XX_SZ_KEYPAD-1,
   .flags = IORESOURCE_MEM,
},
[1] = {
   .start = IRQ_KEYPAD,
   .end = IRQ_KEYPAD,
   .flags = IORESOURCE_IRQ,
}
   };

struct platform_device s3c_device_keypad = {
   .name = "s3c-keypad",
   .id = -1,
   .num_resource =ARRAY_SIZE(s3c_keypad_resource ),
   .resource = s3c_keypad_resource,
   };
   EXPORT_SYMBOL(s3c_device_keypad);

static struct platform_device *smdk6410_devices[] __initdata = {
     ...
    &s3c_device_keypad ,
   }

static void __init smdk6410_machine_init (void)
{
    ...
    platform_add_devices (smdk6410_devices,ARRAY_SIZE(smdk6410_devices));
    ...
}

int platform_add_devices (struct platform_device **devs, int num)
{
int i,ret = 0;
for(i=0;i<num;i++){
   ret = platform_device_register(devs[i]);
   if(ret){
      while(--i >= 0)
   platform_device_unregister(devs[i]);
      break;
   }
}
return ret;
   }

2.驱动注册与注销
   module_init(s3c_keypad_init);
   module_exit(s3c_keypad_exit);

static int __init s3c_keypad_init (void)
{
   int ret;

   ret = platform_driver_register(&s3c_keypad_driver);
   if(!ret)
      printk(KERN_INFO"S3C Keypad Driver//n");

   return ret;
}

static void __exit s3c_keypad_exit (void)
{
   platform_driver_unregister(&s3c_keypad_driver );
}

platform_driver结构体:
static struct platform_driver s3c_keypad_driver = {
   .probe =s3c_keypad_probe,
   .remove =s3c_keypad_remove,
   .suspend =s3c_keypad_suspend,
   .resume =s3c_keypad_resume,
   .driver = {
    .owner = THIS_MODULE,
      .name = "s3c-keypad",
    },
};

3.设备探测
static int __init s3c_keypad_probe (struct platform_device *pdev)
{
struct resource *res, *keypad_mem, *keypad_irq = NULL;
struct input_dev *input_dev;

int ret, size;
int key, code;
struct s3c_keypad_extra    *extra = NULL;
struct s3c_keypad_gpio_key *gpio_key;
int i;
char * input_dev_name;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取设备内存信息
if (res == NULL) {
   dev_err(&pdev->dev,"no memory resource specified//n");
   return -ENOENT;
}

size = (res->end - res->start) + 1;

keypad_mem = request_mem_region(res->start, size, pdev->name);
if (keypad_mem == NULL) {
   dev_err(&pdev->dev, "failed to get memory region//n");
   ret = -ENOENT;
   goto err_req;
}

key_base = ioremap(res->start, size);    //IO空间映射
if (key_base == NULL) {
   printk(KERN_ERR "Failed to remap register block//n");
   ret = -ENOMEM;
   goto err_map;
}

keypad_clock = clk_get(&pdev->dev, "keypad");     //获取keypad对应的时钟
if (IS_ERR(keypad_clock)) {
   dev_err(&pdev->dev, "failed to find keypad clock source//n");
   ret = PTR_ERR(keypad_clock);
   goto err_clk;
}

clk_enable(keypad_clock);    //使能keypad模块的时钟

s3c_keypad_data = kzalloc(sizeof(struct s3c_keypad), GFP_KERNEL);

input_dev = input_allocate_device(); //申请一个input_dev设备
input_dev_name = (char *)kmalloc(sizeof("s3c-keypad-revxxxx "), GFP_KERNEL); //这里就是用户空间提到的键值配置表

if (!s3c_keypad_data || !input_dev) {
   ret = -ENOMEM;
   goto err_alloc;
}

platform_set_drvdata(pdev, s3c_keypad_data);

for (i=0; i<sizeof(s3c_keypad_extra)/sizeof(struct s3c_keypad_extra); i++)
{
   if (s3c_keypad_extra[i].board_num == system_rev) {
    extra = &s3c_keypad_extra[i];
    sprintf(input_dev_name, "%s%s%04x", DEVICE_NAME, "-rev", system_rev);
    DPRINTK(": board rev 0x%04x is detected!//n", s3c_keypad_extra[i].board_num);
    break;
   }
}

if(!extra) {
   extra = &s3c_keypad_extra[0];
   sprintf(input_dev_name, "%s%s", DEVICE_NAME, "-rev0000");     //default revison
   DPRINTK(": failed to detect board rev. set default rev00//n");
}
DPRINTK(": input device name: %s.//n", input_dev_name);

s3c_keypad_data->dev = input_dev;
s3c_keypad_data->extra = extra;
gpio_key = extra->gpio_key;

/* create and register the input driver */
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
s3c_keypad_data->nr_rows = KEYPAD_ROWS;
s3c_keypad_data->no_cols = KEYPAD_COLUMNS;

for(key = 0; key < 32; key++){
   code = s3c_keypad_data->keycodes[key] = keypad_keycode[key];
   if(code<=0)
    continue;
   set_bit(code & KEY_MAX, input_dev->keybit);
}
for (i=0; i<extra->gpio_key_num; i++ ){
        input_set_capability(input_dev, EV_KEY, (gpio_key+i)->keycode);
}

input_dev->name = DEVICE_NAME;
input_dev->phys = "s3c-keypad/input0";

input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0001;

input_dev->keycode = keypad_keycode;

/* init_timer(&keypad_timer); */
keypad_timer.function = keypad_timer_handler;
keypad_timer.data = (unsigned long)s3c_keypad_data;


for (i=0; i<extra->gpio_key_num; i++, gpio_key+=1)
{
   s3c_gpio_cfgpin(gpio_key->gpio, S3C_GPIO_SFN(gpio_key->gpio_af));
   s3c_gpio_setpull(gpio_key->gpio, S3C_GPIO_PULL_NONE);

   set_irq_type(gpio_key->eint, IRQ_TYPE_EDGE_BOTH);

   ret = request_irq(gpio_key->eint, gpio_int_handler , IRQF_DISABLED,
       "s3c_keypad gpio key", (void *)s3c_keypad_data);   //中断注册
   if (ret) {
    printk(KERN_ERR "request_irq(%d) failed (IRQ for GPIO KEY) !!!//n", gpio_key->eint);
    ret = -EIO;
    goto err_irq;
   }
}

ret = input_register_device(input_dev);   //向输入子系统注册此设备
if (ret) {
   printk("Unable to register s3c-keypad input device!!!//n");
   goto out;
}

return 0;

out:
   input_free_device(input_dev);
   kfree(s3c_keypad_data);

err_irq:
   free_irq(keypad_irq->start, input_dev);
   free_irq(keypad_irq->end, input_dev);

   gpio_key = extra->gpio_key;
   for (i=0; i<extra->gpio_key_num; i++, gpio_key+=1)
     free_irq(gpio_key->eint, s3c_keypad_data);

err_alloc:
   clk_disable(keypad_clock);
   clk_put(keypad_clock);

err_clk:
   iounmap(key_base);

err_map:
   release_resource(keypad_mem);
   kfree(keypad_mem);

err_req:
   return ret;
}
4.按键出发中断,中断处理与数据上传
static irqreturn_t gpio_int_handler (int irq, void *dev_id)
{
struct input_dev           *dev = s3c_keypad_data->dev;
struct s3c_keypad_extra    *extra = s3c_keypad_data->extra;
struct s3c_keypad_gpio_key *gpio_key = extra->gpio_key;
int i,state;


for (i=0; i<extra->gpio_key_num; i++)
{
   if (gpio_key[i].eint == irq)
   {
    gpio_key = &gpio_key[i];
    break;
   }
}

if (gpio_key != NULL)
{
   state = gpio_get_value(gpio_key->gpio);
   state ^= gpio_key->state_upset;

        if(state) {
            input_report_key(dev, gpio_key->keycode, 1);
        }
       else {
    input_report_key(dev, gpio_key->keycode, 0);
   }
}
return IRQ_HANDLED;
}
数 据上传input_report_key-》input_event-》input_handle_event-》input_pass_event-》 handle->handler->event(对应函数:evdev_event)-》数据暂存event(input_event结构 体),以供用户空间读写操作。

5.input事件在传输过程中的一些函数
void input_event (struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
    unsigned long flags;

    if (is_event_supported(type, dev->evbit, EV_MAX)) {
        spin_lock_irqsave(&dev->event_lock, flags);
        add_input_randomness(type, code, value);//因为按键的存在随机性,所以按键是给系统提供墒随机数的好来源.
        input_handle_event(dev, type, code, value);
        spin_unlock_irqrestore(&dev->event_lock, flags);
    }
}


static void input_handle_event (struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
        ...
        case EV_KEY:
        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
            !!test_bit(code, dev->key) != value) {//这次来的是否为新的键值

            if (value != 2) {
                __change_bit(code, dev->key);// 通过异或^操作,反转code对应的bitmap,如果value等于2,那么将忽略该按键
                if (value)
                    input_start_autorepeat(dev, code);
//键盘按下,那么开启定时检测,这样可以出现连续输入的效果
            }

            disposition = INPUT_PASS_TO_HANDLERS;
        }
        break;
    ...
}


static void input_start_autorepeat (struct input_dev *dev, int code)
{
    if (test_bit(EV_REP, dev->evbit) &&
     dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
     dev->timer.data) {
        dev->repeat_key = code;
        mod_timer(&dev->timer,
//重新启动定时器input_repeat_key,时间间隔msecs_to_jiffies(dev->rep[REP_DELAY])
             jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
    }
}

static void input_repeat_key (unsigned long data)
{
    struct input_dev *dev = (void *) data;
    unsigned long flags;

    spin_lock_irqsave(&dev->event_lock, flags);

    if (test_bit(dev->repeat_key, dev->key) &&
     is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {

        input_pass_event(dev, EV_KEY, dev->repeat_key, 2);//交给处理按键函数

        if (dev->sync) {
            /*
             * Only send SYN_REPORT if we are not in a middle
             * of driver parsing a new hardware packet.
             * Otherwise assume that the driver will send
             * SYN_REPORT once it/'s done.
             */
            input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
        }

        if (dev->rep[REP_PERIOD])
            mod_timer(&dev->timer, jiffies +
                    msecs_to_jiffies(dev->rep[REP_PERIOD]));
    }

    spin_unlock_irqrestore(&dev->event_lock, flags);
}

以上驱动是input方式完成的,不清楚的可查阅Linux input输入子设备。

Android 12.0 通过驱动实现禁用usb鼠标和usb键盘功能 在12.0的系统产品定制化开发中,在进行定制中有关于usb键盘和usb鼠标的需求中,产品要求禁止usb口挂载usb鼠标和usb键盘,所以需要要求在usb挂载类型的时候 判断如果是usb鼠标和usb键盘就不让挂载,这就需要从驱动方面入手来解决这个问题,接下来看下驱动的某些挂载usb的相关文件来解决这个功能的禁用问题 阅读详情

相关推荐

android串口键盘

amlogic串口键盘简例,不是所有键值都有,只有部分,仅供参考

android系统移植之按键驱动篇

平台:MX53_QSB开发板 MX53_QSB开发板上一起有四个按键,分别为RESET,POWER,USER1,USER2。其中RESET为纯硬件复位按键,无须软件控制。POWER,USER1,USER2三个按键均需要程序控制。默认BSP包中将三个按钮全设置为上升和下降沿触

armeasy的专栏 2万+

WIFI 相关的频偏调试以及天线调试记录

WIFI RF 相关的频偏调试以及天线调试 1,频率误差(Frequency Error) 频率误差(Frequency Error):表征射频信号偏离该信号所处信道中心频率的大小,单位PPM。频偏误差要求范围如下表。 频偏越小越好。PPM的计算公式如下: 问题: 我们ESP8089认证测试的时候频偏测试超了。需要修改哪些呢。 测试频率点在2.411865385GHz 宣称点:2.412GHz 频率偏移计算:{(2.412GHz-2.411865385GHz)÷2...

armkits的博客 1万+

android 键盘驱动编写

Android framework 451

TruckSim与Simulink联合仿真中的车轮转角精确控制策略

本文深入探讨了TruckSim与Simulink联合仿真中实现车轮转角精确控制的关键策略。针对多轴车辆路径跟踪时转角指令失灵的常见问题,核心在于正确配置TruckSim转向轴的外部输入模式(Advanced Settings),并确保仿真接口的稳定搭建。文章详细解析了从单轴到多轴协同转向的配置方法,并提供了提升MPC路径跟踪精度的实战技巧与调试经验。

weixin_29035147的博客 367

FreeRTOS笔记(十五)FreeRTOS总结

文章目录01 - 裸机和FreeRTOS区别1.1 - 裸机1.2 - FreeRTOS1.3 - 区别02 - 对FreeRTOS的感受03 - 推荐 上一文链接:FreeRTOS笔记(十四)[简] 软件定时器、事件组、任务通知 01 - 裸机和FreeRTOS区别   学完FreeRTOS,应该要自己总结一下FreeRTOS和裸机的区别,宏观上说,FreeRTOS是一个运行在裸机上的微内核,...

单眼皮根号三的博客 4113

安卓驱动开发-摁键的驱动开发

步骤一:移植matrix_keypad.c ~/workspace/Q2806_KAIOS_DEV_BSP_V1/kernel/msm-4.9/drivers/input/keyboard/matrix_keypad.c 步骤二:新修改要检查配置kconfig 和Makefile 和 deconfig 如: ~/workspace/Q2806_KAIOS_DEV_BSP_V1/kernel/msm-4.9]$ vim arch/arm/configs/vendor/msm8937go_defconfig

weixin_45540369的博客 1424

【阿里云大模型高级工程师ACP习题集】2.9 大模型应用生产实践(下篇)

【摘要】这是我精心整理出对应的习题集,里面足足有 30 道题目,从基础概念到深度拓展,全方位覆盖章节重点、难点。不管你是想检验自己的学习成果,还是想针对薄弱环节进行强化训练,它都能完美适配!

davidkorhenn的博客 2235

ADROID 架构解析及驱动 键盘篇

ADROID 架构解析及驱动 键盘篇 一、用户空间            ADROID 2.1 架构解析 7 键盘      以上链接,详细介绍了Android用户空间按键的操作,最终通过不断轮询所有设备,直到读取有POLLIN事件产生的设备状态:if(mFDs[i].revents & POLLIN) {res = read(mFDs[i].fd, &iev, sizeof(i

gooogleman#foxmail.com 3623

基于传统算法的半导体晶圆缺陷检测原理及代码(二)

了解基于传统算法的半导体晶圆缺陷检测原理和方法,对于深入理解半导体制造工艺和质量控制具有重要意义。在半导体制造技术持续创新的浪潮中,基于传统算法的缺陷检测技术也将不断演进,为半导体产业的高质量发展提供坚实可靠的技术支撑,确保在芯片制造的每一个环节都能精准识别和管控缺陷,推动半导体产业迈向更高的发展水平。基于传统算法的半导体晶圆缺陷检测技术在半导体制造的长期发展历程中扮演了重要角色,凭借其成熟的技术体系、较快的检测速度和相对较低的成本,在各个工艺阶段为保障晶圆质量发挥了关键作用。

m0_44975814的博客 2219

【前端基础篇】HTML5 + CSS3 入门知识

,HTML5和CSS3核心知识

前端知识分享喵 2982

安卓设备HID协议深度解析:从系统底层实现万能键盘鼠标模拟

在移动设备功能边界不断扩展的今天,安卓手机通过USB HID协议模拟标准输入设备的技术正展现出其独特价值。基于开源项目android-hid-client,我们可以深入探讨这一技术实现背后的原理与应用前景。前100字内,我们重点分析HID协议在安卓系统中的应用机制,这种底层驱动级通信方式让手机能够被电脑、智能电视等设备识别为原生键盘鼠标。 ## 🔬 技术架构深度剖析 ### 系统层HID设备

gitblog_01168的博客 1346

人形机器人电源系统硬件开发:从原理图设计到PCB布局的完整流程

人形机器人是“移动的智能终端”,其电源系统如同“心脏+血管”:既要为大脑(主控)、肌肉(电机)、感官(传感器)提供稳定能量,又要在有限体积内应对高动态负载(如跳跃时电机瞬间大电流)。本文聚焦“硬件开发”维度,覆盖从需求分析到PCB制板的完整流程,适合硬件工程师、机器人爱好者快速掌握工程实战方法。

AI天才研究院 2174

Android(安卓)架构大致分析

Android的五层架构: 从上到下一共5层: 一、| 应用层(APP)| 二、| 应用框架层(framework) | 三、| 系统运行库层 | 四、| 硬件抽象层HAL | 五、| Linux内核层 | 接下来大致解释一下各个层是干什么的,自己学习心得,逻辑有些杂乱。 1.应用层(APP层):简单点说就是手机上面的设置和app软件,它负责和用户直接交互。 2.应用框架层(framewo...

我的征途是星辰大海 833

VN5620以太网测试——DoIP配置

CANoe(CAN open environment)VN5620 :是一个紧凑而强大的接口,用于以太网网络的分析、仿真、测试和验证。VN5620 接口支持各种可能的应用。它适用于与其他总线系统、网络参与(例如在模拟和生成帧、测试中的负载和错误)的同步以太网监控。在2021年Vector公司的以太网接口卡VN5610和VN5640设备已经陆续停产,相应被VN5620和VN5650代替。参考文章了解DoIP协议——汽车以太网应用介绍。

诊断协议那些事儿's blog 3008

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

在平台RK3288上编写键盘驱动

环境介绍 硬件:RK3288、键盘驱动芯片PCA9535(I2C-GPIO) 软件:android 7.1 linux4.4 原理图: I2C1_INT:GPIO5_B3 I2C1_RST:GPIO7_B4 配置介绍 1.dts &i2c1 { status = "okay"; clock-frequency = <400000>; pca9535@20 { compatible = "nxp,pca9535_keypad"; reg = <0x20>;

gddw1954的专栏 1375

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

iic键盘驱动 android,IIC的键盘驱动

首先简单说说这个键盘的实现原理,IIC总线工作原理没必要废话,s3c2410的手册中讲的很明白。硬件方面这个键盘通过一个AVR单片机(ATMEGA48)接在IIC总线上,也就是说,直接与IIC总线链接的设备并不是我们用的键盘,而是这个单片机,键盘产生的一切数据由这个单片机经过加工包装成一定的数据结构再发给s3c2410。当s3c2410芯片收到数据后会由IIC控制器触发一个中断,在中断处理程序中我...

weixin_42205405的博客 565

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Android 系统架构

我为什么要学习安卓开发? 因为没有仔细看《培养方案》……以为安卓开发是移动方向才有的课,谁知道我们突然开了这一门课~ 我当时的内心想法是:哦耶~~~~~~废话少说!开始学习! Android系统架构是基于Linux内核的软件平台和操作系统。采用了软件堆层的架构,总共分为五层,如下图所示: 如图所示,Android系统架构分为五层,从下到上他们分别是: 文章目录Linux Kernel(Lin...

lesileqin的博客 3427

深度解析:安卓调用自编驱动全流程!

利用Java Native Interface (JNI) 进行本地代码调用是实现硬件功能控制的一种有效方式。本文将深入探讨安卓Linux驱动程序的构建过程,以及如何通过JNI在应用中实现与这些驱动程序的通信,这一过程不仅对底层驱动开发者至关重要,也提供了一种为系统添加特殊功能接口的方法。

分享价值,持续输出高质量内容! 1299

Android基础学习笔记4:安卓平台架构

Android基础学习笔记4:安卓平台架构

m0_63691734的博客 426

Android Studio 学习笔记-安卓平台架构04

对于运行 Androi 作业

shan_chu的博客 749
上一篇: Android Binder
下一篇: Android事件处理分析
hellolwl
博客等级 码龄24年 16粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值