Annotation of sys/arch/sparc64/dev/pcons.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pcons.c,v 1.11 2007/06/29 04:32:39 deraadt Exp $ */
2: /* $NetBSD: pcons.c,v 1.7 2001/05/02 10:32:20 scw Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 Eduardo E. Horvath
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * Default console driver. Uses the PROM or whatever
34: * driver(s) are appropriate.
35: */
36:
37: #include <sys/param.h>
38: #include <sys/systm.h>
39: #include <sys/conf.h>
40: #include <sys/device.h>
41: #include <sys/file.h>
42: #include <sys/ioctl.h>
43: #include <sys/kernel.h>
44: #include <sys/proc.h>
45: #include <sys/tty.h>
46: #include <sys/time.h>
47: #include <sys/syslog.h>
48:
49: #include <machine/autoconf.h>
50: #include <machine/openfirm.h>
51: #include <machine/bsd_openprom.h>
52: #include <machine/conf.h>
53: #include <machine/cpu.h>
54: #include <machine/eeprom.h>
55: #include <machine/psl.h>
56:
57: #include <dev/cons.h>
58:
59: #include "wsdisplay.h"
60:
61: #if NWSDISPLAY > 0
62: #include <dev/wscons/wsconsio.h>
63: #include <dev/wscons/wsdisplayvar.h>
64: #endif
65:
66: struct pconssoftc {
67: struct device of_dev;
68:
69: #if NWSDISPLAY > 0
70: int sc_wsdisplay;
71: u_int sc_nscreens;
72: #endif
73:
74: struct tty *of_tty;
75: struct timeout sc_poll_to;
76: int of_flags;
77: };
78: /* flags: */
79: #define OFPOLL 1
80:
81: #define OFBURSTLEN 128 /* max number of bytes to write in one chunk */
82:
83: /* XXXXXXXX - this is in MI code in NetBSD */
84: /*
85: * Stuff to handle debugger magic key sequences.
86: */
87: #define CNS_LEN 128
88: #define CNS_MAGIC_VAL(x) ((x)&0x1ff)
89: #define CNS_MAGIC_NEXT(x) (((x)>>9)&0x7f)
90: #define CNS_TERM 0x7f /* End of sequence */
91:
92: typedef struct cnm_state {
93: int cnm_state;
94: u_short *cnm_magic;
95: } cnm_state_t;
96: #ifdef DDB
97: #include <ddb/db_var.h>
98: #define cn_trap() do { if (db_console) Debugger(); } while (0)
99: #else
100: #define cn_trap()
101: #endif
102: #define cn_isconsole(d) ((d) == cn_tab->cn_dev)
103: void cn_init_magic(cnm_state_t *cnm);
104: void cn_destroy_magic(cnm_state_t *cnm);
105: int cn_set_magic(char *magic);
106: int cn_get_magic(char *magic, int len);
107: /* This should be called for each byte read */
108: #ifndef cn_check_magic
109: #define cn_check_magic(d, k, s) \
110: do { \
111: if (cn_isconsole(d)) { \
112: int v = (s).cnm_magic[(s).cnm_state]; \
113: if ((k) == CNS_MAGIC_VAL(v)) { \
114: (s).cnm_state = CNS_MAGIC_NEXT(v); \
115: if ((s).cnm_state == CNS_TERM) { \
116: cn_trap(); \
117: (s).cnm_state = 0; \
118: } \
119: } else { \
120: (s).cnm_state = 0; \
121: } \
122: } \
123: } while (/* CONSTCOND */ 0)
124: #endif
125:
126: /* Encode out-of-band events this way when passing to cn_check_magic() */
127: #define CNC_BREAK 0x100
128:
129: /* XXXXXXXXXX - end of this part of cnmagic, more at the end of this file. */
130:
131: #include <sparc64/dev/cons.h>
132:
133: int pconsmatch(struct device *, void *, void *);
134: void pconsattach(struct device *, struct device *, void *);
135:
136: struct cfattach pcons_ca = {
137: sizeof(struct pconssoftc), pconsmatch, pconsattach
138: };
139:
140: struct cfdriver pcons_cd = {
141: NULL, "pcons", DV_TTY
142: };
143:
144: extern struct cfdriver pcons_cd;
145: static struct cnm_state pcons_cnm_state;
146:
147: static int pconsprobe(void);
148: static void pcons_wsdisplay_init(struct pconssoftc *);
149: extern struct consdev *cn_tab;
150:
151: cons_decl(prom_);
152:
153: int
154: pconsmatch(parent, match, aux)
155: struct device *parent;
156: void *match;
157: void *aux;
158: {
159: struct mainbus_attach_args *ma = aux;
160:
161: /* Only attach if no other console has attached. */
162: return (strcmp("pcons", ma->ma_name) == 0 &&
163: cn_tab->cn_getc == prom_cngetc);
164: }
165:
166: void pcons_poll(void *);
167:
168: void
169: pconsattach(parent, self, aux)
170: struct device *parent, *self;
171: void *aux;
172: {
173: struct pconssoftc *sc = (struct pconssoftc *) self;
174: #if NWSDISPLAY > 0
175: char buffer[128];
176: extern struct consdev wsdisplay_cons;
177: extern int wsdisplay_getc_dummy(dev_t);
178: #endif
179:
180: printf("\n");
181: if (!pconsprobe())
182: return;
183:
184: #if NWSDISPLAY > 0
185: /*
186: * Attach a dumb wsdisplay device if a wscons input driver has
187: * registered as the console, or is about to do so (usb keyboards).
188: */
189: if (wsdisplay_cons.cn_getc != wsdisplay_getc_dummy)
190: sc->sc_wsdisplay = 1;
191: else {
192: if (OF_getprop(OF_instance_to_package(stdin), "compatible",
193: buffer, sizeof(buffer)) != -1 &&
194: strncmp("usb", buffer, 3) == 0)
195: sc->sc_wsdisplay = 1;
196: }
197:
198: if (sc->sc_wsdisplay != 0) {
199: pcons_wsdisplay_init(sc);
200: return;
201: }
202: #endif
203: cn_init_magic(&pcons_cnm_state);
204: cn_set_magic("+++++");
205: timeout_set(&sc->sc_poll_to, pcons_poll, sc);
206: }
207:
208: void pconsstart(struct tty *);
209: int pconsparam(struct tty *, struct termios *);
210:
211: int
212: pconsopen(dev, flag, mode, p)
213: dev_t dev;
214: int flag, mode;
215: struct proc *p;
216: {
217: struct pconssoftc *sc;
218: int unit = minor(dev);
219: struct tty *tp;
220:
221: if (unit >= pcons_cd.cd_ndevs)
222: return ENXIO;
223: sc = pcons_cd.cd_devs[unit];
224: if (!sc)
225: return ENXIO;
226: #if NWSDISPLAY > 0
227: if (sc->sc_wsdisplay != 0)
228: return ENXIO;
229: #endif
230: if (!(tp = sc->of_tty)) {
231: sc->of_tty = tp = ttymalloc();
232: }
233: tp->t_oproc = pconsstart;
234: tp->t_param = pconsparam;
235: tp->t_dev = dev;
236: cn_tab->cn_dev = dev;
237: if (!(tp->t_state & TS_ISOPEN)) {
238: ttychars(tp);
239: tp->t_iflag = TTYDEF_IFLAG;
240: tp->t_oflag = TTYDEF_OFLAG;
241: tp->t_cflag = TTYDEF_CFLAG;
242: tp->t_lflag = TTYDEF_LFLAG;
243: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
244: pconsparam(tp, &tp->t_termios);
245: ttsetwater(tp);
246: } else if ((tp->t_state & TS_XCLUDE) && suser(p, 0))
247: return EBUSY;
248: tp->t_state |= TS_CARR_ON;
249:
250: if (!(sc->of_flags & OFPOLL)) {
251: sc->of_flags |= OFPOLL;
252: timeout_add(&sc->sc_poll_to, 1);
253: }
254:
255: return (*linesw[tp->t_line].l_open)(dev, tp);
256: }
257:
258: int
259: pconsclose(dev, flag, mode, p)
260: dev_t dev;
261: int flag, mode;
262: struct proc *p;
263: {
264: struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)];
265: struct tty *tp = sc->of_tty;
266:
267: timeout_del(&sc->sc_poll_to);
268: sc->of_flags &= ~OFPOLL;
269: (*linesw[tp->t_line].l_close)(tp, flag);
270: ttyclose(tp);
271: return 0;
272: }
273:
274: int
275: pconsread(dev, uio, flag)
276: dev_t dev;
277: struct uio *uio;
278: int flag;
279: {
280: struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)];
281: struct tty *tp = sc->of_tty;
282:
283: return (*linesw[tp->t_line].l_read)(tp, uio, flag);
284: }
285:
286: int
287: pconswrite(dev, uio, flag)
288: dev_t dev;
289: struct uio *uio;
290: int flag;
291: {
292: struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)];
293: struct tty *tp = sc->of_tty;
294:
295: return (*linesw[tp->t_line].l_write)(tp, uio, flag);
296: }
297:
298: int
299: pconsioctl(dev, cmd, data, flag, p)
300: dev_t dev;
301: u_long cmd;
302: caddr_t data;
303: int flag;
304: struct proc *p;
305: {
306: struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)];
307: struct tty *tp = sc->of_tty;
308: int error;
309:
310: if ((error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p)) >= 0)
311: return error;
312: if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0)
313: return error;
314: return ENOTTY;
315: }
316:
317: struct tty *
318: pconstty(dev)
319: dev_t dev;
320: {
321: struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)];
322:
323: return sc->of_tty;
324: }
325:
326: int
327: pconsstop(tp, flag)
328: struct tty *tp;
329: int flag;
330: {
331: return 0;
332: }
333:
334: void
335: pconsstart(tp)
336: struct tty *tp;
337: {
338: struct clist *cl;
339: int s, len;
340: u_char buf[OFBURSTLEN];
341:
342: s = spltty();
343: if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
344: splx(s);
345: return;
346: }
347: tp->t_state |= TS_BUSY;
348: splx(s);
349: cl = &tp->t_outq;
350: len = q_to_b(cl, buf, OFBURSTLEN);
351: OF_write(stdout, buf, len);
352: s = spltty();
353: tp->t_state &= ~TS_BUSY;
354: if (cl->c_cc) {
355: tp->t_state |= TS_TIMEOUT;
356: timeout_add(&tp->t_rstrt_to, 1);
357: }
358: if (cl->c_cc <= tp->t_lowat) {
359: if (tp->t_state & TS_ASLEEP) {
360: tp->t_state &= ~TS_ASLEEP;
361: wakeup(cl);
362: }
363: selwakeup(&tp->t_wsel);
364: }
365: splx(s);
366: }
367:
368: int
369: pconsparam(tp, t)
370: struct tty *tp;
371: struct termios *t;
372: {
373: tp->t_ispeed = t->c_ispeed;
374: tp->t_ospeed = t->c_ospeed;
375: tp->t_cflag = t->c_cflag;
376: return 0;
377: }
378:
379: void
380: pcons_poll(aux)
381: void *aux;
382: {
383: struct pconssoftc *sc = aux;
384: struct tty *tp = sc->of_tty;
385: char ch;
386:
387: while (OF_read(stdin, &ch, 1) > 0) {
388: cn_check_magic(tp->t_dev, ch, pcons_cnm_state);
389: if (tp && (tp->t_state & TS_ISOPEN)) {
390: if (ch == '\b')
391: ch = '\177';
392: (*linesw[tp->t_line].l_rint)(ch, tp);
393: }
394: }
395: timeout_add(&sc->sc_poll_to, 1);
396: }
397:
398: int
399: pconsprobe()
400: {
401: if (!stdin) stdin = OF_stdin();
402: if (!stdout) stdout = OF_stdout();
403:
404: return (stdin && stdout);
405: }
406:
407: void
408: pcons_cnpollc(dev, on)
409: dev_t dev;
410: int on;
411: {
412: struct pconssoftc *sc = NULL;
413:
414: if (pcons_cd.cd_devs)
415: sc = pcons_cd.cd_devs[minor(dev)];
416:
417: if (sc == NULL)
418: return;
419:
420: if (on) {
421: if (sc->of_flags & OFPOLL)
422: timeout_del(&sc->sc_poll_to);
423: sc->of_flags &= ~OFPOLL;
424: } else {
425: /* Resuming kernel. */
426: if (!(sc->of_flags & OFPOLL)) {
427: sc->of_flags |= OFPOLL;
428: timeout_add(&sc->sc_poll_to, 1);
429: }
430: }
431: }
432:
433: /* XXXXXXXX --- more cnmagic stuff. */
434: #define ENCODE_STATE(c, n) (short)(((c)&0x1ff)|(((n)&0x7f)<<9))
435:
436: static unsigned short cn_magic[CNS_LEN];
437:
438: /*
439: * Initialize a cnm_state_t.
440: */
441: void
442: cn_init_magic(cnm_state_t *cnm)
443: {
444: cnm->cnm_state = 0;
445: cnm->cnm_magic = cn_magic;
446: }
447:
448: /*
449: * Destroy a cnm_state_t.
450: */
451: void
452: cn_destroy_magic(cnm_state_t *cnm)
453: {
454: cnm->cnm_state = 0;
455: cnm->cnm_magic = NULL;
456: }
457:
458: /*
459: * Translate a magic string to a state
460: * machine table.
461: */
462: int
463: cn_set_magic(char *magic)
464: {
465: unsigned int i, c, n;
466: unsigned short m[CNS_LEN];
467:
468: for (i=0; i<CNS_LEN; i++) {
469: c = (*magic++)&0xff;
470: n = *magic ? i+1 : CNS_TERM;
471: switch (c) {
472: case 0:
473: /* End of string */
474: if (i == 0) {
475: /* empty string? */
476: cn_magic[0] = 0;
477: #ifdef DEBUG
478: printf("cn_set_magic(): empty!\n");
479: #endif
480: return (0);
481: }
482: do {
483: cn_magic[i] = m[i];
484: } while (i--);
485: return(0);
486: case 0x27:
487: /* Escape sequence */
488: c = (*magic++)&0xff;
489: n = *magic ? i+1 : CNS_TERM;
490: switch (c) {
491: case 0x27:
492: break;
493: case 0x01:
494: /* BREAK */
495: c = CNC_BREAK;
496: break;
497: case 0x02:
498: /* NUL */
499: c = 0;
500: break;
501: }
502: /* FALLTHROUGH */
503: default:
504: /* Transition to the next state. */
505: #ifdef DEBUG
506: if (!cold)
507: printf("mag %d %x:%x\n", i, c, n);
508: #endif
509: m[i] = ENCODE_STATE(c, n);
510: break;
511: }
512: }
513: return (EINVAL);
514: }
515:
516: /*
517: * Translate a state machine table back to
518: * a magic string.
519: */
520: int
521: cn_get_magic(char *magic, int maglen) {
522: unsigned int i, c;
523:
524: for (i=0; i<CNS_LEN; i++) {
525: c = cn_magic[i];
526: /* Translate a character */
527: switch (CNS_MAGIC_VAL(c)) {
528: case CNC_BREAK:
529: *magic++ = 0x27;
530: *magic++ = 0x01;
531: break;
532: case 0:
533: *magic++ = 0x27;
534: *magic++ = 0x02;
535: break;
536: case 0x27:
537: *magic++ = 0x27;
538: *magic++ = 0x27;
539: break;
540: default:
541: *magic++ = (c&0x0ff);
542: break;
543: }
544: /* Now go to the next state */
545: i = CNS_MAGIC_NEXT(c);
546: if (i == CNS_TERM || i == 0) {
547: /* Either termination state or empty machine */
548: *magic++ = 0;
549: return (0);
550: }
551: }
552: return (EINVAL);
553: }
554:
555: #if NWSDISPLAY > 0
556:
557: int pcons_alloc_screen(void *, const struct wsscreen_descr *, void **,
558: int *, int *, long *);
559: void pcons_cursor(void *, int, int, int);
560: void pcons_free_screen(void *, void *);
561: int pcons_ioctl(void *, u_long, caddr_t, int, struct proc *);
562: int pcons_mapchar(void *, int, unsigned int *);
563: paddr_t pcons_mmap(void *, off_t, int);
564: void pcons_putchar(void *, int, int, u_int, long);
565: int pcons_show_screen(void *, void *, int, void (*)(void *, int, int),
566: void *);
567:
568: struct wsdisplay_emulops pcons_emulops = {
569: NULL,
570: pcons_mapchar,
571: pcons_putchar
572: };
573:
574: struct wsscreen_descr pcons_stdscreen = {
575: "dumb", 80, 34, &pcons_emulops, 12, 22, 0
576: };
577:
578: const struct wsscreen_descr *pcons_scrlist[] = {
579: &pcons_stdscreen
580: };
581:
582: struct wsscreen_list pcons_screenlist = {
583: 1, pcons_scrlist
584: };
585:
586: struct wsdisplay_accessops pcons_accessops = {
587: pcons_ioctl,
588: pcons_mmap,
589: pcons_alloc_screen,
590: pcons_free_screen,
591: pcons_show_screen
592: };
593:
594: int
595: pcons_alloc_screen(void *v, const struct wsscreen_descr *typ, void **cookiep,
596: int *curxp, int *curyp, long *attrp)
597: {
598: struct pconssoftc *sc = v;
599: int *rowp, *colp;
600: int row, col;
601:
602: if (sc->sc_nscreens > 0)
603: return (ENOMEM);
604:
605: row = col = 0;
606: if (romgetcursoraddr(&rowp, &colp) == 0) {
607: if (rowp != NULL)
608: row = *rowp;
609: if (colp != NULL)
610: col = *colp;
611: }
612:
613: *cookiep = v;
614: *attrp = 0;
615: *curxp = col;
616: *curyp = row;
617:
618: sc->sc_nscreens++;
619: return (0);
620: }
621:
622: void
623: pcons_free_screen(void *v, void *cookie)
624: {
625: struct pconssoftc *sc = v;
626:
627: sc->sc_nscreens--;
628: }
629:
630: int
631: pcons_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
632: {
633: switch (cmd) {
634: case WSDISPLAYIO_GTYPE:
635: *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
636: break;
637: default:
638: return (-1);
639: }
640:
641: return (0);
642: }
643:
644: paddr_t
645: pcons_mmap(void *v, off_t off, int prot)
646: {
647: return ((paddr_t)-1);
648: }
649:
650: int
651: pcons_show_screen(void *v, void *cookie, int waitok,
652: void (*cb)(void *, int, int), void *arg)
653: {
654: return (0);
655: }
656:
657: int
658: pcons_mapchar(void *v, int uc, unsigned int *idx)
659: {
660: if ((uc & 0xff) == uc) {
661: *idx = uc;
662: return (1);
663: } else {
664: *idx = ' ';
665: return (0);
666: }
667: }
668:
669: void
670: pcons_putchar(void *v, int row, int col, u_int uc, long attr)
671: {
672: u_char buf[1];
673: int s;
674:
675: buf[0] = (u_char)uc;
676: s = splhigh();
677: OF_write(stdout, &buf, 1);
678: splx(s);
679: }
680:
681: void
682: pcons_wsdisplay_init(struct pconssoftc *sc)
683: {
684: struct wsemuldisplaydev_attach_args waa;
685: int *rowp, *colp;
686: int options, row, col;
687:
688: row = col = 0;
689: if (romgetcursoraddr(&rowp, &colp) == 0) {
690: if (rowp != NULL)
691: row = *rowp;
692: if (colp != NULL)
693: col = *colp;
694: }
695:
696: options = OF_finddevice("/options");
697: pcons_stdscreen.nrows = getpropint(options, "screen-#rows", 34);
698: pcons_stdscreen.ncols = getpropint(options, "screen-#columns", 80);
699:
700: /*
701: * We claim console here, because we can only get there if stdin
702: * is a keyboard. However, the PROM could have been configured with
703: * stdin being a keyboard and stdout being a serial sink.
704: * But since this combination is not supported under OpenBSD at the
705: * moment, it is reasonably safe to attach a dumb display as console
706: * here.
707: */
708: wsdisplay_cnattach(&pcons_stdscreen, sc, col, row, 0);
709:
710: waa.console = 1;
711: waa.scrdata = &pcons_screenlist;
712: waa.accessops = &pcons_accessops;
713: waa.accesscookie = sc;
714: waa.defaultscreens = 1;
715:
716: config_found((struct device *)sc, &waa, wsemuldisplaydevprint);
717: }
718: #endif
CVSweb