xref: /openbmc/linux/drivers/input/keyboard/sunkbd.c (revision 14474950)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (c) 1999-2001 Vojtech Pavlik
4  */
5 
6 /*
7  * Sun keyboard driver for Linux
8  */
9 
10 /*
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/sched.h>
15 #include <linux/slab.h>
16 #include <linux/module.h>
17 #include <linux/interrupt.h>
18 #include <linux/input.h>
19 #include <linux/serio.h>
20 #include <linux/workqueue.h>
21 
22 #define DRIVER_DESC	"Sun keyboard driver"
23 
24 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
25 MODULE_DESCRIPTION(DRIVER_DESC);
26 MODULE_LICENSE("GPL");
27 
28 static unsigned char sunkbd_keycode[128] = {
29 	  0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
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 
59 struct sunkbd {
60 	unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
61 	struct input_dev *dev;
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;
68 	bool enabled;
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 
78 static irqreturn_t sunkbd_interrupt(struct serio *serio,
79 		unsigned char data, unsigned int flags)
80 {
81 	struct sunkbd *sunkbd = serio_get_drvdata(serio);
82 
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;
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 
101 	case SUNKBD_RET_RESET:
102 		schedule_work(&sunkbd->tq);
103 		sunkbd->reset = -1;
104 		break;
105 
106 	case SUNKBD_RET_LAYOUT:
107 		sunkbd->layout = -1;
108 		break;
109 
110 	case SUNKBD_RET_ALLUP: /* All keys released */
111 		break;
112 
113 	default:
114 		if (!sunkbd->enabled)
115 			break;
116 
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 		}
128 	}
129 out:
130 	return IRQ_HANDLED;
131 }
132 
133 /*
134  * sunkbd_event() handles events from the input module.
135  */
136 
137 static int sunkbd_event(struct input_dev *dev,
138 			unsigned int type, unsigned int code, int value)
139 {
140 	struct sunkbd *sunkbd = input_get_drvdata(dev);
141 
142 	switch (type) {
143 
144 	case EV_LED:
145 
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;
153 
154 	case EV_SND:
155 
156 		switch (code) {
157 
158 		case SND_CLICK:
159 			serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
160 			return 0;
161 
162 		case SND_BELL:
163 			serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
164 			return 0;
165 		}
166 
167 		break;
168 	}
169 
170 	return -1;
171 }
172 
173 /*
174  * sunkbd_initialize() checks for a Sun keyboard attached, and determines
175  * its type.
176  */
177 
178 static int sunkbd_initialize(struct sunkbd *sunkbd)
179 {
180 	sunkbd->reset = -2;
181 	serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
182 	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
183 	if (sunkbd->reset < 0)
184 		return -1;
185 
186 	sunkbd->type = sunkbd->reset;
187 
188 	if (sunkbd->type == 4) {	/* Type 4 keyboard */
189 		sunkbd->layout = -2;
190 		serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
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;
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 
207 static void sunkbd_reinit(struct work_struct *work)
208 {
209 	struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
210 
211 	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
212 
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));
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));
223 }
224 
225 static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
226 {
227 	serio_pause_rx(sunkbd->serio);
228 	sunkbd->enabled = enable;
229 	serio_continue_rx(sunkbd->serio);
230 }
231 
232 /*
233  * sunkbd_connect() probes for a Sun keyboard and fills the necessary
234  * structures.
235  */
236 
237 static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
238 {
239 	struct sunkbd *sunkbd;
240 	struct input_dev *input_dev;
241 	int err = -ENOMEM;
242 	int i;
243 
244 	sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
245 	input_dev = input_allocate_device();
246 	if (!sunkbd || !input_dev)
247 		goto fail1;
248 
249 	sunkbd->serio = serio;
250 	sunkbd->dev = input_dev;
251 	init_waitqueue_head(&sunkbd->wait);
252 	INIT_WORK(&sunkbd->tq, sunkbd_reinit);
253 	snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys);
254 
255 	serio_set_drvdata(serio, sunkbd);
256 
257 	err = serio_open(serio, drv);
258 	if (err)
259 		goto fail2;
260 
261 	if (sunkbd_initialize(sunkbd) < 0) {
262 		err = -ENODEV;
263 		goto fail3;
264 	}
265 
266 	snprintf(sunkbd->name, sizeof(sunkbd->name),
267 		 "Sun Type %d keyboard", sunkbd->type);
268 	memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
269 
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;
276 	input_dev->dev.parent = &serio->dev;
277 
278 	input_set_drvdata(input_dev, sunkbd);
279 
280 	input_dev->event = sunkbd_event;
281 
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);
287 
288 	input_dev->keycode = sunkbd->keycode;
289 	input_dev->keycodesize = sizeof(unsigned char);
290 	input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
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);
294 
295 	sunkbd_enable(sunkbd, true);
296 
297 	err = input_register_device(sunkbd->dev);
298 	if (err)
299 		goto fail4;
300 
301 	return 0;
302 
303  fail4:	sunkbd_enable(sunkbd, false);
304  fail3:	serio_close(serio);
305  fail2:	serio_set_drvdata(serio, NULL);
306  fail1:	input_free_device(input_dev);
307 	kfree(sunkbd);
308 	return err;
309 }
310 
311 /*
312  * sunkbd_disconnect() unregisters and closes behind us.
313  */
314 
315 static void sunkbd_disconnect(struct serio *serio)
316 {
317 	struct sunkbd *sunkbd = serio_get_drvdata(serio);
318 
319 	sunkbd_enable(sunkbd, false);
320 	input_unregister_device(sunkbd->dev);
321 	serio_close(serio);
322 	serio_set_drvdata(serio, NULL);
323 	kfree(sunkbd);
324 }
325 
326 static const struct serio_device_id sunkbd_serio_ids[] = {
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 
342 MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
343 
344 static 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 
355 module_serio_driver(sunkbd_drv);
356