linux keypad driver

linux keypad driverDTS文件、driver文件

大家好,又见面了,我是你们的朋友全栈君。

1、DTS文件

&keypad {
    keypad,num-rows = <8>;
    keypad,num-columns = <8>;
    linux,keymap = <0x00000012    /* KEY_E */
            0x00010013    /* KEY_R */
            0x00020014    /* KEY_T */
            0x00030066    /* KEY_HOME */
            0x0004003f    /* KEY_F5 */
            0x000500f0    /* KEY_UNKNOWN */
            0x00060017    /* KEY_I */
            0x0007002a    /* KEY_LEFTSHIFT */
            0x01000020    /* KEY_D*/
            0x01010021    /* KEY_F */
            0x01020022    /* KEY_G */
            0x010300e7    /* KEY_SEND */
            0x01040040    /* KEY_F6 */
            0x010500f0    /* KEY_UNKNOWN */
            0x01060025    /* KEY_K */
            0x0107001c    /* KEY_ENTER */
            0x0200002d    /* KEY_X */
            0x0201002e    /* KEY_C */
            0x0202002f    /* KEY_V */
            0x0203006b    /* KEY_END */
            0x02040041    /* KEY_F7 */
            0x020500f0    /* KEY_UNKNOWN */
            0x02060034    /* KEY_DOT */
            0x0207003a    /* KEY_CAPSLOCK */
            0x0300002c    /* KEY_Z */
            0x0301004e    /* KEY_KPLUS */
            0x03020030    /* KEY_B */
            0x0303003b    /* KEY_F1 */
            0x03040042    /* KEY_F8 */
            0x030500f0    /* KEY_UNKNOWN */
            0x03060018    /* KEY_O */
            0x03070039    /* KEY_SPACE */
            0x04000011    /* KEY_W */
            0x04010015    /* KEY_Y */
            0x04020016    /* KEY_U */
            0x0403003c    /* KEY_F2 */
            0x04040073    /* KEY_VOLUMEUP */
            0x040500f0    /* KEY_UNKNOWN */
            0x04060026    /* KEY_L */
            0x04070069    /* KEY_LEFT */
            0x0500001f    /* KEY_S */
            0x05010023    /* KEY_H */
            0x05020024    /* KEY_J */
            0x0503003d    /* KEY_F3 */
            0x05040043    /* KEY_F9 */
            0x05050072    /* KEY_VOLUMEDOWN */
            0x05060032    /* KEY_M */
            0x0507006a    /* KEY_RIGHT */
            0x06000010    /* KEY_Q */
            0x0601001e    /* KEY_A */
            0x06020031    /* KEY_N */
            0x0603009e    /* KEY_BACK */
            0x0604000e    /* KEY_BACKSPACE */
            0x060500f0    /* KEY_UNKNOWN */
            0x06060019    /* KEY_P */
            0x06070067    /* KEY_UP */
            0x07000094    /* KEY_PROG1 */
            0x07010095    /* KEY_PROG2 */
            0x070200ca    /* KEY_PROG3 */
            0x070300cb    /* KEY_PROG4 */
            0x0704003e    /* KEY_F4 */
            0x070500f0    /* KEY_UNKNOWN */
            0x07060160    /* KEY_OK */
            0x0707006c>;    /* KEY_DOWN */
    linux,input-no-autorepeat;
};

总行列数目,num-rows最大行数目,num-columns最大列数目。

0x00030066    /* KEY_HOME*/

00行,03列,键值0x66即HOME建

2、驱动

路径 linux\drivers\input\keybord\

2、1 probe

