Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfashe...
[linux-2.6] / sound / oss / ac97.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include "ac97.h"
5
6 /* Flag for mono controls. */
7 #define MO 0
8 /* And for stereo. */
9 #define ST 1
10
11 /* Whether or not the bits in the channel are inverted. */
12 #define INV 1
13 #define NINV 0
14
15 static struct ac97_chn_desc {
16     int ac97_regnum;
17     int oss_channel;
18     int maxval;
19     int is_stereo;
20     int oss_mask;
21     int recordNum;
22     u16 regmask;
23     int is_inverted;
24 } mixerRegs[] = {
25     { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME,   0x3f, ST, SOUND_MASK_VOLUME,   5, 0x0000, INV  },
26     { AC97_MASTER_VOL_MONO,   SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000, INV  },
27     { AC97_MASTER_TONE,       SOUND_MIXER_TREBLE,   0x0f, MO, SOUND_MASK_TREBLE,  -1, 0x00ff, INV  },
28     { AC97_MASTER_TONE,       SOUND_MIXER_BASS,     0x0f, MO, SOUND_MASK_BASS,    -1, 0xff00, INV  },
29     { AC97_PCBEEP_VOL,        SOUND_MIXER_SPEAKER,  0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e, INV  },
30     { AC97_PHONE_VOL,         SOUND_MIXER_PHONEIN,  0x1f, MO, SOUND_MASK_PHONEIN,  7, 0x0000, INV  },
31     { AC97_MIC_VOL,           SOUND_MIXER_MIC,      0x1f, MO, SOUND_MASK_MIC,      0, 0x0000, INV  },
32     { AC97_LINEIN_VOL,        SOUND_MIXER_LINE,     0x1f, ST, SOUND_MASK_LINE,     4, 0x0000, INV  },
33     { AC97_CD_VOL,            SOUND_MIXER_CD,       0x1f, ST, SOUND_MASK_CD,       1, 0x0000, INV  },
34     { AC97_VIDEO_VOL,         SOUND_MIXER_VIDEO,    0x1f, ST, SOUND_MASK_VIDEO,    2, 0x0000, INV  },
35     { AC97_AUX_VOL,           SOUND_MIXER_LINE1,    0x1f, ST, SOUND_MASK_LINE1,    3, 0x0000, INV  },
36     { AC97_PCMOUT_VOL,        SOUND_MIXER_PCM,      0x1f, ST, SOUND_MASK_PCM,     -1, 0x0000, INV  },
37     { AC97_RECORD_GAIN,       SOUND_MIXER_IGAIN,    0x0f, ST, SOUND_MASK_IGAIN,   -1, 0x0000, NINV },
38     { -1,                     -1,                   0xff, 0,  0,                  -1, 0x0000, 0    },
39 };
40
41 static struct ac97_chn_desc *
42 ac97_find_chndesc (struct ac97_hwint *dev, int oss_channel)
43 {
44     int x;
45
46     for (x = 0; mixerRegs[x].oss_channel != -1; x++) {
47         if (mixerRegs[x].oss_channel == oss_channel)
48             return mixerRegs + x;
49     }
50
51     return NULL;
52 }
53
54 static inline int
55 ac97_is_valid_channel (struct ac97_hwint *dev, struct ac97_chn_desc *chn)
56 {
57     return (dev->last_written_mixer_values[chn->ac97_regnum / 2]
58             != AC97_REG_UNSUPPORTED);
59 }
60
61 int
62 ac97_init (struct ac97_hwint *dev)
63 {
64     int x;
65     int reg0;
66
67     /* Clear out the arrays of cached values. */
68     for (x = 0; x < AC97_REG_CNT; x++)
69         dev->last_written_mixer_values[x] = AC97_REGVAL_UNKNOWN;
70
71     for (x = 0; x < SOUND_MIXER_NRDEVICES; x++)
72         dev->last_written_OSS_values[x] = AC97_REGVAL_UNKNOWN;
73
74     /* Clear the device masks.  */
75     dev->mixer_devmask = 0;
76     dev->mixer_stereomask = 0;
77     dev->mixer_recmask = 0;
78
79     /* ??? Do a "standard reset" via register 0? */
80
81     /* Hardware-dependent reset.  */
82     if (dev->reset_device (dev))
83         return -1;
84
85     /* Check the mixer device capabilities.  */
86     reg0 = dev->read_reg (dev, AC97_RESET);
87
88     if (reg0 < 0)
89         return -1;
90
91     /* Check for support for treble/bass controls.  */
92     if (! (reg0 & 4)) {
93         dev->last_written_mixer_values[AC97_MASTER_TONE / 2] 
94             = AC97_REG_UNSUPPORTED;
95     }
96
97     /* ??? There may be other tests here? */
98
99     /* Fill in the device masks.  */
100     for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
101         if (ac97_is_valid_channel (dev, mixerRegs + x)) {
102             dev->mixer_devmask |= mixerRegs[x].oss_mask;
103
104             if (mixerRegs[x].is_stereo)
105                 dev->mixer_stereomask |= mixerRegs[x].oss_mask;
106
107             if (mixerRegs[x].recordNum != -1)
108                 dev->mixer_recmask |= mixerRegs[x].oss_mask;
109         }
110     }
111
112     return 0;
113 }
114
115 /* Return the contents of register REG; use the cache if the value in it
116    is valid.  Returns a negative error code on failure. */
117 static int
118 ac97_get_register (struct ac97_hwint *dev, u8 reg) 
119 {
120     if (reg > 127 || (reg & 1))
121         return -EINVAL;
122
123     /* See if it's in the cache, or if it's just plain invalid.  */
124     switch (dev->last_written_mixer_values[reg / 2]) {
125     case AC97_REG_UNSUPPORTED:
126         return -EINVAL;
127         break;
128     case AC97_REGVAL_UNKNOWN:
129         dev->last_written_mixer_values[reg / 2] = dev->read_reg (dev, reg);
130         break;
131     default:
132         break;
133     }
134     return dev->last_written_mixer_values[reg / 2];
135 }
136
137 /* Write VALUE to AC97 register REG, and cache its value in the last-written
138    cache.  Returns a negative error code on failure, or 0 on success. */
139 int
140 ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value)
141 {
142     if (reg > 127 || (reg & 1))
143         return -EINVAL;
144
145     if (dev->last_written_mixer_values[reg / 2] == AC97_REG_UNSUPPORTED)
146         return -EINVAL;
147     else {
148         int res = dev->write_reg (dev, reg, value);
149         if (res >= 0) {
150             dev->last_written_mixer_values[reg / 2] = value;
151             return 0;
152         }
153         else
154             return res;
155     }
156 }
157
158 /* Scale VALUE (a value fro 0 to MAXVAL) to a value from 0-100.  If
159    IS_STEREO is set, VALUE is a stereo value; the left channel value
160    is in the lower 8 bits, and the right channel value is in the upper
161    8 bits.
162
163    A negative error code is returned on failure, or the unsigned
164    scaled value on success.  */
165
166 static int
167 ac97_scale_to_oss_val (int value, int maxval, int is_stereo, int inv)
168 {
169     /* Muted?  */
170     if (value & AC97_MUTE)
171         return 0;
172
173     if (is_stereo)
174         return (ac97_scale_to_oss_val (value & 255, maxval, 0, inv) << 8)
175         | (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
176     else {
177         int i;
178         
179         /* Inverted. */
180         if (inv)
181             value = maxval - value;
182
183         i = (value * 100 + (maxval / 2)) / maxval;
184         if (i > 100)
185              i = 100;
186         if (i < 0)
187             i = 0;
188         return i;
189     }
190 }
191
192 static int
193 ac97_scale_from_oss_val (int value, int maxval, int is_stereo, int inv)
194 {
195     if (is_stereo)
196         return (ac97_scale_from_oss_val (value & 255, maxval, 0, inv) << 8)
197         | (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
198     else {
199         int i = ((value & 255) * maxval + 50) / 100;
200         if (inv)
201             i = maxval - i;
202         if (i < 0)
203             i = 0;
204         if (i > maxval)
205             i = maxval;
206         return i;
207     }
208 }
209
210 static int
211 ac97_set_mixer (struct ac97_hwint *dev, int oss_channel, u16 oss_value)
212 {
213     int scaled_value;
214     struct ac97_chn_desc *channel = ac97_find_chndesc (dev, oss_channel);
215     int result;
216
217     if (channel == NULL)
218         return -ENODEV;
219     if (! ac97_is_valid_channel (dev, channel))
220         return -ENODEV;
221     scaled_value = ac97_scale_from_oss_val (oss_value, channel->maxval,
222                                             channel->is_stereo, 
223                                             channel->is_inverted);
224     if (scaled_value < 0)
225         return scaled_value;
226
227     if (channel->regmask != 0) {
228         int mv;
229
230         int oldval = ac97_get_register (dev, channel->ac97_regnum);
231         if (oldval < 0)
232             return oldval;
233
234         for (mv = channel->regmask; ! (mv & 1); mv >>= 1)
235             scaled_value <<= 1;
236
237         scaled_value &= channel->regmask;
238         scaled_value |= (oldval & ~channel->regmask);
239     }
240     result = ac97_put_register (dev, channel->ac97_regnum, scaled_value);
241     if (result == 0)
242         dev->last_written_OSS_values[oss_channel] = oss_value;
243     return result;
244 }
245
246 static int
247 ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel)
248 {
249     struct ac97_chn_desc *channel = ac97_find_chndesc (dev, oss_channel);
250     int regval;
251
252     if (channel == NULL)
253         return -ENODEV;
254
255     if (! ac97_is_valid_channel (dev, channel))
256         return -ENODEV;
257
258     regval = ac97_get_register (dev, channel->ac97_regnum);
259
260     if (regval < 0)
261         return regval;
262
263     if (channel->regmask != 0) {
264         int mv;
265
266         regval &= channel->regmask;
267
268         for (mv = channel->regmask; ! (mv & 1); mv >>= 1)
269             regval >>= 1;
270     }
271     return ac97_scale_to_oss_val (regval, channel->maxval,
272                                   channel->is_stereo, 
273                                   channel->is_inverted);
274 }
275
276 static int
277 ac97_get_recmask (struct ac97_hwint *dev)
278 {
279     int recReg = ac97_get_register (dev, AC97_RECORD_SELECT);
280
281     if (recReg < 0)
282         return recReg;
283     else {
284         int x;
285         for (x = 0; mixerRegs[x].ac97_regnum >= 0; x++) {
286             if (mixerRegs[x].recordNum == (recReg & 7))
287                 return mixerRegs[x].oss_mask;
288         }
289         return -ENODEV;
290     }
291 }
292
293 static int
294 ac97_set_recmask (struct ac97_hwint *dev, int oss_recmask)
295 {
296     int x;
297
298     if (oss_recmask == 0)
299         oss_recmask = SOUND_MIXER_MIC;
300
301     for (x = 0; mixerRegs[x].ac97_regnum >= 0; x++) { 
302         if ((mixerRegs[x].recordNum >= 0)
303              && (oss_recmask & mixerRegs[x].oss_mask))
304             break;
305     }
306     if (mixerRegs[x].ac97_regnum < 0)
307         return -ENODEV;
308     else {
309         int regval = (mixerRegs[x].recordNum << 8) | mixerRegs[x].recordNum;
310         int res = ac97_put_register (dev, AC97_RECORD_SELECT, regval);
311         if (res == 0)
312             return ac97_get_recmask (dev);
313         else
314             return res;
315     }
316 }
317
318 /* Set the mixer DEV to the list of values in VALUE_LIST.  Return 0 on
319    success, or a negative error code.  */
320 int
321 ac97_set_values (struct ac97_hwint *dev, 
322                  struct ac97_mixer_value_list *value_list)
323 {
324     int x;
325
326     for (x = 0; value_list[x].oss_channel != -1; x++) {
327         int chnum = value_list[x].oss_channel;
328         struct ac97_chn_desc *chent = ac97_find_chndesc (dev, chnum);
329         if (chent != NULL) {
330             u16 val;
331             int res;
332
333             if (chent->is_stereo)
334                 val = (value_list[x].value.stereo.right << 8) 
335                       | value_list[x].value.stereo.left;
336             else {
337                 /* We do this so the returned value looks OK in the
338                    mixer app.  It's not necessary otherwise.  */
339                 val = (value_list[x].value.mono << 8) 
340                       | value_list[x].value.mono;
341             }
342             res = ac97_set_mixer (dev, chnum, val);
343             if (res < 0)
344                 return res;
345         }
346         else
347             return -ENODEV;
348     }
349     return 0;
350 }
351
352 int
353 ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, void __user *arg)
354 {
355     int ret;
356
357     switch (cmd) {
358     case SOUND_MIXER_READ_RECSRC:
359         ret = ac97_get_recmask (dev);
360         break;
361
362     case SOUND_MIXER_WRITE_RECSRC:
363         {
364             if (get_user (ret, (int __user *) arg))
365                 ret = -EFAULT;
366             else
367                 ret = ac97_set_recmask (dev, ret);
368         }
369         break;
370
371     case SOUND_MIXER_READ_CAPS:
372         ret = SOUND_CAP_EXCL_INPUT;
373         break;
374
375     case SOUND_MIXER_READ_DEVMASK:
376         ret = dev->mixer_devmask;
377         break;
378
379     case SOUND_MIXER_READ_RECMASK:
380         ret = dev->mixer_recmask;
381         break;
382
383     case SOUND_MIXER_READ_STEREODEVS:
384         ret = dev->mixer_stereomask;
385         break;
386
387     default:
388         /* Read or write request. */
389         ret = -EINVAL;
390         if (_IOC_TYPE (cmd) == 'M') {
391             int dir = _SIOC_DIR (cmd);
392             int channel = _IOC_NR (cmd);
393
394             if (channel >= 0 && channel < SOUND_MIXER_NRDEVICES) {
395                 ret = 0;
396                 if (dir & _SIOC_WRITE) {
397                     int val;
398                     if (get_user (val, (int __user *) arg) == 0)
399                         ret = ac97_set_mixer (dev, channel, val);
400                     else
401                         ret = -EFAULT;
402                 }
403                 if (ret >= 0 && (dir & _SIOC_READ)) {
404                     if (dev->last_written_OSS_values[channel]
405                         == AC97_REGVAL_UNKNOWN)
406                         dev->last_written_OSS_values[channel]
407                             = ac97_get_mixer_scaled (dev, channel);
408                     ret = dev->last_written_OSS_values[channel];
409                 }
410             }
411         }
412         break;
413     }
414
415     if (ret < 0)
416         return ret;
417     else
418         return put_user(ret, (int __user *) arg);
419 }
420
421 EXPORT_SYMBOL(ac97_init);
422 EXPORT_SYMBOL(ac97_set_values);
423 EXPORT_SYMBOL(ac97_put_register);
424 EXPORT_SYMBOL(ac97_mixer_ioctl);
425 MODULE_LICENSE("GPL");
426
427 \f
428 /*
429  * Local variables:
430  *  c-basic-offset: 4
431  * End:
432  */