akbd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /* $OpenBSD: akbd.c,v 1.14 2014/01/26 17:48:08 miod Exp $ */
  2. /* $NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $ */
  3. /*
  4. * Copyright (C) 1998 Colin Wood
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. All advertising materials mentioning features or use of this software
  16. * must display the following acknowledgement:
  17. * This product includes software developed by Colin Wood.
  18. * 4. The name of the author may not be used to endorse or promote products
  19. * derived from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  22. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  23. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  24. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include <sys/param.h>
  33. #include <sys/timeout.h>
  34. #include <sys/kernel.h>
  35. #include <sys/device.h>
  36. #include <sys/systm.h>
  37. #include <dev/wscons/wsconsio.h>
  38. #include <dev/wscons/wskbdvar.h>
  39. #include <dev/wscons/wsksymdef.h>
  40. #include <dev/wscons/wsksymvar.h>
  41. #include <machine/autoconf.h>
  42. #include <machine/cpu.h>
  43. #include <dev/adb/adb.h>
  44. #include <dev/adb/akbdmap.h>
  45. #include <dev/adb/akbdvar.h>
  46. #include <dev/adb/keyboard.h>
  47. /*
  48. * Function declarations.
  49. */
  50. int akbdmatch(struct device *, void *, void *);
  51. void akbdattach(struct device *, struct device *, void *);
  52. /* Driver definition. */
  53. struct cfattach akbd_ca = {
  54. sizeof(struct akbd_softc), akbdmatch, akbdattach
  55. };
  56. struct cfdriver akbd_cd = {
  57. NULL, "akbd", DV_DULL
  58. };
  59. int akbd_enable(void *, int);
  60. void akbd_set_leds(void *, int);
  61. int akbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
  62. struct wskbd_accessops akbd_accessops = {
  63. akbd_enable,
  64. akbd_set_leds,
  65. akbd_ioctl,
  66. };
  67. struct wskbd_mapdata akbd_keymapdata = {
  68. akbd_keydesctab,
  69. #ifdef AKBD_LAYOUT
  70. AKBD_LAYOUT,
  71. #else
  72. KB_US | KB_DEFAULT,
  73. #endif
  74. };
  75. void akbd_adbcomplete(caddr_t, caddr_t, int);
  76. void akbd_capslockwrapper(struct akbd_softc *, int);
  77. void akbd_input(struct akbd_softc *, int);
  78. void akbd_processevent(struct akbd_softc *, adb_event_t *);
  79. #ifdef notyet
  80. u_char getleds(int);
  81. int setleds(struct akbd_softc *, u_char);
  82. void blinkleds(struct akbd_softc *);
  83. #endif
  84. int
  85. akbdmatch(struct device *parent, void *vcf, void *aux)
  86. {
  87. struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
  88. if (strcmp(aa_args->name, adb_device_name) != 0)
  89. return (0);
  90. if (aa_args->origaddr == ADBADDR_KBD)
  91. return (1);
  92. else
  93. return (0);
  94. }
  95. void
  96. akbdattach(struct device *parent, struct device *self, void *aux)
  97. {
  98. ADBSetInfoBlock adbinfo;
  99. struct akbd_softc *sc = (struct akbd_softc *)self;
  100. struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
  101. int error, kbd_done;
  102. short cmd;
  103. u_char buffer[9];
  104. struct wskbddev_attach_args a;
  105. static int akbd_console_initted;
  106. int wskbd_eligible = 1;
  107. sc->origaddr = aa_args->origaddr;
  108. sc->adbaddr = aa_args->adbaddr;
  109. sc->handler_id = aa_args->handler_id;
  110. sc->sc_leds = (u_int8_t)0x00; /* initially off */
  111. sc->sc_caps = 0;
  112. sc->sc_iso = 0;
  113. adbinfo.siServiceRtPtr = (Ptr)akbd_adbcomplete;
  114. adbinfo.siDataAreaAddr = (caddr_t)sc;
  115. printf(": ");
  116. switch (sc->handler_id) {
  117. case ADB_STDKBD:
  118. printf("standard keyboard\n");
  119. break;
  120. case ADB_ISOKBD:
  121. printf("standard keyboard (ISO layout)\n");
  122. sc->sc_iso = 1;
  123. break;
  124. case ADB_EXTKBD:
  125. cmd = ADBTALK(sc->adbaddr, 1);
  126. kbd_done =
  127. (adb_op_sync((Ptr)buffer, cmd) == 0);
  128. /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
  129. if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
  130. printf("Mouseman (non-EMP) pseudo keyboard\n");
  131. adbinfo.siServiceRtPtr = (Ptr)0;
  132. adbinfo.siDataAreaAddr = (Ptr)0;
  133. wskbd_eligible = 0;
  134. } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
  135. printf("Trackman (non-EMP) pseudo keyboard\n");
  136. adbinfo.siServiceRtPtr = (Ptr)0;
  137. adbinfo.siDataAreaAddr = (Ptr)0;
  138. wskbd_eligible = 0;
  139. } else {
  140. printf("extended keyboard\n");
  141. #ifdef notyet
  142. blinkleds(sc);
  143. #endif
  144. }
  145. break;
  146. case ADB_EXTISOKBD:
  147. printf("extended keyboard (ISO layout)\n");
  148. sc->sc_iso = 1;
  149. #ifdef notyet
  150. blinkleds(sc);
  151. #endif
  152. break;
  153. case ADB_KBDII:
  154. printf("keyboard II\n");
  155. break;
  156. case ADB_ISOKBDII:
  157. printf("keyboard II (ISO layout)\n");
  158. sc->sc_iso = 1;
  159. break;
  160. case ADB_PBKBD:
  161. printf("PowerBook keyboard\n");
  162. break;
  163. case ADB_PBISOKBD:
  164. printf("PowerBook keyboard (ISO layout)\n");
  165. sc->sc_iso = 1;
  166. break;
  167. case ADB_ADJKPD:
  168. printf("adjustable keypad\n");
  169. wskbd_eligible = 0;
  170. break;
  171. case ADB_ADJKBD:
  172. printf("adjustable keyboard\n");
  173. break;
  174. case ADB_ADJISOKBD:
  175. printf("adjustable keyboard (ISO layout)\n");
  176. sc->sc_iso = 1;
  177. break;
  178. case ADB_ADJJAPKBD:
  179. printf("adjustable keyboard (Japanese layout)\n");
  180. break;
  181. case ADB_PBEXTISOKBD:
  182. printf("PowerBook extended keyboard (ISO layout)\n");
  183. sc->sc_iso = 1;
  184. break;
  185. case ADB_PBEXTJAPKBD:
  186. printf("PowerBook extended keyboard (Japanese layout)\n");
  187. break;
  188. case ADB_JPKBDII:
  189. printf("keyboard II (Japanese layout)\n");
  190. break;
  191. case ADB_PBEXTKBD:
  192. printf("PowerBook extended keyboard\n");
  193. break;
  194. case ADB_DESIGNKBD:
  195. printf("extended keyboard\n");
  196. #ifdef notyet
  197. blinkleds(sc);
  198. #endif
  199. break;
  200. case ADB_PBJPKBD:
  201. printf("PowerBook keyboard (Japanese layout)\n");
  202. break;
  203. case ADB_PBG3JPKBD:
  204. printf("PowerBook G3 keyboard (Japanese layout)\n");
  205. break;
  206. case ADB_PBG4KBD:
  207. printf("PowerBook G4 keyboard (Inverted T)\n");
  208. break;
  209. case ADB_IBITISOKBD:
  210. printf("iBook keyboard with inverted T (ISO layout)\n");
  211. sc->sc_iso = 1;
  212. break;
  213. default:
  214. printf("mapped device (%d)\n", sc->handler_id);
  215. #if 0
  216. wskbd_eligible = 0;
  217. #endif
  218. break;
  219. }
  220. error = set_adb_info(&adbinfo, sc->adbaddr);
  221. #ifdef ADB_DEBUG
  222. if (adb_debug)
  223. printf("akbd: returned %d from set_adb_info\n", error);
  224. #endif
  225. if (akbd_is_console() && wskbd_eligible)
  226. a.console = (++akbd_console_initted == 1);
  227. else
  228. a.console = 0;
  229. a.keymap = &akbd_keymapdata;
  230. a.accessops = &akbd_accessops;
  231. a.accesscookie = sc;
  232. sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
  233. }
  234. /*
  235. * Handle putting the keyboard data received from the ADB into
  236. * an ADB event record.
  237. */
  238. void
  239. akbd_adbcomplete(caddr_t buffer, caddr_t data_area, int adb_command)
  240. {
  241. adb_event_t event;
  242. struct akbd_softc *sc;
  243. int adbaddr;
  244. #ifdef ADB_DEBUG
  245. int i;
  246. if (adb_debug)
  247. printf("adb: transaction completion\n");
  248. #endif
  249. adbaddr = ADB_CMDADDR(adb_command);
  250. sc = (struct akbd_softc *)data_area;
  251. event.byte_count = buffer[0];
  252. memcpy(event.bytes, buffer + 1, event.byte_count);
  253. #ifdef ADB_DEBUG
  254. if (adb_debug) {
  255. printf("akbd: from %d at %d (org %d) %d:", adbaddr,
  256. sc->handler_id, sc->origaddr, buffer[0]);
  257. for (i = 1; i <= buffer[0]; i++)
  258. printf(" %x", buffer[i]);
  259. printf("\n");
  260. }
  261. #endif
  262. if (sc->sc_wskbddev != NULL)
  263. akbd_processevent(sc, &event);
  264. }
  265. #ifdef notyet
  266. /*
  267. * Get the actual hardware LED state and convert it to softc format.
  268. */
  269. u_char
  270. getleds(int addr)
  271. {
  272. short cmd;
  273. u_char buffer[9], leds;
  274. leds = 0x00; /* all off */
  275. buffer[0] = 0;
  276. cmd = ADBTALK(addr, 2);
  277. if (adb_op_sync((Ptr)buffer, cmd) == 0 &&
  278. buffer[0] > 0)
  279. leds = ~(buffer[2]) & 0x07;
  280. return (leds);
  281. }
  282. /*
  283. * Set the keyboard LED's.
  284. *
  285. * Automatically translates from ioctl/softc format to the
  286. * actual keyboard register format
  287. */
  288. int
  289. setleds(struct akbd_softc *sc, u_char leds)
  290. {
  291. int addr;
  292. short cmd;
  293. u_char buffer[9];
  294. addr = sc->adbaddr;
  295. buffer[0] = 0;
  296. cmd = ADBTALK(addr, 2);
  297. if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
  298. return (EIO);
  299. leds = ~leds & 0x07;
  300. buffer[2] &= 0xf8;
  301. buffer[2] |= leds;
  302. cmd = ADBLISTEN(addr, 2);
  303. adb_op_sync((Ptr)buffer, cmd);
  304. /* talk R2 */
  305. cmd = ADBTALK(addr, 2);
  306. if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
  307. return (EIO);
  308. if ((buffer[2] & 0xf8) != leds)
  309. return (EIO);
  310. else
  311. return (0);
  312. }
  313. /*
  314. * Toggle all of the LED's on and off, just for show.
  315. */
  316. void
  317. blinkleds(struct akbd_softc *sc)
  318. {
  319. u_char origleds;
  320. origleds = getleds(sc->adbaddr);
  321. setleds(sc, LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK);
  322. delay(400000);
  323. setleds(sc, origleds);
  324. if (origleds & LED_NUMLOCK)
  325. sc->sc_leds |= WSKBD_LED_NUM;
  326. if (origleds & LED_CAPSLOCK)
  327. sc->sc_leds |= WSKBD_LED_CAPS;
  328. if (origleds & LED_SCROLL_LOCK)
  329. sc->sc_leds |= WSKBD_LED_SCROLL;
  330. }
  331. #endif
  332. int
  333. akbd_enable(void *v, int on)
  334. {
  335. return 0;
  336. }
  337. void
  338. akbd_set_leds(void *v, int on)
  339. {
  340. #ifdef notyet
  341. struct akbd_softc *sc = v;
  342. int leds;
  343. if (sc->sc_extended) {
  344. if (sc->sc_leds == on)
  345. return;
  346. leds = 0;
  347. if (on & WSKBD_LED_NUM)
  348. leds |= LED_NUMLOCK;
  349. if (on & WSKBD_LED_CAPS)
  350. leds |= LED_CAPSLOCK;
  351. if (on & WSKBD_LED_SCROLL)
  352. leds |= LED_SCROLL_LOCK;
  353. setleds(sc, leds);
  354. }
  355. #endif
  356. }
  357. int
  358. akbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
  359. {
  360. struct akbd_softc *sc = v;
  361. switch (cmd) {
  362. case WSKBDIO_GTYPE:
  363. *(int *)data = WSKBD_TYPE_ADB;
  364. return 0;
  365. case WSKBDIO_SETLEDS:
  366. akbd_set_leds(v, *(int *)data);
  367. return 0;
  368. case WSKBDIO_GETLEDS:
  369. *(int *)data = sc->sc_leds;
  370. return 0;
  371. #ifdef WSDISPLAY_COMPAT_RAWKBD
  372. case WSKBDIO_SETMODE:
  373. sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
  374. return (0);
  375. #endif
  376. default:
  377. return (-1);
  378. }
  379. }
  380. /*
  381. * The ``caps lock'' key is special: since on earlier keyboards, the physical
  382. * key stays down when pressed, we will get a notification of the key press,
  383. * but not of the key release. Then, when it is pressed again, we will not get
  384. * a notification of the key press, but will see the key release.
  385. *
  386. * This is not exactly true. We see the missing release and press events both
  387. * as the release of the power (reset) key.
  388. *
  389. * To avoid confusing them with real power key presses, we maintain two
  390. * states for the caps lock key: logically down (from wscons' point of view),
  391. * and ``physically'' down (from the adb messages point of view), to ignore
  392. * the power key. But since one may press the power key while the caps lock
  393. * is held down, we also have to remember the state of the power key... this
  394. * is quite messy.
  395. */
  396. /*
  397. * Values for caps lock state machine
  398. */
  399. #define CL_DOWN_ADB 0x01
  400. #define CL_DOWN_LOGICAL 0x02
  401. #define CL_DOWN_RESET 0x04
  402. /*
  403. * Given a keyboard ADB event, decode the keycodes and pass them to wskbd.
  404. */
  405. void
  406. akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
  407. {
  408. switch (event->byte_count) {
  409. case 1:
  410. akbd_capslockwrapper(sc, event->bytes[0]);
  411. break;
  412. case 2:
  413. /*
  414. * The reset (or power) key sends 0x7f7f on press and
  415. * 0xffff on release, and we ignore it.
  416. */
  417. if (event->bytes[0] == event->bytes[1] &&
  418. ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) {
  419. if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET))
  420. SET(sc->sc_caps, CL_DOWN_RESET);
  421. else {
  422. if (ISSET(sc->sc_caps, CL_DOWN_RESET))
  423. CLR(sc->sc_caps, CL_DOWN_RESET);
  424. else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) {
  425. akbd_input(sc, ISSET(sc->sc_caps,
  426. CL_DOWN_LOGICAL) ?
  427. ADBK_KEYDOWN(ADBK_CAPSLOCK) :
  428. ADBK_KEYUP(ADBK_CAPSLOCK));
  429. sc->sc_caps ^= CL_DOWN_LOGICAL;
  430. }
  431. }
  432. } else {
  433. akbd_capslockwrapper(sc, event->bytes[0]);
  434. akbd_capslockwrapper(sc, event->bytes[1]);
  435. }
  436. break;
  437. default:
  438. #ifdef DIAGNOSTIC
  439. printf("%s: unexpected message length %d\n",
  440. sc->sc_dev.dv_xname, event->byte_count);
  441. #endif
  442. break;
  443. }
  444. }
  445. void
  446. akbd_capslockwrapper(struct akbd_softc *sc, int key)
  447. {
  448. if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK)
  449. sc->sc_caps ^= CL_DOWN_ADB;
  450. if (key != 0xff)
  451. akbd_input(sc, key);
  452. }
  453. static inline int
  454. akbd_iso_swap(int keycode)
  455. {
  456. switch (keycode) {
  457. case 10:
  458. return (50);
  459. case 50:
  460. return (10);
  461. default:
  462. return (keycode);
  463. }
  464. }
  465. int adb_polledkey;
  466. void
  467. akbd_input(struct akbd_softc *sc, int key)
  468. {
  469. int press, val;
  470. int type;
  471. press = ADBK_PRESS(key);
  472. val = ADBK_KEYVAL(key);
  473. if (sc->sc_iso)
  474. val = akbd_iso_swap(val);
  475. type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
  476. if (adb_polling) {
  477. adb_polledkey = key;
  478. #ifdef WSDISPLAY_COMPAT_RAWKBD
  479. } else if (sc->sc_rawkbd) {
  480. char cbuf[2];
  481. int c, j, s;
  482. j = 0;
  483. c = keyboard[val];
  484. if (c == 0) {
  485. return; /* XXX */
  486. }
  487. if (c & 0x80)
  488. cbuf[j++] = 0xe0;
  489. cbuf[j] = c & 0x7f;
  490. if (type == WSCONS_EVENT_KEY_UP)
  491. cbuf[j] |= 0x80;
  492. j++;
  493. s = spltty();
  494. wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
  495. splx(s);
  496. #endif
  497. } else {
  498. wskbd_input(sc->sc_wskbddev, type, val);
  499. }
  500. }