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