Annotation of sys/arch/sparc64/dev/comkbd_ebus.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: comkbd_ebus.c,v 1.18 2005/11/11 16:44:51 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
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: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: *
28: * Effort sponsored in part by the Defense Advanced Research Projects
29: * Agency (DARPA) and Air Force Research Laboratory, Air Force
30: * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31: *
32: */
33:
34: #include <sys/param.h>
35: #include <sys/systm.h>
36: #include <sys/proc.h>
37: #include <sys/device.h>
38: #include <sys/conf.h>
39: #include <sys/file.h>
40: #include <sys/ioctl.h>
41: #include <sys/malloc.h>
42: #include <sys/tty.h>
43: #include <sys/time.h>
44: #include <sys/kernel.h>
45: #include <sys/syslog.h>
46:
47: #include <machine/bus.h>
48: #include <machine/autoconf.h>
49: #include <machine/openfirm.h>
50:
51: #include <sparc64/dev/ebusreg.h>
52: #include <sparc64/dev/ebusvar.h>
53:
54: #include <dev/wscons/wsconsio.h>
55: #include <dev/wscons/wskbdvar.h>
56:
57: #include <dev/sun/sunkbdreg.h>
58: #include <dev/sun/sunkbdvar.h>
59:
60: #include <dev/ic/comreg.h>
61: #include <dev/ic/comvar.h>
62: #include <dev/ic/ns16550reg.h>
63:
64: #include <dev/cons.h>
65:
66: #define COMK_RX_RING 64
67: #define COMK_TX_RING 64
68:
69: struct comkbd_softc {
70: struct sunkbd_softc sc_base;
71:
72: bus_space_tag_t sc_iot; /* bus tag */
73: bus_space_handle_t sc_ioh; /* bus handle */
74: void *sc_ih, *sc_si; /* interrupt vectors */
75:
76: u_int sc_rxcnt;
77: u_int8_t sc_rxbuf[COMK_RX_RING];
78: u_int8_t *sc_rxbeg, *sc_rxend, *sc_rxget, *sc_rxput;
79:
80: u_int sc_txcnt;
81: u_int8_t sc_txbuf[COMK_TX_RING];
82: u_int8_t *sc_txbeg, *sc_txend, *sc_txget, *sc_txput;
83:
84: u_int8_t sc_ier;
85: };
86:
87: #define COM_WRITE(sc,r,v) \
88: bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
89: #define COM_READ(sc,r) \
90: bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (r))
91:
92: int comkbd_match(struct device *, void *, void *);
93: void comkbd_attach(struct device *, struct device *, void *);
94: int comkbd_iskbd(int);
95:
96: /* wskbd glue */
97: void comkbd_cnpollc(void *, int);
98: void comkbd_cngetc(void *, u_int *, int *);
99:
100: /* internals */
101: int comkbd_enqueue(void *, u_int8_t *, u_int);
102: int comkbd_init(struct comkbd_softc *);
103: void comkbd_putc(struct comkbd_softc *, u_int8_t);
104: int comkbd_intr(void *);
105: void comkbd_soft(void *);
106:
107: struct cfattach comkbd_ca = {
108: sizeof(struct comkbd_softc), comkbd_match, comkbd_attach
109: };
110:
111: struct cfdriver comkbd_cd = {
112: NULL, "comkbd", DV_DULL
113: };
114:
115: const char *comkbd_names[] = {
116: "su",
117: "su_pnp",
118: NULL
119: };
120:
121: struct wskbd_consops comkbd_consops = {
122: comkbd_cngetc,
123: comkbd_cnpollc
124: };
125:
126: int
127: comkbd_iskbd(node)
128: int node;
129: {
130: if (OF_getproplen(node, "keyboard") == 0)
131: return (10);
132: return (0);
133: }
134:
135: int
136: comkbd_match(parent, match, aux)
137: struct device *parent;
138: void *match;
139: void *aux;
140: {
141: struct ebus_attach_args *ea = aux;
142: int i;
143:
144: for (i = 0; comkbd_names[i]; i++)
145: if (strcmp(ea->ea_name, comkbd_names[i]) == 0)
146: return (comkbd_iskbd(ea->ea_node));
147:
148: if (strcmp(ea->ea_name, "serial") == 0) {
149: char compat[80];
150:
151: if ((i = OF_getproplen(ea->ea_node, "compatible")) &&
152: OF_getprop(ea->ea_node, "compatible", compat,
153: sizeof(compat)) == i) {
154: if (strcmp(compat, "su16550") == 0 ||
155: strcmp(compat, "su") == 0)
156: return (comkbd_iskbd(ea->ea_node));
157: }
158: }
159: return (0);
160: }
161:
162: void
163: comkbd_attach(parent, self, aux)
164: struct device *parent, *self;
165: void *aux;
166: {
167: struct comkbd_softc *sc = (void *)self;
168: struct sunkbd_softc *ss = (void *)sc;
169: struct ebus_attach_args *ea = aux;
170: struct wskbddev_attach_args a;
171: int console;
172:
173: ss->sc_sendcmd = comkbd_enqueue;
174: timeout_set(&ss->sc_bellto, sunkbd_bellstop, sc);
175:
176: sc->sc_iot = ea->ea_memtag;
177:
178: sc->sc_rxget = sc->sc_rxput = sc->sc_rxbeg = sc->sc_rxbuf;
179: sc->sc_rxend = sc->sc_rxbuf + COMK_RX_RING;
180: sc->sc_rxcnt = 0;
181:
182: sc->sc_txget = sc->sc_txput = sc->sc_txbeg = sc->sc_txbuf;
183: sc->sc_txend = sc->sc_txbuf + COMK_TX_RING;
184: sc->sc_txcnt = 0;
185:
186: console = (ea->ea_node == OF_instance_to_package(OF_stdin()));
187:
188: sc->sc_si = softintr_establish(IPL_TTY, comkbd_soft, sc);
189: if (sc->sc_si == NULL) {
190: printf(": can't get soft intr\n");
191: return;
192: }
193:
194: /* Use prom address if available, otherwise map it. */
195: if (ea->ea_nvaddrs && bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
196: BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) == 0) {
197: sc->sc_iot = ea->ea_memtag;
198: } else if (ebus_bus_map(ea->ea_memtag, 0,
199: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
200: ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
201: sc->sc_iot = ea->ea_memtag;
202: } else if (ebus_bus_map(ea->ea_iotag, 0,
203: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
204: ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
205: sc->sc_iot = ea->ea_iotag;
206: } else {
207: printf(": can't map register space\n");
208: return;
209: }
210:
211: sc->sc_ih = bus_intr_establish(sc->sc_iot,
212: ea->ea_intrs[0], IPL_TTY, 0, comkbd_intr, sc, self->dv_xname);
213: if (sc->sc_ih == NULL) {
214: printf(": can't get hard intr\n");
215: return;
216: }
217:
218: if (comkbd_init(sc) == 0) {
219: return;
220: }
221:
222: ss->sc_click =
223: strcmp(getpropstring(optionsnode, "keyboard-click?"), "true") == 0;
224: sunkbd_setclick(ss, ss->sc_click);
225:
226: a.console = console;
227: if (ISTYPE5(ss->sc_layout)) {
228: a.keymap = &sunkbd5_keymapdata;
229: #ifndef SUNKBD5_LAYOUT
230: if (ss->sc_layout < MAXSUNLAYOUT &&
231: sunkbd_layouts[ss->sc_layout] != -1)
232: sunkbd5_keymapdata.layout =
233: sunkbd_layouts[ss->sc_layout];
234: #endif
235: } else {
236: a.keymap = &sunkbd_keymapdata;
237: #ifndef SUNKBD_LAYOUT
238: if (ss->sc_layout < MAXSUNLAYOUT &&
239: sunkbd_layouts[ss->sc_layout] != -1)
240: sunkbd_keymapdata.layout =
241: sunkbd_layouts[ss->sc_layout];
242: #endif
243: }
244: a.accessops = &sunkbd_accessops;
245: a.accesscookie = sc;
246:
247: if (console) {
248: cn_tab->cn_dev = makedev(77, ss->sc_dev.dv_unit); /* XXX */
249: cn_tab->cn_pollc = wskbd_cnpollc;
250: cn_tab->cn_getc = wskbd_cngetc;
251: wskbd_cnattach(&comkbd_consops, sc, a.keymap);
252: sc->sc_ier = IER_ETXRDY | IER_ERXRDY;
253: COM_WRITE(sc, com_ier, sc->sc_ier);
254: COM_READ(sc, com_iir);
255: COM_WRITE(sc, com_mcr, MCR_IENABLE | MCR_DTR | MCR_RTS);
256: }
257:
258: ss->sc_wskbddev = config_found(self, &a, wskbddevprint);
259: }
260:
261: void
262: comkbd_cnpollc(vsc, on)
263: void *vsc;
264: int on;
265: {
266: }
267:
268: void
269: comkbd_cngetc(v, type, data)
270: void *v;
271: u_int *type;
272: int *data;
273: {
274: struct comkbd_softc *sc = v;
275: int s;
276: u_int8_t c;
277:
278: s = splhigh();
279: while (1) {
280: if (COM_READ(sc, com_lsr) & LSR_RXRDY)
281: break;
282: }
283: c = COM_READ(sc, com_data);
284: COM_READ(sc, com_iir);
285: splx(s);
286:
287: sunkbd_decode(c, type, data);
288: }
289:
290: void
291: comkbd_putc(sc, c)
292: struct comkbd_softc *sc;
293: u_int8_t c;
294: {
295: int s, timo;
296:
297: s = splhigh();
298:
299: timo = 150000;
300: while (--timo) {
301: if (COM_READ(sc, com_lsr) & LSR_TXRDY)
302: break;
303: }
304:
305: COM_WRITE(sc, com_data, c);
306: bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, COM_NPORTS,
307: BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
308:
309: timo = 150000;
310: while (--timo) {
311: if (COM_READ(sc, com_lsr) & LSR_TXRDY)
312: break;
313: }
314:
315: splx(s);
316: }
317:
318: int
319: comkbd_enqueue(v, buf, buflen)
320: void *v;
321: u_int8_t *buf;
322: u_int buflen;
323: {
324: struct comkbd_softc *sc = v;
325: int s;
326: u_int i;
327:
328: s = spltty();
329:
330: /* See if there is room... */
331: if ((sc->sc_txcnt + buflen) > COMK_TX_RING) {
332: splx(s);
333: return (-1);
334: }
335:
336: for (i = 0; i < buflen; i++) {
337: *sc->sc_txget = *buf;
338: buf++;
339: sc->sc_txcnt++;
340: sc->sc_txget++;
341: if (sc->sc_txget == sc->sc_txend)
342: sc->sc_txget = sc->sc_txbeg;
343: }
344:
345: comkbd_soft(sc);
346:
347: splx(s);
348: return (0);
349: }
350:
351: void
352: comkbd_soft(vsc)
353: void *vsc;
354: {
355: struct comkbd_softc *sc = vsc;
356: struct sunkbd_softc *ss = (void *)sc;
357: u_int type;
358: int value;
359: u_int8_t c;
360:
361: while (sc->sc_rxcnt) {
362: c = *sc->sc_rxget;
363: if (++sc->sc_rxget == sc->sc_rxend)
364: sc->sc_rxget = sc->sc_rxbeg;
365: sc->sc_rxcnt--;
366: sunkbd_decode(c, &type, &value);
367: wskbd_input(ss->sc_wskbddev, type, value);
368: }
369:
370: if (sc->sc_txcnt) {
371: c = sc->sc_ier | IER_ETXRDY;
372: if (c != sc->sc_ier) {
373: COM_WRITE(sc, com_ier, c);
374: sc->sc_ier = c;
375: }
376: if (COM_READ(sc, com_lsr) & LSR_TXRDY) {
377: sc->sc_txcnt--;
378: COM_WRITE(sc, com_data, *sc->sc_txput);
379: if (++sc->sc_txput == sc->sc_txend)
380: sc->sc_txput = sc->sc_txbeg;
381: }
382: }
383: }
384:
385: int
386: comkbd_intr(vsc)
387: void *vsc;
388: {
389: struct comkbd_softc *sc = vsc;
390: u_int8_t iir, lsr, data;
391: int needsoft = 0;
392:
393: /* Nothing to do */
394: iir = COM_READ(sc, com_iir);
395: if (iir & IIR_NOPEND)
396: return (0);
397:
398: for (;;) {
399: lsr = COM_READ(sc, com_lsr);
400: if (lsr & LSR_RXRDY) {
401: needsoft = 1;
402:
403: do {
404: data = COM_READ(sc, com_data);
405: if (sc->sc_rxcnt != COMK_RX_RING) {
406: *sc->sc_rxput = data;
407: if (++sc->sc_rxput == sc->sc_rxend)
408: sc->sc_rxput = sc->sc_rxbeg;
409: sc->sc_rxcnt++;
410: }
411: lsr = COM_READ(sc, com_lsr);
412: } while (lsr & LSR_RXRDY);
413: }
414:
415: if (lsr & LSR_TXRDY) {
416: if (sc->sc_txcnt == 0) {
417: /* Nothing further to send */
418: sc->sc_ier &= ~IER_ETXRDY;
419: COM_WRITE(sc, com_ier, sc->sc_ier);
420: } else
421: needsoft = 1;
422: }
423:
424: iir = COM_READ(sc, com_iir);
425: if (iir & IIR_NOPEND)
426: break;
427: }
428:
429: if (needsoft)
430: softintr_schedule(sc->sc_si);
431:
432: return (1);
433: }
434:
435: int
436: comkbd_init(sc)
437: struct comkbd_softc *sc;
438: {
439: struct sunkbd_softc *ss = (void *)sc;
440: u_int8_t stat, c;
441: int tries;
442:
443: for (tries = 5; tries != 0; tries--) {
444: int ltries;
445:
446: ss->sc_leds = 0;
447: ss->sc_layout = -1;
448:
449: /* Send reset request */
450: comkbd_putc(sc, SKBD_CMD_RESET);
451:
452: ltries = 1000;
453: while (--ltries > 0) {
454: stat = COM_READ(sc,com_lsr);
455: if (stat & LSR_RXRDY) {
456: c = COM_READ(sc, com_data);
457:
458: sunkbd_raw(ss, c);
459: if (ss->sc_kbdstate == SKBD_STATE_RESET)
460: break;
461: }
462: DELAY(1000);
463: }
464: if (ltries == 0)
465: continue;
466:
467: /* Wait for reset to finish. */
468: ltries = 1000;
469: while (--ltries > 0) {
470: stat = COM_READ(sc, com_lsr);
471: if (stat & LSR_RXRDY) {
472: c = COM_READ(sc, com_data);
473: sunkbd_raw(ss, c);
474: if (ss->sc_kbdstate == SKBD_STATE_GETKEY)
475: break;
476: }
477: DELAY(1000);
478: }
479: if (ltries == 0)
480: continue;
481:
482:
483: /* Send layout request */
484: comkbd_putc(sc, SKBD_CMD_LAYOUT);
485:
486: ltries = 1000;
487: while (--ltries > 0) {
488: stat = COM_READ(sc, com_lsr);
489: if (stat & LSR_RXRDY) {
490: c = COM_READ(sc, com_data);
491: sunkbd_raw(ss, c);
492: if (ss->sc_layout != -1)
493: break;
494: }
495: DELAY(1000);
496: }
497: if (ltries != 0)
498: break;
499: }
500: if (tries == 0)
501: printf(": no keyboard\n");
502: else
503: printf(": layout %d\n", ss->sc_layout);
504:
505: return tries;
506: }
CVSweb