1 /*
2 * Linux and BSD
3 */
4 #include <sys/ioctl.h>
5 #ifdef __linux__
6 #include <linux/soundcard.h>
7 #else
8 #include <sys/soundcard.h>
9 #endif
10 #include "u.h"
11 #include "lib.h"
12 #include "dat.h"
13 #include "fns.h"
14 #include "error.h"
15 #include "devaudio.h"
16
17 enum
18 {
19 Channels = 2,
20 Rate = 44100,
21 Bits = 16,
22 Bigendian = 1,
23 };
24
25 static int afd = -1;
26 static int cfd= -1;
27 static int speed;
28
29 /* maybe this should return -1 instead of sysfatal */
30 void
audiodevopen(void)31 audiodevopen(void)
32 {
33 int t;
34 ulong ul;
35
36 afd = -1;
37 cfd = -1;
38 if((afd = open("/dev/dsp", OWRITE)) < 0)
39 goto err;
40 if((cfd = open("/dev/mixer", ORDWR)) < 0)
41 goto err;
42
43 t = Bits;
44 if(ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &t) < 0)
45 goto err;
46
47 t = Channels-1;
48 if(ioctl(afd, SNDCTL_DSP_STEREO, &t) < 0)
49 goto err;
50
51 speed = Rate;
52 ul = Rate;
53 if(ioctl(afd, SNDCTL_DSP_SPEED, &ul) < 0)
54 goto err;
55
56 return;
57
58 err:
59 if(afd >= 0)
60 close(afd);
61 afd = -1;
62 oserror();
63 }
64
65 void
audiodevclose(void)66 audiodevclose(void)
67 {
68 close(afd);
69 close(cfd);
70 afd = -1;
71 cfd = -1;
72 }
73
74 static struct {
75 int id9;
76 int id;
77 } names[] = {
78 Vaudio, SOUND_MIXER_VOLUME,
79 Vbass, SOUND_MIXER_BASS,
80 Vtreb, SOUND_MIXER_TREBLE,
81 Vline, SOUND_MIXER_LINE,
82 Vpcm, SOUND_MIXER_PCM,
83 Vsynth, SOUND_MIXER_SYNTH,
84 Vcd, SOUND_MIXER_CD,
85 Vmic, SOUND_MIXER_MIC,
86 // "record", SOUND_MIXER_RECLEV,
87 // "mix", SOUND_MIXER_IMIX,
88 // "pcm2", SOUND_MIXER_ALTPCM,
89 Vspeaker, SOUND_MIXER_SPEAKER
90 // "line1", SOUND_MIXER_LINE1,
91 // "line2", SOUND_MIXER_LINE2,
92 // "line3", SOUND_MIXER_LINE3,
93 // "digital1", SOUND_MIXER_DIGITAL1,
94 // "digital2", SOUND_MIXER_DIGITAL2,
95 // "digital3", SOUND_MIXER_DIGITAL3,
96 // "phonein", SOUND_MIXER_PHONEIN,
97 // "phoneout", SOUND_MIXER_PHONEOUT,
98 // "radio", SOUND_MIXER_RADIO,
99 // "video", SOUND_MIXER_VIDEO,
100 // "monitor", SOUND_MIXER_MONITOR,
101 // "igain", SOUND_MIXER_IGAIN,
102 // "ogain", SOUND_MIXER_OGAIN,
103 };
104
105 static int
lookname(int id9)106 lookname(int id9)
107 {
108 int i;
109
110 for(i=0; i<nelem(names); i++)
111 if(names[i].id9 == id9)
112 return names[i].id;
113 return -1;
114 }
115
116 void
audiodevsetvol(int what,int left,int right)117 audiodevsetvol(int what, int left, int right)
118 {
119 int id;
120 ulong x;
121 int can, v;
122
123 if(cfd < 0)
124 error("audio device not open");
125 if(what == Vspeed){
126 x = left;
127 if(ioctl(afd, SNDCTL_DSP_SPEED, &x) < 0)
128 oserror();
129 speed = x;
130 return;
131 }
132 if((id = lookname(what)) < 0)
133 return;
134 if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
135 can = ~0;
136 if(!(can & (1<<id)))
137 return;
138 v = left | (right<<8);
139 if(ioctl(cfd, MIXER_WRITE(id), &v) < 0)
140 oserror();
141 }
142
143 void
audiodevgetvol(int what,int * left,int * right)144 audiodevgetvol(int what, int *left, int *right)
145 {
146 int id;
147 int can, v;
148
149 if(cfd < 0)
150 error("audio device not open");
151 if(what == Vspeed){
152 *left = *right = speed;
153 return;
154 }
155 if((id = lookname(what)) < 0)
156 return;
157 if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
158 can = ~0;
159 if(!(can & (1<<id)))
160 return;
161 if(ioctl(cfd, MIXER_READ(id), &v) < 0)
162 oserror();
163 *left = v&0xFF;
164 *right = (v>>8)&0xFF;
165 }
166
167 int
audiodevwrite(void * v,int n)168 audiodevwrite(void *v, int n)
169 {
170 int m, tot;
171
172 for(tot=0; tot<n; tot+=m)
173 if((m = write(afd, (uchar*)v+tot, n-tot)) <= 0)
174 oserror();
175 return tot;
176 }
177
178 int
audiodevread(void * v,int n)179 audiodevread(void *v, int n)
180 {
181 error("no reading");
182 return -1;
183 }
184