serial.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2014-2018 K. Lange
  5. *
  6. * Serial communication device
  7. *
  8. */
  9. #include <kernel/system.h>
  10. #include <kernel/fs.h>
  11. #include <kernel/pipe.h>
  12. #include <kernel/logging.h>
  13. #include <kernel/args.h>
  14. #include <kernel/module.h>
  15. #define SERIAL_PORT_A 0x3F8
  16. #define SERIAL_PORT_B 0x2F8
  17. #define SERIAL_PORT_C 0x3E8
  18. #define SERIAL_PORT_D 0x2E8
  19. #define SERIAL_IRQ_AC 4
  20. #define SERIAL_IRQ_BD 3
  21. static char serial_recv(int device);
  22. static fs_node_t * _serial_port_a = NULL;
  23. static fs_node_t * _serial_port_b = NULL;
  24. static fs_node_t * _serial_port_c = NULL;
  25. static fs_node_t * _serial_port_d = NULL;
  26. static uint8_t convert(uint8_t in) {
  27. switch (in) {
  28. case 0x7F:
  29. return 0x08;
  30. case 0x0D:
  31. return '\n';
  32. default:
  33. return in;
  34. }
  35. }
  36. static fs_node_t ** pipe_for_port(int port) {
  37. switch (port) {
  38. case SERIAL_PORT_A: return &_serial_port_a;
  39. case SERIAL_PORT_B: return &_serial_port_b;
  40. case SERIAL_PORT_C: return &_serial_port_c;
  41. case SERIAL_PORT_D: return &_serial_port_d;
  42. }
  43. __builtin_unreachable();
  44. }
  45. static int serial_handler_ac(struct regs *r) {
  46. char serial;
  47. int port = 0;
  48. if (inportb(SERIAL_PORT_A+1) & 0x01) {
  49. port = SERIAL_PORT_A;
  50. } else {
  51. port = SERIAL_PORT_C;
  52. }
  53. serial = serial_recv(port);
  54. irq_ack(SERIAL_IRQ_AC);
  55. uint8_t buf[] = {convert(serial), 0};
  56. write_fs(*pipe_for_port(port), 0, 1, buf);
  57. return 1;
  58. }
  59. static int serial_handler_bd(struct regs *r) {
  60. char serial;
  61. int port = 0;
  62. debug_print(NOTICE, "Received something on secondary port");
  63. if (inportb(SERIAL_PORT_B+1) & 0x01) {
  64. port = SERIAL_PORT_B;
  65. } else {
  66. port = SERIAL_PORT_D;
  67. }
  68. serial = serial_recv(port);
  69. irq_ack(SERIAL_IRQ_BD);
  70. uint8_t buf[] = {convert(serial), 0};
  71. write_fs(*pipe_for_port(port), 0, 1, buf);
  72. return 1;
  73. }
  74. static void serial_enable(int port) {
  75. outportb(port + 1, 0x00); /* Disable interrupts */
  76. outportb(port + 3, 0x80); /* Enable divisor mode */
  77. outportb(port + 0, 0x01); /* Div Low: 01 Set the port to 115200 bps */
  78. outportb(port + 1, 0x00); /* Div High: 00 */
  79. outportb(port + 3, 0x03); /* Disable divisor mode, set parity */
  80. outportb(port + 2, 0xC7); /* Enable FIFO and clear */
  81. outportb(port + 4, 0x0B); /* Enable interrupts */
  82. outportb(port + 1, 0x01); /* Enable interrupts */
  83. }
  84. static int serial_rcvd(int device) {
  85. return inportb(device + 5) & 1;
  86. }
  87. static char serial_recv(int device) {
  88. while (serial_rcvd(device) == 0) ;
  89. return inportb(device);
  90. }
  91. static int serial_transmit_empty(int device) {
  92. return inportb(device + 5) & 0x20;
  93. }
  94. static void serial_send(int device, char out) {
  95. while (serial_transmit_empty(device) == 0);
  96. outportb(device, out);
  97. }
  98. static void serial_string(char * out) {
  99. for (uint32_t i = 0; i < strlen(out); ++i) {
  100. serial_send(SERIAL_PORT_A, out[i]);
  101. }
  102. }
  103. static uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
  104. static uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
  105. static void open_serial(fs_node_t *node, unsigned int flags);
  106. static void close_serial(fs_node_t *node);
  107. static uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  108. return read_fs(*pipe_for_port((int)node->device), offset, size, buffer);
  109. }
  110. static uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  111. uint32_t sent = 0;
  112. while (sent < size) {
  113. serial_send((int)node->device, buffer[sent]);
  114. sent++;
  115. }
  116. return size;
  117. }
  118. static void open_serial(fs_node_t * node, unsigned int flags) {
  119. return;
  120. }
  121. static void close_serial(fs_node_t * node) {
  122. return;
  123. }
  124. static int wait_serial(fs_node_t * node, void * process) {
  125. return selectwait_fs(*pipe_for_port((int)node->device), process);
  126. }
  127. static int check_serial(fs_node_t * node) {
  128. return selectcheck_fs(*pipe_for_port((int)node->device));
  129. }
  130. static int have_installed_ac = 0;
  131. static int have_installed_bd = 0;
  132. static fs_node_t * serial_device_create(int device) {
  133. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  134. memset(fnode, 0x00, sizeof(fs_node_t));
  135. fnode->device= (void *)device;
  136. strcpy(fnode->name, "serial");
  137. fnode->uid = 0;
  138. fnode->gid = 0;
  139. fnode->mask = 0660;
  140. fnode->flags = FS_CHARDEVICE;
  141. fnode->read = read_serial;
  142. fnode->write = write_serial;
  143. fnode->open = open_serial;
  144. fnode->close = close_serial;
  145. fnode->readdir = NULL;
  146. fnode->finddir = NULL;
  147. fnode->ioctl = NULL; /* TODO ioctls for raw serial devices */
  148. fnode->selectcheck = check_serial;
  149. fnode->selectwait = wait_serial;
  150. fnode->atime = now();
  151. fnode->mtime = fnode->atime;
  152. fnode->ctime = fnode->atime;
  153. serial_enable(device);
  154. if (device == SERIAL_PORT_A || device == SERIAL_PORT_C) {
  155. if (!have_installed_ac) {
  156. irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac, "serial ac");
  157. have_installed_ac = 1;
  158. }
  159. } else {
  160. if (!have_installed_bd) {
  161. irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd, "serial bd");
  162. have_installed_bd = 1;
  163. }
  164. }
  165. *pipe_for_port(device) = make_pipe(128);
  166. return fnode;
  167. }
  168. static int serial_mount_devices(void) {
  169. fs_node_t * ttyS0 = serial_device_create(SERIAL_PORT_A);
  170. vfs_mount("/dev/ttyS0", ttyS0);
  171. fs_node_t * ttyS1 = serial_device_create(SERIAL_PORT_B);
  172. vfs_mount("/dev/ttyS1", ttyS1);
  173. fs_node_t * ttyS2 = serial_device_create(SERIAL_PORT_C);
  174. vfs_mount("/dev/ttyS2", ttyS2);
  175. fs_node_t * ttyS3 = serial_device_create(SERIAL_PORT_D);
  176. vfs_mount("/dev/ttyS3", ttyS3);
  177. char * c;
  178. if ((c = args_value("logtoserial"))) {
  179. debug_file = ttyS0;
  180. if (!strcmp(c,"INFO") || !strcmp(c,"info")) {
  181. debug_level = INFO;
  182. } else if (!strcmp(c,"NOTICE") || !strcmp(c,"notice")) {
  183. debug_level = NOTICE;
  184. } else if (!strcmp(c,"WARNING") || !strcmp(c,"warning")) {
  185. debug_level = WARNING;
  186. } else if (!strcmp(c,"ERROR") || !strcmp(c,"error")) {
  187. debug_level = ERROR;
  188. } else if (!strcmp(c,"CRITICAL") || !strcmp(c,"critical")) {
  189. debug_level = CRITICAL;
  190. } else if (!strcmp(c,"INSANE") || !strcmp(c,"insane")) {
  191. debug_level = INSANE;
  192. } else {
  193. debug_level = atoi(c);
  194. }
  195. debug_print(NOTICE, "Serial logging enabled at level %d.", debug_level);
  196. }
  197. return 0;
  198. }
  199. static int serial_finalize(void) {
  200. return 0;
  201. }
  202. MODULE_DEF(serial, serial_mount_devices, serial_finalize);