drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / input / keyboard / sunkbd.c
CommitLineData
1da177e4 1/*
1da177e4
LT
2 * Copyright (c) 1999-2001 Vojtech Pavlik
3 */
4
5/*
6 * Sun keyboard driver for Linux
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Should you need to contact me, the author, you can do so either by
25 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
26 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
27 */
28
29#include <linux/delay.h>
d43c36dc 30#include <linux/sched.h>
1da177e4
LT
31#include <linux/slab.h>
32#include <linux/module.h>
33#include <linux/interrupt.h>
34#include <linux/init.h>
35#include <linux/input.h>
36#include <linux/serio.h>
37#include <linux/workqueue.h>
38
39#define DRIVER_DESC "Sun keyboard driver"
40
41MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
42MODULE_DESCRIPTION(DRIVER_DESC);
43MODULE_LICENSE("GPL");
44
45static unsigned char sunkbd_keycode[128] = {
8d9a9ae3 46 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
1da177e4
LT
47 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3,
48 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
49 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
50 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32,
51 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
52 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
53 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78
54};
55
56#define SUNKBD_CMD_RESET 0x1
57#define SUNKBD_CMD_BELLON 0x2
58#define SUNKBD_CMD_BELLOFF 0x3
59#define SUNKBD_CMD_CLICK 0xa
60#define SUNKBD_CMD_NOCLICK 0xb
61#define SUNKBD_CMD_SETLED 0xe
62#define SUNKBD_CMD_LAYOUT 0xf
63
64#define SUNKBD_RET_RESET 0xff
65#define SUNKBD_RET_ALLUP 0x7f
66#define SUNKBD_RET_LAYOUT 0xfe
67
68#define SUNKBD_LAYOUT_5_MASK 0x20
69#define SUNKBD_RELEASE 0x80
70#define SUNKBD_KEY 0x7f
71
72/*
73 * Per-keyboard data.
74 */
75
76struct sunkbd {
7cac9cd9 77 unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
3c42f0c3 78 struct input_dev *dev;
1da177e4
LT
79 struct serio *serio;
80 struct work_struct tq;
81 wait_queue_head_t wait;
82 char name[64];
83 char phys[32];
84 char type;
7cac9cd9 85 bool enabled;
1da177e4
LT
86 volatile s8 reset;
87 volatile s8 layout;
88};
89
90/*
91 * sunkbd_interrupt() is called by the low level driver when a character
92 * is received.
93 */
94
95static irqreturn_t sunkbd_interrupt(struct serio *serio,
7d12e780 96 unsigned char data, unsigned int flags)
1da177e4 97{
7cac9cd9 98 struct sunkbd *sunkbd = serio_get_drvdata(serio);
1da177e4 99
7cac9cd9
DT
100 if (sunkbd->reset <= -1) {
101 /*
102 * If cp[i] is 0xff, sunkbd->reset will stay -1.
103 * The keyboard sends 0xff 0xff 0xID on powerup.
104 */
105 sunkbd->reset = data;
1da177e4
LT
106 wake_up_interruptible(&sunkbd->wait);
107 goto out;
108 }
109
110 if (sunkbd->layout == -1) {
111 sunkbd->layout = data;
112 wake_up_interruptible(&sunkbd->wait);
113 goto out;
114 }
115
116 switch (data) {
117
7cac9cd9
DT
118 case SUNKBD_RET_RESET:
119 schedule_work(&sunkbd->tq);
120 sunkbd->reset = -1;
121 break;
1da177e4 122
7cac9cd9
DT
123 case SUNKBD_RET_LAYOUT:
124 sunkbd->layout = -1;
125 break;
1da177e4 126
7cac9cd9
DT
127 case SUNKBD_RET_ALLUP: /* All keys released */
128 break;
129
130 default:
131 if (!sunkbd->enabled)
1da177e4
LT
132 break;
133
7cac9cd9
DT
134 if (sunkbd->keycode[data & SUNKBD_KEY]) {
135 input_report_key(sunkbd->dev,
136 sunkbd->keycode[data & SUNKBD_KEY],
137 !(data & SUNKBD_RELEASE));
138 input_sync(sunkbd->dev);
139 } else {
140 printk(KERN_WARNING
141 "sunkbd.c: Unknown key (scancode %#x) %s.\n",
142 data & SUNKBD_KEY,
143 data & SUNKBD_RELEASE ? "released" : "pressed");
144 }
1da177e4
LT
145 }
146out:
147 return IRQ_HANDLED;
148}
149
150/*
151 * sunkbd_event() handles events from the input module.
152 */
153
7cac9cd9
DT
154static int sunkbd_event(struct input_dev *dev,
155 unsigned int type, unsigned int code, int value)
1da177e4 156{
b356872f 157 struct sunkbd *sunkbd = input_get_drvdata(dev);
1da177e4
LT
158
159 switch (type) {
160
7cac9cd9 161 case EV_LED:
1da177e4 162
7cac9cd9
DT
163 serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
164 serio_write(sunkbd->serio,
165 (!!test_bit(LED_CAPSL, dev->led) << 3) |
166 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
167 (!!test_bit(LED_COMPOSE, dev->led) << 1) |
168 !!test_bit(LED_NUML, dev->led));
169 return 0;
1da177e4 170
7cac9cd9 171 case EV_SND:
1da177e4 172
7cac9cd9 173 switch (code) {
1da177e4 174
7cac9cd9
DT
175 case SND_CLICK:
176 serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
177 return 0;
1da177e4 178
7cac9cd9
DT
179 case SND_BELL:
180 serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
181 return 0;
182 }
1da177e4 183
7cac9cd9 184 break;
1da177e4
LT
185 }
186
187 return -1;
188}
189
190/*
191 * sunkbd_initialize() checks for a Sun keyboard attached, and determines
192 * its type.
193 */
194
195static int sunkbd_initialize(struct sunkbd *sunkbd)
196{
197 sunkbd->reset = -2;
dd0d5443 198 serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
1da177e4 199 wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
3c42f0c3 200 if (sunkbd->reset < 0)
1da177e4
LT
201 return -1;
202
203 sunkbd->type = sunkbd->reset;
204
205 if (sunkbd->type == 4) { /* Type 4 keyboard */
206 sunkbd->layout = -2;
dd0d5443 207 serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
7cac9cd9
DT
208 wait_event_interruptible_timeout(sunkbd->wait,
209 sunkbd->layout >= 0, HZ / 4);
210 if (sunkbd->layout < 0)
211 return -1;
212 if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
213 sunkbd->type = 5;
1da177e4
LT
214 }
215
216 return 0;
217}
218
219/*
220 * sunkbd_reinit() sets leds and beeps to a state the computer remembers they
221 * were in.
222 */
223
c4028958 224static void sunkbd_reinit(struct work_struct *work)
1da177e4 225{
c4028958 226 struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
1da177e4
LT
227
228 wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
229
dd0d5443
DT
230 serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
231 serio_write(sunkbd->serio,
232 (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) |
233 (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
234 (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
235 !!test_bit(LED_NUML, sunkbd->dev->led));
7cac9cd9
DT
236 serio_write(sunkbd->serio,
237 SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
238 serio_write(sunkbd->serio,
239 SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
3c42f0c3
DT
240}
241
7cac9cd9 242static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
3c42f0c3
DT
243{
244 serio_pause_rx(sunkbd->serio);
9bc83dcf 245 sunkbd->enabled = enable;
3c42f0c3 246 serio_continue_rx(sunkbd->serio);
1da177e4
LT
247}
248
249/*
7cac9cd9
DT
250 * sunkbd_connect() probes for a Sun keyboard and fills the necessary
251 * structures.
1da177e4
LT
252 */
253
254static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
255{
256 struct sunkbd *sunkbd;
3c42f0c3
DT
257 struct input_dev *input_dev;
258 int err = -ENOMEM;
1da177e4 259 int i;
1da177e4 260
3c42f0c3
DT
261 sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
262 input_dev = input_allocate_device();
263 if (!sunkbd || !input_dev)
2b03b60e 264 goto fail1;
1da177e4
LT
265
266 sunkbd->serio = serio;
3c42f0c3
DT
267 sunkbd->dev = input_dev;
268 init_waitqueue_head(&sunkbd->wait);
c4028958 269 INIT_WORK(&sunkbd->tq, sunkbd_reinit);
3c42f0c3 270 snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys);
1da177e4
LT
271
272 serio_set_drvdata(serio, sunkbd);
273
274 err = serio_open(serio, drv);
3c42f0c3 275 if (err)
2b03b60e 276 goto fail2;
1da177e4
LT
277
278 if (sunkbd_initialize(sunkbd) < 0) {
2b03b60e
DT
279 err = -ENODEV;
280 goto fail3;
1da177e4
LT
281 }
282
7cac9cd9
DT
283 snprintf(sunkbd->name, sizeof(sunkbd->name),
284 "Sun Type %d keyboard", sunkbd->type);
1da177e4 285 memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
1da177e4 286
3c42f0c3
DT
287 input_dev->name = sunkbd->name;
288 input_dev->phys = sunkbd->phys;
289 input_dev->id.bustype = BUS_RS232;
290 input_dev->id.vendor = SERIO_SUNKBD;
291 input_dev->id.product = sunkbd->type;
292 input_dev->id.version = 0x0100;
469ba4df 293 input_dev->dev.parent = &serio->dev;
b356872f
DT
294
295 input_set_drvdata(input_dev, sunkbd);
296
3c42f0c3
DT
297 input_dev->event = sunkbd_event;
298
7b19ada2
JS
299 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
300 BIT_MASK(EV_SND) | BIT_MASK(EV_REP);
301 input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) |
302 BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML);
303 input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL);
3c42f0c3
DT
304
305 input_dev->keycode = sunkbd->keycode;
306 input_dev->keycodesize = sizeof(unsigned char);
307 input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
7cac9cd9
DT
308 for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
309 __set_bit(sunkbd->keycode[i], input_dev->keybit);
310 __clear_bit(KEY_RESERVED, input_dev->keybit);
1da177e4 311
7cac9cd9 312 sunkbd_enable(sunkbd, true);
2b03b60e
DT
313
314 err = input_register_device(sunkbd->dev);
315 if (err)
316 goto fail4;
317
1da177e4 318 return 0;
3c42f0c3 319
7cac9cd9 320 fail4: sunkbd_enable(sunkbd, false);
2b03b60e
DT
321 fail3: serio_close(serio);
322 fail2: serio_set_drvdata(serio, NULL);
323 fail1: input_free_device(input_dev);
3c42f0c3
DT
324 kfree(sunkbd);
325 return err;
1da177e4
LT
326}
327
328/*
329 * sunkbd_disconnect() unregisters and closes behind us.
330 */
331
332static void sunkbd_disconnect(struct serio *serio)
333{
334 struct sunkbd *sunkbd = serio_get_drvdata(serio);
3c42f0c3 335
7cac9cd9 336 sunkbd_enable(sunkbd, false);
3c42f0c3 337 input_unregister_device(sunkbd->dev);
1da177e4
LT
338 serio_close(serio);
339 serio_set_drvdata(serio, NULL);
340 kfree(sunkbd);
341}
342
343static struct serio_device_id sunkbd_serio_ids[] = {
344 {
345 .type = SERIO_RS232,
346 .proto = SERIO_SUNKBD,
347 .id = SERIO_ANY,
348 .extra = SERIO_ANY,
349 },
350 {
351 .type = SERIO_RS232,
352 .proto = SERIO_UNKNOWN, /* sunkbd does probe */
353 .id = SERIO_ANY,
354 .extra = SERIO_ANY,
355 },
356 { 0 }
357};
358
359MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
360
361static struct serio_driver sunkbd_drv = {
362 .driver = {
363 .name = "sunkbd",
364 },
365 .description = DRIVER_DESC,
366 .id_table = sunkbd_serio_ids,
367 .interrupt = sunkbd_interrupt,
368 .connect = sunkbd_connect,
369 .disconnect = sunkbd_disconnect,
370};
371
65ac9f7a 372module_serio_driver(sunkbd_drv);