static int omap4_keypad_probe(struct platform_device *pdev)
{
	const struct omap4_keypad_platform_data *pdata =
				dev_get_platdata(&pdev->dev);
	const struct matrix_keymap_data *keymap_data =
				pdata ? pdata->keymap_data : NULL;
	struct omap4_keypad *keypad_data;
	struct input_dev *input_dev;
	struct resource *res;
	unsigned int max_keys;
	int rev;
	int irq;
	int error;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "no base address specified\n");
		return -EINVAL;
	}

	irq = platform_get_irq(pdev, 0);
	if (!irq) {
		dev_err(&pdev->dev, "no keyboard irq assigned\n");
		return -EINVAL;
	}

	keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
	if (!keypad_data) {
		dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
		return -ENOMEM;
	}

	keypad_data->irq = irq;

	if (pdata) {
		keypad_data->rows = pdata->rows;
		keypad_data->cols = pdata->cols;
	} else {
		error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
		if (error)
			return error;
	}

	res = request_mem_region(res->start, resource_size(res), pdev->name);
	if (!res) {
		dev_err(&pdev->dev, "can't request mem region\n");
		error = -EBUSY;
		goto err_free_keypad;
	}

	keypad_data->base = ioremap(res->start, resource_size(res));
	if (!keypad_data->base) {
		dev_err(&pdev->dev, "can't ioremap mem resource\n");
		error = -ENOMEM;
		goto err_release_mem;
	}


	/*
	 * Enable clocks for the keypad module so that we can read
	 * revision register.
	 */
	pm_runtime_enable(&pdev->dev);
	error = pm_runtime_get_sync(&pdev->dev);
	if (error) {
		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
		goto err_unmap;
	}
	rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
	rev &= 0x03 << 30;
	rev >>= 30;
	switch (rev) {
	case KBD_REVISION_OMAP4:
		keypad_data->reg_offset = 0x00;
		keypad_data->irqreg_offset = 0x00;
		break;
	case KBD_REVISION_OMAP5:
		keypad_data->reg_offset = 0x10;
		keypad_data->irqreg_offset = 0x0c;
		break;
	default:
		dev_err(&pdev->dev,
			"Keypad reports unsupported revision %d", rev);
		error = -EINVAL;
		goto err_pm_put_sync;
	}

	/* input device allocation */
	keypad_data->input = input_dev = input_allocate_device();
	if (!input_dev) {
		error = -ENOMEM;
		goto err_pm_put_sync;
	}

	input_dev->name = pdev->name;
	input_dev->dev.parent = &pdev->dev;
	input_dev->id.bustype = BUS_HOST;
	input_dev->id.vendor = 0x0001;
	input_dev->id.product = 0x0001;
	input_dev->id.version = 0x0001;

	input_dev->open = omap4_keypad_open;
	input_dev->close = omap4_keypad_close;

	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
	if (!keypad_data->no_autorepeat)
		__set_bit(EV_REP, input_dev->evbit);

	input_set_drvdata(input_dev, keypad_data);

	keypad_data->row_shift = get_count_order(keypad_data->cols);
	max_keys = keypad_data->rows << keypad_data->row_shift;
	keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]),
				      GFP_KERNEL);
	if (!keypad_data->keymap) {
		dev_err(&pdev->dev, "Not enough memory for keymap\n");
		error = -ENOMEM;
		goto err_free_input;
	}

	error = matrix_keypad_build_keymap(keymap_data, NULL,
					   keypad_data->rows, keypad_data->cols,
					   keypad_data->keymap, input_dev);
	if (error) {
		dev_err(&pdev->dev, "failed to build keymap\n");
		goto err_free_keymap;
	}

	error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
				     omap4_keypad_irq_thread_fn, 0,
				     "omap4-keypad", keypad_data);
	if (error) {
		dev_err(&pdev->dev, "failed to register interrupt\n");
		goto err_free_input;
	}

	device_init_wakeup(&pdev->dev, true);
	pm_runtime_put_sync(&pdev->dev);

	error = input_register_device(keypad_data->input);
	if (error < 0) {
		dev_err(&pdev->dev, "failed to register input device\n");
		goto err_pm_disable;
	}

	platform_set_drvdata(pdev, keypad_data);
	return 0;

err_pm_disable:
	pm_runtime_disable(&pdev->dev);
	device_init_wakeup(&pdev->dev, false);
	free_irq(keypad_data->irq, keypad_data);
err_free_keymap:
	kfree(keypad_data->keymap);
err_free_input:
	input_free_device(input_dev);
err_pm_put_sync:
	pm_runtime_put_sync(&pdev->dev);
err_unmap:
	iounmap(keypad_data->base);
err_release_mem:
	release_mem_region(res->start, resource_size(res));
err_free_keypad:
	kfree(keypad_data);
	return error;
}

2、2  parse

