xref: /inferno-os/os/pc/uartpci.c (revision 4eb166cf184c1f102fb79e31b1465ea3e2021c39)
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*
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*
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