tty.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* -*- linux-c -*- ------------------------------------------------------- *
  2. *
  3. * Copyright (C) 1991, 1992 Linus Torvalds
  4. * Copyright 2007 rPath, Inc. - All Rights Reserved
  5. * Copyright 2009 Intel Corporation; author H. Peter Anvin
  6. *
  7. * This file is part of the Linux kernel, and is made available under
  8. * the terms of the GNU General Public License version 2.
  9. *
  10. * ----------------------------------------------------------------------- */
  11. /*
  12. * Very simple screen and serial I/O
  13. */
  14. #include "boot.h"
  15. #define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */
  16. static int early_serial_base;
  17. #define XMTRDY 0x20
  18. #define DLAB 0x80
  19. #define TXR 0 /* Transmit register (WRITE) */
  20. #define RXR 0 /* Receive register (READ) */
  21. #define IER 1 /* Interrupt Enable */
  22. #define IIR 2 /* Interrupt ID */
  23. #define FCR 2 /* FIFO control */
  24. #define LCR 3 /* Line control */
  25. #define MCR 4 /* Modem control */
  26. #define LSR 5 /* Line Status */
  27. #define MSR 6 /* Modem Status */
  28. #define DLL 0 /* Divisor Latch Low */
  29. #define DLH 1 /* Divisor latch High */
  30. #define DEFAULT_BAUD 9600
  31. /*
  32. * These functions are in .inittext so they can be used to signal
  33. * error during initialization.
  34. */
  35. static void __attribute__((section(".inittext"))) serial_putchar(int ch)
  36. {
  37. unsigned timeout = 0xffff;
  38. while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
  39. cpu_relax();
  40. outb(ch, early_serial_base + TXR);
  41. }
  42. static void __attribute__((section(".inittext"))) bios_putchar(int ch)
  43. {
  44. struct biosregs ireg;
  45. initregs(&ireg);
  46. ireg.bx = 0x0007;
  47. ireg.cx = 0x0001;
  48. ireg.ah = 0x0e;
  49. ireg.al = ch;
  50. intcall(0x10, &ireg, NULL);
  51. }
  52. void __attribute__((section(".inittext"))) putchar(int ch)
  53. {
  54. if (ch == '\n')
  55. putchar('\r'); /* \n -> \r\n */
  56. bios_putchar(ch);
  57. if (early_serial_base != 0)
  58. serial_putchar(ch);
  59. }
  60. void __attribute__((section(".inittext"))) puts(const char *str)
  61. {
  62. while (*str)
  63. putchar(*str++);
  64. }
  65. /*
  66. * Read the CMOS clock through the BIOS, and return the
  67. * seconds in BCD.
  68. */
  69. static u8 gettime(void)
  70. {
  71. struct biosregs ireg, oreg;
  72. initregs(&ireg);
  73. ireg.ah = 0x02;
  74. intcall(0x1a, &ireg, &oreg);
  75. return oreg.dh;
  76. }
  77. /*
  78. * Read from the keyboard
  79. */
  80. int getchar(void)
  81. {
  82. struct biosregs ireg, oreg;
  83. initregs(&ireg);
  84. /* ireg.ah = 0x00; */
  85. intcall(0x16, &ireg, &oreg);
  86. return oreg.al;
  87. }
  88. static int kbd_pending(void)
  89. {
  90. struct biosregs ireg, oreg;
  91. initregs(&ireg);
  92. ireg.ah = 0x01;
  93. intcall(0x16, &ireg, &oreg);
  94. return !(oreg.eflags & X86_EFLAGS_ZF);
  95. }
  96. void kbd_flush(void)
  97. {
  98. for (;;) {
  99. if (!kbd_pending())
  100. break;
  101. getchar();
  102. }
  103. }
  104. int getchar_timeout(void)
  105. {
  106. int cnt = 30;
  107. int t0, t1;
  108. t0 = gettime();
  109. while (cnt) {
  110. if (kbd_pending())
  111. return getchar();
  112. t1 = gettime();
  113. if (t0 != t1) {
  114. cnt--;
  115. t0 = t1;
  116. }
  117. }
  118. return 0; /* Timeout! */
  119. }
  120. static void early_serial_init(int baud)
  121. {
  122. unsigned char c;
  123. unsigned divisor;
  124. outb(0x3, early_serial_base + LCR); /* 8n1 */
  125. outb(0, early_serial_base + IER); /* no interrupt */
  126. outb(0, early_serial_base + FCR); /* no fifo */
  127. outb(0x3, early_serial_base + MCR); /* DTR + RTS */
  128. divisor = 115200 / baud;
  129. c = inb(early_serial_base + LCR);
  130. outb(c | DLAB, early_serial_base + LCR);
  131. outb(divisor & 0xff, early_serial_base + DLL);
  132. outb((divisor >> 8) & 0xff, early_serial_base + DLH);
  133. outb(c & ~DLAB, early_serial_base + LCR);
  134. }
  135. void console_init(void)
  136. {
  137. int baud = DEFAULT_BAUD;
  138. char arg[32];
  139. int pos = 0;
  140. if (cmdline_find_option("earlyprintk", arg, sizeof arg) > 0) {
  141. char *e;
  142. if (!strncmp(arg, "serial", 6)) {
  143. early_serial_base = DEFAULT_SERIAL_PORT;
  144. pos += 6;
  145. }
  146. if (arg[pos] == ',')
  147. pos++;
  148. if (!strncmp(arg, "ttyS", 4)) {
  149. static const int bases[] = { 0x3f8, 0x2f8 };
  150. int port = 0;
  151. if (!strncmp(arg + pos, "ttyS", 4))
  152. pos += 4;
  153. if (arg[pos++] == '1')
  154. port = 1;
  155. early_serial_base = bases[port];
  156. }
  157. if (arg[pos] == ',')
  158. pos++;
  159. baud = simple_strtoull(arg + pos, &e, 0);
  160. if (baud == 0 || arg + pos == e)
  161. baud = DEFAULT_BAUD;
  162. }
  163. if (early_serial_base != 0)
  164. early_serial_init(baud);
  165. }