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