xref: /linux/drivers/input/keyboard/newtonkbd.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  Copyright (c) 2000 Justin Cormack
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds /*
71da177e4SLinus Torvalds  * Newton keyboard driver for Linux
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/slab.h>
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/input.h>
131da177e4SLinus Torvalds #include <linux/serio.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #define DRIVER_DESC	"Newton keyboard driver"
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>");
181da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
191da177e4SLinus Torvalds MODULE_LICENSE("GPL");
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #define NKBD_KEY	0x7f
221da177e4SLinus Torvalds #define NKBD_PRESS	0x80
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds static unsigned char nkbd_keycode[128] = {
251da177e4SLinus Torvalds 	KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
261da177e4SLinus Torvalds 	KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
271da177e4SLinus Torvalds 	KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
281da177e4SLinus Torvalds 	KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O,
291da177e4SLinus Torvalds 	KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE,
301da177e4SLinus Torvalds 	KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT,
311da177e4SLinus Torvalds 	KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA,
321da177e4SLinus Torvalds 	KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0,
331da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
341da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371da177e4SLinus Torvalds 	KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
381da177e4SLinus Torvalds };
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds struct nkbd {
411da177e4SLinus Torvalds 	unsigned char keycode[128];
423c42f0c3SDmitry Torokhov 	struct input_dev *dev;
431da177e4SLinus Torvalds 	struct serio *serio;
441da177e4SLinus Torvalds 	char phys[32];
451da177e4SLinus Torvalds };
461da177e4SLinus Torvalds 
nkbd_interrupt(struct serio * serio,unsigned char data,unsigned int flags)471da177e4SLinus Torvalds static irqreturn_t nkbd_interrupt(struct serio *serio,
487d12e780SDavid Howells 		unsigned char data, unsigned int flags)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	struct nkbd *nkbd = serio_get_drvdata(serio);
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	/* invalid scan codes are probably the init sequence, so we ignore them */
531da177e4SLinus Torvalds 	if (nkbd->keycode[data & NKBD_KEY]) {
543c42f0c3SDmitry Torokhov 		input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
553c42f0c3SDmitry Torokhov 		input_sync(nkbd->dev);
561da177e4SLinus Torvalds 	}
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	else if (data == 0xe7) /* end of init sequence */
593c42f0c3SDmitry Torokhov 		printk(KERN_INFO "input: %s on %s\n", nkbd->dev->name, serio->phys);
601da177e4SLinus Torvalds 	return IRQ_HANDLED;
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
nkbd_connect(struct serio * serio,struct serio_driver * drv)641da177e4SLinus Torvalds static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	struct nkbd *nkbd;
673c42f0c3SDmitry Torokhov 	struct input_dev *input_dev;
683c42f0c3SDmitry Torokhov 	int err = -ENOMEM;
691da177e4SLinus Torvalds 	int i;
701da177e4SLinus Torvalds 
71*bb8706a4SErick Archer 	nkbd = kzalloc(sizeof(*nkbd), GFP_KERNEL);
723c42f0c3SDmitry Torokhov 	input_dev = input_allocate_device();
733c42f0c3SDmitry Torokhov 	if (!nkbd || !input_dev)
742b03b60eSDmitry Torokhov 		goto fail1;
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	nkbd->serio = serio;
773c42f0c3SDmitry Torokhov 	nkbd->dev = input_dev;
78ea08c6faSDmitry Torokhov 	snprintf(nkbd->phys, sizeof(nkbd->phys), "%s/input0", serio->phys);
793c42f0c3SDmitry Torokhov 	memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
801da177e4SLinus Torvalds 
813c42f0c3SDmitry Torokhov 	input_dev->name = "Newton Keyboard";
823c42f0c3SDmitry Torokhov 	input_dev->phys = nkbd->phys;
833c42f0c3SDmitry Torokhov 	input_dev->id.bustype = BUS_RS232;
843c42f0c3SDmitry Torokhov 	input_dev->id.vendor = SERIO_NEWTON;
853c42f0c3SDmitry Torokhov 	input_dev->id.product = 0x0001;
863c42f0c3SDmitry Torokhov 	input_dev->id.version = 0x0100;
87469ba4dfSDmitry Torokhov 	input_dev->dev.parent = &serio->dev;
883c42f0c3SDmitry Torokhov 
897b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
903c42f0c3SDmitry Torokhov 	input_dev->keycode = nkbd->keycode;
913c42f0c3SDmitry Torokhov 	input_dev->keycodesize = sizeof(unsigned char);
923c42f0c3SDmitry Torokhov 	input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode);
933c42f0c3SDmitry Torokhov 	for (i = 0; i < 128; i++)
943c42f0c3SDmitry Torokhov 		set_bit(nkbd->keycode[i], input_dev->keybit);
953c42f0c3SDmitry Torokhov 	clear_bit(0, input_dev->keybit);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	serio_set_drvdata(serio, nkbd);
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	err = serio_open(serio, drv);
1003c42f0c3SDmitry Torokhov 	if (err)
1012b03b60eSDmitry Torokhov 		goto fail2;
1023c42f0c3SDmitry Torokhov 
1032b03b60eSDmitry Torokhov 	err = input_register_device(nkbd->dev);
1042b03b60eSDmitry Torokhov 	if (err)
1052b03b60eSDmitry Torokhov 		goto fail3;
1062b03b60eSDmitry Torokhov 
1073c42f0c3SDmitry Torokhov 	return 0;
1083c42f0c3SDmitry Torokhov 
1092b03b60eSDmitry Torokhov  fail3:	serio_close(serio);
1102b03b60eSDmitry Torokhov  fail2:	serio_set_drvdata(serio, NULL);
1112b03b60eSDmitry Torokhov  fail1:	input_free_device(input_dev);
1121da177e4SLinus Torvalds 	kfree(nkbd);
1131da177e4SLinus Torvalds 	return err;
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds 
nkbd_disconnect(struct serio * serio)1161da177e4SLinus Torvalds static void nkbd_disconnect(struct serio *serio)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds 	struct nkbd *nkbd = serio_get_drvdata(serio);
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	serio_close(serio);
1211da177e4SLinus Torvalds 	serio_set_drvdata(serio, NULL);
1223c42f0c3SDmitry Torokhov 	input_unregister_device(nkbd->dev);
1231da177e4SLinus Torvalds 	kfree(nkbd);
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds 
1269780930aSArvind Yadav static const struct serio_device_id nkbd_serio_ids[] = {
1271da177e4SLinus Torvalds 	{
1281da177e4SLinus Torvalds 		.type	= SERIO_RS232,
1291da177e4SLinus Torvalds 		.proto	= SERIO_NEWTON,
1301da177e4SLinus Torvalds 		.id	= SERIO_ANY,
1311da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
1321da177e4SLinus Torvalds 	},
1331da177e4SLinus Torvalds 	{ 0 }
1341da177e4SLinus Torvalds };
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, nkbd_serio_ids);
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds static struct serio_driver nkbd_drv = {
1391da177e4SLinus Torvalds 	.driver		= {
1401da177e4SLinus Torvalds 		.name	= "newtonkbd",
1411da177e4SLinus Torvalds 	},
1421da177e4SLinus Torvalds 	.description	= DRIVER_DESC,
1431da177e4SLinus Torvalds 	.id_table	= nkbd_serio_ids,
1441da177e4SLinus Torvalds 	.interrupt	= nkbd_interrupt,
1451da177e4SLinus Torvalds 	.connect	= nkbd_connect,
1461da177e4SLinus Torvalds 	.disconnect	= nkbd_disconnect,
1471da177e4SLinus Torvalds };
1481da177e4SLinus Torvalds 
14965ac9f7aSAxel Lin module_serio_driver(nkbd_drv);
150