]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/audioac97mix.c
devdraw: get rid of softscreen==0xa110c hack and make attachscreen() return Memdata*
[plan9front.git] / sys / src / 9 / pc / audioac97mix.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 #include "../port/audioif.h"
9
10 enum {
11         Reset = 0x0,
12                 Capmic = 0x1,
13                 Captonectl = 0x4,
14                 Capsimstereo = 0x8,
15                 Capheadphones = 0x10,
16                 Caploudness = 0x20,
17                 Capdac18 = 0x40,
18                 Capdac20 = 0x80,
19                 Capadc18 = 0x100,
20                 Capadc20 = 0x200,
21                 Capenh = 0xfc00,
22
23         Recsel = 0x1A,
24         General = 0x20,
25         ThreeDctl = 0x22,
26         Ac97RESER = 0x24,
27         Powerdowncsr = 0x26,
28                 Adcpower = 0x1,
29                 Dacpower = 0x2,
30                 Anlpower = 0x4,
31                 Refpower = 0x8,
32                 Inpower = 0x100,
33                 Outpower = 0x200,
34                 Mixpower = 0x400,
35                 Mixvrefpower = 0x800,
36                 Aclinkpower = 0x1000,
37                 Clkpower = 0x2000,
38                 Auxpower = 0x4000,
39                 Eamppower = 0x8000,
40         Extid = 0x28,
41         Extcsr = 0x2A,
42                 Extvra = 1<<0,
43                 Extdra = 1<<1,
44                 Extspdif = 1<<2,
45                 Extvrm = 1<<3,
46                 Extiddsa0 = 0<<4,       /* extid only */
47                 Extiddsa1 = 1<<4,       /* extid only */
48                 Extiddsa2 = 2<<4,       /* extid only */
49                 Extiddsa3 = 3<<4,       /* extid only */
50                 Extcsrspsa34 = 0<<4,    /* extcsr only */
51                 Extcsrspsa78 = 1<<4,    /* extcsr only */
52                 Extcsrspsa69 = 2<<4,    /* extcsr only */
53                 ExtcsrspsaAB = 3<<4,    /* extcsr only */
54                 Extcdac = 1<<6,
55                 Extsdac = 1<<7,
56                 Extldac = 1<<8,
57                 Extidamap = 1<<9,       /* extid only */
58                 Extidrev11 = 0<<10,     /* extid only */
59                 Extidrev22 = 1<<10,     /* extid only */
60                 Extidrev23 = 2<<10,     /* extid only */
61                 Extidprim = 0<<14,      /* extid only */
62                 Extidsec0 = 1<<14,      /* extid only */
63                 Extidsec1 = 2<<14,      /* extid only */
64                 Extidsec2 = 3<<14,      /* extid only */
65                 Extcsrmadc = 1<<9,      /* extcsr only */
66                 Extcsrspcv = 1<<10,     /* extcsr only */
67                 Extcsrpri = 1<<11,      /* extcsr only */
68                 Extcsrprj = 1<<12,      /* extcsr only */
69                 Extcsrprk = 1<<13,      /* extcsr only */
70                 Extcsrprl = 1<<14,      /* extcsr only */
71                 Extcsrvcfg = 1<<15,     /* extcsr only */
72         Pcmfrontdacrate = 0x2C,
73         Pcmsurrounddacrate = 0x2E,
74         Pcmlfedacrate = 0x30,
75         Pcmadcrate = 0x32,
76         Pcmmicadcrate = 0x34,
77         CenterLfe = 0x36,
78         LrSurround = 0x38,
79         Spdifcsr = 0x3a,
80                 Spdifpro = 1<<0,
81                 Spdifnonaudio = 1<<1,
82                 Spdifcopy = 1<<2,
83                 Spdifpre = 1<<3,
84                 SpdifCC = 0x7f<<4,
85                 Spdifl = 1<<11,
86                 Spdif44k1 = 0<<12,
87                 Spdif32k = 1<<12,
88                 Spdif48k = 2<<12,
89                 Spdifdsr = 1<<14,
90                 Spdifv = 1<<15,
91         VID1 = 0x7c,
92         VID2 = 0x7e,
93 };
94
95 enum {
96         Vmaster,
97         Vhead,
98         Vaudio,
99         Vcd,
100         Vbass,
101         Vtreb,
102         Vbeep,
103         Vphone,
104         Vmic,
105         Vline,
106         Vvideo,
107         Vaux,
108         Vrecgain,
109         Vmicgain,
110         Vspeed,
111         Vdelay,
112 };
113
114 static Volume voltab[] = {
115         [Vmaster] "master", 0x02, -63, Stereo, 0,
116         [Vaudio] "audio", 0x18, -31, Stereo, 0,
117         [Vhead] "head", 0x04, -31, Stereo, Capheadphones,
118         [Vbass] "bass", 0x08, 15, Left, Captonectl,
119         [Vtreb] "treb", 0x08, 15, Right, Captonectl,
120         [Vbeep] "beep", 0x0a, -31, Right, 0,
121         [Vphone] "phone", 0x0c, -31, Right, 0,
122         [Vmic] "mic", 0x0e, -31, Right, Capmic,
123         [Vline] "line", 0x10, -31, Stereo, 0,
124         [Vcd] "cd", 0x12, -31, Stereo,  0,
125         [Vvideo] "video", 0x14, -31, Stereo, 0,
126         [Vaux] "aux", 0x16, -63, Stereo, 0,
127         [Vrecgain] "recgain", 0x1c, 15, Stereo, 0,
128         [Vmicgain] "micgain", 0x1e, 15, Right, Capmic,
129         [Vspeed] "speed", 0x2c, 0, Absolute, 0,
130         [Vdelay] "delay", 0, 0, Absolute, 0,
131         0
132 };
133
134 typedef struct Mixer Mixer;
135 struct Mixer
136 {
137         ushort (*rr)(Audio *, int);
138         void (*wr)(Audio *, int, ushort);
139         int vra;
140 };
141
142 static int
143 ac97volget(Audio *adev, int x, int a[2])
144 {
145         Mixer *m = adev->mixer;
146         Volume *vol;
147         ushort v;
148
149         vol = voltab+x;
150         switch(vol->type){
151         case Absolute:
152                 if(x == Vdelay){
153                         a[0] = adev->delay;
154                         break;
155                 }
156                 a[0] = m->rr(adev, vol->reg);
157                 break;
158         default:
159                 v = m->rr(adev, vol->reg);
160                 if(v & 0x8000){
161                         a[0] = a[1] = vol->range < 0 ? 0x7f : 0;
162                 } else {
163                         a[0] = ((v>>8) & 0x7f);
164                         a[1] = (v & 0x7f);
165                 }
166         }
167         return 0;
168 }
169
170 static int
171 ac97volset(Audio *adev, int x, int a[2])
172 {
173         Mixer *m = adev->mixer;
174         Volume *vol;
175         ushort v, w;
176
177         vol = voltab+x;
178         switch(vol->type){
179         case Absolute:
180                 if(x == Vdelay){
181                         adev->delay = a[0];
182                         return 0;
183                 }
184                 m->wr(adev, vol->reg, a[0]);            
185                 if(x == Vspeed){
186                         m->wr(adev, 0x32, a[0]);        /* adc rate */
187                         adev->speed = m->rr(adev, vol->reg);
188                 }
189                 break;
190         case Left:
191                 v = a[0] & 0x7f;
192                 w = m->rr(adev, vol->reg) & 0x7f;
193                 m->wr(adev, vol->reg, (v<<8)|w);
194                 break;
195         case Right:
196                 v = m->rr(adev, vol->reg) & 0x7f00;
197                 w = a[1] & 0x7f;
198                 m->wr(adev, vol->reg, v|w);
199                 break;
200         case Stereo:
201                 v = a[0] & 0x7f;
202                 w = a[1] & 0x7f;
203                 m->wr(adev, vol->reg, (v<<8)|w);
204                 break;
205         }
206         return 0;
207 }
208
209
210 static long
211 ac97mixread(Audio *adev, void *a, long n, vlong)
212 {
213         Mixer *m = adev->mixer;
214         ulong caps;
215
216         caps = m->rr(adev, Reset);
217         caps |= m->rr(adev, Extid) << 16;
218         return genaudiovolread(adev, a, n, 0, voltab, ac97volget, caps);
219 }
220
221 static long
222 ac97mixwrite(Audio *adev, void *a, long n, vlong)
223 {
224         Mixer *m = adev->mixer;
225         ulong caps;
226
227         caps = m->rr(adev, Reset);
228         caps |= m->rr(adev, Extid) << 16;
229         return genaudiovolwrite(adev, a, n, 0, voltab, ac97volset, caps);
230 }
231
232 void
233 ac97mixreset(Audio *adev, void (*wr)(Audio*,int,ushort), ushort (*rr)(Audio*,int))
234 {
235         Mixer *m;
236         ushort t;
237
238         m = malloc(sizeof(Mixer));
239         if(m == nil){
240                 print("ac97mix: no memory for Mixer\n");
241                 return;
242         }
243         m->wr = wr;
244         m->rr = rr;
245         m->wr(adev, Reset, 0);
246         m->wr(adev, Powerdowncsr, 0);
247         delay(1000);
248         t = (Adcpower | Dacpower | Anlpower | Refpower);
249         if((m->rr(adev, Powerdowncsr) & t) != t)
250                 print("#A%d: ac97 exhausted waiting powerup\n", adev->ctlrno);
251
252         t = m->rr(adev, Extid);
253         print("#A%d: ac97 codec ext:%s%s%s%s%s%s%s\n", adev->ctlrno,
254                 (t & Extvra) ? " vra" : "",
255                 (t & Extdra) ? " dra" : "",
256                 (t & Extspdif) ? " spdif" : "",
257                 (t & Extvrm) ? " vrm" : "",
258                 (t & Extcdac) ? " cdac" : "",
259                 (t & Extsdac) ? " sdac" : "",
260                 (t & Extldac) ? " ldac" : "");
261
262         if(t & Extvra){
263                 m->wr(adev, Extcsr, Extvra);
264                 m->vra = 1;
265         } else {
266                 print("#A%d: ac97 vra extension not supported\n", adev->ctlrno);
267                 m->vra = 0;
268         }
269
270         adev->mixer = m;
271         adev->volread = ac97mixread;
272         adev->volwrite = ac97mixwrite;
273 }