Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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