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