xref: /plan9/sys/src/9/mtx/devarch.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include "u.h"
2*9a747e4fSDavid du Colombier #include "../port/lib.h"
3*9a747e4fSDavid du Colombier #include "mem.h"
4*9a747e4fSDavid du Colombier #include "dat.h"
5*9a747e4fSDavid du Colombier #include "fns.h"
6*9a747e4fSDavid du Colombier #include "io.h"
7*9a747e4fSDavid du Colombier #include "../port/error.h"
8*9a747e4fSDavid du Colombier 
9*9a747e4fSDavid du Colombier typedef struct IOMap IOMap;
10*9a747e4fSDavid du Colombier struct IOMap
11*9a747e4fSDavid du Colombier {
12*9a747e4fSDavid du Colombier 	IOMap	*next;
13*9a747e4fSDavid du Colombier 	char	tag[13];
14*9a747e4fSDavid du Colombier 	ulong	start;
15*9a747e4fSDavid du Colombier 	ulong	end;
16*9a747e4fSDavid du Colombier };
17*9a747e4fSDavid du Colombier 
18*9a747e4fSDavid du Colombier static struct
19*9a747e4fSDavid du Colombier {
20*9a747e4fSDavid du Colombier 	Lock;
21*9a747e4fSDavid du Colombier 	IOMap	*m;
22*9a747e4fSDavid du Colombier 	IOMap	*free;
23*9a747e4fSDavid du Colombier 	IOMap	maps[32];		// some initial free maps
24*9a747e4fSDavid du Colombier 
25*9a747e4fSDavid du Colombier 	QLock	ql;			// lock for reading map
26*9a747e4fSDavid du Colombier } iomap;
27*9a747e4fSDavid du Colombier 
28*9a747e4fSDavid du Colombier enum {
29*9a747e4fSDavid du Colombier 	Qdir = 0,
30*9a747e4fSDavid du Colombier 	Qioalloc = 1,
31*9a747e4fSDavid du Colombier 	Qiob,
32*9a747e4fSDavid du Colombier 	Qiow,
33*9a747e4fSDavid du Colombier 	Qiol,
34*9a747e4fSDavid du Colombier 	Qbase,
35*9a747e4fSDavid du Colombier 
36*9a747e4fSDavid du Colombier 	Qmax = 16,
37*9a747e4fSDavid du Colombier };
38*9a747e4fSDavid du Colombier 
39*9a747e4fSDavid du Colombier typedef long Rdwrfn(Chan*, void*, long, vlong);
40*9a747e4fSDavid du Colombier 
41*9a747e4fSDavid du Colombier static Rdwrfn *readfn[Qmax];
42*9a747e4fSDavid du Colombier static Rdwrfn *writefn[Qmax];
43*9a747e4fSDavid du Colombier 
44*9a747e4fSDavid du Colombier static Dirtab archdir[] = {
45*9a747e4fSDavid du Colombier 	".",	{ Qdir, 0, QTDIR },	0,	0555,
46*9a747e4fSDavid du Colombier 	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
47*9a747e4fSDavid du Colombier 	"iob",		{ Qiob, 0 },		0,	0660,
48*9a747e4fSDavid du Colombier 	"iow",		{ Qiow, 0 },		0,	0660,
49*9a747e4fSDavid du Colombier 	"iol",		{ Qiol, 0 },		0,	0660,
50*9a747e4fSDavid du Colombier };
51*9a747e4fSDavid du Colombier Lock archwlock;	/* the lock is only for changing archdir */
52*9a747e4fSDavid du Colombier int narchdir = Qbase;
53*9a747e4fSDavid du Colombier int (*_pcmspecial)(char *, ISAConf *);
54*9a747e4fSDavid du Colombier void (*_pcmspecialclose)(int);
55*9a747e4fSDavid du Colombier 
56*9a747e4fSDavid du Colombier /*
57*9a747e4fSDavid du Colombier  * Add a file to the #P listing.  Once added, you can't delete it.
58*9a747e4fSDavid du Colombier  * You can't add a file with the same name as one already there,
59*9a747e4fSDavid du Colombier  * and you get a pointer to the Dirtab entry so you can do things
60*9a747e4fSDavid du Colombier  * like change the Qid version.  Changing the Qid path is disallowed.
61*9a747e4fSDavid du Colombier  */
62*9a747e4fSDavid du Colombier Dirtab*
addarchfile(char * name,int perm,Rdwrfn * rdfn,Rdwrfn * wrfn)63*9a747e4fSDavid du Colombier addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
64*9a747e4fSDavid du Colombier {
65*9a747e4fSDavid du Colombier 	int i;
66*9a747e4fSDavid du Colombier 	Dirtab d;
67*9a747e4fSDavid du Colombier 	Dirtab *dp;
68*9a747e4fSDavid du Colombier 
69*9a747e4fSDavid du Colombier 	memset(&d, 0, sizeof d);
70*9a747e4fSDavid du Colombier 	strcpy(d.name, name);
71*9a747e4fSDavid du Colombier 	d.perm = perm;
72*9a747e4fSDavid du Colombier 
73*9a747e4fSDavid du Colombier 	lock(&archwlock);
74*9a747e4fSDavid du Colombier 	if(narchdir >= Qmax){
75*9a747e4fSDavid du Colombier 		unlock(&archwlock);
76*9a747e4fSDavid du Colombier 		return nil;
77*9a747e4fSDavid du Colombier 	}
78*9a747e4fSDavid du Colombier 
79*9a747e4fSDavid du Colombier 	for(i=0; i<narchdir; i++)
80*9a747e4fSDavid du Colombier 		if(strcmp(archdir[i].name, name) == 0){
81*9a747e4fSDavid du Colombier 			unlock(&archwlock);
82*9a747e4fSDavid du Colombier 			return nil;
83*9a747e4fSDavid du Colombier 		}
84*9a747e4fSDavid du Colombier 
85*9a747e4fSDavid du Colombier 	d.qid.path = narchdir;
86*9a747e4fSDavid du Colombier 	archdir[narchdir] = d;
87*9a747e4fSDavid du Colombier 	readfn[narchdir] = rdfn;
88*9a747e4fSDavid du Colombier 	writefn[narchdir] = wrfn;
89*9a747e4fSDavid du Colombier 	dp = &archdir[narchdir++];
90*9a747e4fSDavid du Colombier 	unlock(&archwlock);
91*9a747e4fSDavid du Colombier 
92*9a747e4fSDavid du Colombier 	return dp;
93*9a747e4fSDavid du Colombier }
94*9a747e4fSDavid du Colombier 
95*9a747e4fSDavid du Colombier void
ioinit(void)96*9a747e4fSDavid du Colombier ioinit(void)
97*9a747e4fSDavid du Colombier {
98*9a747e4fSDavid du Colombier 	int i;
99*9a747e4fSDavid du Colombier 
100*9a747e4fSDavid du Colombier 	for(i = 0; i < nelem(iomap.maps)-1; i++)
101*9a747e4fSDavid du Colombier 		iomap.maps[i].next = &iomap.maps[i+1];
102*9a747e4fSDavid du Colombier 	iomap.maps[i].next = nil;
103*9a747e4fSDavid du Colombier 	iomap.free = iomap.maps;
104*9a747e4fSDavid du Colombier 
105*9a747e4fSDavid du Colombier 	// a dummy entry at 2^17
106*9a747e4fSDavid du Colombier 	ioalloc(0x20000, 1, 0, "dummy");
107*9a747e4fSDavid du Colombier }
108*9a747e4fSDavid du Colombier 
109*9a747e4fSDavid du Colombier //
110*9a747e4fSDavid du Colombier //	alloc some io port space and remember who it was
111*9a747e4fSDavid du Colombier //	alloced to.  if port < 0, find a free region.
112*9a747e4fSDavid du Colombier //
113*9a747e4fSDavid du Colombier int
ioalloc(int port,int size,int align,char * tag)114*9a747e4fSDavid du Colombier ioalloc(int port, int size, int align, char *tag)
115*9a747e4fSDavid du Colombier {
116*9a747e4fSDavid du Colombier 	IOMap *m, **l;
117*9a747e4fSDavid du Colombier 	int i;
118*9a747e4fSDavid du Colombier 
119*9a747e4fSDavid du Colombier 	lock(&iomap);
120*9a747e4fSDavid du Colombier 	if(port < 0){
121*9a747e4fSDavid du Colombier 		// find a free port above 0x400 and below 0x1000
122*9a747e4fSDavid du Colombier 		port = 0x400;
123*9a747e4fSDavid du Colombier 		for(l = &iomap.m; *l; l = &(*l)->next){
124*9a747e4fSDavid du Colombier 			m = *l;
125*9a747e4fSDavid du Colombier 			i = m->start - port;
126*9a747e4fSDavid du Colombier 			if(i > size)
127*9a747e4fSDavid du Colombier 				break;
128*9a747e4fSDavid du Colombier 			if(align > 0)
129*9a747e4fSDavid du Colombier 				port = ((port+align-1)/align)*align;
130*9a747e4fSDavid du Colombier 			else
131*9a747e4fSDavid du Colombier 				port = m->end;
132*9a747e4fSDavid du Colombier 		}
133*9a747e4fSDavid du Colombier 		if(*l == nil){
134*9a747e4fSDavid du Colombier 			unlock(&iomap);
135*9a747e4fSDavid du Colombier 			return -1;
136*9a747e4fSDavid du Colombier 		}
137*9a747e4fSDavid du Colombier 	} else {
138*9a747e4fSDavid du Colombier 		// see if the space clashes with previously allocated ports
139*9a747e4fSDavid du Colombier 		for(l = &iomap.m; *l; l = &(*l)->next){
140*9a747e4fSDavid du Colombier 			m = *l;
141*9a747e4fSDavid du Colombier 			if(m->end <= port)
142*9a747e4fSDavid du Colombier 				continue;
143*9a747e4fSDavid du Colombier 			if(m->start >= port+size)
144*9a747e4fSDavid du Colombier 				break;
145*9a747e4fSDavid du Colombier 			unlock(&iomap);
146*9a747e4fSDavid du Colombier 			return -1;
147*9a747e4fSDavid du Colombier 		}
148*9a747e4fSDavid du Colombier 	}
149*9a747e4fSDavid du Colombier 	m = iomap.free;
150*9a747e4fSDavid du Colombier 	if(m == nil){
151*9a747e4fSDavid du Colombier 		print("ioalloc: out of maps");
152*9a747e4fSDavid du Colombier 		unlock(&iomap);
153*9a747e4fSDavid du Colombier 		return port;
154*9a747e4fSDavid du Colombier 	}
155*9a747e4fSDavid du Colombier 	iomap.free = m->next;
156*9a747e4fSDavid du Colombier 	m->next = *l;
157*9a747e4fSDavid du Colombier 	m->start = port;
158*9a747e4fSDavid du Colombier 	m->end = port + size;
159*9a747e4fSDavid du Colombier 	strncpy(m->tag, tag, sizeof(m->tag));
160*9a747e4fSDavid du Colombier 	m->tag[sizeof(m->tag)-1] = 0;
161*9a747e4fSDavid du Colombier 	*l = m;
162*9a747e4fSDavid du Colombier 
163*9a747e4fSDavid du Colombier 	archdir[0].qid.vers++;
164*9a747e4fSDavid du Colombier 
165*9a747e4fSDavid du Colombier 	unlock(&iomap);
166*9a747e4fSDavid du Colombier 	return m->start;
167*9a747e4fSDavid du Colombier }
168*9a747e4fSDavid du Colombier 
169*9a747e4fSDavid du Colombier void
iofree(int port)170*9a747e4fSDavid du Colombier iofree(int port)
171*9a747e4fSDavid du Colombier {
172*9a747e4fSDavid du Colombier 	IOMap *m, **l;
173*9a747e4fSDavid du Colombier 
174*9a747e4fSDavid du Colombier 	lock(&iomap);
175*9a747e4fSDavid du Colombier 	for(l = &iomap.m; *l; l = &(*l)->next){
176*9a747e4fSDavid du Colombier 		if((*l)->start == port){
177*9a747e4fSDavid du Colombier 			m = *l;
178*9a747e4fSDavid du Colombier 			*l = m->next;
179*9a747e4fSDavid du Colombier 			m->next = iomap.free;
180*9a747e4fSDavid du Colombier 			iomap.free = m;
181*9a747e4fSDavid du Colombier 			break;
182*9a747e4fSDavid du Colombier 		}
183*9a747e4fSDavid du Colombier 		if((*l)->start > port)
184*9a747e4fSDavid du Colombier 			break;
185*9a747e4fSDavid du Colombier 	}
186*9a747e4fSDavid du Colombier 	archdir[0].qid.vers++;
187*9a747e4fSDavid du Colombier 	unlock(&iomap);
188*9a747e4fSDavid du Colombier }
189*9a747e4fSDavid du Colombier 
190*9a747e4fSDavid du Colombier int
iounused(int start,int end)191*9a747e4fSDavid du Colombier iounused(int start, int end)
192*9a747e4fSDavid du Colombier {
193*9a747e4fSDavid du Colombier 	IOMap *m;
194*9a747e4fSDavid du Colombier 
195*9a747e4fSDavid du Colombier 	for(m = iomap.m; m; m = m->next){
196*9a747e4fSDavid du Colombier 		if(start >= m->start && start < m->end
197*9a747e4fSDavid du Colombier 		|| start <= m->start && end > m->start)
198*9a747e4fSDavid du Colombier 			return 0;
199*9a747e4fSDavid du Colombier 	}
200*9a747e4fSDavid du Colombier 	return 1;
201*9a747e4fSDavid du Colombier }
202*9a747e4fSDavid du Colombier 
203*9a747e4fSDavid du Colombier static void
checkport(int start,int end)204*9a747e4fSDavid du Colombier checkport(int start, int end)
205*9a747e4fSDavid du Colombier {
206*9a747e4fSDavid du Colombier 	/* standard vga regs are OK */
207*9a747e4fSDavid du Colombier 	if(start >= 0x2b0 && end <= 0x2df+1)
208*9a747e4fSDavid du Colombier 		return;
209*9a747e4fSDavid du Colombier 	if(start >= 0x3c0 && end <= 0x3da+1)
210*9a747e4fSDavid du Colombier 		return;
211*9a747e4fSDavid du Colombier 
212*9a747e4fSDavid du Colombier 	if(iounused(start, end))
213*9a747e4fSDavid du Colombier 		return;
214*9a747e4fSDavid du Colombier 	error(Eperm);
215*9a747e4fSDavid du Colombier }
216*9a747e4fSDavid du Colombier 
217*9a747e4fSDavid du Colombier static Chan*
archattach(char * spec)218*9a747e4fSDavid du Colombier archattach(char* spec)
219*9a747e4fSDavid du Colombier {
220*9a747e4fSDavid du Colombier 	return devattach('P', spec);
221*9a747e4fSDavid du Colombier }
222*9a747e4fSDavid du Colombier 
223*9a747e4fSDavid du Colombier Walkqid*
archwalk(Chan * c,Chan * nc,char ** name,int nname)224*9a747e4fSDavid du Colombier archwalk(Chan* c, Chan *nc, char** name, int nname)
225*9a747e4fSDavid du Colombier {
226*9a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
227*9a747e4fSDavid du Colombier }
228*9a747e4fSDavid du Colombier 
229*9a747e4fSDavid du Colombier static int
archstat(Chan * c,uchar * dp,int n)230*9a747e4fSDavid du Colombier archstat(Chan* c, uchar* dp, int n)
231*9a747e4fSDavid du Colombier {
232*9a747e4fSDavid du Colombier 	return devstat(c, dp, n, archdir, narchdir, devgen);
233*9a747e4fSDavid du Colombier }
234*9a747e4fSDavid du Colombier 
235*9a747e4fSDavid du Colombier static Chan*
archopen(Chan * c,int omode)236*9a747e4fSDavid du Colombier archopen(Chan* c, int omode)
237*9a747e4fSDavid du Colombier {
238*9a747e4fSDavid du Colombier 	return devopen(c, omode, archdir, nelem(archdir), devgen);
239*9a747e4fSDavid du Colombier }
240*9a747e4fSDavid du Colombier 
241*9a747e4fSDavid du Colombier static void
archclose(Chan *)242*9a747e4fSDavid du Colombier archclose(Chan*)
243*9a747e4fSDavid du Colombier {
244*9a747e4fSDavid du Colombier }
245*9a747e4fSDavid du Colombier 
246*9a747e4fSDavid du Colombier enum
247*9a747e4fSDavid du Colombier {
248*9a747e4fSDavid du Colombier 	Linelen= 31,
249*9a747e4fSDavid du Colombier };
250*9a747e4fSDavid du Colombier 
251*9a747e4fSDavid du Colombier static long
archread(Chan * c,void * a,long n,vlong offset)252*9a747e4fSDavid du Colombier archread(Chan *c, void *a, long n, vlong offset)
253*9a747e4fSDavid du Colombier {
254*9a747e4fSDavid du Colombier 	char buf[Linelen+1], *p;
255*9a747e4fSDavid du Colombier 	int port;
256*9a747e4fSDavid du Colombier 	ushort *sp;
257*9a747e4fSDavid du Colombier 	ulong *lp;
258*9a747e4fSDavid du Colombier 	IOMap *m;
259*9a747e4fSDavid du Colombier 	Rdwrfn *fn;
260*9a747e4fSDavid du Colombier 
261*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
262*9a747e4fSDavid du Colombier 
263*9a747e4fSDavid du Colombier 	case Qdir:
264*9a747e4fSDavid du Colombier 		return devdirread(c, a, n, archdir, nelem(archdir), devgen);
265*9a747e4fSDavid du Colombier 
266*9a747e4fSDavid du Colombier 	case Qiob:
267*9a747e4fSDavid du Colombier 		port = offset;
268*9a747e4fSDavid du Colombier 		checkport(offset, offset+n);
269*9a747e4fSDavid du Colombier 		for(p = a; port < offset+n; port++)
270*9a747e4fSDavid du Colombier 			*p++ = inb(port);
271*9a747e4fSDavid du Colombier 		return n;
272*9a747e4fSDavid du Colombier 
273*9a747e4fSDavid du Colombier 	case Qiow:
274*9a747e4fSDavid du Colombier 		if((n & 0x01) || (offset & 0x01))
275*9a747e4fSDavid du Colombier 			error(Ebadarg);
276*9a747e4fSDavid du Colombier 		checkport(offset, offset+n+1);
277*9a747e4fSDavid du Colombier 		n /= 2;
278*9a747e4fSDavid du Colombier 		sp = a;
279*9a747e4fSDavid du Colombier 		for(port = offset; port < offset+n; port += 2)
280*9a747e4fSDavid du Colombier 			*sp++ = ins(port);
281*9a747e4fSDavid du Colombier 		return n*2;
282*9a747e4fSDavid du Colombier 
283*9a747e4fSDavid du Colombier 	case Qiol:
284*9a747e4fSDavid du Colombier 		if((n & 0x03) || (offset & 0x03))
285*9a747e4fSDavid du Colombier 			error(Ebadarg);
286*9a747e4fSDavid du Colombier 		checkport(offset, offset+n+3);
287*9a747e4fSDavid du Colombier 		n /= 4;
288*9a747e4fSDavid du Colombier 		lp = a;
289*9a747e4fSDavid du Colombier 		for(port = offset; port < offset+n; port += 4)
290*9a747e4fSDavid du Colombier 			*lp++ = inl(port);
291*9a747e4fSDavid du Colombier 		return n*4;
292*9a747e4fSDavid du Colombier 
293*9a747e4fSDavid du Colombier 	case Qioalloc:
294*9a747e4fSDavid du Colombier 		break;
295*9a747e4fSDavid du Colombier 
296*9a747e4fSDavid du Colombier 	default:
297*9a747e4fSDavid du Colombier 		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
298*9a747e4fSDavid du Colombier 			return fn(c, a, n, offset);
299*9a747e4fSDavid du Colombier 		error(Eperm);
300*9a747e4fSDavid du Colombier 		break;
301*9a747e4fSDavid du Colombier 	}
302*9a747e4fSDavid du Colombier 
303*9a747e4fSDavid du Colombier 	offset = offset/Linelen;
304*9a747e4fSDavid du Colombier 	n = n/Linelen;
305*9a747e4fSDavid du Colombier 	p = a;
306*9a747e4fSDavid du Colombier 	lock(&iomap);
307*9a747e4fSDavid du Colombier 	for(m = iomap.m; n > 0 && m != nil; m = m->next){
308*9a747e4fSDavid du Colombier 		if(offset-- > 0)
309*9a747e4fSDavid du Colombier 			continue;
310*9a747e4fSDavid du Colombier 		if(strcmp(m->tag, "dummy") == 0)
311*9a747e4fSDavid du Colombier 			break;
312*9a747e4fSDavid du Colombier 		sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
313*9a747e4fSDavid du Colombier 		memmove(p, buf, Linelen);
314*9a747e4fSDavid du Colombier 		p += Linelen;
315*9a747e4fSDavid du Colombier 		n--;
316*9a747e4fSDavid du Colombier 	}
317*9a747e4fSDavid du Colombier 	unlock(&iomap);
318*9a747e4fSDavid du Colombier 
319*9a747e4fSDavid du Colombier 	return p - (char*)a;
320*9a747e4fSDavid du Colombier }
321*9a747e4fSDavid du Colombier 
322*9a747e4fSDavid du Colombier static long
archwrite(Chan * c,void * a,long n,vlong offset)323*9a747e4fSDavid du Colombier archwrite(Chan *c, void *a, long n, vlong offset)
324*9a747e4fSDavid du Colombier {
325*9a747e4fSDavid du Colombier 	char *p;
326*9a747e4fSDavid du Colombier 	int port;
327*9a747e4fSDavid du Colombier 	ushort *sp;
328*9a747e4fSDavid du Colombier 	ulong *lp;
329*9a747e4fSDavid du Colombier 	Rdwrfn *fn;
330*9a747e4fSDavid du Colombier 
331*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
332*9a747e4fSDavid du Colombier 
333*9a747e4fSDavid du Colombier 	case Qiob:
334*9a747e4fSDavid du Colombier 		p = a;
335*9a747e4fSDavid du Colombier 		checkport(offset, offset+n);
336*9a747e4fSDavid du Colombier 		for(port = offset; port < offset+n; port++)
337*9a747e4fSDavid du Colombier 			outb(port, *p++);
338*9a747e4fSDavid du Colombier 		return n;
339*9a747e4fSDavid du Colombier 
340*9a747e4fSDavid du Colombier 	case Qiow:
341*9a747e4fSDavid du Colombier 		if((n & 01) || (offset & 01))
342*9a747e4fSDavid du Colombier 			error(Ebadarg);
343*9a747e4fSDavid du Colombier 		checkport(offset, offset+n+1);
344*9a747e4fSDavid du Colombier 		n /= 2;
345*9a747e4fSDavid du Colombier 		sp = a;
346*9a747e4fSDavid du Colombier 		for(port = offset; port < offset+n; port += 2)
347*9a747e4fSDavid du Colombier 			outs(port, *sp++);
348*9a747e4fSDavid du Colombier 		return n*2;
349*9a747e4fSDavid du Colombier 
350*9a747e4fSDavid du Colombier 	case Qiol:
351*9a747e4fSDavid du Colombier 		if((n & 0x03) || (offset & 0x03))
352*9a747e4fSDavid du Colombier 			error(Ebadarg);
353*9a747e4fSDavid du Colombier 		checkport(offset, offset+n+3);
354*9a747e4fSDavid du Colombier 		n /= 4;
355*9a747e4fSDavid du Colombier 		lp = a;
356*9a747e4fSDavid du Colombier 		for(port = offset; port < offset+n; port += 4)
357*9a747e4fSDavid du Colombier 			outl(port, *lp++);
358*9a747e4fSDavid du Colombier 		return n*4;
359*9a747e4fSDavid du Colombier 
360*9a747e4fSDavid du Colombier 	default:
361*9a747e4fSDavid du Colombier 		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
362*9a747e4fSDavid du Colombier 			return fn(c, a, n, offset);
363*9a747e4fSDavid du Colombier 		error(Eperm);
364*9a747e4fSDavid du Colombier 		break;
365*9a747e4fSDavid du Colombier 	}
366*9a747e4fSDavid du Colombier 	return 0;
367*9a747e4fSDavid du Colombier }
368*9a747e4fSDavid du Colombier 
369*9a747e4fSDavid du Colombier Dev archdevtab = {
370*9a747e4fSDavid du Colombier 	'P',
371*9a747e4fSDavid du Colombier 	"arch",
372*9a747e4fSDavid du Colombier 
373*9a747e4fSDavid du Colombier 	devreset,
374*9a747e4fSDavid du Colombier 	devinit,
375*9a747e4fSDavid du Colombier 	devshutdown,
376*9a747e4fSDavid du Colombier 	archattach,
377*9a747e4fSDavid du Colombier 	archwalk,
378*9a747e4fSDavid du Colombier 	archstat,
379*9a747e4fSDavid du Colombier 	archopen,
380*9a747e4fSDavid du Colombier 	devcreate,
381*9a747e4fSDavid du Colombier 	archclose,
382*9a747e4fSDavid du Colombier 	archread,
383*9a747e4fSDavid du Colombier 	devbread,
384*9a747e4fSDavid du Colombier 	archwrite,
385*9a747e4fSDavid du Colombier 	devbwrite,
386*9a747e4fSDavid du Colombier 	devremove,
387*9a747e4fSDavid du Colombier 	devwstat,
388*9a747e4fSDavid du Colombier };
389*9a747e4fSDavid du Colombier 
390*9a747e4fSDavid du Colombier int
pcmspecial(char * idstr,ISAConf * isa)391*9a747e4fSDavid du Colombier pcmspecial(char *idstr, ISAConf *isa)
392*9a747e4fSDavid du Colombier {
393*9a747e4fSDavid du Colombier 	return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
394*9a747e4fSDavid du Colombier }
395*9a747e4fSDavid du Colombier 
396*9a747e4fSDavid du Colombier void
pcmspecialclose(int a)397*9a747e4fSDavid du Colombier pcmspecialclose(int a)
398*9a747e4fSDavid du Colombier {
399*9a747e4fSDavid du Colombier 	if (_pcmspecialclose != nil)
400*9a747e4fSDavid du Colombier 		_pcmspecialclose(a);
401*9a747e4fSDavid du Colombier }
402