static int omap4_keypad_parse_dt(struct device *dev,
				 struct omap4_keypad *keypad_data)
{
	struct device_node *np = dev->of_node;
	int err;

	err = matrix_keypad_parse_of_params(dev, &keypad_data->rows,
					    &keypad_data->cols);
	if (err)
		return err;

	if (of_get_property(np, "linux,input-no-autorepeat", NULL))
		keypad_data->no_autorepeat = true;

	return 0;
}

int matrix_keypad_parse_of_params(struct device *dev,
				  unsigned int *rows, unsigned int *cols)
{
	struct device_node *np = dev->of_node;

	if (!np) {
		dev_err(dev, "missing DT data");
		return -EINVAL;
	}
	of_property_read_u32(np, "keypad,num-rows", rows);
	of_property_read_u32(np, "keypad,num-columns", cols);
	if (!*rows || !*cols) {
		dev_err(dev, "number of keypad rows/columns not specified\n");
		return -EINVAL;
	}

	return 0;
}

2、3  build keymap

int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
			       const char *keymap_name,
			       unsigned int rows, unsigned int cols,
			       unsigned short *keymap,
			       struct input_dev *input_dev)
{
	unsigned int row_shift = get_count_order(cols);
	size_t max_keys = rows << row_shift;
	int i;
	int error;

	if (WARN_ON(!input_dev->dev.parent))
		return -EINVAL;

	if (!keymap) {
		keymap = devm_kzalloc(input_dev->dev.parent,
				      max_keys * sizeof(*keymap),
				      GFP_KERNEL);
		if (!keymap) {
			dev_err(input_dev->dev.parent,
				"Unable to allocate memory for keymap");
			return -ENOMEM;
		}
	}

	input_dev->keycode = keymap;
	input_dev->keycodesize = sizeof(*keymap);
	input_dev->keycodemax = max_keys;

	__set_bit(EV_KEY, input_dev->evbit);

	if (keymap_data) {
		for (i = 0; i < keymap_data->keymap_size; i++) {
			unsigned int key = keymap_data->keymap[i];

			if (!matrix_keypad_map_key(input_dev, rows, cols,
						   row_shift, key))
				return -EINVAL;
		}
	} else {
		error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
						      input_dev);
		if (error)
			return error;
	}

	__clear_bit(KEY_RESERVED, input_dev->keybit);

	return 0;
}

static int matrix_keypad_parse_of_keymap(const char *propname,
					 unsigned int rows, unsigned int cols,
					 struct input_dev *input_dev)
{
	struct device *dev = input_dev->dev.parent;
	struct device_node *np = dev->of_node;
	unsigned int row_shift = get_count_order(cols);
	unsigned int max_keys = rows << row_shift;
	unsigned int proplen, i, size;
	const __be32 *prop;

	if (!np)
		return -ENOENT;

	if (!propname)
		propname = "linux,keymap";

	prop = of_get_property(np, propname, &proplen);
	if (!prop) {
		dev_err(dev, "OF: %s property not defined in %s\n",
			propname, np->full_name);
		return -ENOENT;
	}

	if (proplen % sizeof(u32)) {
		dev_err(dev, "OF: Malformed keycode property %s in %s\n",
			propname, np->full_name);
		return -EINVAL;
	}

	size = proplen / sizeof(u32);
	if (size > max_keys) {
		dev_err(dev, "OF: %s size overflow\n", propname);
		return -EINVAL;
	}

	for (i = 0; i < size; i++) {
		unsigned int key = be32_to_cpup(prop + i);

		if (!matrix_keypad_map_key(input_dev, rows, cols,
					   row_shift, key))
			return -EINVAL;
	}

	return 0;
}

static bool matrix_keypad_map_key(struct input_dev *input_dev,
				  unsigned int rows, unsigned int cols,
				  unsigned int row_shift, unsigned int key)
{
	unsigned short *keymap = input_dev->keycode;
	unsigned int row = KEY_ROW(key);
	unsigned int col = KEY_COL(key);
	unsigned short code = KEY_VAL(key);

	if (row >= rows || col >= cols) {
		dev_err(input_dev->dev.parent,
			"%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n",
			__func__, key, row, col, rows, cols);
		return false;
	}

	keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
	__set_bit(code, input_dev->keybit);

	return true;
}

