xref: /inferno-os/os/port/devpci.c (revision 9dc22068e29604f4b484e746112a9a4efe6fd57f)
1 /*
2  *	access to PCI configuration space (devpnp.c without PNP)
3  *
4  *	TODO
5  *		- extend PCI raw access to configuration space (writes, byte/short access?)
6  *		- implement PCI access to memory/io space/BIOS ROM
7  *		- use c->aux instead of performing lookup on each read/write?
8  */
9 #include	"u.h"
10 #include	"../port/lib.h"
11 #include	"mem.h"
12 #include	"dat.h"
13 #include	"fns.h"
14 #include	"io.h"
15 #include	"../port/error.h"
16 
17 #define	DPRINT	if(0) print
18 #define	XPRINT	if(1) print
19 
20 enum {
21 	Qtopdir = 0,
22 
23 	Qpcidir,
24 	Qpcictl,
25 	Qpciraw,
26 };
27 
28 #define TYPE(q)		((ulong)(q).path & 0x0F)
29 #define QID(c, t)	(((c)<<4)|(t))
30 
31 static Dirtab topdir[] = {
32 	".",	{ Qtopdir, 0, QTDIR },	0,	0555,
33 	"pci",	{ Qpcidir, 0, QTDIR },	0,	0555,
34 };
35 
36 extern Dev pcidevtab;
37 
38 static int
39 pcigen2(Chan *c, int t, int tbdf, Dir *dp)
40 {
41 	Qid q;
42 
43 	q = (Qid){BUSBDF(tbdf)|t, 0, 0};
44 	switch(t) {
45 	case Qpcictl:
46 		sprint(up->genbuf, "%d.%d.%dctl", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
47 		devdir(c, q, up->genbuf, 0, eve, 0444, dp);
48 		return 1;
49 	case Qpciraw:
50 		sprint(up->genbuf, "%d.%d.%draw", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
51 		devdir(c, q, up->genbuf, 128, eve, 0444, dp);
52 		return 1;
53 	}
54 	return -1;
55 }
56 
57 static int
58 pcigen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
59 {
60 	Qid q;
61 	Pcidev *p;
62 	int tbdf;
63 
64 	switch(TYPE(c->qid)){
65 	case Qtopdir:
66 		if(s == DEVDOTDOT){
67 			q = (Qid){QID(0, Qtopdir), 0, QTDIR};
68 			sprint(up->genbuf, "#%C", pcidevtab.dc);
69 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
70 			return 1;
71 		}
72 		return devgen(c, nil, topdir, nelem(topdir), s, dp);
73 	case Qpcidir:
74 		if(s == DEVDOTDOT){
75 			q = (Qid){QID(0, Qtopdir), 0, QTDIR};
76 			sprint(up->genbuf, "#%C", pcidevtab.dc);
77 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
78 			return 1;
79 		}
80 		p = pcimatch(nil, 0, 0);
81 		while(s >= 2 && p != nil) {
82 			p = pcimatch(p, 0, 0);
83 			s -= 2;
84 		}
85 		if(p == nil)
86 			return -1;
87 		return pcigen2(c, s+Qpcictl, p->tbdf, dp);
88 	case Qpcictl:
89 	case Qpciraw:
90 		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
91 		p = pcimatchtbdf(tbdf);
92 		if(p == nil)
93 			return -1;
94 		return pcigen2(c, TYPE(c->qid), tbdf, dp);
95 	default:
96 		break;
97 	}
98 	return -1;
99 }
100 
101 static Chan*
102 pciattach(char *spec)
103 {
104 	return devattach(pcidevtab.dc, spec);
105 }
106 
107 Walkqid*
108 pciwalk(Chan* c, Chan *nc, char** name, int nname)
109 {
110 	return devwalk(c, nc, name, nname, nil, 0, pcigen);
111 }
112 
113 static int
114 pcistat(Chan* c, uchar* dp, int n)
115 {
116 	return devstat(c, dp, n, nil, 0, pcigen);
117 }
118 
119 static Chan*
120 pciopen(Chan *c, int omode)
121 {
122 	return devopen(c, omode, nil, 0, pcigen);
123 }
124 
125 static void
126 pciclose(Chan*)
127 {
128 }
129 
130 static long
131 pciread(Chan *c, void *va, long n, vlong offset)
132 {
133 	ulong x;
134 	Pcidev *p;
135 	char buf[256], *ebuf, *w;
136 	char *a = va;
137 	int i, tbdf, r;
138 
139 	switch(TYPE(c->qid)){
140 	case Qtopdir:
141 	case Qpcidir:
142 		return devdirread(c, a, n, nil, 0, pcigen);
143 	case Qpcictl:
144 		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
145 		p = pcimatchtbdf(tbdf);
146 		if(p == nil)
147 			error(Egreg);
148 		ebuf = buf+sizeof buf-1;	/* -1 for newline */
149 		w = seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
150 			p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);
151 		for(i=0; i<nelem(p->mem); i++){
152 			if(p->mem[i].size == 0)
153 				continue;
154 			w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
155 		}
156 		*w++ = '\n';
157 		*w = '\0';
158 		return readstr(offset, a, n, buf);
159 	case Qpciraw:
160 		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
161 		p = pcimatchtbdf(tbdf);
162 		if(p == nil)
163 			error(Egreg);
164 		if(offset > 256)
165 			return 0;
166 		if(n+offset > 256)
167 			n = 256-offset;
168 		if(offset%4)
169 			error(Ebadarg);
170 		r = offset;
171 		for(i = 0; i+4 <= n; i+=4) {
172 			x = pcicfgr32(p, r);
173 			a[0] = x;
174 			a[1] = (x>>8);
175 			a[2] = (x>>16);
176 			a[3] = (x>>24);
177 			a += 4;
178 			r += 4;
179 		}
180 		return i;
181 	default:
182 		error(Egreg);
183 	}
184 	return n;
185 }
186 
187 static long
188 pciwrite(Chan *c, void *a, long n, vlong)
189 {
190 	char buf[256];
191 
192 	if(n >= sizeof(buf))
193 		n = sizeof(buf)-1;
194 	strncpy(buf, a, n);
195 	buf[n] = 0;
196 
197 	switch(TYPE(c->qid)){
198 	case Qpcictl:
199 	case Qpciraw:
200 		error(Eperm);
201 	default:
202 		error(Egreg);
203 	}
204 	return n;
205 }
206 
207 
208 Dev pcidevtab = {
209 	'$',
210 	"pci",
211 
212 	devreset,
213 	devinit,
214 	devshutdown,
215 	pciattach,
216 	pciwalk,
217 	pcistat,
218 	pciopen,
219 	devcreate,
220 	pciclose,
221 	pciread,
222 	devbread,
223 	pciwrite,
224 	devbwrite,
225 	devremove,
226 	devwstat,
227 };
228