root / prex-0.9.0 / bsp / drv / dev / base / wscons.c @ 03e9c04a
History | View | Annotate | Download (10.5 KB)
1 | 03e9c04a | Brad Neuman | /*-
|
---|---|---|---|
2 | * Copyright (c) 2005-2009, Kohsuke Ohtani
|
||
3 | * All rights reserved.
|
||
4 | *
|
||
5 | * Redistribution and use in source and binary forms, with or without
|
||
6 | * modification, are permitted provided that the following conditions
|
||
7 | * are met:
|
||
8 | * 1. Redistributions of source code must retain the above copyright
|
||
9 | * notice, this list of conditions and the following disclaimer.
|
||
10 | * 2. Redistributions in binary form must reproduce the above copyright
|
||
11 | * notice, this list of conditions and the following disclaimer in the
|
||
12 | * documentation and/or other materials provided with the distribution.
|
||
13 | * 3. Neither the name of the author nor the names of any co-contributors
|
||
14 | * may be used to endorse or promote products derived from this software
|
||
15 | * without specific prior written permission.
|
||
16 | *
|
||
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
27 | * SUCH DAMAGE.
|
||
28 | */
|
||
29 | |||
30 | /*
|
||
31 | * wscons.c - "Workstation console" multiplexor driver.
|
||
32 | */
|
||
33 | |||
34 | #include <driver.h> |
||
35 | #include <cons.h> |
||
36 | #include <tty.h> |
||
37 | #include <wscons.h> |
||
38 | |||
39 | /* #define DEBUG_WSCONS 1 */
|
||
40 | |||
41 | #ifdef DEBUG_WSCONS
|
||
42 | #define DPRINTF(a) printf a
|
||
43 | #else
|
||
44 | #define DPRINTF(a)
|
||
45 | #endif
|
||
46 | |||
47 | struct esc_state {
|
||
48 | int index;
|
||
49 | int arg1;
|
||
50 | int arg2;
|
||
51 | int argc;
|
||
52 | int saved_col;
|
||
53 | int saved_row;
|
||
54 | }; |
||
55 | |||
56 | struct wscons_softc {
|
||
57 | device_t dev; /* our device */
|
||
58 | struct tty tty; /* associated tty */ |
||
59 | int row; /* current row */ |
||
60 | int col; /* current col */ |
||
61 | int nrows; /* number of rows */ |
||
62 | int ncols; /* number of cols */ |
||
63 | int attr; /* current attribute */ |
||
64 | struct esc_state esc; /* escape state */ |
||
65 | struct wscons_video_ops *vid_ops; /* video operations */ |
||
66 | struct wscons_kbd_ops *kbd_ops; /* keyboard operations */ |
||
67 | void *vid_aux; /* video private data */ |
||
68 | void *kbd_aux; /* keyboard private data */ |
||
69 | }; |
||
70 | |||
71 | static int wscons_init(struct driver *); |
||
72 | static int wscons_read(device_t, char *, size_t *, int); |
||
73 | static int wscons_write(device_t, char *, size_t *, int); |
||
74 | static int wscons_ioctl(device_t, u_long, void *); |
||
75 | |||
76 | static int wscons_cngetc(device_t); |
||
77 | static void wscons_cnputc(device_t, int); |
||
78 | static void wscons_cnpollc(device_t, int); |
||
79 | |||
80 | |||
81 | static struct devops wscons_devops = { |
||
82 | /* open */ no_open,
|
||
83 | /* close */ no_close,
|
||
84 | /* read */ wscons_read,
|
||
85 | /* write */ wscons_write,
|
||
86 | /* ioctl */ wscons_ioctl,
|
||
87 | /* devctl */ no_devctl,
|
||
88 | }; |
||
89 | |||
90 | struct driver wscons_driver = {
|
||
91 | /* name */ "wscons", |
||
92 | /* devops */ &wscons_devops,
|
||
93 | /* devsz */ sizeof(struct wscons_softc), |
||
94 | /* flags */ 0, |
||
95 | /* probe */ NULL, |
||
96 | /* init */ wscons_init,
|
||
97 | /* unload */ NULL, |
||
98 | }; |
||
99 | |||
100 | static struct consdev wsconsdev = { |
||
101 | /* dev */ NODEV,
|
||
102 | /* devops */ &wscons_devops,
|
||
103 | /* cngetc */ wscons_cngetc,
|
||
104 | /* cnputc */ wscons_cnputc,
|
||
105 | /* cnpollc */ wscons_cnpollc,
|
||
106 | }; |
||
107 | |||
108 | static const u_short ansi_colors[] = {0, 4, 2, 6, 1, 5, 3, 7}; |
||
109 | |||
110 | /*
|
||
111 | * Pointer to the wscons state. There can be only one instance.
|
||
112 | */
|
||
113 | static struct wscons_softc *wscons_softc; |
||
114 | |||
115 | |||
116 | static int |
||
117 | wscons_read(device_t dev, char *buf, size_t *nbyte, int blkno) |
||
118 | { |
||
119 | struct tty *tty = &wscons_softc->tty;
|
||
120 | |||
121 | return tty_read(tty, buf, nbyte);
|
||
122 | } |
||
123 | |||
124 | static int |
||
125 | wscons_write(device_t dev, char *buf, size_t *nbyte, int blkno) |
||
126 | { |
||
127 | struct tty *tty = &wscons_softc->tty;
|
||
128 | |||
129 | return tty_write(tty, buf, nbyte);
|
||
130 | } |
||
131 | |||
132 | static int |
||
133 | wscons_ioctl(device_t dev, u_long cmd, void *arg)
|
||
134 | { |
||
135 | struct tty *tty = &wscons_softc->tty;
|
||
136 | |||
137 | return tty_ioctl(tty, cmd, arg);
|
||
138 | } |
||
139 | |||
140 | static void |
||
141 | wscons_move_cursor(struct wscons_softc *sc)
|
||
142 | { |
||
143 | struct wscons_video_ops *vops = sc->vid_ops;
|
||
144 | |||
145 | vops->cursor(sc->vid_aux, sc->row, sc->col); |
||
146 | } |
||
147 | |||
148 | static void |
||
149 | wscons_set_attr(struct wscons_softc *sc)
|
||
150 | { |
||
151 | struct wscons_video_ops *vops = sc->vid_ops;
|
||
152 | |||
153 | vops->set_attr(sc->vid_aux, sc->attr); |
||
154 | } |
||
155 | |||
156 | static void |
||
157 | wscons_clear(struct wscons_softc *sc)
|
||
158 | { |
||
159 | struct wscons_video_ops *vops = sc->vid_ops;
|
||
160 | |||
161 | vops->eraserows(sc->vid_aux, 0, sc->nrows);
|
||
162 | sc->col = 0;
|
||
163 | sc->row = 0;
|
||
164 | wscons_move_cursor(sc); |
||
165 | } |
||
166 | |||
167 | static void |
||
168 | wscons_scrollup(struct wscons_softc *sc)
|
||
169 | { |
||
170 | struct wscons_video_ops *vops = sc->vid_ops;
|
||
171 | |||
172 | vops->copyrows(sc->vid_aux, 1, 0, sc->nrows - 1); |
||
173 | vops->eraserows(sc->vid_aux, sc->nrows - 1, 1); |
||
174 | } |
||
175 | |||
176 | static void |
||
177 | wscons_newline(struct wscons_softc *sc)
|
||
178 | { |
||
179 | |||
180 | sc->col = 0;
|
||
181 | sc->row++; |
||
182 | if (sc->row >= sc->nrows) {
|
||
183 | sc->row = sc->nrows - 1;
|
||
184 | wscons_scrollup(sc); |
||
185 | } |
||
186 | } |
||
187 | |||
188 | /*
|
||
189 | * Check for escape code sequence.
|
||
190 | * Rreturn true if escape
|
||
191 | *
|
||
192 | * <Support list>
|
||
193 | * ESC[#;#H or : moves cursor to line #, column #
|
||
194 | * ESC[#;#f
|
||
195 | * ESC[#A : moves cursor up # lines
|
||
196 | * ESC[#B : moves cursor down # lines
|
||
197 | * ESC[#C : moves cursor right # spaces
|
||
198 | * ESC[#D : moves cursor left # spaces
|
||
199 | * ESC[#;#R : reports current cursor line & column
|
||
200 | * ESC[s : save cursor position for recall later
|
||
201 | * ESC[u : return to saved cursor position
|
||
202 | * ESC[2J : clear screen and home cursor
|
||
203 | * ESC[K : clear to end of line
|
||
204 | * ESC[#m : attribute (0=attribure off, 4=underline, 5=blink)
|
||
205 | */
|
||
206 | static int |
||
207 | wscons_check_escape(struct wscons_softc *sc, char c) |
||
208 | { |
||
209 | struct esc_state *esc = &sc->esc;
|
||
210 | int move = 0; |
||
211 | int val;
|
||
212 | u_short color; |
||
213 | |||
214 | if (c == 033) { |
||
215 | esc->index = 1;
|
||
216 | esc->argc = 0;
|
||
217 | return 1; |
||
218 | } |
||
219 | if (esc->index == 0) |
||
220 | return 0; |
||
221 | |||
222 | if (c >= '0' && c <= '9') { |
||
223 | val = c - '0';
|
||
224 | switch (esc->argc) {
|
||
225 | case 0: |
||
226 | esc->arg1 = val; |
||
227 | esc->index++; |
||
228 | break;
|
||
229 | case 1: |
||
230 | esc->arg1 = esc->arg1 * 10 + val;
|
||
231 | break;
|
||
232 | case 2: |
||
233 | esc->arg2 = val; |
||
234 | esc->index++; |
||
235 | break;
|
||
236 | case 3: |
||
237 | esc->arg2 = esc->arg2 * 10 + val;
|
||
238 | break;
|
||
239 | default:
|
||
240 | goto reset;
|
||
241 | } |
||
242 | esc->argc++; |
||
243 | return 1; |
||
244 | } |
||
245 | |||
246 | esc->index++; |
||
247 | |||
248 | switch (esc->index) {
|
||
249 | case 2: |
||
250 | if (c != '[') |
||
251 | goto reset;
|
||
252 | return 1; |
||
253 | case 3: |
||
254 | switch (c) {
|
||
255 | case 's': /* Save cursor position */ |
||
256 | esc->saved_col = sc->col; |
||
257 | esc->saved_row = sc->row; |
||
258 | printf("TTY: save %d %d\n", sc->col, sc->row);
|
||
259 | break;
|
||
260 | case 'u': /* Return to saved cursor position */ |
||
261 | sc->col = esc->saved_col; |
||
262 | sc->row = esc->saved_row; |
||
263 | printf("TTY: restore %d %d\n", sc->col, sc->row);
|
||
264 | wscons_move_cursor(sc); |
||
265 | break;
|
||
266 | case 'K': /* Clear to end of line */ |
||
267 | break;
|
||
268 | } |
||
269 | goto reset;
|
||
270 | case 4: |
||
271 | switch (c) {
|
||
272 | case 'A': /* Move cursor up # lines */ |
||
273 | sc->row -= esc->arg1; |
||
274 | if (sc->row < 0) |
||
275 | sc->row = 0;
|
||
276 | move = 1;
|
||
277 | break;
|
||
278 | case 'B': /* Move cursor down # lines */ |
||
279 | sc->row += esc->arg1; |
||
280 | if (sc->row >= sc->nrows)
|
||
281 | sc->row = sc->nrows - 1;
|
||
282 | move = 1;
|
||
283 | break;
|
||
284 | case 'C': /* Move cursor forward # spaces */ |
||
285 | sc->col += esc->arg1; |
||
286 | if (sc->col >= sc->ncols)
|
||
287 | sc->col = sc->ncols - 1;
|
||
288 | move = 1;
|
||
289 | break;
|
||
290 | case 'D': /* Move cursor back # spaces */ |
||
291 | sc->col -= esc->arg1; |
||
292 | if (sc->col < 0) |
||
293 | sc->col = 0;
|
||
294 | move = 1;
|
||
295 | break;
|
||
296 | case ';': |
||
297 | if (esc->argc == 1) |
||
298 | esc->argc = 2;
|
||
299 | return 1; |
||
300 | case 'J': |
||
301 | if (esc->arg1 == 2) /* Clear screen */ |
||
302 | wscons_clear(sc); |
||
303 | break;
|
||
304 | case 'm': /* Change attribute */ |
||
305 | switch (esc->arg1) {
|
||
306 | case 0: /* reset */ |
||
307 | sc->attr = 0x0F;
|
||
308 | break;
|
||
309 | case 1: /* bold */ |
||
310 | sc->attr = 0x0F;
|
||
311 | break;
|
||
312 | case 4: /* under line */ |
||
313 | break;
|
||
314 | case 5: /* blink */ |
||
315 | sc->attr |= 0x80;
|
||
316 | break;
|
||
317 | case 30: case 31: case 32: case 33: |
||
318 | case 34: case 35: case 36: case 37: |
||
319 | color = ansi_colors[esc->arg1 - 30];
|
||
320 | sc->attr = (sc->attr & 0xf0) | color;
|
||
321 | break;
|
||
322 | case 40: case 41: case 42: case 43: |
||
323 | case 44: case 45: case 46: case 47: |
||
324 | color = ansi_colors[esc->arg1 - 40];
|
||
325 | sc->attr = (sc->attr & 0x0f) | (color << 4); |
||
326 | break;
|
||
327 | } |
||
328 | wscons_set_attr(sc); |
||
329 | break;
|
||
330 | |||
331 | } |
||
332 | if (move)
|
||
333 | wscons_move_cursor(sc); |
||
334 | goto reset;
|
||
335 | case 6: |
||
336 | switch (c) {
|
||
337 | case 'H': /* Cursor position */ |
||
338 | case 'f': |
||
339 | sc->row = esc->arg1; |
||
340 | sc->col = esc->arg2; |
||
341 | if (sc->row >= sc->nrows)
|
||
342 | sc->row = sc->nrows - 1;
|
||
343 | if (sc->col >= sc->ncols)
|
||
344 | sc->col = sc->ncols - 1;
|
||
345 | wscons_move_cursor(sc); |
||
346 | break;
|
||
347 | case 'R': |
||
348 | /* XXX */
|
||
349 | break;
|
||
350 | } |
||
351 | goto reset;
|
||
352 | default:
|
||
353 | goto reset;
|
||
354 | } |
||
355 | /* NOTREACHED */
|
||
356 | reset:
|
||
357 | esc->index = 0;
|
||
358 | esc->argc = 0;
|
||
359 | return 1; |
||
360 | } |
||
361 | |||
362 | static void |
||
363 | wscons_putc(int c)
|
||
364 | { |
||
365 | struct wscons_softc *sc = wscons_softc;
|
||
366 | struct wscons_video_ops *vops = sc->vid_ops;
|
||
367 | |||
368 | if (wscons_check_escape(sc, c))
|
||
369 | return;
|
||
370 | |||
371 | switch (c) {
|
||
372 | case '\n': |
||
373 | wscons_newline(sc); |
||
374 | return;
|
||
375 | case '\r': |
||
376 | sc->col = 0;
|
||
377 | return;
|
||
378 | case '\b': |
||
379 | if (sc->col == 0) |
||
380 | return;
|
||
381 | sc->col--; |
||
382 | return;
|
||
383 | } |
||
384 | |||
385 | vops->putc(sc->vid_aux, sc->row, sc->col, c); |
||
386 | |||
387 | sc->col++; |
||
388 | if (sc->col >= sc->ncols) {
|
||
389 | sc->col = 0;
|
||
390 | sc->row++; |
||
391 | if (sc->row >= sc->nrows) {
|
||
392 | sc->row = sc->nrows - 1;
|
||
393 | wscons_scrollup(sc); |
||
394 | } |
||
395 | } |
||
396 | } |
||
397 | |||
398 | /*
|
||
399 | * Start output operation.
|
||
400 | */
|
||
401 | static void |
||
402 | wscons_start(struct tty *tp)
|
||
403 | { |
||
404 | struct wscons_softc *sc = wscons_softc;
|
||
405 | int c;
|
||
406 | |||
407 | while ((c = tty_getc(&tp->t_outq)) >= 0) |
||
408 | wscons_putc(c); |
||
409 | |||
410 | wscons_move_cursor(sc); |
||
411 | tty_done(tp); |
||
412 | } |
||
413 | |||
414 | static int |
||
415 | wscons_cngetc(device_t dev) |
||
416 | { |
||
417 | struct wscons_softc *sc = wscons_softc;
|
||
418 | struct wscons_kbd_ops *kops = sc->kbd_ops;
|
||
419 | |||
420 | return kops->getc(sc->kbd_aux);
|
||
421 | } |
||
422 | |||
423 | static void |
||
424 | wscons_cnputc(device_t dev, int c)
|
||
425 | { |
||
426 | struct wscons_softc *sc = wscons_softc;
|
||
427 | |||
428 | wscons_putc(c); |
||
429 | wscons_move_cursor(sc); |
||
430 | } |
||
431 | |||
432 | static void |
||
433 | wscons_cnpollc(device_t dev, int on)
|
||
434 | { |
||
435 | struct wscons_softc *sc = wscons_softc;
|
||
436 | struct wscons_kbd_ops *kops = sc->kbd_ops;
|
||
437 | |||
438 | kops->set_poll(sc->kbd_aux, on); |
||
439 | } |
||
440 | |||
441 | void
|
||
442 | wscons_kbd_input(int c)
|
||
443 | { |
||
444 | struct wscons_softc *sc = wscons_softc;
|
||
445 | |||
446 | tty_input(c, &sc->tty); |
||
447 | } |
||
448 | |||
449 | void
|
||
450 | wscons_attach_video(struct wscons_video_ops *ops, void *aux) |
||
451 | { |
||
452 | struct wscons_softc *sc = wscons_softc;
|
||
453 | int diag = 0; |
||
454 | |||
455 | sc->vid_ops = ops; |
||
456 | sc->vid_aux = aux; |
||
457 | ops->get_cursor(aux, &sc->col, &sc->row); |
||
458 | |||
459 | #ifdef CONFIG_DIAG_SCREEN
|
||
460 | diag = 1;
|
||
461 | #endif
|
||
462 | wsconsdev.dev = sc->dev; |
||
463 | cons_attach(&wsconsdev, diag); |
||
464 | } |
||
465 | |||
466 | void
|
||
467 | wscons_attach_kbd(struct wscons_kbd_ops *ops, void *aux) |
||
468 | { |
||
469 | struct wscons_softc *sc = wscons_softc;
|
||
470 | |||
471 | sc->kbd_ops = ops; |
||
472 | sc->kbd_aux = aux; |
||
473 | } |
||
474 | |||
475 | static int |
||
476 | wscons_init(struct driver *self)
|
||
477 | { |
||
478 | struct bootinfo *bi;
|
||
479 | struct wscons_softc *sc;
|
||
480 | device_t dev; |
||
481 | |||
482 | dev = device_create(self, "tty", D_CHR|D_TTY);
|
||
483 | |||
484 | sc = device_private(dev); |
||
485 | sc->dev = dev; |
||
486 | sc->esc.index = 0;
|
||
487 | sc->attr = 0x0f;
|
||
488 | wscons_softc = sc; |
||
489 | |||
490 | tty_attach(&sc->tty); |
||
491 | sc->tty.t_dev = dev; |
||
492 | sc->tty.t_oproc = wscons_start; |
||
493 | |||
494 | machine_bootinfo(&bi); |
||
495 | sc->nrows = bi->video.text_y; |
||
496 | sc->ncols = bi->video.text_x; |
||
497 | return 0; |
||
498 | } |