Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/base/wscons.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wscons_read
  2. wscons_write
  3. wscons_ioctl
  4. wscons_move_cursor
  5. wscons_set_attr
  6. wscons_clear
  7. wscons_scrollup
  8. wscons_newline
  9. wscons_check_escape
  10. wscons_putc
  11. wscons_start
  12. wscons_cngetc
  13. wscons_cnputc
  14. wscons_cnpollc
  15. wscons_kbd_input
  16. wscons_attach_video
  17. wscons_attach_kbd
  18. wscons_init

   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 }

/* [<][>][^][v][top][bottom][index][help] */