1499069deSDavid du Colombier #include "u.h"
2499069deSDavid du Colombier #include "lib.h"
3499069deSDavid du Colombier #include "dat.h"
4499069deSDavid du Colombier #include "fns.h"
5499069deSDavid du Colombier #include "error.h"
6499069deSDavid du Colombier #include "devaudio.h"
7499069deSDavid du Colombier
8499069deSDavid du Colombier enum
9499069deSDavid du Colombier {
10499069deSDavid du Colombier Qdir = 0,
11499069deSDavid du Colombier Qaudio,
12499069deSDavid du Colombier Qvolume,
13499069deSDavid du Colombier
14499069deSDavid du Colombier Aclosed = 0,
15499069deSDavid du Colombier Aread,
16499069deSDavid du Colombier Awrite,
17499069deSDavid du Colombier
18499069deSDavid du Colombier Speed = 44100,
19499069deSDavid du Colombier Ncmd = 50, /* max volume command words */
20499069deSDavid du Colombier };
21499069deSDavid du Colombier
22499069deSDavid du Colombier Dirtab
23499069deSDavid du Colombier audiodir[] =
24499069deSDavid du Colombier {
25499069deSDavid du Colombier ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
26499069deSDavid du Colombier "audio", {Qaudio}, 0, 0666,
27499069deSDavid du Colombier "volume", {Qvolume}, 0, 0666,
28499069deSDavid du Colombier };
29499069deSDavid du Colombier
30499069deSDavid du Colombier static struct
31499069deSDavid du Colombier {
32499069deSDavid du Colombier QLock lk;
33499069deSDavid du Colombier Rendez vous;
34499069deSDavid du Colombier int amode; /* Aclosed/Aread/Awrite for /audio */
35499069deSDavid du Colombier } audio;
36499069deSDavid du Colombier
37499069deSDavid du Colombier #define aqlock(a) qlock(&(a)->lk)
38499069deSDavid du Colombier #define aqunlock(a) qunlock(&(a)->lk)
39499069deSDavid du Colombier
40499069deSDavid du Colombier static struct
41499069deSDavid du Colombier {
42499069deSDavid du Colombier char* name;
43499069deSDavid du Colombier int flag;
44499069deSDavid du Colombier int ilval; /* initial values */
45499069deSDavid du Colombier int irval;
46499069deSDavid du Colombier } volumes[] =
47499069deSDavid du Colombier {
48*ec59a3ddSDavid du Colombier "audio", Fout, 50, 50,
49*ec59a3ddSDavid du Colombier "synth", Fin|Fout, 0, 0,
50*ec59a3ddSDavid du Colombier "cd", Fin|Fout, 0, 0,
51*ec59a3ddSDavid du Colombier "line", Fin|Fout, 0, 0,
52*ec59a3ddSDavid du Colombier "mic", Fin|Fout|Fmono, 0, 0,
53*ec59a3ddSDavid du Colombier "speaker", Fout|Fmono, 0, 0,
54499069deSDavid du Colombier
55*ec59a3ddSDavid du Colombier "treb", Fout, 50, 50,
56*ec59a3ddSDavid du Colombier "bass", Fout, 50, 50,
57499069deSDavid du Colombier
58*ec59a3ddSDavid du Colombier "speed", Fin|Fout|Fmono, Speed, Speed,
59499069deSDavid du Colombier 0
60499069deSDavid du Colombier };
61499069deSDavid du Colombier
62499069deSDavid du Colombier static char Emode[] = "illegal open mode";
63499069deSDavid du Colombier static char Evolume[] = "illegal volume specifier";
64499069deSDavid du Colombier
65499069deSDavid du Colombier static void
resetlevel(void)66499069deSDavid du Colombier resetlevel(void)
67499069deSDavid du Colombier {
68499069deSDavid du Colombier int i;
69499069deSDavid du Colombier
70499069deSDavid du Colombier for(i=0; volumes[i].name; i++)
71499069deSDavid du Colombier audiodevsetvol(i, volumes[i].ilval, volumes[i].irval);
72499069deSDavid du Colombier }
73499069deSDavid du Colombier
74499069deSDavid du Colombier static void
audioinit(void)75499069deSDavid du Colombier audioinit(void)
76499069deSDavid du Colombier {
77499069deSDavid du Colombier }
78499069deSDavid du Colombier
79499069deSDavid du Colombier static Chan*
audioattach(char * param)80499069deSDavid du Colombier audioattach(char *param)
81499069deSDavid du Colombier {
82499069deSDavid du Colombier return devattach('A', param);
83499069deSDavid du Colombier }
84499069deSDavid du Colombier
85499069deSDavid du Colombier static Walkqid*
audiowalk(Chan * c,Chan * nc,char ** name,int nname)86499069deSDavid du Colombier audiowalk(Chan *c, Chan *nc, char **name, int nname)
87499069deSDavid du Colombier {
88499069deSDavid du Colombier return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
89499069deSDavid du Colombier }
90499069deSDavid du Colombier
91499069deSDavid du Colombier static int
audiostat(Chan * c,uchar * db,int n)92499069deSDavid du Colombier audiostat(Chan *c, uchar *db, int n)
93499069deSDavid du Colombier {
94499069deSDavid du Colombier return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
95499069deSDavid du Colombier }
96499069deSDavid du Colombier
97499069deSDavid du Colombier static Chan*
audioopen(Chan * c,int omode)98499069deSDavid du Colombier audioopen(Chan *c, int omode)
99499069deSDavid du Colombier {
100499069deSDavid du Colombier int amode;
101499069deSDavid du Colombier
102499069deSDavid du Colombier switch((ulong)c->qid.path) {
103499069deSDavid du Colombier default:
104499069deSDavid du Colombier error(Eperm);
105499069deSDavid du Colombier break;
106499069deSDavid du Colombier
107499069deSDavid du Colombier case Qvolume:
108499069deSDavid du Colombier case Qdir:
109499069deSDavid du Colombier break;
110499069deSDavid du Colombier
111499069deSDavid du Colombier case Qaudio:
112499069deSDavid du Colombier amode = Awrite;
113499069deSDavid du Colombier if((omode&7) == OREAD)
114499069deSDavid du Colombier amode = Aread;
115499069deSDavid du Colombier aqlock(&audio);
116499069deSDavid du Colombier if(waserror()){
117499069deSDavid du Colombier aqunlock(&audio);
118499069deSDavid du Colombier nexterror();
119499069deSDavid du Colombier }
120499069deSDavid du Colombier if(audio.amode != Aclosed)
121499069deSDavid du Colombier error(Einuse);
122499069deSDavid du Colombier audiodevopen();
123499069deSDavid du Colombier audio.amode = amode;
124499069deSDavid du Colombier poperror();
125499069deSDavid du Colombier aqunlock(&audio);
126499069deSDavid du Colombier break;
127499069deSDavid du Colombier }
128499069deSDavid du Colombier c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
129499069deSDavid du Colombier c->mode = openmode(omode);
130499069deSDavid du Colombier c->flag |= COPEN;
131499069deSDavid du Colombier c->offset = 0;
132499069deSDavid du Colombier
133499069deSDavid du Colombier return c;
134499069deSDavid du Colombier }
135499069deSDavid du Colombier
136499069deSDavid du Colombier static void
audioclose(Chan * c)137499069deSDavid du Colombier audioclose(Chan *c)
138499069deSDavid du Colombier {
139499069deSDavid du Colombier switch((ulong)c->qid.path) {
140499069deSDavid du Colombier default:
141499069deSDavid du Colombier error(Eperm);
142499069deSDavid du Colombier break;
143499069deSDavid du Colombier
144499069deSDavid du Colombier case Qdir:
145499069deSDavid du Colombier case Qvolume:
146499069deSDavid du Colombier break;
147499069deSDavid du Colombier
148499069deSDavid du Colombier case Qaudio:
149499069deSDavid du Colombier if(c->flag & COPEN) {
150499069deSDavid du Colombier aqlock(&audio);
151499069deSDavid du Colombier audiodevclose();
152499069deSDavid du Colombier audio.amode = Aclosed;
153499069deSDavid du Colombier aqunlock(&audio);
154499069deSDavid du Colombier }
155499069deSDavid du Colombier break;
156499069deSDavid du Colombier }
157499069deSDavid du Colombier }
158499069deSDavid du Colombier
159499069deSDavid du Colombier static long
audioread(Chan * c,void * v,long n,vlong off)160499069deSDavid du Colombier audioread(Chan *c, void *v, long n, vlong off)
161499069deSDavid du Colombier {
162499069deSDavid du Colombier int liv, riv, lov, rov;
163499069deSDavid du Colombier long m;
164499069deSDavid du Colombier char buf[300];
165499069deSDavid du Colombier int j;
166499069deSDavid du Colombier ulong offset = off;
167499069deSDavid du Colombier char *a;
168499069deSDavid du Colombier
169499069deSDavid du Colombier a = v;
170499069deSDavid du Colombier switch((ulong)c->qid.path) {
171499069deSDavid du Colombier default:
172499069deSDavid du Colombier error(Eperm);
173499069deSDavid du Colombier break;
174499069deSDavid du Colombier
175499069deSDavid du Colombier case Qdir:
176499069deSDavid du Colombier return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
177499069deSDavid du Colombier
178499069deSDavid du Colombier case Qaudio:
179499069deSDavid du Colombier if(audio.amode != Aread)
180499069deSDavid du Colombier error(Emode);
181499069deSDavid du Colombier aqlock(&audio);
182499069deSDavid du Colombier if(waserror()){
183499069deSDavid du Colombier aqunlock(&audio);
184499069deSDavid du Colombier nexterror();
185499069deSDavid du Colombier }
186499069deSDavid du Colombier n = audiodevread(v, n);
187499069deSDavid du Colombier poperror();
188499069deSDavid du Colombier aqunlock(&audio);
189499069deSDavid du Colombier break;
190499069deSDavid du Colombier
191499069deSDavid du Colombier case Qvolume:
192499069deSDavid du Colombier j = 0;
193499069deSDavid du Colombier buf[0] = 0;
194499069deSDavid du Colombier for(m=0; volumes[m].name; m++){
195499069deSDavid du Colombier audiodevgetvol(m, &lov, &rov);
196499069deSDavid du Colombier liv = lov;
197499069deSDavid du Colombier riv = rov;
198499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
199499069deSDavid du Colombier if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){
200499069deSDavid du Colombier if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
201499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
202499069deSDavid du Colombier else{
203499069deSDavid du Colombier if(volumes[m].flag & Fin)
204499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
205499069deSDavid du Colombier " in %d", liv);
206499069deSDavid du Colombier if(volumes[m].flag & Fout)
207499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
208499069deSDavid du Colombier " out %d", lov);
209499069deSDavid du Colombier }
210499069deSDavid du Colombier }else{
211499069deSDavid du Colombier if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
212499069deSDavid du Colombier liv==lov && riv==rov)
213499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
214499069deSDavid du Colombier " left %d right %d",
215499069deSDavid du Colombier liv, riv);
216499069deSDavid du Colombier else{
217499069deSDavid du Colombier if(volumes[m].flag & Fin)
218499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
219499069deSDavid du Colombier " in left %d right %d",
220499069deSDavid du Colombier liv, riv);
221499069deSDavid du Colombier if(volumes[m].flag & Fout)
222499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
223499069deSDavid du Colombier " out left %d right %d",
224499069deSDavid du Colombier lov, rov);
225499069deSDavid du Colombier }
226499069deSDavid du Colombier }
227499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, "\n");
228499069deSDavid du Colombier }
229499069deSDavid du Colombier return readstr(offset, a, n, buf);
230499069deSDavid du Colombier }
231499069deSDavid du Colombier return n;
232499069deSDavid du Colombier }
233499069deSDavid du Colombier
234499069deSDavid du Colombier static long
audiowrite(Chan * c,void * vp,long n,vlong off)235499069deSDavid du Colombier audiowrite(Chan *c, void *vp, long n, vlong off)
236499069deSDavid du Colombier {
237499069deSDavid du Colombier long m;
238499069deSDavid du Colombier int i, v, left, right, in, out;
239499069deSDavid du Colombier Cmdbuf *cb;
240499069deSDavid du Colombier char *a;
241499069deSDavid du Colombier
242499069deSDavid du Colombier USED(off);
243499069deSDavid du Colombier a = vp;
244499069deSDavid du Colombier switch((ulong)c->qid.path) {
245499069deSDavid du Colombier default:
246499069deSDavid du Colombier error(Eperm);
247499069deSDavid du Colombier break;
248499069deSDavid du Colombier
249499069deSDavid du Colombier case Qvolume:
250499069deSDavid du Colombier v = Vaudio;
251499069deSDavid du Colombier left = 1;
252499069deSDavid du Colombier right = 1;
253499069deSDavid du Colombier in = 1;
254499069deSDavid du Colombier out = 1;
255499069deSDavid du Colombier cb = parsecmd(vp, n);
256499069deSDavid du Colombier if(waserror()){
257499069deSDavid du Colombier free(cb);
258499069deSDavid du Colombier nexterror();
259499069deSDavid du Colombier }
260499069deSDavid du Colombier
261499069deSDavid du Colombier for(i = 0; i < cb->nf; i++){
262499069deSDavid du Colombier /*
263499069deSDavid du Colombier * a number is volume
264499069deSDavid du Colombier */
265499069deSDavid du Colombier if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
266499069deSDavid du Colombier m = strtoul(cb->f[i], 0, 10);
267499069deSDavid du Colombier if(!out)
268499069deSDavid du Colombier goto cont0;
269499069deSDavid du Colombier if(left && right)
270499069deSDavid du Colombier audiodevsetvol(v, m, m);
271499069deSDavid du Colombier else if(left)
272499069deSDavid du Colombier audiodevsetvol(v, m, -1);
273499069deSDavid du Colombier else if(right)
274499069deSDavid du Colombier audiodevsetvol(v, -1, m);
275499069deSDavid du Colombier goto cont0;
276499069deSDavid du Colombier }
277499069deSDavid du Colombier
278499069deSDavid du Colombier for(m=0; volumes[m].name; m++) {
279499069deSDavid du Colombier if(strcmp(cb->f[i], volumes[m].name) == 0) {
280499069deSDavid du Colombier v = m;
281499069deSDavid du Colombier in = 1;
282499069deSDavid du Colombier out = 1;
283499069deSDavid du Colombier left = 1;
284499069deSDavid du Colombier right = 1;
285499069deSDavid du Colombier goto cont0;
286499069deSDavid du Colombier }
287499069deSDavid du Colombier }
288499069deSDavid du Colombier
289499069deSDavid du Colombier if(strcmp(cb->f[i], "reset") == 0) {
290499069deSDavid du Colombier resetlevel();
291499069deSDavid du Colombier goto cont0;
292499069deSDavid du Colombier }
293499069deSDavid du Colombier if(strcmp(cb->f[i], "in") == 0) {
294499069deSDavid du Colombier in = 1;
295499069deSDavid du Colombier out = 0;
296499069deSDavid du Colombier goto cont0;
297499069deSDavid du Colombier }
298499069deSDavid du Colombier if(strcmp(cb->f[i], "out") == 0) {
299499069deSDavid du Colombier in = 0;
300499069deSDavid du Colombier out = 1;
301499069deSDavid du Colombier goto cont0;
302499069deSDavid du Colombier }
303499069deSDavid du Colombier if(strcmp(cb->f[i], "left") == 0) {
304499069deSDavid du Colombier left = 1;
305499069deSDavid du Colombier right = 0;
306499069deSDavid du Colombier goto cont0;
307499069deSDavid du Colombier }
308499069deSDavid du Colombier if(strcmp(cb->f[i], "right") == 0) {
309499069deSDavid du Colombier left = 0;
310499069deSDavid du Colombier right = 1;
311499069deSDavid du Colombier goto cont0;
312499069deSDavid du Colombier }
313499069deSDavid du Colombier error(Evolume);
314499069deSDavid du Colombier break;
315499069deSDavid du Colombier cont0:;
316499069deSDavid du Colombier }
317499069deSDavid du Colombier free(cb);
318499069deSDavid du Colombier poperror();
319499069deSDavid du Colombier break;
320499069deSDavid du Colombier
321499069deSDavid du Colombier case Qaudio:
322499069deSDavid du Colombier if(audio.amode != Awrite)
323499069deSDavid du Colombier error(Emode);
324499069deSDavid du Colombier aqlock(&audio);
325499069deSDavid du Colombier if(waserror()){
326499069deSDavid du Colombier aqunlock(&audio);
327499069deSDavid du Colombier nexterror();
328499069deSDavid du Colombier }
329499069deSDavid du Colombier n = audiodevwrite(vp, n);
330499069deSDavid du Colombier poperror();
331499069deSDavid du Colombier aqunlock(&audio);
332499069deSDavid du Colombier break;
333499069deSDavid du Colombier }
334499069deSDavid du Colombier return n;
335499069deSDavid du Colombier }
336499069deSDavid du Colombier
337499069deSDavid du Colombier void
audioswab(uchar * a,uint n)338499069deSDavid du Colombier audioswab(uchar *a, uint n)
339499069deSDavid du Colombier {
340499069deSDavid du Colombier ulong *p, *ep, b;
341499069deSDavid du Colombier
342499069deSDavid du Colombier p = (ulong*)a;
343499069deSDavid du Colombier ep = p + (n>>2);
344499069deSDavid du Colombier while(p < ep) {
345499069deSDavid du Colombier b = *p;
346499069deSDavid du Colombier b = (b>>24) | (b<<24) |
347499069deSDavid du Colombier ((b&0xff0000) >> 8) |
348499069deSDavid du Colombier ((b&0x00ff00) << 8);
349499069deSDavid du Colombier *p++ = b;
350499069deSDavid du Colombier }
351499069deSDavid du Colombier }
352499069deSDavid du Colombier
353499069deSDavid du Colombier Dev audiodevtab = {
354499069deSDavid du Colombier 'A',
355499069deSDavid du Colombier "audio",
356499069deSDavid du Colombier
357499069deSDavid du Colombier devreset,
358499069deSDavid du Colombier audioinit,
359499069deSDavid du Colombier devshutdown,
360499069deSDavid du Colombier audioattach,
361499069deSDavid du Colombier audiowalk,
362499069deSDavid du Colombier audiostat,
363499069deSDavid du Colombier audioopen,
364499069deSDavid du Colombier devcreate,
365499069deSDavid du Colombier audioclose,
366499069deSDavid du Colombier audioread,
367499069deSDavid du Colombier devbread,
368499069deSDavid du Colombier audiowrite,
369499069deSDavid du Colombier devbwrite,
370499069deSDavid du Colombier devremove,
371499069deSDavid du Colombier devwstat,
372499069deSDavid du Colombier };
373