root / prex-0.9.0 / bsp / drv / dev / base / wscons.c @ 03e9c04a
History | View | Annotate | Download (10.5 KB)
1 |
/*-
|
---|---|
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 |
} |