uartpci.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. extern PhysUart i8250physuart;
  9. extern PhysUart pciphysuart;
  10. extern void* i8250alloc(int, int, int);
  11. static Uart *perlehead, *perletail;
  12. static Uart*
  13. uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name,
  14. int iosize)
  15. {
  16. int i, io;
  17. void *ctlr;
  18. char buf[64];
  19. Uart *head, *uart;
  20. io = p->mem[barno].bar & ~0x01;
  21. snprint(buf, sizeof(buf), "%s%d", pciphysuart.name, ctlrno);
  22. if(ioalloc(io, p->mem[barno].size, 0, buf) < 0){
  23. print("uartpci: I/O 0x%uX in use\n", io);
  24. return nil;
  25. }
  26. head = uart = malloc(sizeof(Uart)*n);
  27. for(i = 0; i < n; i++){
  28. ctlr = i8250alloc(io, p->intl, p->tbdf);
  29. io += iosize;
  30. if(ctlr == nil)
  31. continue;
  32. uart->regs = ctlr;
  33. snprint(buf, sizeof(buf), "%s.%8.8uX", name, p->tbdf);
  34. kstrdup(&uart->name, buf);
  35. uart->freq = freq;
  36. uart->phys = &i8250physuart;
  37. if(uart != head)
  38. (uart-1)->next = uart;
  39. uart++;
  40. }
  41. if (head) {
  42. if(perlehead != nil)
  43. perletail->next = head;
  44. else
  45. perlehead = head;
  46. for(perletail = head; perletail->next != nil;
  47. perletail = perletail->next)
  48. ;
  49. }
  50. return head;
  51. }
  52. static Uart *
  53. ultraport16si(int ctlrno, Pcidev *p, ulong freq)
  54. {
  55. int io, i;
  56. char *name;
  57. Uart *uart;
  58. name = "Ultraport16si"; /* 16L788 UARTs */
  59. io = p->mem[4].bar & ~1;
  60. if (ioalloc(io, p->mem[4].size, 0, name) < 0) {
  61. print("uartpci: can't get IO space to set %s to rs-232\n", name);
  62. return nil;
  63. }
  64. for (i = 0; i < 16; i++) {
  65. outb(io, i << 4);
  66. outb(io, (i << 4) + 1); /* set to RS232 mode (Don't ask!) */
  67. }
  68. uart = uartpci(ctlrno, p, 2, 8, freq, name, 16);
  69. if(uart)
  70. uart = uartpci(ctlrno, p, 3, 8, freq, name, 16);
  71. return uart;
  72. }
  73. static Uart*
  74. uartpcipnp(void)
  75. {
  76. Pcidev *p;
  77. char *name;
  78. int ctlrno, subid;
  79. ulong freq;
  80. Uart *uart;
  81. /*
  82. * Loop through all PCI devices looking for simple serial
  83. * controllers (ccrb == 0x07) and configure the ones which
  84. * are familiar. All suitable devices are configured to
  85. * simply point to the generic i8250 driver.
  86. */
  87. perlehead = perletail = nil;
  88. ctlrno = 0;
  89. for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
  90. if(p->ccrb != 0x07 || p->ccru > 2)
  91. continue;
  92. switch(p->did<<16 | p->vid){
  93. default:
  94. continue;
  95. case (0x9835<<16)|0x9710: /* StarTech PCI2S550 */
  96. uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0", 8);
  97. if(uart == nil)
  98. continue;
  99. uart->next = uartpci(ctlrno, p, 1, 1, 1843200,
  100. "PCI2S550-1", 8);
  101. if(uart->next == nil)
  102. continue;
  103. break;
  104. case (0x950A<<16)|0x1415: /* Oxford Semi OX16PCI954 */
  105. /*
  106. * These are common devices used by 3rd-party
  107. * manufacturers.
  108. * Must check the subsystem VID and DID for correct
  109. * match.
  110. */
  111. subid = pcicfgr16(p, PciSVID);
  112. subid |= pcicfgr16(p, PciSID)<<16;
  113. switch(subid){
  114. default:
  115. continue;
  116. case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */
  117. uart = uartpci(ctlrno, p, 0, 1, 18432000,
  118. "CyberSerial-1S", 8);
  119. break;
  120. }
  121. break;
  122. case (0x9050<<16)|0x10B5: /* Perle PCI-Fast4 series */
  123. case (0x9030<<16)|0x10B5: /* Perle Ultraport series */
  124. /*
  125. * These devices consists of a PLX bridge (the above
  126. * PCI VID+DID) behind which are some 16C654 UARTs.
  127. * Must check the subsystem VID and DID for correct
  128. * match.
  129. */
  130. subid = pcicfgr16(p, PciSVID);
  131. subid |= pcicfgr16(p, PciSID)<<16;
  132. freq = 7372800;
  133. switch(subid){
  134. default:
  135. continue;
  136. case (0x0011<<16)|0x12E0: /* Perle PCI-Fast16 */
  137. name = "PCI-Fast16";
  138. uart = uartpci(ctlrno, p, 2, 16, freq, name, 8);
  139. break;
  140. case (0x0021<<16)|0x12E0: /* Perle PCI-Fast8 */
  141. name = "PCI-Fast8";
  142. uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
  143. break;
  144. case (0x0031<<16)|0x12E0: /* Perle PCI-Fast4 */
  145. name = "PCI-Fast4";
  146. uart = uartpci(ctlrno, p, 2, 4, freq, name, 8);
  147. break;
  148. case (0x0021<<16)|0x155F: /* Perle Ultraport8 */
  149. name = "Ultraport8"; /* 16C754 UARTs */
  150. uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
  151. break;
  152. case (0x0041<<16)|0x155F: /* Perle Ultraport16 */
  153. name = "Ultraport16";
  154. uart = uartpci(ctlrno, p, 2, 16, 2 * freq,
  155. name, 8);
  156. break;
  157. case (0x0241<<16)|0x155F: /* Perle Ultraport16 */
  158. uart = ultraport16si(ctlrno, p, 4 * freq);
  159. break;
  160. }
  161. break;
  162. }
  163. if(uart)
  164. ctlrno++;
  165. }
  166. return perlehead;
  167. }
  168. PhysUart pciphysuart = {
  169. .name = "UartPCI",
  170. .pnp = uartpcipnp,
  171. .enable = nil,
  172. .disable = nil,
  173. .kick = nil,
  174. .dobreak = nil,
  175. .baud = nil,
  176. .bits = nil,
  177. .stop = nil,
  178. .parity = nil,
  179. .modemctl = nil,
  180. .rts = nil,
  181. .dtr = nil,
  182. .status = nil,
  183. .fifo = nil,
  184. };