uartpci.c 5.3 KB

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