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 #include "../port/uart.h"
9
10 extern PhysUart i8250physuart;
11 extern PhysUart pciphysuart;
12 extern void* i8250alloc(int, int, int);
13
14 static Uart*
uartpci(int ctlrno,Pcidev * p,int barno,int n,int freq,char * name)15 uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name)
16 {
17 int i, io;
18 void *ctlr;
19 char buf[64];
20 Uart *head, *uart;
21
22 io = p->mem[barno].bar & ~0x01;
23 snprint(buf, sizeof(buf), "%s%d", pciphysuart.name, ctlrno);
24 if(ioalloc(io, p->mem[barno].size, 0, buf) < 0){
25 print("uartpci: I/O 0x%uX in use\n", io);
26 return nil;
27 }
28
29 head = uart = malloc(sizeof(Uart)*n);
30
31 for(i = 0; i < n; i++){
32 ctlr = i8250alloc(io, p->intl, p->tbdf);
33 io += 8;
34 if(ctlr == nil)
35 continue;
36
37 uart->regs = ctlr;
38 snprint(buf, sizeof(buf), "%s.%8.8uX", name, p->tbdf);
39 kstrdup(&uart->name, buf);
40 uart->freq = freq;
41 uart->phys = &i8250physuart;
42 if(uart != head)
43 (uart-1)->next = uart;
44 uart++;
45 }
46
47 return head;
48 }
49
50 static Uart*
uartpcipnp(void)51 uartpcipnp(void)
52 {
53 Pcidev *p;
54 char *name;
55 int ctlrno, n, subid;
56 Uart *head, *tail, *uart;
57
58 /*
59 * Loop through all PCI devices looking for simple serial
60 * controllers (ccrb == 0x07) and configure the ones which
61 * are familiar. All suitable devices are configured to
62 * simply point to the generic i8250 driver.
63 */
64 head = tail = nil;
65 ctlrno = 0;
66 for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
67 if(p->ccrb != 0x07 || p->ccru != 0)
68 continue;
69
70 switch((p->did<<16)|p->vid){
71 default:
72 continue;
73 case (0x9050<<16)|0x10B5: /* Perle PCI-Fast4 series */
74 case (0x9030<<16)|0x10B5: /* Perle Ultraport series */
75 /*
76 * These devices consists of a PLX bridge (the above
77 * PCI VID+DID) behind which are some 16C654 UARTs.
78 * Must check the subsystem VID and DID for correct
79 * match.
80 */
81 subid = pcicfgr16(p, PciSVID);
82 subid |= pcicfgr16(p, PciSID)<<16;
83 switch(subid){
84 default:
85 continue;
86 case (0x0011<<16)|0x12E0: /* Perle PCI-Fast16 */
87 n = 16;
88 name = "PCI-Fast16";
89 break;
90 case (0x0021<<16)|0x12E0: /* Perle PCI-Fast8 */
91 n = 8;
92 name = "PCI-Fast8";
93 break;
94 case (0x0031<<16)|0x12E0: /* Perle PCI-Fast4 */
95 n = 4;
96 name = "PCI-Fast4";
97 break;
98 case (0x0021<<16)|0x155F: /* Perle Ultraport8 */
99 n = 8;
100 name = "Ultraport8"; /* 16C754 UARTs */
101 break;
102 }
103 uart = uartpci(ctlrno, p, 2, n, 7372800, name);
104 if(uart == nil)
105 continue;
106 break;
107 }
108
109 if(head != nil)
110 tail->next = uart;
111 else
112 head = uart;
113 for(tail = uart; tail->next != nil; tail = tail->next)
114 ;
115 ctlrno++;
116 }
117
118 return head;
119 }
120
121 PhysUart pciphysuart = {
122 .name = "UartPCI",
123 .pnp = uartpcipnp,
124 .enable = nil,
125 .disable = nil,
126 .kick = nil,
127 .dobreak = nil,
128 .baud = nil,
129 .bits = nil,
130 .stop = nil,
131 .parity = nil,
132 .modemctl = nil,
133 .rts = nil,
134 .dtr = nil,
135 .status = nil,
136 .fifo = nil,
137 };
138