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

TOMOYO Linux Cross Reference
Linux/sound/oss/ics2101.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.14 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.57 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.138 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.193 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ 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.85 ] ~ [ 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-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  * sound/ics2101.c
  3  *
  4  * Driver for the ICS2101 mixer of GUS v3.7.
  5  *
  6  *
  7  * Copyright (C) by Hannu Savolainen 1993-1997
  8  *
  9  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 10  * Version 2 (June 1991). See the "COPYING" file distributed with this software
 11  * for more info.
 12  *
 13  *
 14  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
 15  * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
 16  */
 17 #include <linux/init.h>
 18 #include <linux/spinlock.h>
 19 #include "sound_config.h"
 20 
 21 #include <linux/ultrasound.h>
 22 
 23 #include "gus.h"
 24 #include "gus_hw.h"
 25 
 26 #define MIX_DEVS        (SOUND_MASK_MIC|SOUND_MASK_LINE| \
 27                          SOUND_MASK_SYNTH| \
 28                          SOUND_MASK_CD | SOUND_MASK_VOLUME)
 29 
 30 extern int     *gus_osp;
 31 extern int      gus_base;
 32 extern spinlock_t gus_lock;
 33 static int      volumes[ICS_MIXDEVS];
 34 static int      left_fix[ICS_MIXDEVS] =
 35 {1, 1, 1, 2, 1, 2};
 36 static int      right_fix[ICS_MIXDEVS] =
 37 {2, 2, 2, 1, 2, 1};
 38 
 39 static int scale_vol(int vol)
 40 {
 41         /*
 42          *  Experimental volume scaling by Risto Kankkunen.
 43          *  This should give smoother volume response than just
 44          *  a plain multiplication.
 45          */
 46          
 47         int e;
 48 
 49         if (vol < 0)
 50                 vol = 0;
 51         if (vol > 100)
 52                 vol = 100;
 53         vol = (31 * vol + 50) / 100;
 54         e = 0;
 55         if (vol)
 56         {
 57                 while (vol < 16)
 58                 {
 59                         vol <<= 1;
 60                         e--;
 61                 }
 62                 vol -= 16;
 63                 e += 7;
 64         }
 65         return ((e << 4) + vol);
 66 }
 67 
 68 static void write_mix(int dev, int chn, int vol)
 69 {
 70         int *selector;
 71         unsigned long flags;
 72         int ctrl_addr = dev << 3;
 73         int attn_addr = dev << 3;
 74 
 75         vol = scale_vol(vol);
 76 
 77         if (chn == CHN_LEFT)
 78         {
 79                 selector = left_fix;
 80                 ctrl_addr |= 0x00;
 81                 attn_addr |= 0x02;
 82         }
 83         else
 84         {
 85                 selector = right_fix;
 86                 ctrl_addr |= 0x01;
 87                 attn_addr |= 0x03;
 88         }
 89 
 90         spin_lock_irqsave(&gus_lock, flags);
 91         outb((ctrl_addr), u_MixSelect);
 92         outb((selector[dev]), u_MixData);
 93         outb((attn_addr), u_MixSelect);
 94         outb(((unsigned char) vol), u_MixData);
 95         spin_unlock_irqrestore(&gus_lock,flags);
 96 }
 97 
 98 static int set_volumes(int dev, int vol)
 99 {
100         int left = vol & 0x00ff;
101         int right = (vol >> 8) & 0x00ff;
102 
103         if (left < 0)
104                 left = 0;
105         if (left > 100)
106                 left = 100;
107         if (right < 0)
108                 right = 0;
109         if (right > 100)
110                 right = 100;
111 
112         write_mix(dev, CHN_LEFT, left);
113         write_mix(dev, CHN_RIGHT, right);
114 
115         vol = left + (right << 8);
116         volumes[dev] = vol;
117         return vol;
118 }
119 
120 static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
121 {
122         int val;
123         
124         if (((cmd >> 8) & 0xff) == 'M') {
125                 if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
126                         
127                         if (get_user(val, (int *)arg))
128                                 return -EFAULT;
129                         switch (cmd & 0xff) {
130                         case SOUND_MIXER_RECSRC:
131                                 return gus_default_mixer_ioctl(dev, cmd, arg);
132 
133                         case SOUND_MIXER_MIC:
134                                 val = set_volumes(DEV_MIC, val);
135                                 break;
136                                 
137                         case SOUND_MIXER_CD:
138                                 val = set_volumes(DEV_CD, val);
139                                 break;
140 
141                         case SOUND_MIXER_LINE:
142                                 val = set_volumes(DEV_LINE, val);
143                                 break;
144 
145                         case SOUND_MIXER_SYNTH:
146                                 val = set_volumes(DEV_GF1, val);
147                                 break;
148 
149                         case SOUND_MIXER_VOLUME:
150                                 val = set_volumes(DEV_VOL, val);
151                                 break;
152 
153                         default:
154                                 return -EINVAL;
155                         }
156                         return put_user(val, (int *)arg);
157                 } else {
158                         switch (cmd & 0xff) {
159                                 /*
160                                  * Return parameters
161                                  */
162                         case SOUND_MIXER_RECSRC:
163                                 return gus_default_mixer_ioctl(dev, cmd, arg);
164 
165                         case SOUND_MIXER_DEVMASK:
166                                 val = MIX_DEVS; 
167                                 break;
168 
169                         case SOUND_MIXER_STEREODEVS:
170                                 val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC; 
171                                 break;
172 
173                         case SOUND_MIXER_RECMASK:
174                                 val = SOUND_MASK_MIC | SOUND_MASK_LINE; 
175                                 break;
176                                 
177                         case SOUND_MIXER_CAPS:
178                                 val = 0; 
179                                 break;
180 
181                         case SOUND_MIXER_MIC:
182                                 val = volumes[DEV_MIC];
183                                 break;
184                                 
185                         case SOUND_MIXER_LINE:
186                                 val = volumes[DEV_LINE];
187                                 break;
188 
189                         case SOUND_MIXER_CD:
190                                 val = volumes[DEV_CD];
191                                 break;
192 
193                         case SOUND_MIXER_VOLUME:
194                                 val = volumes[DEV_VOL];
195                                 break;
196 
197                         case SOUND_MIXER_SYNTH:
198                                 val = volumes[DEV_GF1]; 
199                                 break;
200 
201                         default:
202                                 return -EINVAL;
203                         }
204                         return put_user(val, (int *)arg);
205                 }
206         }
207         return -EINVAL;
208 }
209 
210 static struct mixer_operations ics2101_mixer_operations =
211 {
212         .owner  = THIS_MODULE,
213         .id     = "ICS2101",
214         .name   = "ICS2101 Multimedia Mixer",
215         .ioctl  = ics2101_mixer_ioctl
216 };
217 
218 int __init ics2101_mixer_init(void)
219 {
220         int i;
221         int n;
222 
223         if ((n = sound_alloc_mixerdev()) != -1)
224         {
225                 mixer_devs[n] = &ics2101_mixer_operations;
226 
227                 /*
228                  * Some GUS v3.7 cards had some channels flipped. Disable
229                  * the flipping feature if the model id is other than 5.
230                  */
231 
232                 if (inb(u_MixSelect) != 5)
233                 {
234                         for (i = 0; i < ICS_MIXDEVS; i++)
235                                 left_fix[i] = 1;
236                         for (i = 0; i < ICS_MIXDEVS; i++)
237                                 right_fix[i] = 2;
238                 }
239                 set_volumes(DEV_GF1, 0x5a5a);
240                 set_volumes(DEV_CD, 0x5a5a);
241                 set_volumes(DEV_MIC, 0x0000);
242                 set_volumes(DEV_LINE, 0x5a5a);
243                 set_volumes(DEV_VOL, 0x5a5a);
244                 set_volumes(DEV_UNUSED, 0x0000);
245         }
246         return n;
247 }
248 

~ [ 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