Advertisement
Mysakure

console.c

Nov 19th, 2019
313
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.38 KB | None | 0 0
  1. /* See COPYRIGHT for copyright information. */
  2.  
  3. #include <inc/x86.h>
  4. #include <inc/memlayout.h>
  5. #include <inc/kbdreg.h>
  6. #include <inc/string.h>
  7. #include <inc/assert.h>
  8.  
  9. #include <kern/console.h>
  10.  
  11. static void cons_intr(int (*proc)(void));
  12. static void cons_putc(int c);
  13.  
  14. // Stupid I/O delay routine necessitated by historical PC design flaws
  15. static void
  16. delay(void)
  17. {
  18.     inb(0x84);
  19.     inb(0x84);
  20.     inb(0x84);
  21.     inb(0x84);
  22. }
  23.  
  24. /***** Serial I/O code *****/
  25.  
  26. #define COM1        0x3F8
  27.  
  28. #define COM_RX      0   // In:  Receive buffer (DLAB=0)
  29. #define COM_TX      0   // Out: Transmit buffer (DLAB=0)
  30. #define COM_DLL     0   // Out: Divisor Latch Low (DLAB=1)
  31. #define COM_DLM     1   // Out: Divisor Latch High (DLAB=1)
  32. #define COM_IER     1   // Out: Interrupt Enable Register
  33. #define   COM_IER_RDI   0x01    //   Enable receiver data interrupt
  34. #define COM_IIR     2   // In:  Interrupt ID Register
  35. #define COM_FCR     2   // Out: FIFO Control Register
  36. #define COM_LCR     3   // Out: Line Control Register
  37. #define   COM_LCR_DLAB  0x80    //   Divisor latch access bit
  38. #define   COM_LCR_WLEN8 0x03    //   Wordlength: 8 bits
  39. #define COM_MCR     4   // Out: Modem Control Register
  40. #define   COM_MCR_RTS   0x02    // RTS complement
  41. #define   COM_MCR_DTR   0x01    // DTR complement
  42. #define   COM_MCR_OUT2  0x08    // Out2 complement
  43. #define COM_LSR     5   // In:  Line Status Register
  44. #define   COM_LSR_DATA  0x01    //   Data available
  45. #define   COM_LSR_TXRDY 0x20    //   Transmit buffer avail
  46. #define   COM_LSR_TSRE  0x40    //   Transmitter off
  47.  
  48. static bool serial_exists;
  49.  
  50. static int
  51. serial_proc_data(void)
  52. {
  53.     if (!(inb(COM1+COM_LSR) & COM_LSR_DATA))
  54.         return -1;
  55.     return inb(COM1+COM_RX);
  56. }
  57.  
  58. void
  59. serial_intr(void)
  60. {
  61.     if (serial_exists)
  62.         cons_intr(serial_proc_data);
  63. }
  64.  
  65. static void
  66. serial_putc(int c)
  67. {
  68.     int i;
  69.  
  70.     for (i = 0;
  71.          !(inb(COM1 + COM_LSR) & COM_LSR_TXRDY) && i < 12800;
  72.          i++)
  73.         delay();
  74.  
  75.     outb(COM1 + COM_TX, c);
  76. }
  77.  
  78. static void
  79. serial_init(void)
  80. {
  81.     // Turn off the FIFO
  82.     outb(COM1+COM_FCR, 0);
  83.  
  84.     // Set speed; requires DLAB latch
  85.     outb(COM1+COM_LCR, COM_LCR_DLAB);
  86.     outb(COM1+COM_DLL, (uint8_t) (115200 / 9600));
  87.     outb(COM1+COM_DLM, 0);
  88.  
  89.     // 8 data bits, 1 stop bit, parity off; turn off DLAB latch
  90.     outb(COM1+COM_LCR, COM_LCR_WLEN8 & ~COM_LCR_DLAB);
  91.  
  92.     // No modem controls
  93.     outb(COM1+COM_MCR, 0);
  94.     // Enable rcv interrupts
  95.     outb(COM1+COM_IER, COM_IER_RDI);
  96.  
  97.     // Clear any preexisting overrun indications and interrupts
  98.     // Serial port doesn't exist if COM_LSR returns 0xFF
  99.     serial_exists = (inb(COM1+COM_LSR) != 0xFF);
  100.     (void) inb(COM1+COM_IIR);
  101.     (void) inb(COM1+COM_RX);
  102.  
  103. }
  104.  
  105.  
  106.  
  107. /***** Parallel port output code *****/
  108. // For information on PC parallel port programming, see the class References
  109. // page.
  110.  
  111. static void
  112. lpt_putc(int c)
  113. {
  114.     int i;
  115.  
  116.     for (i = 0; !(inb(0x378+1) & 0x80) && i < 12800; i++)
  117.         delay();
  118.     outb(0x378+0, c);
  119.     outb(0x378+2, 0x08|0x04|0x01);
  120.     outb(0x378+2, 0x08);
  121. }
  122.  
  123.  
  124.  
  125.  
  126. /***** Text-mode CGA/VGA display output *****/
  127.  
  128. static unsigned addr_6845;
  129. static uint16_t *crt_buf;
  130. static uint16_t crt_pos;
  131.  
  132. static void
  133. cga_init(void)
  134. {
  135.     volatile uint16_t *cp;
  136.     uint16_t was;
  137.     unsigned pos;
  138.  
  139.     cp = (uint16_t*) (KERNBASE + CGA_BUF);
  140.     was = *cp;
  141.     *cp = (uint16_t) 0xA55A;
  142.     if (*cp != 0xA55A) {
  143.         cp = (uint16_t*) (KERNBASE + MONO_BUF);
  144.         addr_6845 = MONO_BASE;
  145.     } else {
  146.         *cp = was;
  147.         addr_6845 = CGA_BASE;
  148.     }
  149.  
  150.     /* Extract cursor location */
  151.     outb(addr_6845, 14);
  152.     pos = inb(addr_6845 + 1) << 8;
  153.     outb(addr_6845, 15);
  154.     pos |= inb(addr_6845 + 1);
  155.  
  156.     crt_buf = (uint16_t*) cp;
  157.     crt_pos = pos;
  158. }
  159.  
  160.  
  161.  
  162. static void
  163. cga_putc(int c)
  164. {
  165.     // if no attribute given, then use black on white
  166.     if (!(c & ~0xFF))
  167.         c |= 0x0700;
  168.  
  169.     switch (c & 0xff) {
  170.     case '\b':
  171.         if (crt_pos > 0) {
  172.             crt_pos--;
  173.             crt_buf[crt_pos] = (c & ~0xff) | ' ';
  174.         }
  175.         break;
  176.     case '\n':
  177.         crt_pos += CRT_COLS;
  178.         /* fallthru */
  179.     case '\r':
  180.         crt_pos -= (crt_pos % CRT_COLS);
  181.         break;
  182.     case '\t':
  183.         cons_putc(' ');
  184.         cons_putc(' ');
  185.         cons_putc(' ');
  186.         cons_putc(' ');
  187.         cons_putc(' ');
  188.         break;
  189.     default:
  190.         crt_buf[crt_pos++] = c;     /* write the character */
  191.         break;
  192.     }
  193.  
  194.     // What is the purpose of this?
  195.     if (crt_pos >= CRT_SIZE) {
  196.         int i;
  197.  
  198.         memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t));
  199.         for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)
  200.             crt_buf[i] = 0x0700 | ' ';
  201.         crt_pos -= CRT_COLS;
  202.     }
  203.  
  204.     /* move that little blinky thing */
  205.     outb(addr_6845, 14);
  206.     outb(addr_6845 + 1, crt_pos >> 8);
  207.     outb(addr_6845, 15);
  208.     outb(addr_6845 + 1, crt_pos);
  209. }
  210.  
  211.  
  212. /***** Keyboard input code *****/
  213.  
  214. #define NO      0
  215.  
  216. #define SHIFT       (1<<0)
  217. #define CTL     (1<<1)
  218. #define ALT     (1<<2)
  219.  
  220. #define CAPSLOCK    (1<<3)
  221. #define NUMLOCK     (1<<4)
  222. #define SCROLLLOCK  (1<<5)
  223.  
  224. #define E0ESC       (1<<6)
  225.  
  226. static uint8_t shiftcode[256] =
  227. {
  228.     [0x1D] = CTL,
  229.     [0x2A] = SHIFT,
  230.     [0x36] = SHIFT,
  231.     [0x38] = ALT,
  232.     [0x9D] = CTL,
  233.     [0xB8] = ALT
  234. };
  235.  
  236. static uint8_t togglecode[256] =
  237. {
  238.     [0x3A] = CAPSLOCK,
  239.     [0x45] = NUMLOCK,
  240.     [0x46] = SCROLLLOCK
  241. };
  242.  
  243. static uint8_t normalmap[256] =
  244. {
  245.     NO,   0x1B, '1',  '2',  '3',  '4',  '5',  '6'// 0x00
  246.     '7',  '8',  '9',  '0',  '-',  '=',  '\b', '\t',
  247.     'q',  'w',  'e',  'r',  't',  'y',  'u',  'i'// 0x10
  248.     'o',  'p',  '[',  ']',  '\n', NO,   'a',  's',
  249.     'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';'// 0x20
  250.     '\'', '`',  NO,   '\\', 'z',  'x',  'c',  'v',
  251.     'b',  'n',  'm',  ',',  '.',  '/',  NO,   '*'// 0x30
  252.     NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
  253.     NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7'// 0x40
  254.     '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
  255.     '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
  256.     [0xC7] = KEY_HOME,        [0x9C] = '\n' /*KP_Enter*/,
  257.     [0xB5] = '/' /*KP_Div*/,      [0xC8] = KEY_UP,
  258.     [0xC9] = KEY_PGUP,        [0xCB] = KEY_LF,
  259.     [0xCD] = KEY_RT,          [0xCF] = KEY_END,
  260.     [0xD0] = KEY_DN,          [0xD1] = KEY_PGDN,
  261.     [0xD2] = KEY_INS,         [0xD3] = KEY_DEL
  262. };
  263.  
  264. static uint8_t shiftmap[256] =
  265. {
  266.     NO,   033,  '!',  '@',  '#',  '$',  '%',  '^'// 0x00
  267.     '&',  '*',  '(',  ')',  '_',  '+',  '\b', '\t',
  268.     'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I'// 0x10
  269.     'O',  'P',  '{',  '}',  '\n', NO,   'A',  'S',
  270.     'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':'// 0x20
  271.     '"',  '~',  NO,   '|',  'Z',  'X',  'C',  'V',
  272.     'B',  'N',  'M',  '<',  '>',  '?',  NO,   '*'// 0x30
  273.     NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
  274.     NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7'// 0x40
  275.     '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
  276.     '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
  277.     [0xC7] = KEY_HOME,        [0x9C] = '\n' /*KP_Enter*/,
  278.     [0xB5] = '/' /*KP_Div*/,      [0xC8] = KEY_UP,
  279.     [0xC9] = KEY_PGUP,        [0xCB] = KEY_LF,
  280.     [0xCD] = KEY_RT,          [0xCF] = KEY_END,
  281.     [0xD0] = KEY_DN,          [0xD1] = KEY_PGDN,
  282.     [0xD2] = KEY_INS,         [0xD3] = KEY_DEL
  283. };
  284.  
  285. #define C(x) (x - '@')
  286.  
  287. static uint8_t ctlmap[256] =
  288. {
  289.     NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO,
  290.     NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO,
  291.     C('Q'),  C('W'),  C('E'),  C('R'),  C('T'),  C('Y'),  C('U'),  C('I'),
  292.     C('O'),  C('P'),  NO,      NO,      '\r',    NO,      C('A'),  C('S'),
  293.     C('D'),  C('F'),  C('G'),  C('H'),  C('J'),  C('K'),  C('L'),  NO,
  294.     NO,      NO,      NO,      C('\\'), C('Z'),  C('X'),  C('C'),  C('V'),
  295.     C('B'),  C('N'),  C('M'),  NO,      NO,      C('/'),  NO,      NO,
  296.     [0x97] = KEY_HOME,
  297.     [0xB5] = C('/'),        [0xC8] = KEY_UP,
  298.     [0xC9] = KEY_PGUP,      [0xCB] = KEY_LF,
  299.     [0xCD] = KEY_RT,        [0xCF] = KEY_END,
  300.     [0xD0] = KEY_DN,        [0xD1] = KEY_PGDN,
  301.     [0xD2] = KEY_INS,       [0xD3] = KEY_DEL
  302. };
  303.  
  304. static uint8_t *charcode[4] = {
  305.     normalmap,
  306.     shiftmap,
  307.     ctlmap,
  308.     ctlmap
  309. };
  310.  
  311. /*
  312.  * Get data from the keyboard.  If we finish a character, return it.  Else 0.
  313.  * Return -1 if no data.
  314.  */
  315. static int
  316. kbd_proc_data(void)
  317. {
  318.     int c;
  319.     uint8_t data;
  320.     static uint32_t shift;
  321.  
  322.     if ((inb(KBSTATP) & KBS_DIB) == 0)
  323.         return -1;
  324.  
  325.     data = inb(KBDATAP);
  326.  
  327.     if (data == 0xE0) {
  328.         // E0 escape character
  329.         shift |= E0ESC;
  330.         return 0;
  331.     } else if (data & 0x80) {
  332.         // Key released
  333.         data = (shift & E0ESC ? data : data & 0x7F);
  334.         shift &= ~(shiftcode[data] | E0ESC);
  335.         return 0;
  336.     } else if (shift & E0ESC) {
  337.         // Last character was an E0 escape; or with 0x80
  338.         data |= 0x80;
  339.         shift &= ~E0ESC;
  340.     }
  341.  
  342.     shift |= shiftcode[data];
  343.     shift ^= togglecode[data];
  344.  
  345.     c = charcode[shift & (CTL | SHIFT)][data];
  346.     if (shift & CAPSLOCK) {
  347.         if ('a' <= c && c <= 'z')
  348.             c += 'A' - 'a';
  349.         else if ('A' <= c && c <= 'Z')
  350.             c += 'a' - 'A';
  351.     }
  352.  
  353.     // Process special keys
  354.     // Ctrl-Alt-Del: reboot
  355.     if (!(~shift & (CTL | ALT)) && c == KEY_DEL) {
  356.         cprintf("Rebooting!\n");
  357.         outb(0x92, 0x3); // courtesy of Chris Frost
  358.     }
  359.  
  360.     return c;
  361. }
  362.  
  363. void
  364. kbd_intr(void)
  365. {
  366.     cons_intr(kbd_proc_data);
  367. }
  368.  
  369. static void
  370. kbd_init(void)
  371. {
  372. }
  373.  
  374.  
  375.  
  376. /***** General device-independent console code *****/
  377. // Here we manage the console input buffer,
  378. // where we stash characters received from the keyboard or serial port
  379. // whenever the corresponding interrupt occurs.
  380.  
  381. #define CONSBUFSIZE 512
  382.  
  383. static struct {
  384.     uint8_t buf[CONSBUFSIZE];
  385.     uint32_t rpos;
  386.     uint32_t wpos;
  387. } cons;
  388.  
  389. // called by device interrupt routines to feed input characters
  390. // into the circular console input buffer.
  391. static void
  392. cons_intr(int (*proc)(void))
  393. {
  394.     int c;
  395.  
  396.     while ((c = (*proc)()) != -1) {
  397.         if (c == 0)
  398.             continue;
  399.         cons.buf[cons.wpos++] = c;
  400.         if (cons.wpos == CONSBUFSIZE)
  401.             cons.wpos = 0;
  402.     }
  403. }
  404.  
  405. // return the next input character from the console, or 0 if none waiting
  406. int
  407. cons_getc(void)
  408. {
  409.     int c;
  410.  
  411.     // poll for any pending input characters,
  412.     // so that this function works even when interrupts are disabled
  413.     // (e.g., when called from the kernel monitor).
  414.     serial_intr();
  415.     kbd_intr();
  416.  
  417.     // grab the next character from the input buffer.
  418.     if (cons.rpos != cons.wpos) {
  419.         c = cons.buf[cons.rpos++];
  420.         if (cons.rpos == CONSBUFSIZE)
  421.             cons.rpos = 0;
  422.         return c;
  423.     }
  424.     return 0;
  425. }
  426.  
  427. // output a character to the console
  428. static void
  429. cons_putc(int c)
  430. {
  431.     serial_putc(c);
  432.     lpt_putc(c);
  433.     cga_putc(c);
  434. }
  435.  
  436. // initialize the console devices
  437. void
  438. cons_init(void)
  439. {
  440.     cga_init();
  441.     kbd_init();
  442.     serial_init();
  443.  
  444.     if (!serial_exists)
  445.         cprintf("Serial port does not exist!\n");
  446. }
  447.  
  448.  
  449. // `High'-level console I/O.  Used by readline and cprintf.
  450.  
  451. void
  452. cputchar(int c)
  453. {
  454.     cons_putc(c);
  455. }
  456.  
  457. int
  458. getchar(void)
  459. {
  460.     int c;
  461.  
  462.     while ((c = cons_getc()) == 0)
  463.         /* do nothing */;
  464.     return c;
  465. }
  466.  
  467. int
  468. iscons(int fdnum)
  469. {
  470.     // used by readline
  471.     return 1;
  472. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement