gonzui


Format: Advanced Search

tkernel_2/driver/tef_em1d/console/src/console_drv.cbare sourcepermlink (0.12 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by T-Engine Forum at 2014/09/10.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: 
   16: /*
   17:  *      console_drv.c        Console/Low-level serial I/O driver
   18:  *
   19:  *      Console driver : System-independent
   20:  */
   21: 
   22: #include <basic.h>
   23: #include <sys/consio.h>
   24: #include <tk/tkernel.h>
   25: #include <tk/util.h>
   26: #include <device/serialio.h>
   27: #include <device/rs.h>
   28: #include <sys/imalloc.h>
   29: #include <sys/util.h>
   30: #include <libstr.h>
   31: #include <sys/queue.h>
   32: #include <sys/debug.h>
   33: #include <tm/tmonitor.h>
   34: #include <sys/rominfo.h>
   35: 
   36: #include <sys/svc/ifconsio.h>
   37: 
   38: /* Default console port number */
   39: #ifndef DEFAULT_CONSOLE_PORT
   40: #define DEFAULT_CONSOLE_PORT    CONF_SERIAL_0
   41: #endif
   42: 
   43: EXPORT  W        DebugPort;     /* Serial port number for debugging */
   44: 
   45: IMPORT  ER       con_def_subsys(W svc, W pri, void *svcent, void *brkent);
   46: 
   47: IMPORT  ER       consMLock(FastMLock *lock, INT no);
   48: IMPORT  ER       consMUnlock(FastMLock *lock, INT no);
   49: IMPORT  ER       consCreateMLock(FastMLock *lock, UB *name);
   50: IMPORT  ER       consDeleteMLock(FastMLock *lock);
   51: 
   52: /*----------------------------------------------------------------------
   53:         Console port processing
   54: ----------------------------------------------------------------------*/
   55: /* Console port management block*/
   56: typedef struct {
   57:         QUEUE  q;               /* Queue                             */
   58:         W      port;                /* Port number                                */
   59:         W      in_use;              /* In-use count                             */
   60: 
   61:         W      conf;                /* Configuration                      */
   62:         FastMLock lock;                /* Lock for input-output              */
   63:         ID     flg;                /* Event flag for input-output                */
   64: 
   65:         UB     *in_buf;    /* Input buffer                            */
   66:         UW     in_bufsz;   /* Input buffer size                      */
   67:         UW     in_rptr;    /* Input buffer read-in counter            */
   68:         UW     in_wptr;    /* Input buffer write-counter              */
   69: 
   70:         UB     *ou_buf;    /* Output buffer                   */
   71:         UW     ou_bufsz;   /* Output buffer size                     */
   72:         UW     ou_rptr;    /* Output buffer read-in pointer   */
   73:         UW     ou_wptr;    /* Output buffer write pointer             */
   74: 
   75:         UB     *h_buf;             /* History buffer                  */
   76: 
   77:         UW     rsv:11;
   78:         UW     rcv_xoff:1; /* "XOFF" receive status                */
   79:         UW     disable:2;  /* Send and Receive disabled status      */
   80:         UW     echo:1;             /* The presence or absence of echo */
   81:         UW     newline:1;  /* CR / NL                               */
   82:         UW     input:4;    /* Input mode                              */
   83:         UW     flowc:4;    /* Flow control                            */
   84:         UW     wup_char:8; /* Character to execute "wakeup"        */
   85: 
   86:         ID     wup_tskid;  /* Task ID to execute "wakeup"           */
   87: 
   88:         W      snd_tmout;   /* Send time out                  */
   89:         W      rcv_tmout;   /* Receive time out                       */
   90: } CONSCB;
   91: 
   92: LOCAL   QUEUE     ConsPort;           /* Console port           */
   93: LOCAL   UH        last_port = 0;         /* Last port number            */
   94: 
   95: LOCAL   FastLock  ConsLock;        /* Lock the overall console    */
   96: 
   97: #define DEF_INBUFSZ     256         /* Input buffer size           */
   98: #define DEF_OUBUFSZ     1024                /* Output buffer size         */
   99: #define MIN_BUFSZ       128           /* Minimum buffer size           */
  100: #define HIST_BUFSZ      2048         /* History buffer size         */
  101: 
  102: #define INPTRMASK(p, ptr)       ((ptr) % ((p)->in_bufsz))
  103:                                         /* Input buffer pointer mask       */
  104: #define OUPTRMASK(p, ptr)       ((ptr) % ((p)->ou_bufsz))
  105:                                         /* Output buffer pointer mask      */
  106: 
  107: #define XOFF_MARGIN     64          /* Remaining size to send "XOFF"*/
  108: #define XON_MARGIN      128          /* Remaining size to send "XON" */
  109: 
  110: /* Control character code */
  111: #define BS      ('H'-'@')
  112: #define CAN     ('X'-'@')
  113: #define CTLC    ('C'-'@')
  114: #define DEL     (0x7f)
  115: #define CR      (0x0d)
  116: #define LF      (0x0a)
  117: #define ERASE   ('K'-'@')
  118: #define CAN2    ('U'-'@')
  119: #define TAB     ('I'-'@')
  120: #define ESC     ('['-'@')
  121: #define CUR_UP  ('P'-'@')                /* or ESC [ A */
  122: #define CUR_DWN ('N'-'@')               /* or        ESC [ B */
  123: #define CUR_FWD ('F'-'@')               /* or        ESC [ C */
  124: #define CUR_BWD ('B'-'@')               /* or        ESC [ D */
  125: #define XOFF    ('S'-'@')
  126: #define XON     ('Q'-'@')
  127: 
  128: #define OU_LOCK         17
  129: #define IN_LOCK         16
  130: #define FLG_OU_EVT      (1 << 1)
  131: #define FLG_IN_EVT      (1 << 0)
  132: 
  133: /*
  134:  *      Lock
  135:  */
  136: #define CreLock(lock, name)     consCreateMLock(lock, name)
  137: #define DelLock(lock)           consDeleteMLock(lock)
  138: #define LockIn(lock, no)        consMLock(lock, no)
  139: #define LockOut(lock, no)       consMUnlock(lock, no)
  140: 
  141: /*
  142:  *      Get/Release the memory
  143:  */
  144: #define Malloc(len)     (void*)Imalloc(len)
  145: #define Free(ptr)       Ifree((void*)(ptr))
  146: 
  147: /*
  148:  *      Check the port number
  149:  */
  150: LOCAL   CONSCB    *check_port(W port)
  151: {
  152:         QUEUE  *q;
  153: 
  154:         if (port <= 0) return NULL;
  155:         q = QueSearch(&ConsPort, &ConsPort, port, offsetof(CONSCB, port));
  156:         return (q == &ConsPort) ? NULL : (CONSCB*)q;
  157: }
  158: /*
  159:  *      Check & Use the port number
  160:  */
  161: LOCAL   CONSCB    *get_port(W port)
  162: {
  163:         CONSCB *p;
  164: 
  165:         /* Search the port*/
  166:         Lock(&ConsLock);
  167:         if ((p = check_port(port)) != NULL) p->in_use++; /* Use-count ++*/
  168:         Unlock(&ConsLock);
  169:         return p;
  170: }
  171: /*
  172:  *      Special character processing
  173:  */
  174: LOCAL   W special_char_proc(CONSCB *p, B c)
  175: {
  176:         if (p->input != RAW && c == p->wup_char) {     /* Task "wakeup"*/
  177:                 tk_rel_wai(p->wup_tskid);
  178:                 p->wup_tskid = 0;
  179:         }
  180:         return 0;
  181: }
  182: /*
  183:  *      Write into the console input buffer
  184:  */
  185: LOCAL   W put_consbuf(CONSCB *p, W c, W tmout)
  186: {
  187:         UW     ptr, nptr;
  188:         UINT   flgptn;
  189: 
  190:         /* Special character processing */
  191:         special_char_proc(p, c);
  192: 
  193:         /* Send flow control */
  194:         if (p->flowc & IXON) {
  195:                 if (c == XOFF) {
  196:                         p->rcv_xoff = 1;
  197:                         return 0;
  198:                 }
  199:                 if (c == XON || (p->rcv_xoff && (p->flowc & IXANY))) {
  200:                         if (p->rcv_xoff) {   /* Event occurs */
  201:                                 if (p->flg) tk_set_flg(p->flg, FLG_OU_EVT);
  202:                                 p->rcv_xoff = 0;
  203:                         }
  204:                         return 0;
  205:                 }
  206:         }
  207: 
  208:         ptr = p->in_wptr;
  209:         nptr = INPTRMASK(p, ptr + 1);
  210: 
  211:         /* Input buffer full : wait for the event */
  212:         while (nptr == p->in_rptr) {
  213:                 if (tk_wai_flg(p->flg, FLG_IN_EVT, TWF_ORW | TWF_BITCLR,
  214:                                &flgptn, tmout)) return -1;
  215:         }
  216: 
  217:         /* Store the data in the input buffer */
  218:         p->in_buf[ptr] = c;
  219:         p->in_wptr = nptr;
  220: 
  221:         /* Generate the event when the input-buffer is not empty */
  222:         if (ptr == p->in_rptr) tk_set_flg(p->flg, FLG_IN_EVT);
  223: 
  224:         /* Receive flow control is unnecessary */
  225:         return 0;
  226: }
  227: /*
  228:  *      Read-in from the console input buffer
  229:  */
  230: LOCAL   W read_consbuf(CONSCB *p)
  231: {
  232:         W      c;
  233:         UINT   flgptn;
  234:         UW     ptr;
  235: 
  236:         ptr = p->in_rptr;
  237: 
  238:         /* Input buffer is empty : wait for event */
  239:         while (ptr == p->in_wptr) {
  240:                 if (tk_wai_flg(p->flg, FLG_IN_EVT, TWF_ORW | TWF_BITCLR,
  241:                                &flgptn, p->rcv_tmout)) return -1;
  242:         }
  243: 
  244:         /* Retrieve the data */
  245:         c = p->in_buf[ptr];
  246:         p->in_rptr = INPTRMASK(p, ptr + 1);
  247: 
  248:         /* Event occurs when the input buffer is not full  */
  249:         if (ptr == INPTRMASK(p, p->in_wptr + 1)) {
  250:                 tk_set_flg(p->flg, FLG_IN_EVT);
  251:         }
  252: 
  253:         /* Receive flow control is unnecessary */
  254:         return c;
  255: }
  256: /*
  257:  *      Write into the console output buffer
  258:  */
  259: LOCAL   W write_consbuf(CONSCB *p, W c)
  260: {
  261:         UW     ptr, nptr;
  262:         UINT   flgptn;
  263: 
  264:         ptr = p->ou_wptr;
  265:         nptr = OUPTRMASK(p, ptr + 1);
  266: 
  267:         /* Wait for the event during receiving "XOFF"
  268:                                 or when the output buffer is full */
  269:         while (p->rcv_xoff || nptr == p->ou_rptr) {
  270:                 if (tk_wai_flg(p->flg, FLG_OU_EVT, TWF_ORW | TWF_BITCLR,
  271:                                &flgptn, p->snd_tmout)) return -1;
  272:         }
  273:         p->ou_buf[ptr] = c;
  274:         p->ou_wptr = nptr;
  275: 
  276:         /* Generate the event when the output buffer is not empty */
  277:         if (ptr == p->ou_rptr) tk_set_flg(p->flg, FLG_OU_EVT);
  278: 
  279:         return 0;
  280: }
  281: /*
  282:  *      Read-in from the console output buffer
  283:  */
  284: LOCAL   W get_consbuf(CONSCB *p, W tmout)
  285: {
  286:         W      c;
  287:         UW     ptr;
  288:         UINT   flgptn;
  289: 
  290:         ptr = p->ou_rptr;
  291: 
  292:         /* Output buffer is empty : wait for event */
  293:         while (ptr == p->ou_wptr) {
  294:                 if (tk_wai_flg(p->flg, FLG_OU_EVT, TWF_ORW | TWF_BITCLR,
  295:                                &flgptn, tmout)) return -1;
  296:         }
  297: 
  298:         /* Fetch the data */
  299:         c = p->ou_buf[ptr];
  300:         p->ou_rptr = OUPTRMASK(p, ptr + 1);
  301: 
  302:         /* Event occurs when the buffer is not full */
  303:         if (ptr == OUPTRMASK(p, p->ou_wptr + 1)) {
  304:                 tk_set_flg(p->flg, FLG_OU_EVT);
  305:         }
  306: 
  307:         return c;
  308: }
  309: /*
  310:  *      One character input
  311:  */
  312: LOCAL   W cons_getch(CONSCB *p)
  313: {
  314:         UB     c;
  315:         W      alen;
  316: 
  317:         if (p->conf == CONF_BUFIO)
  318:                 return read_consbuf(p); /* Input from the input-buffer */
  319: 
  320:         /* Input the serial port */
  321:         return (serial_in(p->conf, &c, 1, &alen, p->rcv_tmout) < 0)? -1: c;
  322: }
  323: /*
  324:  *      Output the one character
  325:  */
  326: LOCAL   W cons_putch(CONSCB *p, B c)
  327: {
  328:         W      alen;
  329: 
  330:         if ((p->disable & 0x1) != 0) return 0; /* Stop output   */
  331: 
  332:         if (p->conf == CONF_BUFIO)     /* Output to the output-buffer */
  333:                 return write_consbuf(p, c);
  334: 
  335:         /* Output the serial port */
  336:         return (serial_out(p->conf, &c, 1, &alen, p->snd_tmout) < 0)? -1: 0;
  337: }
  338: /*
  339:  *      Edit line input
  340:  */
  341: LOCAL   W edit_input(CONSCB *p, B *buf, W max)
  342: {
  343:         W      i, c, c1;
  344:         W      cp, ep, hp, esc;
  345:         W      len;
  346:         B      *hist;
  347: 
  348:         cp = ep = esc = 0;
  349:         c1 = 0;
  350:         hp = -1;
  351:         hist = (B*)p->h_buf;
  352: 
  353:         for (;;) {
  354:                 /* Input one character */
  355:                 if ((c = cons_getch(p)) < 0) break;
  356:                 len = 1;
  357:                 if (c & 0x80) {
  358:                         if (c1 == 0) {c1 = c; continue;}
  359:                         c |= c1 << 8;
  360:                         c1 = 0;
  361:                         len = 2;
  362:                 }
  363:                 if (c == ESC) {esc = 1; continue;}
  364:                 if (esc) {    /* "ESC" sequence */
  365:                         if (esc == 1) {esc = (c == '[') ? 2 : 0; continue;}
  366:                         esc = 0;
  367:                         if (c == 'A')                c = CUR_UP;
  368:                         else if (c == 'B')   c = CUR_DWN;
  369:                         else if (c == 'C')   c = CUR_FWD;
  370:                         else if (c == 'D')   c = CUR_BWD;
  371:                         else                 continue;
  372:                 }
  373:                 if (c == CUR_FWD) {
  374:                         if (cp < ep) {
  375:                                 if (buf[cp] & 0x80) cons_putch(p, buf[cp++]);
  376:                                 cons_putch(p, buf[cp++]);
  377:                         }
  378:                         continue;
  379:                 }
  380:                 if (c == CUR_BWD) {
  381:                         if (cp > 0) {
  382:                                 if (buf[--cp] & 0x80){cons_putch(p, BS); cp--;}
  383:                                 cons_putch(p, BS);
  384:                         }
  385:                         continue;
  386:                 }
  387:                 if (c == CUR_UP || c == CUR_DWN) {    /* Call history */
  388:                         if (! hist) continue;
  389: 
  390:                         if (c == CUR_DWN) {
  391:                                 if (hp <= 0) continue;
  392:                                 for (hp--; (--hp) > 0 && hist[hp];);
  393:                                 if (hp) hp++;
  394:                         } else {
  395:                                 i = hp < 0 ? 0 : (STRLEN(&hist[hp]) + hp + 1);
  396:                                 if (hist[i] == 0) continue;
  397:                                 hp = i;
  398:                         }
  399:                         for (; cp > 0; cp--) cons_putch(p, BS);
  400:                         i = STRLEN(&hist[hp]);
  401:                         if (i > max) i = max;
  402:                         for (; cp < i; cp++)
  403:                                 cons_putch(p, buf[cp] = hist[hp + cp]);
  404:                         c = ERASE;
  405:                 }
  406:                 if (c == BS || c == DEL) {
  407:                         if (cp <= 0) continue;
  408:                         len = (buf[cp - 1] & 0x80) ? 2 : 1;
  409:                         if (cp < ep) MEMCPY(&buf[cp-len], &buf[cp], ep - cp);
  410:                         for (i = 0; i < len; i++) {
  411:                                 buf[--ep] = ' ';
  412:                                 cons_putch(p, BS);
  413:                         }
  414:                         cp -= len;
  415:                         for (i = cp; i < ep + len; i++) cons_putch(p, buf[i]);
  416:                         for (; i > cp; i--) cons_putch(p, BS);
  417:                         continue;
  418:                 }
  419:                 if (c == CAN || c == CAN2) {
  420:                         for (; cp > 0; cp--) cons_putch(p, BS);
  421:                         c = ERASE;
  422:                 }
  423:                 if (c == ERASE) {
  424:                         for (i = cp; i < ep; i++) cons_putch(p, ' ');
  425:                         for (; i > cp; i--) cons_putch(p, BS);
  426:                         ep = cp;
  427:                         continue;
  428:                 }
  429:                 if (c == CR || c == LF) {c = LF; break;}
  430: 
  431:                 if (c == CTLC) {cons_putch(p, c); break;}
  432: 
  433:                 if (c < ' ' && c != TAB) continue;
  434: 
  435:                 if (ep + len > max) continue;
  436:                                 /* Ignore the excess number of characters */
  437: 
  438:                 if (cp < ep) MEMMOVE(&buf[cp+len], &buf[cp], ep - cp);
  439:                 if (len == 2) {
  440:                         buf[cp+1] = c & 0xff;
  441:                         c = (c >> 8) & 0xff;
  442:                 }
  443:                 buf[cp] = c;
  444:                 for (ep += len, i = cp; i < ep; i++) cons_putch(p, buf[i]);
  445:                 for (cp += len; i > cp; i--) cons_putch(p, BS);
  446:         }
  447:         if (c == LF) {
  448:                 cons_putch(p, CR);    /* Echo back */
  449:                 cons_putch(p, LF);
  450:         }
  451:         i = ep; /* Valid character-string end */
  452:         if (ep < max && c >= 0) buf[ep++] = c;
  453:         if (ep < max) buf[ep] = 0;
  454:         if (i > 0 && c != CTLC) {              /* Add to the history buffer */
  455:                 if (hist) {
  456:                         MEMMOVE(&hist[i+1], hist, HIST_BUFSZ - 1 - i);
  457:                         MEMCPY(hist, buf, i);
  458:                         hist[i] = 0;
  459:                         hist[HIST_BUFSZ - 2] = 0;
  460:                         hist[HIST_BUFSZ - 1] = 0;
  461:                 }
  462:         }
  463:         return (c == CTLC) ? -1 : ep;
  464: }
  465: /*
  466:  *      Output to the console port :
  467:  *              return: the number of the characters actually output
  468:  */
  469: LOCAL   W _console_out(W port, B *buf, UW len)
  470: {
  471:         CONSCB *p;
  472:         UB     c;
  473:         W      alen = 0;
  474:         ER     er;
  475: 
  476:         /* Check the address */
  477:         er = ChkSpaceR((void*)buf, len);
  478:         if (er < E_OK && er != E_RSFN) return 0;
  479: 
  480:         /* Check the port number */
  481:         if ((p = get_port(port)) != NULL) {
  482: 
  483:                 /* Lock */
  484:                 if (LockIn(&p->lock, OU_LOCK) < 0) goto EEXIT;
  485: 
  486:                 for (; alen < len; alen++) {
  487:                         if ((c = *buf++) == LF && p->newline) {
  488:                                 if (cons_putch(p, CR)) break;
  489:                         }
  490:                         if (cons_putch(p, c)) break;
  491:                 }
  492:                 /* Unlock */
  493:                 LockOut(&p->lock, OU_LOCK);
  494: EEXIT:
  495:                 p->in_use--;          /* Use-count - -*/
  496:         }
  497:         return alen;
  498: }
  499: /*
  500:  *      Input from the console port :
  501:  *              return: the number of the characters actually injput
  502:  */
  503: LOCAL   W _console_in(W port, B *buf, UW len)
  504: {
  505:         CONSCB *p;
  506:         W      c;
  507:         W      alen = 0;
  508: 
  509:         /* Check the address */
  510:         if (ChkSpaceRW((void*)buf, len)) return 0;
  511: 
  512:         /* Check the port number */
  513:         if ((p = get_port(port)) != NULL) {
  514:                 /* Lock */
  515:                 if (LockIn(&p->lock, IN_LOCK) < 0) goto EEXIT;
  516: 
  517:                 /* Input the data */
  518:                 if (p->input == EDIT && len > 1) {
  519:                         alen = edit_input(p, buf, len);
  520:                 } else {
  521:                         while (alen < len) {
  522:                                 if ((c = cons_getch(p)) < 0) break;
  523:                                 if (c == CR && p->input != RAW) c = LF;
  524:                                 if (p->echo) {              /* Echo*/
  525:                                         if (c == LF && p->input != RAW)
  526:                                                 cons_putch(p, CR);
  527:                                         cons_putch(p, c);
  528:                                 }
  529:                                 buf[alen++] = c;
  530:                                 if (p->input == RAW || c == LF || c == CTLC)
  531:                                                         break;
  532:                         }
  533:                 }
  534:                 /* Unlock */
  535:                 LockOut(&p->lock, IN_LOCK);
  536: EEXIT:
  537:                 p->in_use--;          /* Use-count - -*/
  538:         }
  539:         return alen;
  540: }
  541: /*
  542:  *      Control the serial port: return < 0 :error
  543:  */
  544: LOCAL   W _console_ctl(W port, W req, W arg)
  545: {
  546:         CONSCB *p;
  547:         W      n;
  548:         W      rtn = -1;
  549: 
  550:         /* Check the port number */
  551:         if ((p = get_port(port)) != NULL) {
  552: 
  553:                 /* Do not lock */
  554:                 switch (req) {
  555:                 case ECHO|GETCTL:
  556:                         rtn = p->echo;                               break;
  557:                 case ECHO:
  558:                         rtn = 0;     p->echo = arg;              break;
  559:                 case INPUT|GETCTL:
  560:                         rtn = p->input;                              break;
  561:                 case INPUT:
  562:                         rtn = 0;
  563:                         if ((p->input = arg) == EDIT) {
  564:                                 if (!p->h_buf) {
  565:                                         if (!(p->h_buf = Malloc(HIST_BUFSZ)))
  566:                                                         rtn = -1;
  567:                                 }
  568:                                 if (rtn == 0) p->h_buf[0] = 0;
  569:                         } else if (p->h_buf) {
  570:                                 Free(p->h_buf);
  571:                                 p->h_buf = NULL;
  572:                         }
  573:                         break;
  574:                 case NEWLINE|GETCTL:
  575:                         rtn = p->newline;                    break;
  576:                 case NEWLINE:
  577:                         rtn = 0;     p->newline = arg;   break;
  578:                 case FLOWC|GETCTL:
  579:                         rtn = p->flowc;                              break;
  580:                 case FLOWC:
  581:                         rtn = 0;
  582:                         p->flowc = arg;
  583:                         if (p->conf >= 0) {  /* Serial port */
  584:                                 RsFlow flow;
  585:                                 flow.rsv     = 0;
  586:                                 flow.rcvxoff = 0;
  587:                                 flow.csflow  = 0;
  588:                                 flow.rsflow  = 0;
  589:                                 flow.xonany  = (arg & IXANY) != 0;
  590:                                 flow.sxflow  = (arg & IXON ) != 0;
  591:                                 flow.rxflow  = (arg & IXOFF) != 0;
  592:                                 serial_ctl(p->conf, DN_RSFLOW, (void*)&flow);
  593:                         }
  594:                         p->rcv_xoff = 0;
  595:                         break;
  596:                 case SNDTMO|GETCTL:
  597:                         rtn = p->snd_tmout;                  break;
  598:                 case SNDTMO:
  599:                         rtn = 0;
  600:                         p->snd_tmout = (arg < 0) ? -1 : arg; break;
  601:                 case RCVTMO|GETCTL:
  602:                         rtn = p->rcv_tmout;                  break;
  603:                 case RCVTMO:
  604:                         rtn = 0;
  605:                         p->rcv_tmout = (arg < 0) ? -1 : arg; break;
  606:                 case RCVBUFSZ|GETCTL:
  607:                         rtn = p->in_bufsz;                   break;
  608:                 case SNDBUFSZ|GETCTL:
  609:                         rtn = p->ou_bufsz;                   break;
  610:                 case 0x8f:
  611:                         rtn = 0;
  612:                         p->wup_char = arg;
  613:                         if ((n = p->wup_tskid) > 0) tk_wup_tsk(n);
  614:                         p->wup_tskid = tk_get_tid();
  615:                         break;
  616:                 case 0x8e:
  617:                         rtn = 0;     p->disable = arg;   break;
  618:                 }
  619:                 p->in_use--;          /* Use-count - -*/
  620:         }
  621:         return rtn;
  622: }
  623: /*
  624:  *      Write the input data into the console :
  625:  *              return: the number of the characters actually written
  626:  */
  627: LOCAL   W _console_put(W port, B *buf, UW len, W tmout)
  628: {
  629:         CONSCB *p;
  630:         W      alen = 0;
  631: 
  632:         /* Check the address */
  633:         if (ChkSpaceR((void*)buf, len)) return 0;
  634: 
  635:         /* Check the port number */
  636:         if ((p = get_port(port)) != NULL) {
  637:                 /* Do not lock */
  638:                 if (p->conf == CONF_BUFIO && (p->disable & 0x2) == 0) {
  639:                         for (; alen < len; alen++) {
  640:                                 if (put_consbuf(p, (W)*buf++, tmout)) break;
  641:                         }
  642:                 }
  643:                 p->in_use--;          /* Use-count - -*/
  644:         }
  645:         return alen;
  646: }
  647: /*
  648:  *      Read the output data from the console :
  649:  *              return: the number of the characters actually read
  650:  */
  651: LOCAL   W _console_get(W port, B *buf, UW len, W tmout)
  652: {
  653:         CONSCB *p;
  654:         W      c;
  655:         W      alen = 0;
  656: 
  657:         /* Check the address */
  658:         if (ChkSpaceRW((void*)buf, len)) return 0;
  659: 
  660:         /* Check the port number */
  661:         if ((p = get_port(port)) != NULL) {
  662:                 /* Do not lock */
  663:                 if (p->conf == CONF_BUFIO) {
  664:                         for (; alen < len; alen++) {
  665:                                 if ((c = get_consbuf(p, tmout)) < 0) break;
  666:                                 *buf++ = c;
  667:                         }
  668:                 }
  669:                 p->in_use--;          /* Use-count - - */
  670:         }
  671:         return alen;
  672: }
  673: /*
  674:  *      Delete the console
  675:  */
  676: LOCAL   W delete_cons(CONSCB *p)
  677: {
  678:         UW     par[2];
  679: 
  680:         /* Delete from the queue of port */
  681:         QueRemove(&p->q);
  682: 
  683:         /* Lock and delete event flag:Forcibly release the wait */
  684:         if (p->flg) DelLock(&p->lock);
  685: 
  686:         /* Wait until the port is unused */
  687:         while (p->in_use > 0) {
  688:                 if (p->conf >= 0)
  689:                         serial_ctl(p->conf, RS_ABORT, NULL); /* Abort */
  690:                 tk_dly_tsk(10);
  691:         }
  692: 
  693:         /* Release the special setting of the port */
  694:         if (p->conf >= 0) {    /* Serial line port */
  695:                 par[0] = par[1] = 0;
  696:                 serial_ctl(p->conf, RS_EXTFUNC, par);
  697:         }
  698: 
  699:         /* Release the buffer */
  700:         if (p->in_buf) Free(p->in_buf);
  701:         if (p->ou_buf) Free(p->ou_buf);
  702:         if (p->h_buf)  Free(p->h_buf);
  703: 
  704:         /* Delete the port itself */
  705:         Free(p);
  706: 
  707:         return 0;
  708: }
  709: /*
  710:  *      Create the console
  711:  */
  712: LOCAL   W make_cons(W new, W *arg)
  713: {
  714: static  union objname    name = {{ "con0" }};
  715:         CONSCB         *p, *old;
  716:         UH             port;
  717:         W              conf, sz, dmy;
  718:         UW             par[2];
  719: 
  720:         /* Check the "conf" */
  721:         conf = arg[1];
  722:         if (conf != CONF_BUFIO) {
  723:                 /* Check the serial line port */
  724:                 if (conf < 0 || serial_ctl(conf, -DN_RSMODE, &dmy)) return -1;
  725:         }
  726: 
  727:         if (new) {     /* New creation */
  728:                 /* Find the unused port number */
  729:                 for (port = ++last_port; QueSearch(&ConsPort, &ConsPort,
  730:                         (W)port, offsetof(CONSCB, port)) != &ConsPort; port++);
  731:                 arg[0] = (W)(last_port = port);
  732:                 old = NULL;
  733:         } else {       /* Existent :check the port number */
  734:                 port = arg[0];
  735:                 if (!(old = check_port(port))) return -1;
  736:         }
  737: 
  738:         /* Create the new port */
  739:         if (!(p = (CONSCB*)Malloc(sizeof(CONSCB)))) return -1;
  740:         MEMSET((void*)p, 0, sizeof(CONSCB));
  741: 
  742:         /* Object name */
  743:         name.s[3] = '0' + port;
  744: 
  745:         /* Create the event flag/the lock */
  746:         if ((p->flg = CreLock(&p->lock, name.s)) < 0) goto EEXIT;
  747: 
  748:         /* Create the input buffer */
  749:         if (conf == CONF_BUFIO) {
  750:                 if ((sz = arg[2]) < MIN_BUFSZ)
  751:                                 sz = sz ? MIN_BUFSZ : DEF_INBUFSZ;
  752:                 if (!(p->in_buf = Malloc(sz)))        goto EEXIT;
  753:                 p->in_bufsz = sz;
  754:         }
  755:         /* Create the output buffer */
  756:         if (conf == CONF_BUFIO) {
  757:                 if ((sz = arg[3]) < MIN_BUFSZ)
  758:                                 sz = sz ? MIN_BUFSZ : DEF_OUBUFSZ;
  759:                 if (!(p->ou_buf = Malloc(sz)))        goto EEXIT;
  760:                 p->ou_bufsz = sz;
  761:         }
  762: 
  763:         /* Delete the current port when it is not newly created */
  764:         if (new == 0) delete_cons(old);
  765: 
  766:         /* Initialization (except for 0) */
  767:         p->port = port;
  768:         p->conf = conf;
  769:         p->input = CANONICAL;
  770:         p->snd_tmout = p->rcv_tmout = -1;
  771: 
  772:         /* Special setting of port */
  773:         if (conf >= 0) {       /* Serial line port */
  774:                 par[0] = (UW)special_char_proc;
  775:                 par[1] = (UW)p;
  776:                 serial_ctl(conf, RS_EXTFUNC, par);
  777:         }
  778: 
  779:         /* Register to the queue */
  780:         QueInsert(&p->q, &ConsPort);
  781:         return 0;
  782: 
  783: EEXIT:  /* Error processing */
  784:         if (p->in_buf) Free(p->in_buf);
  785:         if (p->ou_buf) Free(p->ou_buf);
  786:         if (p->flg > 0) DelLock(&p->lock);
  787:         Free(p);
  788:         return -1;
  789: }
  790: 
  791: /*
  792:  *      Configuration operation of console
  793:  */
  794: LOCAL   W _console_conf(W req, UW* arg)
  795: {
  796:         CONSCB *p;
  797:         W      n;
  798: 
  799:         /* Skip the address checking */
  800: 
  801:         /* Lock */
  802:         Lock(&ConsLock);
  803: 
  804:         switch(req) {
  805:         case CS_CREATE:                /* Create the console port */
  806:                 n = make_cons(1, (W*)arg);
  807:                 break;
  808: 
  809:         case CS_DELETE:                /* Delete the console port */
  810:                 if (arg[0] > 2 && (p = check_port(arg[0]))) n = delete_cons(p);
  811:                 else  n = -1;
  812:                 break;
  813: 
  814:         case CS_GETCONF:               /* Fetch the console configuration */
  815:                 if ((p = check_port(arg[0])) != NULL) {
  816:                         arg[1] = p->conf;
  817:                         arg[2] = p->in_bufsz;
  818:                         arg[3] = p->ou_bufsz;
  819:                         n = 0;
  820:                 } else        n = -1;
  821:                 break;
  822: 
  823:         case CS_SRCHPORT:              /* Search the console port */
  824:                 n = 0;
  825:                 p = (CONSCB*)&ConsPort;
  826:                 while ((p = (CONSCB*)QueSearch((QUEUE*)p, &ConsPort, arg[1],
  827:                         offsetof(CONSCB, conf))) != (CONSCB*)&ConsPort) {
  828:                         if (p->port > arg[0]) {
  829:                                 arg[0] = n = p->port;
  830:                                 break;
  831:                         }
  832:                 }
  833:                 break;
  834: 
  835:         case CS_SETCONF:               /* Set the console configuration */
  836:                 n = make_cons(0, (W*)arg);
  837:                 break;
  838: 
  839:         case CS_GETPORT:               /* Fetch the standard console port */
  840:                 n = 1;                /* Default #1 */
  841:                 arg[0] = check_port(n) ? n : 1;
  842:                 n = 0;
  843:                 break;
  844: 
  845:         case CS_SETPORT:               /* Set the standard console port */
  846:                 n = -1;
  847:                 break;
  848: 
  849:         default:
  850:                 n = -1;
  851:         }
  852:         /* Unlock */
  853:         Unlock(&ConsLock);
  854:         return n;
  855: }
  856: /*
  857:  *      Console I/O extended SVC
  858:  */
  859: LOCAL   ER        console_io_entry(void *para, W fn, void *gp)
  860: {
  861:         switch ( fn ) {
  862:           /* Input-output between console and buffer */
  863:           case CONSIO_CONSOLE_GET_FN:
  864:                 { CONSIO_CONSOLE_GET_PARA *p = para;
  865:                 return _console_get(p->port, p->buf, p->len, p->tmout); }
  866:           case CONSIO_CONSOLE_PUT_FN:
  867:                 { CONSIO_CONSOLE_PUT_PARA *p = para;
  868:                 return _console_put(p->port, p->buf, p->len, p->tmout); }
  869:           case CONSIO_CONSOLE_CONF_FN:
  870:                 { CONSIO_CONSOLE_CONF_PARA *p = para;
  871:                 return _console_conf(p->req, p->arg); }
  872: 
  873:           /* Input-output between application and buffer */
  874:           case CONSIO_CONSOLE_IN_FN:
  875:                 { CONSIO_CONSOLE_IN_PARA *p = para;
  876:                 return _console_in(p->port, p->buf, p->len); }
  877:           case CONSIO_CONSOLE_OUT_FN:
  878:                 { CONSIO_CONSOLE_OUT_PARA *p = para;
  879:                 return _console_out(p->port, p->buf, p->len); }
  880:           case CONSIO_CONSOLE_CTL_FN:
  881:                 { CONSIO_CONSOLE_CTL_PARA *p = para;
  882:                 return _console_ctl(p->port, p->req, p->arg); }
  883:         }
  884:         return E_RSFN;
  885: }
  886: /*
  887:  *      Console I/O break function
  888:  */
  889: LOCAL   void      console_break(ID tskid)
  890: {
  891:         tk_dis_wai(tskid, TTW_FLG|TTX_SVC);
  892: }
  893: /*
  894:  *      Start-up/end of console
  895:  */
  896: EXPORT  ER       console_startup( BOOL StartUp )
  897: {
  898:         W      n, arg[4];
  899: 
  900:         if ( !StartUp ) {      /* End processing */
  901: 
  902:                 /* Deregister the subsystem */
  903:                 con_def_subsys(CONSIO_SVC, CONSIO_PRI, NULL, NULL);
  904: 
  905:                 /* Delete the all consoles */
  906:                 while (!isQueEmpty(&ConsPort)) {
  907:                         delete_cons((CONSCB*)ConsPort.next);
  908:                 }
  909: 
  910:                 /* Delete the exclusive lock */
  911:                 DeleteLock(&ConsLock);
  912: 
  913:                 return E_OK;
  914:         }
  915: 
  916:         /* Initialization */
  917:         QueInit(&ConsPort);
  918: 
  919:         /* Create the exclusive lock */
  920:         CreateLock(&ConsLock, "cons");
  921: 
  922:         /* Wait for a while */
  923:         tk_dly_tsk(50);
  924: 
  925:         /* Fetch the debug port number from T-Monitor */
  926:         DebugPort = DEFAULT_CONSOLE_PORT;
  927:         if ((n = tm_extsvc(0x04, 0, 0, 0)) >= 0) DebugPort = n;
  928: 
  929:         /* Create the standard console port (#1 : debug console) */
  930:         arg[1] = _isDebugMode() ? DebugPort : CONF_BUFIO;
  931:         arg[2] = arg[3] = 0;
  932:         if (_console_conf(CS_CREATE, (UW*)arg) < E_OK && _isDebugMode()) {
  933:                 /* The debug console is unusable. Therefore, It shall be
  934:                         switched to the buffer I/O to stop send/receive */
  935:                 last_port = 0;
  936:                 arg[1] = CONF_BUFIO;
  937:                 _console_conf(CS_CREATE, (UW*)arg);
  938:                 _console_ctl(1, 0x8e, 0x3);   /* Stop sending/receiving */
  939:         }
  940: 
  941:         /* Create the standard console port (#2 : Serial#1) */
  942:         arg[1] = DebugPort;
  943:         _console_conf(CS_CREATE, (UW*)arg);
  944: 
  945:         /* Initialize the standard console port */
  946:         _console_ctl(1, ECHO, 1);
  947:         _console_ctl(1, INPUT, EDIT);
  948:         _console_ctl(1, NEWLINE, 1);
  949:         _console_ctl(1, FLOWC, IXON | IXOFF);
  950:         if (!_isDebugMode()) _console_ctl(1, 0x8e, 0x3);
  951:                                 /* Stop sending/receiving */
  952: 
  953:         /* Register the subsystem :
  954:                 Overwrite the registration in device common manager */
  955:         return con_def_subsys(CONSIO_SVC, CONSIO_PRI,
  956:                                         console_io_entry, console_break);
  957: }