~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/isa/msnd/msnd_pinnacle_mixer.c

Version: ~ [ linux-5.5-rc7 ] ~ [ linux-5.4.13 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.97 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.166 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.210 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.210 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /***************************************************************************
  2                           msnd_pinnacle_mixer.c  -  description
  3                              -------------------
  4     begin               : Fre Jun 7 2002
  5     copyright           : (C) 2002 by karsten wiese
  6     email               : annabellesgarden@yahoo.de
  7  ***************************************************************************/
  8 
  9 /***************************************************************************
 10  *                                                                         *
 11  *   This program is free software; you can redistribute it and/or modify  *
 12  *   it under the terms of the GNU General Public License as published by  *
 13  *   the Free Software Foundation; either version 2 of the License, or     *
 14  *   (at your option) any later version.                                   *
 15  *                                                                         *
 16  ***************************************************************************/
 17 
 18 #include <linux/io.h>
 19 #include <linux/export.h>
 20 
 21 #include <sound/core.h>
 22 #include <sound/control.h>
 23 #include "msnd.h"
 24 #include "msnd_pinnacle.h"
 25 
 26 
 27 #define MSND_MIXER_VOLUME       0
 28 #define MSND_MIXER_PCM          1
 29 #define MSND_MIXER_AUX          2       /* Input source 1  (aux1) */
 30 #define MSND_MIXER_IMIX         3       /*  Recording monitor  */
 31 #define MSND_MIXER_SYNTH        4
 32 #define MSND_MIXER_SPEAKER      5
 33 #define MSND_MIXER_LINE         6
 34 #define MSND_MIXER_MIC          7
 35 #define MSND_MIXER_RECLEV       11      /* Recording level */
 36 #define MSND_MIXER_IGAIN        12      /* Input gain */
 37 #define MSND_MIXER_OGAIN        13      /* Output gain */
 38 #define MSND_MIXER_DIGITAL      17      /* Digital (input) 1 */
 39 
 40 /*      Device mask bits        */
 41 
 42 #define MSND_MASK_VOLUME        (1 << MSND_MIXER_VOLUME)
 43 #define MSND_MASK_SYNTH         (1 << MSND_MIXER_SYNTH)
 44 #define MSND_MASK_PCM           (1 << MSND_MIXER_PCM)
 45 #define MSND_MASK_SPEAKER       (1 << MSND_MIXER_SPEAKER)
 46 #define MSND_MASK_LINE          (1 << MSND_MIXER_LINE)
 47 #define MSND_MASK_MIC           (1 << MSND_MIXER_MIC)
 48 #define MSND_MASK_IMIX          (1 << MSND_MIXER_IMIX)
 49 #define MSND_MASK_RECLEV        (1 << MSND_MIXER_RECLEV)
 50 #define MSND_MASK_IGAIN         (1 << MSND_MIXER_IGAIN)
 51 #define MSND_MASK_OGAIN         (1 << MSND_MIXER_OGAIN)
 52 #define MSND_MASK_AUX           (1 << MSND_MIXER_AUX)
 53 #define MSND_MASK_DIGITAL       (1 << MSND_MIXER_DIGITAL)
 54 
 55 static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
 56                                 struct snd_ctl_elem_info *uinfo)
 57 {
 58         static const char * const texts[3] = {
 59                 "Analog", "MASS", "SPDIF",
 60         };
 61         struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
 62         unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
 63 
 64         return snd_ctl_enum_info(uinfo, 1, items, texts);
 65 }
 66 
 67 static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
 68                                 struct snd_ctl_elem_value *ucontrol)
 69 {
 70         struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
 71         /* MSND_MASK_IMIX is the default */
 72         ucontrol->value.enumerated.item[0] = 0;
 73 
 74         if (chip->recsrc & MSND_MASK_SYNTH) {
 75                 ucontrol->value.enumerated.item[0] = 1;
 76         } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
 77                  test_bit(F_HAVEDIGITAL, &chip->flags)) {
 78                 ucontrol->value.enumerated.item[0] = 2;
 79         }
 80 
 81 
 82         return 0;
 83 }
 84 
 85 static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
 86 {
 87         unsigned newrecsrc;
 88         int change;
 89         unsigned char msndbyte;
 90 
 91         switch (val) {
 92         case 0:
 93                 newrecsrc = MSND_MASK_IMIX;
 94                 msndbyte = HDEXAR_SET_ANA_IN;
 95                 break;
 96         case 1:
 97                 newrecsrc = MSND_MASK_SYNTH;
 98                 msndbyte = HDEXAR_SET_SYNTH_IN;
 99                 break;
100         case 2:
101                 newrecsrc = MSND_MASK_DIGITAL;
102                 msndbyte = HDEXAR_SET_DAT_IN;
103                 break;
104         default:
105                 return -EINVAL;
106         }
107         change  = newrecsrc != chip->recsrc;
108         if (change) {
109                 change = 0;
110                 if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
111                         if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
112                                 chip->recsrc = newrecsrc;
113                                 change = 1;
114                         }
115         }
116         return change;
117 }
118 
119 static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
120                                 struct snd_ctl_elem_value *ucontrol)
121 {
122         struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
123         return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
124 }
125 
126 
127 static int snd_msndmix_volume_info(struct snd_kcontrol *kcontrol,
128                                    struct snd_ctl_elem_info *uinfo)
129 {
130         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
131         uinfo->count = 2;
132         uinfo->value.integer.min = 0;
133         uinfo->value.integer.max = 100;
134         return 0;
135 }
136 
137 static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
138                                   struct snd_ctl_elem_value *ucontrol)
139 {
140         struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
141         int addr = kcontrol->private_value;
142         unsigned long flags;
143 
144         spin_lock_irqsave(&msnd->mixer_lock, flags);
145         ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
146         ucontrol->value.integer.value[0] /= 0xFFFF;
147         ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
148         ucontrol->value.integer.value[1] /= 0xFFFF;
149         spin_unlock_irqrestore(&msnd->mixer_lock, flags);
150         return 0;
151 }
152 
153 #define update_volm(a, b)                                               \
154         do {                                                            \
155                 writew((dev->left_levels[a] >> 1) *                     \
156                        readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
157                        dev->SMA + SMA_##b##Left);                       \
158                 writew((dev->right_levels[a] >> 1)  *                   \
159                        readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
160                        dev->SMA + SMA_##b##Right);                      \
161         } while (0);
162 
163 #define update_potm(d, s, ar)                                           \
164         do {                                                            \
165                 writeb((dev->left_levels[d] >> 8) *                     \
166                        readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
167                        dev->SMA + SMA_##s##Left);                       \
168                 writeb((dev->right_levels[d] >> 8) *                    \
169                        readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
170                        dev->SMA + SMA_##s##Right);                      \
171                 if (snd_msnd_send_word(dev, 0, 0, ar) == 0)             \
172                         snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);       \
173         } while (0);
174 
175 #define update_pot(d, s, ar)                                            \
176         do {                                                            \
177                 writeb(dev->left_levels[d] >> 8,                        \
178                        dev->SMA + SMA_##s##Left);                       \
179                 writeb(dev->right_levels[d] >> 8,                       \
180                        dev->SMA + SMA_##s##Right);                      \
181                 if (snd_msnd_send_word(dev, 0, 0, ar) == 0)             \
182                         snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);       \
183         } while (0);
184 
185 
186 static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
187 {
188         int bLeft, bRight;
189         int wLeft, wRight;
190         int updatemaster = 0;
191 
192         if (d >= LEVEL_ENTRIES)
193                 return -EINVAL;
194 
195         bLeft = left * 0xff / 100;
196         wLeft = left * 0xffff / 100;
197 
198         bRight = right * 0xff / 100;
199         wRight = right * 0xffff / 100;
200 
201         dev->left_levels[d] = wLeft;
202         dev->right_levels[d] = wRight;
203 
204         switch (d) {
205                 /* master volume unscaled controls */
206         case MSND_MIXER_LINE:                   /* line pot control */
207                 /* scaled by IMIX in digital mix */
208                 writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
209                 writeb(bRight, dev->SMA + SMA_bInPotPosRight);
210                 if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
211                         snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
212                 break;
213         case MSND_MIXER_MIC:                    /* mic pot control */
214                 if (dev->type == msndClassic)
215                         return -EINVAL;
216                 /* scaled by IMIX in digital mix */
217                 writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
218                 writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
219                 if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
220                         snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
221                 break;
222         case MSND_MIXER_VOLUME:         /* master volume */
223                 writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
224                 writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
225                 /* fall through */
226 
227         case MSND_MIXER_AUX:                    /* aux pot control */
228                 /* scaled by master volume */
229                 /* fall through */
230 
231                 /* digital controls */
232         case MSND_MIXER_SYNTH:                  /* synth vol (dsp mix) */
233         case MSND_MIXER_PCM:                    /* pcm vol (dsp mix) */
234         case MSND_MIXER_IMIX:                   /* input monitor (dsp mix) */
235                 /* scaled by master volume */
236                 updatemaster = 1;
237                 break;
238 
239         default:
240                 return -EINVAL;
241         }
242 
243         if (updatemaster) {
244                 /* update master volume scaled controls */
245                 update_volm(MSND_MIXER_PCM, wCurrPlayVol);
246                 update_volm(MSND_MIXER_IMIX, wCurrInVol);
247                 if (dev->type == msndPinnacle)
248                         update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
249                 update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
250         }
251 
252         return 0;
253 }
254 
255 static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
256                                   struct snd_ctl_elem_value *ucontrol)
257 {
258         struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
259         int change, addr = kcontrol->private_value;
260         int left, right;
261         unsigned long flags;
262 
263         left = ucontrol->value.integer.value[0] % 101;
264         right = ucontrol->value.integer.value[1] % 101;
265         spin_lock_irqsave(&msnd->mixer_lock, flags);
266         change = msnd->left_levels[addr] != left
267                 || msnd->right_levels[addr] != right;
268         snd_msndmix_set(msnd, addr, left, right);
269         spin_unlock_irqrestore(&msnd->mixer_lock, flags);
270         return change;
271 }
272 
273 
274 #define DUMMY_VOLUME(xname, xindex, addr) \
275 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
276   .info = snd_msndmix_volume_info, \
277   .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
278   .private_value = addr }
279 
280 
281 static struct snd_kcontrol_new snd_msnd_controls[] = {
282 DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
283 DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
284 DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
285 DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
286 DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
287 DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX),
288 {
289         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
290         .name = "Capture Source",
291         .info = snd_msndmix_info_mux,
292         .get = snd_msndmix_get_mux,
293         .put = snd_msndmix_put_mux,
294 }
295 };
296 
297 
298 int snd_msndmix_new(struct snd_card *card)
299 {
300         struct snd_msnd *chip = card->private_data;
301         unsigned int idx;
302         int err;
303 
304         if (snd_BUG_ON(!chip))
305                 return -EINVAL;
306         spin_lock_init(&chip->mixer_lock);
307         strcpy(card->mixername, "MSND Pinnacle Mixer");
308 
309         for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) {
310                 err = snd_ctl_add(card,
311                                   snd_ctl_new1(snd_msnd_controls + idx, chip));
312                 if (err < 0)
313                         return err;
314         }
315 
316         return 0;
317 }
318 EXPORT_SYMBOL(snd_msndmix_new);
319 
320 void snd_msndmix_setup(struct snd_msnd *dev)
321 {
322         update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
323         update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
324         update_volm(MSND_MIXER_PCM, wCurrPlayVol);
325         update_volm(MSND_MIXER_IMIX, wCurrInVol);
326         if (dev->type == msndPinnacle) {
327                 update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
328                 update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
329         }
330 }
331 EXPORT_SYMBOL(snd_msndmix_setup);
332 
333 int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
334 {
335         dev->recsrc = -1;
336         return snd_msndmix_set_mux(dev, recsrc);
337 }
338 EXPORT_SYMBOL(snd_msndmix_force_recsrc);
339 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp