Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/misc/cobalt_btns.c
15109 views
1
/*
2
* Cobalt button interface driver.
3
*
4
* Copyright (C) 2007-2008 Yoichi Yuasa <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
#include <linux/init.h>
21
#include <linux/input-polldev.h>
22
#include <linux/ioport.h>
23
#include <linux/module.h>
24
#include <linux/platform_device.h>
25
#include <linux/slab.h>
26
27
#define BUTTONS_POLL_INTERVAL 30 /* msec */
28
#define BUTTONS_COUNT_THRESHOLD 3
29
#define BUTTONS_STATUS_MASK 0xfe000000
30
31
static const unsigned short cobalt_map[] = {
32
KEY_RESERVED,
33
KEY_RESTART,
34
KEY_LEFT,
35
KEY_UP,
36
KEY_DOWN,
37
KEY_RIGHT,
38
KEY_ENTER,
39
KEY_SELECT
40
};
41
42
struct buttons_dev {
43
struct input_polled_dev *poll_dev;
44
unsigned short keymap[ARRAY_SIZE(cobalt_map)];
45
int count[ARRAY_SIZE(cobalt_map)];
46
void __iomem *reg;
47
};
48
49
static void handle_buttons(struct input_polled_dev *dev)
50
{
51
struct buttons_dev *bdev = dev->private;
52
struct input_dev *input = dev->input;
53
uint32_t status;
54
int i;
55
56
status = ~readl(bdev->reg) >> 24;
57
58
for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
59
if (status & (1U << i)) {
60
if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
61
input_event(input, EV_MSC, MSC_SCAN, i);
62
input_report_key(input, bdev->keymap[i], 1);
63
input_sync(input);
64
}
65
} else {
66
if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
67
input_event(input, EV_MSC, MSC_SCAN, i);
68
input_report_key(input, bdev->keymap[i], 0);
69
input_sync(input);
70
}
71
bdev->count[i] = 0;
72
}
73
}
74
}
75
76
static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
77
{
78
struct buttons_dev *bdev;
79
struct input_polled_dev *poll_dev;
80
struct input_dev *input;
81
struct resource *res;
82
int error, i;
83
84
bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);
85
poll_dev = input_allocate_polled_device();
86
if (!bdev || !poll_dev) {
87
error = -ENOMEM;
88
goto err_free_mem;
89
}
90
91
memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
92
93
poll_dev->private = bdev;
94
poll_dev->poll = handle_buttons;
95
poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
96
97
input = poll_dev->input;
98
input->name = "Cobalt buttons";
99
input->phys = "cobalt/input0";
100
input->id.bustype = BUS_HOST;
101
input->dev.parent = &pdev->dev;
102
103
input->keycode = bdev->keymap;
104
input->keycodemax = ARRAY_SIZE(bdev->keymap);
105
input->keycodesize = sizeof(unsigned short);
106
107
input_set_capability(input, EV_MSC, MSC_SCAN);
108
__set_bit(EV_KEY, input->evbit);
109
for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)
110
__set_bit(bdev->keymap[i], input->keybit);
111
__clear_bit(KEY_RESERVED, input->keybit);
112
113
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
114
if (!res) {
115
error = -EBUSY;
116
goto err_free_mem;
117
}
118
119
bdev->poll_dev = poll_dev;
120
bdev->reg = ioremap(res->start, resource_size(res));
121
dev_set_drvdata(&pdev->dev, bdev);
122
123
error = input_register_polled_device(poll_dev);
124
if (error)
125
goto err_iounmap;
126
127
return 0;
128
129
err_iounmap:
130
iounmap(bdev->reg);
131
err_free_mem:
132
input_free_polled_device(poll_dev);
133
kfree(bdev);
134
dev_set_drvdata(&pdev->dev, NULL);
135
return error;
136
}
137
138
static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
139
{
140
struct device *dev = &pdev->dev;
141
struct buttons_dev *bdev = dev_get_drvdata(dev);
142
143
input_unregister_polled_device(bdev->poll_dev);
144
input_free_polled_device(bdev->poll_dev);
145
iounmap(bdev->reg);
146
kfree(bdev);
147
dev_set_drvdata(dev, NULL);
148
149
return 0;
150
}
151
152
MODULE_AUTHOR("Yoichi Yuasa <[email protected]>");
153
MODULE_DESCRIPTION("Cobalt button interface driver");
154
MODULE_LICENSE("GPL");
155
/* work with hotplug and coldplug */
156
MODULE_ALIAS("platform:Cobalt buttons");
157
158
static struct platform_driver cobalt_buttons_driver = {
159
.probe = cobalt_buttons_probe,
160
.remove = __devexit_p(cobalt_buttons_remove),
161
.driver = {
162
.name = "Cobalt buttons",
163
.owner = THIS_MODULE,
164
},
165
};
166
167
static int __init cobalt_buttons_init(void)
168
{
169
return platform_driver_register(&cobalt_buttons_driver);
170
}
171
172
static void __exit cobalt_buttons_exit(void)
173
{
174
platform_driver_unregister(&cobalt_buttons_driver);
175
}
176
177
module_init(cobalt_buttons_init);
178
module_exit(cobalt_buttons_exit);
179
180