xref: /plan9/sys/src/cmd/unix/drawterm/kern/devaudio.c (revision 499069debb03e99ea217d35fd87fb49e96918a92)
1*499069deSDavid du Colombier #include	"u.h"
2*499069deSDavid du Colombier #include	"lib.h"
3*499069deSDavid du Colombier #include	"dat.h"
4*499069deSDavid du Colombier #include	"fns.h"
5*499069deSDavid du Colombier #include	"error.h"
6*499069deSDavid du Colombier #include	"devaudio.h"
7*499069deSDavid du Colombier 
8*499069deSDavid du Colombier enum
9*499069deSDavid du Colombier {
10*499069deSDavid du Colombier 	Qdir		= 0,
11*499069deSDavid du Colombier 	Qaudio,
12*499069deSDavid du Colombier 	Qvolume,
13*499069deSDavid du Colombier 
14*499069deSDavid du Colombier 	Aclosed		= 0,
15*499069deSDavid du Colombier 	Aread,
16*499069deSDavid du Colombier 	Awrite,
17*499069deSDavid du Colombier 
18*499069deSDavid du Colombier 	Speed		= 44100,
19*499069deSDavid du Colombier 	Ncmd		= 50,		/* max volume command words */
20*499069deSDavid du Colombier };
21*499069deSDavid du Colombier 
22*499069deSDavid du Colombier Dirtab
23*499069deSDavid du Colombier audiodir[] =
24*499069deSDavid du Colombier {
25*499069deSDavid du Colombier 	".",	{Qdir, 0, QTDIR},		0,	DMDIR|0555,
26*499069deSDavid du Colombier 	"audio",	{Qaudio},		0,	0666,
27*499069deSDavid du Colombier 	"volume",	{Qvolume},		0,	0666,
28*499069deSDavid du Colombier };
29*499069deSDavid du Colombier 
30*499069deSDavid du Colombier static	struct
31*499069deSDavid du Colombier {
32*499069deSDavid du Colombier 	QLock	lk;
33*499069deSDavid du Colombier 	Rendez	vous;
34*499069deSDavid du Colombier 	int	amode;		/* Aclosed/Aread/Awrite for /audio */
35*499069deSDavid du Colombier } audio;
36*499069deSDavid du Colombier 
37*499069deSDavid du Colombier #define aqlock(a) qlock(&(a)->lk)
38*499069deSDavid du Colombier #define aqunlock(a) qunlock(&(a)->lk)
39*499069deSDavid du Colombier 
40*499069deSDavid du Colombier static	struct
41*499069deSDavid du Colombier {
42*499069deSDavid du Colombier 	char*	name;
43*499069deSDavid du Colombier 	int	flag;
44*499069deSDavid du Colombier 	int	ilval;		/* initial values */
45*499069deSDavid du Colombier 	int	irval;
46*499069deSDavid du Colombier } volumes[] =
47*499069deSDavid du Colombier {
48*499069deSDavid du Colombier [Vaudio]		"audio",	Fout, 		50,	50,
49*499069deSDavid du Colombier [Vsynth]		"synth",	Fin|Fout,	0,	0,
50*499069deSDavid du Colombier [Vcd]		"cd",		Fin|Fout,	0,	0,
51*499069deSDavid du Colombier [Vline]		"line",	Fin|Fout,	0,	0,
52*499069deSDavid du Colombier [Vmic]		"mic",	Fin|Fout|Fmono,	0,	0,
53*499069deSDavid du Colombier [Vspeaker]	"speaker",	Fout|Fmono,	0,	0,
54*499069deSDavid du Colombier 
55*499069deSDavid du Colombier [Vtreb]		"treb",		Fout, 		50,	50,
56*499069deSDavid du Colombier [Vbass]		"bass",		Fout, 		50,	50,
57*499069deSDavid du Colombier 
58*499069deSDavid du Colombier [Vspeed]	"speed",	Fin|Fout|Fmono,	Speed,	Speed,
59*499069deSDavid du Colombier 		0
60*499069deSDavid du Colombier };
61*499069deSDavid du Colombier 
62*499069deSDavid du Colombier static	char	Emode[]		= "illegal open mode";
63*499069deSDavid du Colombier static	char	Evolume[]	= "illegal volume specifier";
64*499069deSDavid du Colombier 
65*499069deSDavid du Colombier static	void
66*499069deSDavid du Colombier resetlevel(void)
67*499069deSDavid du Colombier {
68*499069deSDavid du Colombier 	int i;
69*499069deSDavid du Colombier 
70*499069deSDavid du Colombier 	for(i=0; volumes[i].name; i++)
71*499069deSDavid du Colombier 		audiodevsetvol(i, volumes[i].ilval, volumes[i].irval);
72*499069deSDavid du Colombier }
73*499069deSDavid du Colombier 
74*499069deSDavid du Colombier static void
75*499069deSDavid du Colombier audioinit(void)
76*499069deSDavid du Colombier {
77*499069deSDavid du Colombier }
78*499069deSDavid du Colombier 
79*499069deSDavid du Colombier static Chan*
80*499069deSDavid du Colombier audioattach(char *param)
81*499069deSDavid du Colombier {
82*499069deSDavid du Colombier 	return devattach('A', param);
83*499069deSDavid du Colombier }
84*499069deSDavid du Colombier 
85*499069deSDavid du Colombier static Walkqid*
86*499069deSDavid du Colombier audiowalk(Chan *c, Chan *nc, char **name, int nname)
87*499069deSDavid du Colombier {
88*499069deSDavid du Colombier 	return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
89*499069deSDavid du Colombier }
90*499069deSDavid du Colombier 
91*499069deSDavid du Colombier static int
92*499069deSDavid du Colombier audiostat(Chan *c, uchar *db, int n)
93*499069deSDavid du Colombier {
94*499069deSDavid du Colombier 	return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
95*499069deSDavid du Colombier }
96*499069deSDavid du Colombier 
97*499069deSDavid du Colombier static Chan*
98*499069deSDavid du Colombier audioopen(Chan *c, int omode)
99*499069deSDavid du Colombier {
100*499069deSDavid du Colombier 	int amode;
101*499069deSDavid du Colombier 
102*499069deSDavid du Colombier 	switch((ulong)c->qid.path) {
103*499069deSDavid du Colombier 	default:
104*499069deSDavid du Colombier 		error(Eperm);
105*499069deSDavid du Colombier 		break;
106*499069deSDavid du Colombier 
107*499069deSDavid du Colombier 	case Qvolume:
108*499069deSDavid du Colombier 	case Qdir:
109*499069deSDavid du Colombier 		break;
110*499069deSDavid du Colombier 
111*499069deSDavid du Colombier 	case Qaudio:
112*499069deSDavid du Colombier 		amode = Awrite;
113*499069deSDavid du Colombier 		if((omode&7) == OREAD)
114*499069deSDavid du Colombier 			amode = Aread;
115*499069deSDavid du Colombier 		aqlock(&audio);
116*499069deSDavid du Colombier 		if(waserror()){
117*499069deSDavid du Colombier 			aqunlock(&audio);
118*499069deSDavid du Colombier 			nexterror();
119*499069deSDavid du Colombier 		}
120*499069deSDavid du Colombier 		if(audio.amode != Aclosed)
121*499069deSDavid du Colombier 			error(Einuse);
122*499069deSDavid du Colombier 		audiodevopen();
123*499069deSDavid du Colombier 		audio.amode = amode;
124*499069deSDavid du Colombier 		poperror();
125*499069deSDavid du Colombier 		aqunlock(&audio);
126*499069deSDavid du Colombier 		break;
127*499069deSDavid du Colombier 	}
128*499069deSDavid du Colombier 	c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
129*499069deSDavid du Colombier 	c->mode = openmode(omode);
130*499069deSDavid du Colombier 	c->flag |= COPEN;
131*499069deSDavid du Colombier 	c->offset = 0;
132*499069deSDavid du Colombier 
133*499069deSDavid du Colombier 	return c;
134*499069deSDavid du Colombier }
135*499069deSDavid du Colombier 
136*499069deSDavid du Colombier static void
137*499069deSDavid du Colombier audioclose(Chan *c)
138*499069deSDavid du Colombier {
139*499069deSDavid du Colombier 	switch((ulong)c->qid.path) {
140*499069deSDavid du Colombier 	default:
141*499069deSDavid du Colombier 		error(Eperm);
142*499069deSDavid du Colombier 		break;
143*499069deSDavid du Colombier 
144*499069deSDavid du Colombier 	case Qdir:
145*499069deSDavid du Colombier 	case Qvolume:
146*499069deSDavid du Colombier 		break;
147*499069deSDavid du Colombier 
148*499069deSDavid du Colombier 	case Qaudio:
149*499069deSDavid du Colombier 		if(c->flag & COPEN) {
150*499069deSDavid du Colombier 			aqlock(&audio);
151*499069deSDavid du Colombier 			audiodevclose();
152*499069deSDavid du Colombier 			audio.amode = Aclosed;
153*499069deSDavid du Colombier 			aqunlock(&audio);
154*499069deSDavid du Colombier 		}
155*499069deSDavid du Colombier 		break;
156*499069deSDavid du Colombier 	}
157*499069deSDavid du Colombier }
158*499069deSDavid du Colombier 
159*499069deSDavid du Colombier static long
160*499069deSDavid du Colombier audioread(Chan *c, void *v, long n, vlong off)
161*499069deSDavid du Colombier {
162*499069deSDavid du Colombier 	int liv, riv, lov, rov;
163*499069deSDavid du Colombier 	long m;
164*499069deSDavid du Colombier 	char buf[300];
165*499069deSDavid du Colombier 	int j;
166*499069deSDavid du Colombier 	ulong offset = off;
167*499069deSDavid du Colombier 	char *a;
168*499069deSDavid du Colombier 
169*499069deSDavid du Colombier 	a = v;
170*499069deSDavid du Colombier 	switch((ulong)c->qid.path) {
171*499069deSDavid du Colombier 	default:
172*499069deSDavid du Colombier 		error(Eperm);
173*499069deSDavid du Colombier 		break;
174*499069deSDavid du Colombier 
175*499069deSDavid du Colombier 	case Qdir:
176*499069deSDavid du Colombier 		return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
177*499069deSDavid du Colombier 
178*499069deSDavid du Colombier 	case Qaudio:
179*499069deSDavid du Colombier 		if(audio.amode != Aread)
180*499069deSDavid du Colombier 			error(Emode);
181*499069deSDavid du Colombier 		aqlock(&audio);
182*499069deSDavid du Colombier 		if(waserror()){
183*499069deSDavid du Colombier 			aqunlock(&audio);
184*499069deSDavid du Colombier 			nexterror();
185*499069deSDavid du Colombier 		}
186*499069deSDavid du Colombier 		n = audiodevread(v, n);
187*499069deSDavid du Colombier 		poperror();
188*499069deSDavid du Colombier 		aqunlock(&audio);
189*499069deSDavid du Colombier 		break;
190*499069deSDavid du Colombier 
191*499069deSDavid du Colombier 	case Qvolume:
192*499069deSDavid du Colombier 		j = 0;
193*499069deSDavid du Colombier 		buf[0] = 0;
194*499069deSDavid du Colombier 		for(m=0; volumes[m].name; m++){
195*499069deSDavid du Colombier 			audiodevgetvol(m, &lov, &rov);
196*499069deSDavid du Colombier 			liv = lov;
197*499069deSDavid du Colombier 			riv = rov;
198*499069deSDavid du Colombier 			j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
199*499069deSDavid du Colombier 			if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){
200*499069deSDavid du Colombier 				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
201*499069deSDavid du Colombier 					j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
202*499069deSDavid du Colombier 				else{
203*499069deSDavid du Colombier 					if(volumes[m].flag & Fin)
204*499069deSDavid du Colombier 						j += snprint(buf+j, sizeof(buf)-j,
205*499069deSDavid du Colombier 							" in %d", liv);
206*499069deSDavid du Colombier 					if(volumes[m].flag & Fout)
207*499069deSDavid du Colombier 						j += snprint(buf+j, sizeof(buf)-j,
208*499069deSDavid du Colombier 							" out %d", lov);
209*499069deSDavid du Colombier 				}
210*499069deSDavid du Colombier 			}else{
211*499069deSDavid du Colombier 				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
212*499069deSDavid du Colombier 				    liv==lov && riv==rov)
213*499069deSDavid du Colombier 					j += snprint(buf+j, sizeof(buf)-j,
214*499069deSDavid du Colombier 						" left %d right %d",
215*499069deSDavid du Colombier 						liv, riv);
216*499069deSDavid du Colombier 				else{
217*499069deSDavid du Colombier 					if(volumes[m].flag & Fin)
218*499069deSDavid du Colombier 						j += snprint(buf+j, sizeof(buf)-j,
219*499069deSDavid du Colombier 							" in left %d right %d",
220*499069deSDavid du Colombier 							liv, riv);
221*499069deSDavid du Colombier 					if(volumes[m].flag & Fout)
222*499069deSDavid du Colombier 						j += snprint(buf+j, sizeof(buf)-j,
223*499069deSDavid du Colombier 							" out left %d right %d",
224*499069deSDavid du Colombier 							lov, rov);
225*499069deSDavid du Colombier 				}
226*499069deSDavid du Colombier 			}
227*499069deSDavid du Colombier 			j += snprint(buf+j, sizeof(buf)-j, "\n");
228*499069deSDavid du Colombier 		}
229*499069deSDavid du Colombier 		return readstr(offset, a, n, buf);
230*499069deSDavid du Colombier 	}
231*499069deSDavid du Colombier 	return n;
232*499069deSDavid du Colombier }
233*499069deSDavid du Colombier 
234*499069deSDavid du Colombier static long
235*499069deSDavid du Colombier audiowrite(Chan *c, void *vp, long n, vlong off)
236*499069deSDavid du Colombier {
237*499069deSDavid du Colombier 	long m;
238*499069deSDavid du Colombier 	int i, v, left, right, in, out;
239*499069deSDavid du Colombier 	Cmdbuf *cb;
240*499069deSDavid du Colombier 	char *a;
241*499069deSDavid du Colombier 
242*499069deSDavid du Colombier 	USED(off);
243*499069deSDavid du Colombier 	a = vp;
244*499069deSDavid du Colombier 	switch((ulong)c->qid.path) {
245*499069deSDavid du Colombier 	default:
246*499069deSDavid du Colombier 		error(Eperm);
247*499069deSDavid du Colombier 		break;
248*499069deSDavid du Colombier 
249*499069deSDavid du Colombier 	case Qvolume:
250*499069deSDavid du Colombier 		v = Vaudio;
251*499069deSDavid du Colombier 		left = 1;
252*499069deSDavid du Colombier 		right = 1;
253*499069deSDavid du Colombier 		in = 1;
254*499069deSDavid du Colombier 		out = 1;
255*499069deSDavid du Colombier 		cb = parsecmd(vp, n);
256*499069deSDavid du Colombier 		if(waserror()){
257*499069deSDavid du Colombier 			free(cb);
258*499069deSDavid du Colombier 			nexterror();
259*499069deSDavid du Colombier 		}
260*499069deSDavid du Colombier 
261*499069deSDavid du Colombier 		for(i = 0; i < cb->nf; i++){
262*499069deSDavid du Colombier 			/*
263*499069deSDavid du Colombier 			 * a number is volume
264*499069deSDavid du Colombier 			 */
265*499069deSDavid du Colombier 			if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
266*499069deSDavid du Colombier 				m = strtoul(cb->f[i], 0, 10);
267*499069deSDavid du Colombier 				if(!out)
268*499069deSDavid du Colombier 					goto cont0;
269*499069deSDavid du Colombier 				if(left && right)
270*499069deSDavid du Colombier 					audiodevsetvol(v, m, m);
271*499069deSDavid du Colombier 				else if(left)
272*499069deSDavid du Colombier 					audiodevsetvol(v, m, -1);
273*499069deSDavid du Colombier 				else if(right)
274*499069deSDavid du Colombier 					audiodevsetvol(v, -1, m);
275*499069deSDavid du Colombier 				goto cont0;
276*499069deSDavid du Colombier 			}
277*499069deSDavid du Colombier 
278*499069deSDavid du Colombier 			for(m=0; volumes[m].name; m++) {
279*499069deSDavid du Colombier 				if(strcmp(cb->f[i], volumes[m].name) == 0) {
280*499069deSDavid du Colombier 					v = m;
281*499069deSDavid du Colombier 					in = 1;
282*499069deSDavid du Colombier 					out = 1;
283*499069deSDavid du Colombier 					left = 1;
284*499069deSDavid du Colombier 					right = 1;
285*499069deSDavid du Colombier 					goto cont0;
286*499069deSDavid du Colombier 				}
287*499069deSDavid du Colombier 			}
288*499069deSDavid du Colombier 
289*499069deSDavid du Colombier 			if(strcmp(cb->f[i], "reset") == 0) {
290*499069deSDavid du Colombier 				resetlevel();
291*499069deSDavid du Colombier 				goto cont0;
292*499069deSDavid du Colombier 			}
293*499069deSDavid du Colombier 			if(strcmp(cb->f[i], "in") == 0) {
294*499069deSDavid du Colombier 				in = 1;
295*499069deSDavid du Colombier 				out = 0;
296*499069deSDavid du Colombier 				goto cont0;
297*499069deSDavid du Colombier 			}
298*499069deSDavid du Colombier 			if(strcmp(cb->f[i], "out") == 0) {
299*499069deSDavid du Colombier 				in = 0;
300*499069deSDavid du Colombier 				out = 1;
301*499069deSDavid du Colombier 				goto cont0;
302*499069deSDavid du Colombier 			}
303*499069deSDavid du Colombier 			if(strcmp(cb->f[i], "left") == 0) {
304*499069deSDavid du Colombier 				left = 1;
305*499069deSDavid du Colombier 				right = 0;
306*499069deSDavid du Colombier 				goto cont0;
307*499069deSDavid du Colombier 			}
308*499069deSDavid du Colombier 			if(strcmp(cb->f[i], "right") == 0) {
309*499069deSDavid du Colombier 				left = 0;
310*499069deSDavid du Colombier 				right = 1;
311*499069deSDavid du Colombier 				goto cont0;
312*499069deSDavid du Colombier 			}
313*499069deSDavid du Colombier 			error(Evolume);
314*499069deSDavid du Colombier 			break;
315*499069deSDavid du Colombier 		cont0:;
316*499069deSDavid du Colombier 		}
317*499069deSDavid du Colombier 		free(cb);
318*499069deSDavid du Colombier 		poperror();
319*499069deSDavid du Colombier 		break;
320*499069deSDavid du Colombier 
321*499069deSDavid du Colombier 	case Qaudio:
322*499069deSDavid du Colombier 		if(audio.amode != Awrite)
323*499069deSDavid du Colombier 			error(Emode);
324*499069deSDavid du Colombier 		aqlock(&audio);
325*499069deSDavid du Colombier 		if(waserror()){
326*499069deSDavid du Colombier 			aqunlock(&audio);
327*499069deSDavid du Colombier 			nexterror();
328*499069deSDavid du Colombier 		}
329*499069deSDavid du Colombier 		n = audiodevwrite(vp, n);
330*499069deSDavid du Colombier 		poperror();
331*499069deSDavid du Colombier 		aqunlock(&audio);
332*499069deSDavid du Colombier 		break;
333*499069deSDavid du Colombier 	}
334*499069deSDavid du Colombier 	return n;
335*499069deSDavid du Colombier }
336*499069deSDavid du Colombier 
337*499069deSDavid du Colombier void
338*499069deSDavid du Colombier audioswab(uchar *a, uint n)
339*499069deSDavid du Colombier {
340*499069deSDavid du Colombier 	ulong *p, *ep, b;
341*499069deSDavid du Colombier 
342*499069deSDavid du Colombier 	p = (ulong*)a;
343*499069deSDavid du Colombier 	ep = p + (n>>2);
344*499069deSDavid du Colombier 	while(p < ep) {
345*499069deSDavid du Colombier 		b = *p;
346*499069deSDavid du Colombier 		b = (b>>24) | (b<<24) |
347*499069deSDavid du Colombier 			((b&0xff0000) >> 8) |
348*499069deSDavid du Colombier 			((b&0x00ff00) << 8);
349*499069deSDavid du Colombier 		*p++ = b;
350*499069deSDavid du Colombier 	}
351*499069deSDavid du Colombier }
352*499069deSDavid du Colombier 
353*499069deSDavid du Colombier Dev audiodevtab = {
354*499069deSDavid du Colombier 	'A',
355*499069deSDavid du Colombier 	"audio",
356*499069deSDavid du Colombier 
357*499069deSDavid du Colombier 	devreset,
358*499069deSDavid du Colombier 	audioinit,
359*499069deSDavid du Colombier 	devshutdown,
360*499069deSDavid du Colombier 	audioattach,
361*499069deSDavid du Colombier 	audiowalk,
362*499069deSDavid du Colombier 	audiostat,
363*499069deSDavid du Colombier 	audioopen,
364*499069deSDavid du Colombier 	devcreate,
365*499069deSDavid du Colombier 	audioclose,
366*499069deSDavid du Colombier 	audioread,
367*499069deSDavid du Colombier 	devbread,
368*499069deSDavid du Colombier 	audiowrite,
369*499069deSDavid du Colombier 	devbwrite,
370*499069deSDavid du Colombier 	devremove,
371*499069deSDavid du Colombier 	devwstat,
372*499069deSDavid du Colombier };
373