cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipaq-micro-keys.c (4014B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 * h3600 atmel micro companion support, key subdevice
      5 * based on previous kernel 2.4 version
      6 * Author : Alessandro Gardich <gremlin@gremlin.it>
      7 * Author : Linus Walleij <linus.walleij@linaro.org>
      8 */
      9#include <linux/module.h>
     10#include <linux/init.h>
     11#include <linux/fs.h>
     12#include <linux/interrupt.h>
     13#include <linux/sched.h>
     14#include <linux/pm.h>
     15#include <linux/sysctl.h>
     16#include <linux/proc_fs.h>
     17#include <linux/delay.h>
     18#include <linux/device.h>
     19#include <linux/input.h>
     20#include <linux/platform_device.h>
     21#include <linux/mfd/ipaq-micro.h>
     22
     23struct ipaq_micro_keys {
     24	struct ipaq_micro *micro;
     25	struct input_dev *input;
     26	u16 *codes;
     27};
     28
     29static const u16 micro_keycodes[] = {
     30	KEY_RECORD,		/* 1:  Record button			*/
     31	KEY_CALENDAR,		/* 2:  Calendar				*/
     32	KEY_ADDRESSBOOK,	/* 3:  Contacts (looks like Outlook)	*/
     33	KEY_MAIL,		/* 4:  Envelope (Q on older iPAQs)	*/
     34	KEY_HOMEPAGE,		/* 5:  Start (looks like swoopy arrow)	*/
     35	KEY_UP,			/* 6:  Up				*/
     36	KEY_RIGHT,		/* 7:  Right				*/
     37	KEY_LEFT,		/* 8:  Left				*/
     38	KEY_DOWN,		/* 9:  Down				*/
     39};
     40
     41static void micro_key_receive(void *data, int len, unsigned char *msg)
     42{
     43	struct ipaq_micro_keys *keys = data;
     44	int key, down;
     45
     46	down = 0x80 & msg[0];
     47	key  = 0x7f & msg[0];
     48
     49	if (key < ARRAY_SIZE(micro_keycodes)) {
     50		input_report_key(keys->input, keys->codes[key], down);
     51		input_sync(keys->input);
     52	}
     53}
     54
     55static void micro_key_start(struct ipaq_micro_keys *keys)
     56{
     57	spin_lock(&keys->micro->lock);
     58	keys->micro->key = micro_key_receive;
     59	keys->micro->key_data = keys;
     60	spin_unlock(&keys->micro->lock);
     61}
     62
     63static void micro_key_stop(struct ipaq_micro_keys *keys)
     64{
     65	spin_lock(&keys->micro->lock);
     66	keys->micro->key = NULL;
     67	keys->micro->key_data = NULL;
     68	spin_unlock(&keys->micro->lock);
     69}
     70
     71static int micro_key_open(struct input_dev *input)
     72{
     73	struct ipaq_micro_keys *keys = input_get_drvdata(input);
     74
     75	micro_key_start(keys);
     76
     77	return 0;
     78}
     79
     80static void micro_key_close(struct input_dev *input)
     81{
     82	struct ipaq_micro_keys *keys = input_get_drvdata(input);
     83
     84	micro_key_stop(keys);
     85}
     86
     87static int micro_key_probe(struct platform_device *pdev)
     88{
     89	struct ipaq_micro_keys *keys;
     90	int error;
     91	int i;
     92
     93	keys = devm_kzalloc(&pdev->dev, sizeof(*keys), GFP_KERNEL);
     94	if (!keys)
     95		return -ENOMEM;
     96
     97	keys->micro = dev_get_drvdata(pdev->dev.parent);
     98
     99	keys->input = devm_input_allocate_device(&pdev->dev);
    100	if (!keys->input)
    101		return -ENOMEM;
    102
    103	keys->input->keycodesize = sizeof(micro_keycodes[0]);
    104	keys->input->keycodemax = ARRAY_SIZE(micro_keycodes);
    105	keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes,
    106			   keys->input->keycodesize * keys->input->keycodemax,
    107			   GFP_KERNEL);
    108	keys->input->keycode = keys->codes;
    109
    110	__set_bit(EV_KEY, keys->input->evbit);
    111	for (i = 0; i < ARRAY_SIZE(micro_keycodes); i++)
    112		__set_bit(micro_keycodes[i], keys->input->keybit);
    113
    114	keys->input->name = "h3600 micro keys";
    115	keys->input->open = micro_key_open;
    116	keys->input->close = micro_key_close;
    117	input_set_drvdata(keys->input, keys);
    118
    119	error = input_register_device(keys->input);
    120	if (error)
    121		return error;
    122
    123	platform_set_drvdata(pdev, keys);
    124	return 0;
    125}
    126
    127static int __maybe_unused micro_key_suspend(struct device *dev)
    128{
    129	struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
    130
    131	micro_key_stop(keys);
    132
    133	return 0;
    134}
    135
    136static int __maybe_unused micro_key_resume(struct device *dev)
    137{
    138	struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
    139	struct input_dev *input = keys->input;
    140
    141	mutex_lock(&input->mutex);
    142
    143	if (input_device_enabled(input))
    144		micro_key_start(keys);
    145
    146	mutex_unlock(&input->mutex);
    147
    148	return 0;
    149}
    150
    151static SIMPLE_DEV_PM_OPS(micro_key_dev_pm_ops,
    152			 micro_key_suspend, micro_key_resume);
    153
    154static struct platform_driver micro_key_device_driver = {
    155	.driver = {
    156		.name    = "ipaq-micro-keys",
    157		.pm	= &micro_key_dev_pm_ops,
    158	},
    159	.probe   = micro_key_probe,
    160};
    161module_platform_driver(micro_key_device_driver);
    162
    163MODULE_LICENSE("GPL");
    164MODULE_DESCRIPTION("driver for iPAQ Atmel micro keys");
    165MODULE_ALIAS("platform:ipaq-micro-keys");