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