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