2、4 irq

static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
{
	struct omap4_keypad *keypad_data = dev_id;
	struct input_dev *input_dev = keypad_data->input;
	unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
	unsigned int col, row, code, changed;
	u32 *new_state = (u32 *) key_state;

	*new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
	*(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);

	for (row = 0; row < keypad_data->rows; row++) {
		changed = key_state[row] ^ keypad_data->key_state[row];
		if (!changed)
			continue;

		for (col = 0; col < keypad_data->cols; col++) {
			if (changed & (1 << col)) {
				code = MATRIX_SCAN_CODE(row, col,
						keypad_data->row_shift);
				input_event(input_dev, EV_MSC, MSC_SCAN, code);
				input_report_key(input_dev,
						 keypad_data->keymap[code],
						 key_state[row] & (1 << col));
			}
		}
	}

	input_sync(input_dev);

	memcpy(keypad_data->key_state, key_state,
		sizeof(keypad_data->key_state));

	/* clear pending interrupts */
	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));

	/* enable interrupts */
	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
		OMAP4_DEF_IRQENABLE_EVENTEN |
				OMAP4_DEF_IRQENABLE_LONGKEY);

	return IRQ_HANDLED;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133118.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 屠龙之技 作者:长铗

    屠龙之技 作者:长铗一  雨水从宽阔的大理石台阶上淌下来,打湿了年轻人制作考究的山羊皮皮鞋。他的身形颀长瘦削,撑一把漆黑的木柄雨伞,侧脸仰望着灰蒙蒙的天空。年轻人推开图书馆那扇锈涩厚重的大门时,一只鸽子飞了出来。他钝重的步子在高耸狭窄的空间里激荡回响。这是一个由教堂改建而成的街区图书馆,在这个时代,聆听圣音的人已经不多了。  年轻人停住了脚步,目光蓦地垂落到教堂内远远的一角。冬日灰冷的阳光从高窗上的彩色玻璃中透下…

  • vue v-if 多条件_vue vnode

    vue v-if 多条件_vue vnodev-if在模板中,可以根据条件进行渲染。条件用到的是v-if、v-else-if以及v-else来组合实现的。示例代码如下:<divid="app"><p

  • nacicat15 激活码_在线激活

    (nacicat15 激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~S32PGH0SQB-eyJsaWNlb…

  • SoundFlower+QuickTime录屏Mac含系统声音[通俗易懂]

    SoundFlower+QuickTime录屏Mac含系统声音[通俗易懂]Mac自带的录屏软件QuickTime不能录系统声音。为此,使用soundflower插件来解决。其原理是添加虚拟声卡,使系统声音输出到该声卡,再将其作为QuickTime录屏的输入。soundflower是一个开源插件,已于2014年停止维护,但其最新版本仍可用于当前版本的mac。同一开发者开发了新软件Loopback,功能类似,多了图形界面。它更好用,但是录制20分钟后会人为加噪,迫使用户购买付费版本($99)????。soundflower最新release:https://github.com/

  • ROC及AUC计算方法及原理「建议收藏」

    ROC及AUC计算方法及原理「建议收藏」1.非均衡分类问题在大多数情况下不同类别的分类代价并不相等,即将样本分类为正例或反例的代价是不能相提并论的。例如在垃圾邮件过滤中,我们希望重要的邮件永远不要被误判为垃圾邮件,还有在癌症检测中,宁愿误判也不漏判。在这种情况下,仅仅使用分类错误率来度量是不充分的,这样的度量错误掩盖了样例如何被错分的事实。所以,在分类中,当某个类别的重要性高于其他类别时,可以使用Precison和Recall多个比…

  • Linux错误 E325: 注意 发现交换文件

    Linux错误 E325: 注意 发现交换文件方法1、恢复文件:vim-rnginx.conf恢复以后把.swap文件删掉,再打开时就不会用提示,注意.swap文件是个隐藏文件。可用:la查看。以.开头的是隐藏文件。方法2、ls-a查询隐藏文件,删除后缀名为.swp的文件删除rm-f文件名.swp转载:https://blog.csdn.net/u012686154/article/details…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号