zs_kbd.c revision 1.1 1 /* $NetBSD: zs_kbd.c,v 1.1 2004/07/08 22:30:53 sekiya Exp $ */
2
3 /*
4 * Copyright (c) 2004 Steve Rumble
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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * IP12/IP20 serial keyboard driver attached to zs channel 0 at 600bps.
32 * This layer is the parent of wskbd.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: zs_kbd.c,v 1.1 2004/07/08 22:30:53 sekiya Exp $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/conf.h>
41 #include <sys/device.h>
42
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wscons/wskbdvar.h>
45 #include <dev/wscons/wsksymdef.h>
46 #include <dev/wscons/wsksymvar.h>
47
48 #include <dev/ic/z8530reg.h>
49 #include <machine/machtype.h>
50 #include <machine/z8530var.h>
51
52 #define ZSKBD_BAUD 600
53 #define ZSKBD_TXQ_LEN 16 /* power of 2 */
54 #define ZSKBD_RXQ_LEN 64 /* power of 2 */
55
56 #define ZSKBD_DIP_SYNC 0x6E
57 #define ZSKBD_KEY_UP 0x80
58
59 struct zskbd_softc {
60 struct device sc_dev;
61
62 /* transmit tail-chasing fifo */
63 u_char txq[ZSKBD_TXQ_LEN];
64 u_int txq_head;
65 u_int txq_tail;
66
67 /* receive tail-chasing fifo */
68 u_char rxq[ZSKBD_RXQ_LEN];
69 u_int rxq_head;
70 u_int rxq_tail;
71
72 /* state */
73 #define TX_READY 0x1
74 #define RX_DIP 0x2
75 u_int state;
76
77 /* keyboard configuration */
78 #define ZSKBD_CTRL_A 0x0
79 #define ZSKBD_CTRL_A_SBEEP 0x2 /* 200 ms */
80 #define ZSKBD_CTRL_A_LBEEP 0x4 /* 1000 ms */
81 #define ZSKBD_CTRL_A_NOCLICK 0x8 /* turn off keyboard click */
82 #define ZSKBD_CTRL_A_RCB 0x10 /* request config byte */
83 #define ZSKBD_CTRL_A_NUMLK 0x20 /* num lock led */
84 #define ZSKBD_CTRL_A_CAPSLK 0x40 /* caps lock led */
85 #define ZSKBD_CTRL_A_AUTOREP 0x80 /* auto-repeat after 650 ms, 28x/sec */
86
87 #define ZSKBD_CTRL_B 0x1
88 #define ZSKBD_CTRL_B_CMPL_DS1_2 0x2 /* complement of ds1+ds2 (num+capslk) */
89 #define ZSKBD_CTRL_B_SCRLK 0x4 /* scroll lock light */
90 #define ZSKBD_CTRL_B_L1 0x8 /* user-configurable lights */
91 #define ZSKBD_CTRL_B_L2 0x10
92 #define ZSKBD_CTRL_B_L3 0x20
93 #define ZSKBD_CTRL_B_L4 0x40
94 u_char kbd_conf[2];
95
96 /* dip switch settings */
97 u_char dip;
98
99 /* wscons glue */
100 struct device *wskbddev;
101 int enabled;
102 };
103
104 static int zskbd_match(struct device *, struct cfdata *, void *);
105 static void zskbd_attach(struct device *, struct device *, void *);
106 static void zskbd_rxint(struct zs_chanstate *);
107 static void zskbd_stint(struct zs_chanstate *, int);
108 static void zskbd_txint(struct zs_chanstate *);
109 static void zskbd_softint(struct zs_chanstate *);
110 static void zskbd_send(struct zs_chanstate *, u_char *, u_int);
111 static void zskbd_ctrl(struct zs_chanstate *, u_char, u_char,
112 u_char, u_char);
113
114 static void zskbd_wskbd_input(struct zs_chanstate *, u_char);
115 static int zskbd_wskbd_enable(void *, int);
116 static void zskbd_wskbd_set_leds(void *, int);
117 static int zskbd_wskbd_get_leds(void *);
118 static void zskbd_wskbd_set_keyclick(void *, int);
119 static int zskbd_wskbd_get_keyclick(void *);
120 static int zskbd_wskbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
121
122 void zskbd_cnattach(int, int);
123 static void zskbd_wskbd_getc(void *, u_int *, int *);
124 static void zskbd_wskbd_pollc(void *, int);
125 static void zskbd_wskbd_bell(void *, u_int, u_int, u_int);
126
127 extern struct zschan *zs_get_chan_addr(int, int);
128 extern int zs_getc(void *);
129 extern void zs_putc(void *, int);
130
131 CFATTACH_DECL(zskbd, sizeof(struct zskbd_softc),
132 zskbd_match, zskbd_attach, NULL, NULL);
133
134 static struct zsops zskbd_zsops = {
135 zskbd_rxint,
136 zskbd_stint,
137 zskbd_txint,
138 zskbd_softint
139 };
140
141 extern const struct wscons_keydesc wssgi_keydesctab[];
142 const struct wskbd_mapdata sgikbd_wskbd_keymapdata = {
143 wssgi_keydesctab, KB_US
144 };
145
146 const struct wskbd_accessops zskbd_wskbd_accessops = {
147 zskbd_wskbd_enable,
148 zskbd_wskbd_set_leds,
149 zskbd_wskbd_ioctl
150 };
151
152 const struct wskbd_consops zskbd_wskbd_consops = {
153 zskbd_wskbd_getc,
154 zskbd_wskbd_pollc,
155 zskbd_wskbd_bell
156 };
157
158 static int
159 zskbd_match(struct device *parent, struct cfdata *cf, void *aux)
160 {
161 if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20) {
162 struct zsc_attach_args *args = aux;
163
164 if (args->channel == 0)
165 return (1);
166 }
167
168 return (0);
169 }
170
171 static void
172 zskbd_attach(struct device *parent, struct device *self, void *aux)
173 {
174 int s, channel;
175 struct zsc_softc *zsc = (struct zsc_softc *)parent;
176 struct zskbd_softc *sc = (struct zskbd_softc *)self;
177 struct zsc_attach_args *args = aux;
178 struct zs_chanstate *cs;
179 struct wskbddev_attach_args wskaa;
180
181 /* Establish ourself with the MD z8530 driver */
182 channel = args->channel;
183 cs = zsc->zsc_cs[channel];
184 cs->cs_ops = &zskbd_zsops;
185 cs->cs_private = sc;
186
187 sc->txq_tail = 0;
188 sc->txq_tail = 0;
189 sc->rxq_tail = 0;
190 sc->rxq_tail = 0;
191 sc->state = TX_READY;
192 sc->dip = 0;
193 sc->kbd_conf[ZSKBD_CTRL_A] = 0;
194 sc->kbd_conf[ZSKBD_CTRL_B] = 0;
195 sc->enabled = 0;
196
197 printf(": baud rate %d\n", ZSKBD_BAUD);
198
199 s = splzs();
200 zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET);
201 cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE;
202 cs->cs_preg[4] = (cs->cs_preg[4] & ZSWR4_CLK_MASK) |
203 (ZSWR4_ONESB | ZSWR4_PARENB); /* 1 stop, odd parity */
204 zs_set_speed(cs, ZSKBD_BAUD);
205 zs_loadchannelregs(cs);
206
207 /* request DIP switch settings just in case */
208 zskbd_ctrl(cs, ZSKBD_CTRL_A_RCB, 0, 0, 0);
209
210 splx(s);
211
212 /* attach wskbd */
213 wskaa.console = 0; /* XXX */
214 wskaa.keymap = &sgikbd_wskbd_keymapdata;
215 wskaa.accessops = &zskbd_wskbd_accessops;
216 wskaa.accesscookie = cs;
217 sc->wskbddev = config_found(self, &wskaa, wskbddevprint);
218 }
219
220 static void
221 zskbd_rxint(struct zs_chanstate *cs)
222 {
223 u_char c, r;
224 struct zskbd_softc *sc = (struct zskbd_softc *)cs->cs_private;
225
226 /* clear errors */
227 r = zs_read_reg(cs, 1);
228 if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE))
229 zs_write_csr(cs, ZSWR0_RESET_ERRORS);
230
231 /* read byte and append to our queue */
232 c = zs_read_data(cs);
233
234 sc->rxq[sc->rxq_tail] = c;
235 sc->rxq_tail = (sc->rxq_tail + 1) & ~ZSKBD_RXQ_LEN;
236
237 cs->cs_softreq = 1;
238 }
239
240 static void
241 zskbd_stint(struct zs_chanstate *cs, int force)
242 {
243 zs_write_csr(cs, ZSWR0_RESET_STATUS);
244 cs->cs_softreq = 1;
245 }
246
247 static void
248 zskbd_txint(struct zs_chanstate *cs)
249 {
250 struct zskbd_softc *sc = (struct zskbd_softc *)cs->cs_private;
251
252 zs_write_reg(cs, 0, ZSWR0_RESET_TXINT);
253 sc->state |= TX_READY;
254 cs->cs_softreq = 1;
255 }
256
257 static void
258 zskbd_softint(struct zs_chanstate *cs)
259 {
260 struct zskbd_softc *sc = (struct zskbd_softc *)cs->cs_private;
261 /* handle pending transmissions */
262 if (sc->txq_head != sc->txq_tail && (sc->state & TX_READY)) {
263 int s;
264
265 sc->state &= ~TX_READY;
266
267 s = splzs();
268 zs_write_data(cs, sc->txq[sc->txq_head]);
269 splx(s);
270
271 sc->txq_head = (sc->txq_head + 1) & ~ZSKBD_TXQ_LEN;
272 }
273
274 /* don't bother if nobody is listening */
275 if (!sc->enabled) {
276 sc->rxq_head = sc->rxq_tail;
277 return;
278 }
279
280 /* handle incoming keystrokes/config */
281 while (sc->rxq_head != sc->rxq_tail) {
282 u_char key = sc->rxq[sc->rxq_head];
283
284 if (sc->state & RX_DIP) {
285 sc->dip = key;
286 sc->state &= ~RX_DIP;
287 } else if (key == ZSKBD_DIP_SYNC) {
288 sc->state |= RX_DIP;
289 } else {
290 /* toss wskbd a bone */
291 zskbd_wskbd_input(cs, key);
292 }
293
294 sc->rxq_head = (sc->rxq_head + 1) & ~ZSKBD_RXQ_LEN;
295 }
296 }
297
298 /* expects to be in splzs() */
299 static void
300 zskbd_send(struct zs_chanstate *cs, u_char *c, u_int len)
301 {
302 u_int i;
303 struct zskbd_softc *sc = (struct zskbd_softc *)cs->cs_private;
304
305 for (i = 0; i < len; i++) {
306 if (sc->state & TX_READY) {
307 zs_write_data(cs, c[i]);
308 sc->state &= ~TX_READY;
309 } else {
310 sc->txq[sc->txq_tail] = c[i];
311 sc->txq_tail = (sc->txq_tail + 1) & ~ZSKBD_TXQ_LEN;
312 }
313 }
314 }
315
316 /* expects to be in splzs() */
317 static void
318 zskbd_ctrl(struct zs_chanstate *cs, u_char a_on, u_char a_off,
319 u_char b_on, u_char b_off)
320 {
321 struct zskbd_softc *sc = (struct zskbd_softc *)cs->cs_private;
322
323 sc->kbd_conf[ZSKBD_CTRL_A] |= a_on;
324 sc->kbd_conf[ZSKBD_CTRL_A] &= ~(a_off | ZSKBD_CTRL_B);
325 sc->kbd_conf[ZSKBD_CTRL_B] &= ~b_off;
326 sc->kbd_conf[ZSKBD_CTRL_B] |= (b_on | ZSKBD_CTRL_B);
327
328 zskbd_send(cs, sc->kbd_conf, 2);
329
330 /* make sure we don't resend these each time */
331 sc->kbd_conf[ZSKBD_CTRL_A] &= ~(ZSKBD_CTRL_A_RCB | ZSKBD_CTRL_A_SBEEP |
332 ZSKBD_CTRL_A_LBEEP);
333 }
334
335 /******************************************************************************
336 * wskbd glue
337 ******************************************************************************/
338
339 static void
340 zskbd_wskbd_input(struct zs_chanstate *cs, u_char key)
341 {
342 u_int type;
343 struct zskbd_softc *sc = (struct zskbd_softc *)cs->cs_private;
344
345 if (key & ZSKBD_KEY_UP)
346 type = WSCONS_EVENT_KEY_UP;
347 else
348 type = WSCONS_EVENT_KEY_DOWN;
349
350 wskbd_input(sc->wskbddev, type, (key & ~ZSKBD_KEY_UP));
351
352 #ifdef WSDISPLAY_COMPAT_RAWKBD
353 wskbd_rawinput(sc->wskbddev, &key, 1);
354 #endif
355 }
356
357 static int
358 zskbd_wskbd_enable(void *cookie, int on)
359 {
360 struct zskbd_softc *sc = (struct zskbd_softc *)
361 ((struct zs_chanstate *)cookie)->cs_private;
362 if (on) {
363 if (sc->enabled)
364 return (EBUSY);
365 else
366 sc->enabled = 1;
367 } else
368 sc->enabled = 0;
369
370 return (0);
371 }
372
373 static void
374 zskbd_wskbd_set_leds(void *cookie, int leds)
375 {
376 int s;
377 u_char a_on = 0, a_off = 0, b_on = 0, b_off = 0;
378
379 if (leds & WSKBD_LED_CAPS)
380 a_on |= ZSKBD_CTRL_A_CAPSLK;
381 else
382 a_off |= ZSKBD_CTRL_A_CAPSLK;
383
384 if (leds & WSKBD_LED_NUM)
385 a_on |= ZSKBD_CTRL_A_NUMLK;
386 else
387 a_off |= ZSKBD_CTRL_A_NUMLK;
388
389 if (leds & WSKBD_LED_SCROLL)
390 b_on |= ZSKBD_CTRL_B_SCRLK;
391 else
392 b_off |= ZSKBD_CTRL_B_SCRLK;
393
394 s = splzs();
395 zskbd_ctrl((struct zs_chanstate *)cookie, a_on, a_off, b_on, b_off);
396 splx(s);
397 }
398
399 static int
400 zskbd_wskbd_get_leds(void *cookie)
401 {
402 int leds = 0;
403 struct zskbd_softc *sc = (struct zskbd_softc *)
404 ((struct zs_chanstate *)cookie)->cs_private;
405
406 if (sc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_NUMLK)
407 leds |= WSKBD_LED_NUM;
408
409 if (sc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_CAPSLK)
410 leds |= WSKBD_LED_CAPS;
411
412 if (sc->kbd_conf[ZSKBD_CTRL_B] & ZSKBD_CTRL_B_SCRLK)
413 leds |= WSKBD_LED_SCROLL;
414
415 return (leds);
416 }
417
418 static void
419 zskbd_wskbd_set_keyclick(void *cookie, int on)
420 {
421 int s;
422 struct zs_chanstate *cs = (struct zs_chanstate *)cookie;
423
424 if (on) {
425 if (!zskbd_wskbd_get_keyclick(cookie)) {
426 s = splzs();
427 zskbd_ctrl(cs, 0, ZSKBD_CTRL_A_NOCLICK, 0, 0);
428 splx(s);
429 }
430 } else {
431 if (zskbd_wskbd_get_keyclick(cookie)) {
432 s = splzs();
433 zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0);
434 splx(s);
435 }
436 }
437 }
438
439 static int
440 zskbd_wskbd_get_keyclick(void *cookie)
441 {
442 struct zskbd_softc *sc = (struct zskbd_softc *)
443 ((struct zs_chanstate *)cookie)->cs_private;
444
445 if (sc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_NOCLICK)
446 return (0);
447 else
448 return (1);
449 }
450
451 static int
452 zskbd_wskbd_ioctl(void *cookie, u_long cmd,
453 caddr_t data, int flag, struct proc *p)
454 {
455 switch (cmd) {
456 case WSKBDIO_GTYPE:
457 *(int *)data = WSKBD_TYPE_SGI;
458 break;
459
460 #ifdef notyet
461 case WSKBDIO_BELL:
462 case WSKBDIO_COMPLEXBELL:
463 case WSKBDIO_SETBELL:
464 case WSKBDIO_GETBELL:
465 case WSKBDIO_SETDEFAULTBELL:
466 case WSKBDIO_GETDEFAULTBELL:
467 case WSKBDIO_SETKEYREPEAT:
468 case WSKBDIO_GETKEYREPEAT:
469 case WSKBDIO_SETDEFAULTKEYREPEAT:
470 case WSKBDIO_GETDEFAULTKEYREPEAT:
471 #endif
472
473 case WSKBDIO_SETLEDS:
474 zskbd_wskbd_set_leds(cookie, *(int *)data);
475 break;
476
477 case WSKBDIO_GETLEDS:
478 *(int *)data = zskbd_wskbd_get_leds(cookie);
479 break;
480
481 #ifdef notyet
482 case WSKBDIO_GETMAP:
483 case WSKBDIO_SETMAP:
484 case WSKBDIO_GETENCODING:
485 case WSKBDIO_SETENCODING:
486 case WSKBDIO_SETMODE:
487 case WSKBDIO_GETMODE:
488 #endif
489
490 case WSKBDIO_SETKEYCLICK:
491 zskbd_wskbd_set_keyclick(cookie, *(int *)data);
492 break;
493
494 case WSKBDIO_GETKEYCLICK:
495 *(int *)data = zskbd_wskbd_get_keyclick(cookie);
496 break;
497
498 default:
499 return (EPASSTHROUGH);
500 }
501
502 return (0);
503 }
504
505 /*
506 * console routines
507 */
508 void
509 zskbd_cnattach(int zsunit, int zschan)
510 {
511 wskbd_cnattach(&zskbd_wskbd_consops, zs_get_chan_addr(zsunit, zschan),
512 &sgikbd_wskbd_keymapdata);
513 }
514
515 static void
516 zskbd_wskbd_getc(void *cookie, u_int *type, int *data)
517 {
518 int key = zs_getc(cookie);
519
520 if (key & ZSKBD_KEY_UP)
521 *type = WSCONS_EVENT_KEY_UP;
522 else
523 *type = WSCONS_EVENT_KEY_DOWN;
524
525 *data = key & ~ZSKBD_KEY_UP;
526 }
527
528 static void
529 zskbd_wskbd_pollc(void *cookie, int on)
530 {
531 }
532
533 static void
534 zskbd_wskbd_bell(void *cookie, u_int pitch, u_int period, u_int volume)
535 {
536 /*
537 * Since we don't have any state, this'll nuke our lights,
538 * key click, and other bits in ZSKBD_CTRL_A.
539 */
540 if (period >= 1000)
541 zs_putc(cookie, ZSKBD_CTRL_A_LBEEP);
542 else
543 zs_putc(cookie, ZSKBD_CTRL_A_SBEEP);
544 }
545