Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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