文档章节

Android GoldFish新加键盘驱动

c
 clement
发布于 2015/05/10 10:48
字数 1412
阅读 66
收藏 0

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

在项目选型决定之前,sw工作有些可以通过模拟器完成,比如一些驱动的框架。

sample参考drivers\input\kerboard\gpio_keys.c,采取的是platform driver的模型。

platform device和driver,他们的name段必须相同。否则不能对应devices信息和driver

device是虚拟的设备,主要是注册和声明资源。driver是资源使用者。那样相同的driver可以挂载在不同的资源段上。

以下是改好的key驱动

/*
 * Driver for test.
 *
 * Copyright 2015 Clement Zhao
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/sysdev.h>

#include <linux/input.h>
#include <linux/gpio_keys.h>


struct test_drvdata {
	struct gpio_keys_button *button;
	struct input_dev *input;
};

static ssize_t test_read(struct device *dev,
					  struct device_attribute *attr,
					  char *buf)
{
	struct test_drvdata *ddata = dev_get_drvdata(dev);
	struct input_dev *input = ddata->input;
	
	//report key down
	input_report_key(input, KEY_1, 1);
	//report key up
	input_report_key(input, KEY_1, 0);

	input_sync(input);

	printk("file read\n");
	
        return 0;
}

static ssize_t test_write(struct device *dev,
				struct device_attribute *attr,
				const char *buf,
				size_t count)
{
	struct test_drvdata *ddata = dev_get_drvdata(dev);
	struct input_dev *input = ddata->input;
	
	//report key down
	input_report_key(input, KEY_1, 1);
	//report key up
	input_report_key(input, KEY_1, 0);

	input_sync(input);

	printk("file write\n");

     	return count;
}

//create dev_attr_xxx attr
static DEVICE_ATTR(test, S_IRUGO | S_IWUGO, test_read, test_write);

static int __devinit test_probe(struct platform_device *pdev)
{
	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;

	struct test_drvdata *ddata;
	struct input_dev *input;

	int wakeup = 0;
	int error = 0;
	
	ddata = kzalloc(sizeof(struct test_drvdata),
			GFP_KERNEL);
	input = input_allocate_device();
	if (!ddata || !input) {
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, ddata);
	
	input->name = pdev->name;
	input->phys = "test/input0";
	input->dev.parent = &pdev->dev;
	input->id.bustype = BUS_HOST;
	//for idc/dl file index
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0000;

	// Enable auto repeat feature of Linux input subsystem 
	if (pdata->rep)
		__set_bit(EV_REP, input->evbit);

	ddata->input = input;
	
	struct gpio_keys_button *button = pdata->buttons;
	ddata->button = button;
	
	unsigned int type = button->type;

	if (button->wakeup){
		wakeup = 1;
		
		input_set_capability(input, type, button->code);
		//printk("%d %d %d %d\n", EV_KEY, KEY_1, type, button->code);

	}

	error = input_register_device(input);
	if (error) {
		pr_err("gpio-keys: Unable to register input device, "
			"error: %d\n", error);
		goto fail1;

	}

	device_init_wakeup(&pdev->dev, wakeup);
	
	//create sysfs node
	error = device_create_file(&pdev->dev, &dev_attr_test);
	if (error < 0){
		input_unregister_device(input);
        	goto fail1;
	}

	return 0;

fail1:
	input_free_device(input);

	kfree(ddata);

	return error;
}

static int __devexit test_remove(struct platform_device *pdev)
{
	struct test_drvdata *ddata = dev_get_drvdata(&pdev->dev);
	struct input_dev *input = ddata->input;

	input_unregister_device(input);
	input_free_device(input);
	
	kfree(ddata);
	
	//remove sysfs node
	device_remove_file(&pdev->dev, &dev_attr_test);
	
	return 0; 
}

static int test_suspend(struct platform_device *pdev, pm_message_t state)
{
	return 0;
}



static int test_resume(struct platform_device *pdev)
{
	return 0;
}


static struct platform_driver test_device_driver = {
	.probe		= test_probe,
	.remove		= __devexit_p(test_remove),
	.suspend	= test_suspend,
	.resume		= test_resume,
	.driver		= {
		.name	= "test",
		.owner	= THIS_MODULE,
	}
};

static int __init platdrv_test_init(void)
{
	return platform_driver_register(&test_device_driver);
}

static void __exit platdrv_test_exit(void)
{
	platform_driver_unregister(&test_device_driver);
}

module_init(platdrv_test_init);
module_exit(platdrv_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Clement Zhao <clement@zhimou.io");
MODULE_DESCRIPTION("test driver for CPU GPIOs");
MODULE_ALIAS("platform:test");

因为是模拟的,所以需要建立触发输入键值的机制。proc和sysfs都是可以使用的,但貌似sysfs比较先进一点,那就直接上sysfs吧。从头文件中还可以找到 show/store 函数的原型,注意到它和虚拟字符设备或 proc 项的 read/write 的作用很类似,但有一点不同是show/store 函数上的 buf/count 参数是在 sysfs 层已作了用户区/内核区的内存复制,虚拟字符设备上常见的 __user属性在这里并不需要,因而也不需要多一次 copy_from_user/copy_to_user, 在 show/store 函数参数上的buf/count 参数已经是内核区的地址,可以直接操作。

device_create_file和sysfs_create_group是2组不同的sysfs节点创建方式。sysfs_create_group要建立koject对象。device_create_file相对简单,直接可以在platform drvier上用。无需额外char或者misc设备。

代码通过DEVICE_ATTR注册了dev_attr_xxx名字的attr,也就是可以通过读写文件节点,进行手动输入。

在kernel启动后,adb shell进入\sys\devices\platform\test,里面建立的test节点可以通过cat/echo进行交互。


接下来就要注册资源,修改arch\mips\mach-goldfish\goldfish-platform.c,加入以下代码

static struct gpio_keys_button gpio_buttons[] = {
	{
		.code			= KEY_MENU,
		.gpio			= 7,
		.active_low 		= 1,
		.desc			= "user",
		.type			= EV_KEY,
		.wakeup			= 1,
		
	},
};

static struct gpio_keys_platform_data gpio_key_info = {
	.buttons	= &gpio_buttons,
	.nbuttons	= ARRAY_SIZE(gpio_buttons),
};

static struct platform_device test = {
	.name	= "test",
	.id	= -1,
	.dev	= {
		.platform_data	= &gpio_key_info,
	},
};

struct platform_device goldfish_pdev_bus_device = {
	.name = "goldfish_pdev_bus",
	.id = -1,
	.num_resources = ARRAY_SIZE(goldfish_pdev_bus_resources),
	.resource = goldfish_pdev_bus_resources
};

static void __init goldfish_init(void)
{
	platform_device_register(&goldfish_pdev_bus_device);

	if (platform_device_register(&test) < 0)
		printk("Goldfish Unable to register test device\n");
	else
		printk("Goldfish Register test device success\n");
}

修改mach-goldfish下的makefile,把编译对象加进去,kerne启动后就自动加载此驱动。

按键驱动扫描到,先input_report_key上报一个键值

http://wenku.baidu.com/link?url=6vHnUBq9k9TzirWiG3j6la6OkanlZGmgGM2CRSGlPyz7Jy8LfKFoSfrR6BYExdMUNCCDdFHTpTF4mBPPWLWVNGWnBud2gQ_ZR7yUTfrv8xG

android系统中,获取到键盘的键值后,会搜索/system/usr/keylayout/*.kl这个文件

Android标准的键值映射表文件为qwerty.kl

WAKE: 当设备睡眠时按下此键,设备将被唤醒,按键事件将会被发送到应用程序.

WAKE_DROPPED: 当设备睡眠时按下此键,设备将被唤醒,而按键事件不会被发送到应用程序.

kecode对照表http://blog.csdn.net/feizhixuan46789/article/details/16801429

那么在Android下外加自己的键盘驱动,还需要以下工作:

1.先要注册platform驱动,然后driver的keycode要和platform里面的keycode要对应。没有注册的keycode无法上传

2.设备根据id的vendor、product code来识别idc文件(另一种是加上version)。idc里面定义kl和kcm文件,这个可以复用qwerty.idc里面的

文件都在framework/base/data/keyboard,新增文件加到common.mk里面即可

3.成功注册后,打印提示:

ventHub: New device: id=2, fd=97, path='/dev/input/event0', name='test', classes=0x1, configuration='/system/usr/idc/Vendor_0001_Product_0001.idc', keyLayout='/system/usr/keylayout/qwerty.kl', keyCharacterMap='/system/usr/keychars/qwerty.kcm', builtinKeyboard=false

InputReader: Device added: id=2, name='test', sources=0x00000101

4.keycode有分scan code和event code,分别在include/linux/input.h定义scan code

kl文件作为scan code和event code的映射关系


根据代码,我们创建一个Vendor_0001_Product_0001.idc,里面内容完全复制qwerty.idc即可,除非是想连kl和kcm文件都要改。

接着在framework/base/data/keyboards/common.mk下加上此文件,重新编译android。配合上我们新建的kernel,模拟器就可以得到用户触发的input输入了。

© 著作权归作者所有

c
粉丝 0
博文 2
码字总数 3761
作品 0
广州
私信 提问
Android对Linux内核的改动你知道多少?

我们知道Android是一个开源系统,但是并不彻底,而且Android从多个方面对Linux内核进行了改动与增强,尽管一度和Linux基金会在内核方面闹得不愉快,但是最终也达成了和解。下面将对此进行详细...

AlphaJay
2011/07/29
1K
1
简单分析下Android 内核

通过和标准的Linux 2.6.25 Kernel的对比,我们可以发现,其主要增加了以下的内容: 1.增加了yaffs2 FLASH文件系统,相应增加的目录为: kernel/fs/yaffs2 实际上,Android包经过编译后生成的syste...

sprinl
2011/07/03
550
0
编译andorid kernel for moudle (android LKM)的配置

具体编译android source和android kernle 的过程参考:http://my.oschina.net/u/561492/blog/89965 1、特别要注意,如果要编写LKM for android ,一点要在编译内核源码之前对其加一步配置: ...

wangxigui
2012/11/14
278
0
android 内核编译 无法启动模拟器

Android源码,编译也通过了,可以正常启动模拟器。但是Android源码内是不包含kernel源码的模拟器,添加自己新编译的内核就启动不了 启动新编译的内核的模拟器的命令如下: 但是就是启动不了,...

andy521zhu
2014/05/11
830
0
Ubuntu11.10下编译android内核源码

在之前的文章中,为读者介绍了《Ubuntu Linux下android源码下载方法》、《Ubuntu11.10下配置android的Eclipse开发环境》、配置过程中遇到的一些问题,以及《Ubuntu11.10下android源码4.0.3的...

Taskiller
2012/01/11
3.4K
0

没有更多内容

加载失败,请刷新页面

加载更多

如何更改iOS应用程序的名称?

我前几天用一个愚蠢的开发代码名称开始了一个iPhone项目,现在我想改变项目的名称,因为它已经接近完成了。 但是我不知道如何使用Xcode来做这件事,尝试在info.plist文件中更改应用程序的名称...

技术盛宴
39分钟前
5
0
关于win10tensorflow的配置(CPU+GPU)

主要内容 CPU篇 GPU篇 【前期准备与注意事项】 环境:window1064位+python36(37)+CUDA9.0+cuDNN7.6+tensorflow_gpu-1.12.0 软件:anaconda+pycharm 硬件:有nvidia显卡的笔记本或台式(非A...

放只虎归个山
47分钟前
3
0
C#中的多行字符串文字

有没有一种简单的方法可以在C#中创建多行字符串文字? 这是我现在所拥有的: string query = "SELECT foo, bar"+ " FROM table"+ " WHERE id = 42"; 我知道PHP有 <<<BLOCKBLOCK; C#是......

javail
55分钟前
4
0
微信支付之小微商户扫盲!支持信用卡,免营业执照!

微信支付商户申请面向线下小微商户开放,符合条件的微信支付服务商可为小微商户发起接入申请。无需营业执照。 小微商户日收款额度为5万元~30万元 。 信用卡支付日限额为1千;月限额1万。 结算...

吴伟祥
今天
4
0
大话SDWebImage(三)-- 图片下载层

四、图片下载层 SDWebImageDownloader是处理图片下载的类 4.1 图片下载步骤 首先介绍下dispatch_barrier,GCD中的dispatch_barrier目的是在并发队列实现串行的效果,创建下载任务SDWebImageD...

aron1992
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部