i8250.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "io.h"
  15. /*
  16. * INS8250 uart
  17. */
  18. enum
  19. {
  20. /*
  21. * register numbers
  22. */
  23. Data= 0, /* xmit/rcv buffer */
  24. Iena= 1, /* interrupt enable */
  25. Ircv= (1<<0), /* for char rcv'd */
  26. Ixmt= (1<<1), /* for xmit buffer empty */
  27. Irstat=(1<<2), /* for change in rcv'er status */
  28. Imstat=(1<<3), /* for change in modem status */
  29. Istat= 2, /* interrupt flag (read) */
  30. Tctl= 2, /* test control (write) */
  31. Format= 3, /* byte format */
  32. Bits8= (3<<0), /* 8 bits/byte */
  33. Stop2= (1<<2), /* 2 stop bits */
  34. Pena= (1<<3), /* generate parity */
  35. Peven= (1<<4), /* even parity */
  36. Pforce=(1<<5), /* force parity */
  37. Break= (1<<6), /* generate a break */
  38. Dra= (1<<7), /* address the divisor */
  39. Mctl= 4, /* modem control */
  40. Dtr= (1<<0), /* data terminal ready */
  41. Rts= (1<<1), /* request to send */
  42. Ri= (1<<2), /* ring */
  43. Inton= (1<<3), /* turn on interrupts */
  44. Loop= (1<<4), /* loop back */
  45. Lstat= 5, /* line status */
  46. Inready=(1<<0), /* receive buffer full */
  47. Oerror=(1<<1), /* receiver overrun */
  48. Perror=(1<<2), /* receiver parity error */
  49. Ferror=(1<<3), /* rcv framing error */
  50. Outready=(1<<5), /* output buffer empty */
  51. Mstat= 6, /* modem status */
  52. Ctsc= (1<<0), /* clear to send changed */
  53. Dsrc= (1<<1), /* data set ready changed */
  54. Rire= (1<<2), /* rising edge of ring indicator */
  55. Dcdc= (1<<3), /* data carrier detect changed */
  56. Cts= (1<<4), /* complement of clear to send line */
  57. Dsr= (1<<5), /* complement of data set ready line */
  58. Ring= (1<<6), /* complement of ring indicator line */
  59. Dcd= (1<<7), /* complement of data carrier detect line */
  60. Scratch=7, /* scratchpad */
  61. Dlsb= 0, /* divisor lsb */
  62. Dmsb= 1, /* divisor msb */
  63. Serial= 0,
  64. Modem= 1,
  65. };
  66. typedef struct Uart Uart;
  67. struct Uart
  68. {
  69. int port;
  70. int freq;
  71. uint8_t sticky[8]; /* sticky write register values */
  72. uint8_t txbusy;
  73. void (*rx)(int); /* routine to take a received character */
  74. int (*tx)(void); /* routine to get a character to transmit */
  75. uint32_t frame;
  76. uint32_t overrun;
  77. };
  78. static Uart com[2];
  79. static Uart* uart;
  80. #define UartFREQ 1843200
  81. #define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v))
  82. #define uartrdreg(u,r) inb((u)->port + r)
  83. /*
  84. * set the baud rate by calculating and setting the baudrate
  85. * generator constant. This will work with fairly non-standard
  86. * baud rates.
  87. */
  88. static void
  89. uartsetbaud(Uart *up, int rate)
  90. {
  91. uint32_t brconst;
  92. brconst = (up->freq+8*rate-1)/(16*rate);
  93. uartwrreg(up, Format, Dra);
  94. outb(up->port+Dmsb, (brconst>>8) & 0xff);
  95. outb(up->port+Dlsb, brconst & 0xff);
  96. uartwrreg(up, Format, 0);
  97. }
  98. /*
  99. * toggle DTR
  100. */
  101. static void
  102. uartdtr(Uart *up, int n)
  103. {
  104. if(n)
  105. up->sticky[Mctl] |= Dtr;
  106. else
  107. up->sticky[Mctl] &= ~Dtr;
  108. uartwrreg(up, Mctl, 0);
  109. }
  110. /*
  111. * toggle RTS
  112. */
  113. static void
  114. uartrts(Uart *up, int n)
  115. {
  116. if(n)
  117. up->sticky[Mctl] |= Rts;
  118. else
  119. up->sticky[Mctl] &= ~Rts;
  120. uartwrreg(up, Mctl, 0);
  121. }
  122. static void
  123. uartintr(Ureg*, void *arg)
  124. {
  125. Uart *up;
  126. int ch;
  127. int s, l, loops;
  128. up = arg;
  129. for(loops = 0; loops < 1024; loops++){
  130. s = uartrdreg(up, Istat);
  131. switch(s & 0x3F){
  132. case 6: /* receiver line status */
  133. l = uartrdreg(up, Lstat);
  134. if(l & Ferror)
  135. up->frame++;
  136. if(l & Oerror)
  137. up->overrun++;
  138. break;
  139. case 4: /* received data available */
  140. case 12:
  141. ch = inb(up->port+Data);
  142. if(up->rx)
  143. (*up->rx)(ch);
  144. break;
  145. case 2: /* transmitter empty */
  146. ch = -1;
  147. if(up->tx)
  148. ch = (*up->tx)();
  149. if(ch != -1)
  150. outb(up->port+Data, ch);
  151. else
  152. up->txbusy = 0;
  153. break;
  154. case 0: /* modem status */
  155. uartrdreg(up, Mstat);
  156. break;
  157. default:
  158. if(s&1)
  159. return;
  160. print("weird modem interrupt #%2.2ux\n", s);
  161. break;
  162. }
  163. }
  164. panic("uartintr: 0x%2.2ux\n", uartrdreg(up, Istat));
  165. }
  166. /*
  167. * turn on a port's interrupts. set DTR and RTS
  168. */
  169. static void
  170. uartenable(Uart *up)
  171. {
  172. /*
  173. * turn on interrupts
  174. */
  175. up->sticky[Iena] = 0;
  176. if(up->tx)
  177. up->sticky[Iena] |= Ixmt;
  178. if(up->rx)
  179. up->sticky[Iena] |= Ircv|Irstat;
  180. uartwrreg(up, Iena, 0);
  181. /*
  182. * turn on DTR and RTS
  183. */
  184. uartdtr(up, 1);
  185. uartrts(up, 1);
  186. }
  187. static void
  188. uartdisable(Uart* up)
  189. {
  190. /*
  191. * Disable interrupts.
  192. */
  193. up->sticky[Iena] = 0;
  194. uartwrreg(up, Iena, 0);
  195. uartdtr(up, 0);
  196. uartrts(up, 0);
  197. }
  198. static void
  199. i8250thre(Uart* up)
  200. {
  201. int i;
  202. for(i = 0; i < 100; i++){
  203. if(uartrdreg(up, Lstat) & Outready)
  204. break;
  205. delay(1);
  206. }
  207. }
  208. int
  209. uartspecial(int which, void (*rx)(int), int (*tx)(void), int baud)
  210. {
  211. Uart *up;
  212. int freq, port, vector;
  213. ISAConf isa;
  214. switch(which){
  215. case 0:
  216. port = 0x3F8;
  217. vector = VectorUART0;
  218. freq = UartFREQ;
  219. up = &com[0];
  220. break;
  221. case 1:
  222. port = 0x2F8;
  223. vector = VectorUART1;
  224. freq = UartFREQ;
  225. up = &com[1];
  226. break;
  227. default:
  228. return 0;
  229. }
  230. memset(&isa, 0, sizeof(isa));
  231. if(isaconfig("eia", which, &isa) != 0){
  232. if(isa.port != 0)
  233. port = isa.port;
  234. if(isa.irq != 0)
  235. vector = VectorPIC+isa.irq;
  236. if(isa.freq != 0)
  237. freq = isa.freq;
  238. }
  239. /*
  240. * Does it exist?
  241. * Should be able to write/read
  242. * the Scratch Pad.
  243. */
  244. outb(port+Scratch, 0x55);
  245. if(inb(port+Scratch) != 0x55)
  246. return 0;
  247. if(uart != nil && uart != up)
  248. uartdisable(uart);
  249. uart = up;
  250. if(up->port == 0){
  251. up->port = port;
  252. setvec(vector, uartintr, up);
  253. }
  254. i8250thre(up);
  255. /*
  256. * set rate to 9600 baud.
  257. * 8 bits/character.
  258. * 1 stop bit.
  259. * interrupts enabled.
  260. */
  261. up->freq = freq;
  262. uartsetbaud(up, 9600);
  263. up->sticky[Format] = Bits8;
  264. uartwrreg(up, Format, 0);
  265. up->sticky[Mctl] |= Inton;
  266. uartwrreg(up, Mctl, 0x0);
  267. up->rx = rx;
  268. up->tx = tx;
  269. uartenable(up);
  270. if(baud)
  271. uartsetbaud(up, baud);
  272. return 1;
  273. }
  274. void
  275. uartputc(int c)
  276. {
  277. Uart *up;
  278. if((up = uart) == nil)
  279. return;
  280. i8250thre(up);
  281. outb(up->port+Data, c);
  282. }
  283. void
  284. uartputs(IOQ *q, char *s, int n)
  285. {
  286. Uart *up;
  287. int c, x;
  288. if((up = uart) == nil)
  289. return;
  290. while(n--){
  291. if(*s == '\n')
  292. q->putc(q, '\r');
  293. q->putc(q, *s++);
  294. }
  295. x = splhi();
  296. if(up->txbusy == 0 && (c = q->getc(q)) != -1){
  297. uartputc(c & 0xFF);
  298. up->txbusy = 1;
  299. }
  300. splx(x);
  301. }
  302. void
  303. uartdrain(IOQ *q)
  304. {
  305. Uart *up;
  306. int c, timeo;
  307. if((up = uart) == nil)
  308. return;
  309. for(timeo = 0; timeo < 10000 && up->txbusy; timeo++)
  310. delay(1);
  311. while((c = q->getc(q)) != -1)
  312. uartputc(c & 0xFF);
  313. uartdisable(up);
  314. }