sunkbd.c 8.8 KB

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