source: GPL/branches/uniaud32-2.1.x/lib32/soundmixer.c@ 519

Last change on this file since 519 was 519, checked in by David Azarewicz, 15 years ago

Changes to PCI bus scan, malloc, cleanup all warnings, misc other changes

File size: 34.6 KB
Line 
1/* $Id: soundmixer.c,v 1.1.1.1 2003/07/02 13:57:02 eleph Exp $ */
2/*
3 * MMPM/2 to OSS interface translation layer
4 *
5 * (C) 2000-2002 InnoTek Systemberatung GmbH
6 * (C) 2000-2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
21 * USA.
22 *
23 */
24
25#include <sound/core.h>
26#include <sound/control.h>
27#include <sound/info.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/minors.h>
31#include <linux/file.h>
32#include <linux/soundcard.h>
33
34#define LINUX
35#include <ossidc32.h>
36#include <stacktoflat.h>
37#include <stdlib.h>
38#include "soundoss.h"
39
40extern OpenedHandles opened_handles[8 * 256]; // from sound.c
41
42static struct {
43 char *name;
44 unsigned int index;
45 unsigned int recsrc;
46} ossid[OSS_MIXER_NRDEVICES] = {
47 /* OSS_MIXER_VOLUME */ { "Master", 0 , -1},
48 /* OSS_MIXER_BASS */ { "Tone Control - Bass", 0, -1},
49 /* OSS_MIXER_TREBLE */ { "Tone Control - Treble", 0, -1},
50 /* OSS_MIXER_SYNTH */ { "Synth", 0 , OSS32_MIX_RECSRC_SYNTH},
51 /* OSS_MIXER_PCM */ { "PCM", 0 , -1},
52 /* OSS_MIXER_PCSPEAKER */ { "PC Speaker", 0 , -1},
53 /* OSS_MIXER_LINE */ { "Line", 0 , OSS32_MIX_RECSRC_LINE},
54 /* OSS_MIXER_MIC */ { "Mic", 0, OSS32_MIX_RECSRC_MIC},
55 /* OSS_MIXER_CD */ { "CD", 0 , OSS32_MIX_RECSRC_CD},
56 /* OSS_MIXER_IMIX */ { "Monitor Mix", 0 , OSS32_MIX_RECSRC_MIXER},
57 /* OSS_MIXER_ALTPCM */ { "PCM", 1 , -1},
58 /* OSS_MIXER_RECLEV */ { "-- nothing --", 0 , -1},
59 /* OSS_MIXER_IGAIN */ { "Capture", 0 , -1},
60 /* OSS_MIXER_OGAIN */ { "Playback", 0 , -1},
61 /* OSS_MIXER_LINE1 */ { "Aux", 0 , OSS32_MIX_RECSRC_AUX},
62 /* OSS_MIXER_LINE2 */ { "Aux", 1 , -1},
63 /* OSS_MIXER_LINE3 */ { "Aux", 2 , -1},
64 /* OSS_MIXER_DIGITAL1 */ { "Digital", 0 , -1},
65 /* OSS_MIXER_DIGITAL2 */ { "Digital", 1 , -1},
66 /* OSS_MIXER_DIGITAL3 */ { "Digital", 2 , -1},
67 /* OSS_MIXER_PHONEIN */ { "Phone", 0 , OSS32_MIX_RECSRC_PHONE},
68 /* OSS_MIXER_PHONEOUT */ { "Phone", 1 , -1},
69 /* OSS_MIXER_VIDEO */ { "Video", 0 , OSS32_MIX_RECSRC_VIDEO},
70 /* OSS_MIXER_RADIO */ { "Radio", 0 , -1},
71 /* OSS_MIXER_MONITOR */ { "Monitor", 0 , -1},
72 /* OSS_MIXER_3DDEPTH */ { "3D Control - Depth", 0 , -1},
73 /* OSS_MIXER_3DCENTER */ { "3D Control - Center", 0 , -1},
74 /* OSS_MIXER_FRONT */ { "Front", 0 , -1},
75 /* OSS_MIXER_SPEAKER */ { "Speaker", 0 , -1},
76 /* OSS_MIXER_HEADPHONE */ { "Headphone", 0 , -1},
77};
78char *szRecSources[OSS32_MIX_RECSRC_MAX] = {
79 "Mic", "CD", "Line", "Video", "Aux", "Mix", "Mix Mono", "Phone", "Synth"
80};
81
82static unsigned char LinToLog[OSS32_MAX_VOLUME+1] = {
83 0, 0, 0, 0, 1, 2, 2, 5, 5, 10,
84 10, 10, 16, 19, 20, 22, 24, 25, 27, 27,
85 28, 28, 29, 30, 30, 35, 35, 35, 39, 39,
86 43, 44, 45, 47, 48, 49, 50, 51, 52, 53,
87 55, 56, 57, 59, 60, 62, 63, 64, 65, 66,
88 67, 68, 69, 70, 71, 72, 73, 74, 74, 75,
89 76, 77, 78, 79, 79, 80, 81, 82, 83, 84,
90 85, 86, 87, 88, 89, 90, 91, 92, 92, 93,
91 93, 94, 94, 95, 95, 96, 96, 97, 97, 98,
92 98, 99, 99, 99, 99, 100, 100, 100, 100, 100,
93 100
94};
95
96//******************************************************************************
97//Convert linear volume to logarithmic
98//******************************************************************************
99ULONG ConvertVolume(ULONG ulLinVolume, ULONG ulLogVolMax)
100{
101 if(ulLinVolume > OSS32_MAX_VOLUME) {
102 ulLinVolume = OSS32_MAX_VOLUME;
103 }
104 ulLinVolume = LinToLog[ulLinVolume];
105
106 return (ulLinVolume * ulLogVolMax) / OSS32_MAX_VOLUME;
107}
108
109//******************************************************************************
110//******************************************************************************
111OSSRET OSS32_MixOpen(ULONG deviceid, OSSSTREAMID *pStreamId)
112{
113 mixerhandle *pHandle = NULL;
114 int ret, i, j, sz;
115
116 if(pStreamId == NULL) {
117 DebugInt3();
118 return OSSERR_INVALID_PARAMETER;
119 }
120 *pStreamId = 0;
121
122 if(alsa_fops == NULL) {
123 ret = OSSERR_NO_DEVICE_AVAILABLE;
124 goto failure;
125 }
126
127 sz = sizeof(mixerhandle);
128 pHandle = kmalloc(sz, GFP_KERNEL);
129 if(pHandle == NULL) {
130 ret = OSSERR_OUT_OF_MEMORY;
131 goto failure;
132 }
133 memset(pHandle, 0, sizeof(mixerhandle));
134
135 //set operation to non-blocking
136 pHandle->file.f_flags = O_NONBLOCK;
137
138 //setup pointers in file structure (used internally by ALSA)
139 pHandle->file.f_dentry = &pHandle->d_entry;
140 pHandle->file.f_dentry->d_inode = &pHandle->inode;
141
142 pHandle->file.f_mode = FMODE_WRITE;
143 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
144
145 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
146 if(ret) {
147 goto failure;
148 }
149 //retrieve mixer information
150 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
151 SNDRV_CTL_IOCTL_CARD_INFO,
152 (ULONG)&pHandle->info);
153 if(ret) {
154 goto failure;
155 }
156 //get the number of mixer elements
157 pHandle->list.offset = 0;
158 pHandle->list.space = 0;
159 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
160 SNDRV_CTL_IOCTL_ELEM_LIST,
161 (ULONG)&pHandle->list);
162 if(ret) {
163 goto failure;
164 }
165 //allocate memory for all mixer elements
166 pHandle->pids = (struct snd_ctl_elem_id *)kmalloc(sizeof(struct snd_ctl_elem_id)*pHandle->list.count, GFP_KERNEL);
167 if(pHandle->pids == NULL) {
168 goto failure;
169 }
170 //and retrieve all mixer elements
171 pHandle->list.offset = 0;
172 pHandle->list.space = pHandle->list.count;
173 pHandle->list.pids = pHandle->pids;
174 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
175 SNDRV_CTL_IOCTL_ELEM_LIST,
176 (ULONG)&pHandle->list);
177 if(ret) {
178 goto failure;
179 }
180
181#if 0
182 dprintf(("Mixer name: %s", pHandle->info.mixername));
183 dprintf(("List of mixer elements:"));
184 for(i=0;i<pHandle->list.count;i++) {
185 dprintf(("index %d name %s id %d device %d subdevice %d", pHandle->pids[i].index, pHandle->pids[i].name, pHandle->pids[i].numid, pHandle->pids[i].device, pHandle->pids[i].subdevice));
186 }
187#endif
188
189 //Extract standard mixer controls from array with control names
190 for(j=0;j<OSS_MIXER_NRDEVICES;j++)
191 {
192 int namelen = strlen(ossid[j].name);
193
194 pHandle->controls[j].idxVolume = -1;
195 pHandle->controls[j].idxMute = -1;
196 pHandle->controls[j].idxCustom = -1;
197 pHandle->controls[j].idxCaptureSwitch = -1;
198
199 for(i=0;i<pHandle->list.count;i++)
200 {
201 if (pHandle->pids[i].index == ossid[j].index &&
202 strncmp(pHandle->pids[i].name, ossid[j].name, namelen) == 0)
203 {
204 int controlnamelen = strlen(pHandle->pids[i].name);
205
206 if(namelen == controlnamelen)
207 {//control names are identical; found exact match
208 pHandle->controls[j].idxVolume = i;
209 break;
210 }
211 else
212 {//first part of the control name is correct; now find out what
213 //is it exactly
214 char *nextword = &pHandle->pids[i].name[namelen];
215 while(*nextword && *nextword == ' ') nextword++;
216
217 if(strncmp(nextword, MIXER_PLAYBACKVOLUME, sizeof(MIXER_PLAYBACKVOLUME)-1) == 0 ||
218 strncmp(nextword, MIXER_VOLUME, sizeof(MIXER_VOLUME)-1) == 0)
219 {//volume control
220 pHandle->controls[j].idxVolume = i;
221 }
222 else
223 if(strncmp(nextword, MIXER_PLAYBACKSWITCH, sizeof(MIXER_PLAYBACKSWITCH)-1) == 0 ||
224 strncmp(nextword, MIXER_SWITCH, sizeof(MIXER_SWITCH)-1) == 0)
225 {//mute control
226 pHandle->controls[j].idxMute = i;
227 if (pHandle->controls[j].idxVolume == -1)
228 pHandle->controls[j].idxVolume = i;
229 }
230 else
231 if(strncmp(nextword, MIXER_SOURCE, sizeof(MIXER_SOURCE)-1) == 0)
232 {//source control (e.g. recording source)
233 pHandle->controls[j].idxCustom = i;
234 }
235 else
236 if(strncmp(nextword, MIXER_CAPTUREROUTE, sizeof(MIXER_CAPTUREROUTE)-1) == 0 ||
237 strncmp(nextword, MIXER_CAPTURESWITCH, sizeof(MIXER_CAPTURESWITCH)-1) == 0)
238 {//source control for recording (per input)
239 pHandle->controls[j].idxCaptureSwitch = i;
240 }
241 else
242 if(i == OSS_MIXER_MIC) {
243 if(strncmp(nextword, MIXER_BOOST, sizeof(MIXER_BOOST)-1) == 0)
244 {//mic boost switch
245 pHandle->controls[j].idxCustom = i;
246 }
247 }
248 }
249 }
250 }
251 }
252
253 pHandle->reccaps = 0;
254 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
255 pHandle->idxRecCaps[j] = -1;
256 }
257
258 //request information about available capture sources
259 if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1)
260 {
261 struct snd_ctl_elem_info *pElemInfo = NULL;
262 int idx, j;
263
264 idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom;
265
266 //set operation to non-blocking
267 pHandle->file.f_flags = O_NONBLOCK;
268
269 pHandle->rectype = RECTYPE_SELECTOR;
270
271 //too big to put on the stack
272 pElemInfo = (struct snd_ctl_elem_info *)kmalloc(sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
273 if(pElemInfo == NULL) {
274 DebugInt3();
275 goto failure;
276 }
277
278 pElemInfo->value.enumerated.items = 1;
279 for(i=0;i<pElemInfo->value.enumerated.items;i++)
280 {
281 pElemInfo->value.enumerated.item = i;
282 pElemInfo->id.numid = pHandle->pids[idx].numid;
283 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
284 if(ret) {
285 DebugInt3();
286 break;
287 }
288 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
289 DebugInt3();
290 break;
291 }
292 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
293 if(!strcmp(pElemInfo->value.enumerated.name, szRecSources[j])) {
294 pHandle->reccaps |= OSS32_MIX_FLAG(j);
295 pHandle->idxRecCaps[j] = i; //save alsa index
296 break;
297 }
298 }
299 }
300 kfree(pElemInfo);
301 }
302 else
303 {//This card has no record source selection, but probably route switches for
304 //each input source (SB mixers (also ALS4000), CMedia)
305 pHandle->rectype = RECTYPE_SWITCH;
306 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
307 pHandle->idxRecCaps[j] = -1;
308 }
309 for(j=0;j<OSS_MIXER_NRDEVICES;j++)
310 {
311 if(pHandle->controls[j].idxCaptureSwitch != -1) {
312 pHandle->reccaps |= OSS32_MIX_FLAG(ossid[j].recsrc);
313 pHandle->idxRecCaps[ossid[j].recsrc] = pHandle->controls[j].idxCaptureSwitch; //save alsa index
314 }
315 }
316 }
317
318 pHandle->magic = MAGIC_MIXER_ALSA32;
319 *pStreamId = (ULONG)pHandle;
320 return OSSERR_SUCCESS;
321
322failure:
323 if(pHandle) {
324 if(pHandle->pids) kfree(pHandle->pids);
325 kfree(pHandle);
326 }
327 DebugInt3();
328 return OSSERR_OUT_OF_MEMORY;
329}
330//******************************************************************************
331//******************************************************************************
332OSSRET OSS32_MixClose(OSSSTREAMID streamid)
333{
334 mixerhandle *pHandle = (mixerhandle *)streamid;
335 int ret;
336
337 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
338 DebugInt3();
339 return OSSERR_INVALID_STREAMID;
340 }
341 //set operation to non-blocking
342 pHandle->file.f_flags = O_NONBLOCK;
343 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
344 kfree(pHandle->pids); //free mixer element array
345 kfree(pHandle); //free handle data
346
347 if(ret) {
348 DebugInt3();
349 return UNIXToOSSError(ret);
350 }
351 return OSSERR_SUCCESS;
352}
353//******************************************************************************
354//******************************************************************************
355OSSRET OSS32_MixGetVolume(OSSSTREAMID streamid, ULONG line, ULONG *pVolume)
356{
357 mixerhandle *pHandle = (mixerhandle *)streamid;
358 int ret;
359
360 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
361 DebugInt3();
362 return OSSERR_INVALID_STREAMID;
363 }
364 //set operation to non-blocking
365 pHandle->file.f_flags = O_NONBLOCK;
366
367 return OSSERR_NOT_SUPPORTED;
368}
369//******************************************************************************
370//******************************************************************************
371OSSRET OSS32_MixSetVolume(OSSSTREAMID streamid, ULONG line, ULONG volume)
372{
373 mixerhandle *pHandle = (mixerhandle *)streamid;
374 struct snd_ctl_elem_value *pElem = NULL;
375 struct snd_ctl_elem_info *pElemInfo;
376 int ret, idx, lVol, rVol = 0, idxMute, cnt;
377
378 //dprintf(("OSS32_MixSetVolume line=%d\n", line));
379 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
380 printk("Invalid handle in OSS32_MixSetVolume\n");
381 DebugInt3();
382 return OSSERR_INVALID_STREAMID;
383 }
384 //set operation to non-blocking
385 pHandle->file.f_flags = O_NONBLOCK;
386
387 //too big to put on the stack
388 pElem = (struct snd_ctl_elem_value *)kmalloc(sizeof(struct snd_ctl_elem_value) + sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
389 if(pElem == NULL) {
390 printk("Out of memory in OSS32_MixSetVolume\n");
391 DebugInt3();
392 return OSSERR_OUT_OF_MEMORY;
393 }
394 pElemInfo = (struct snd_ctl_elem_info *)(pElem+1);
395
396 switch(line) {
397 case OSS32_MIX_VOLUME_MASTER_FRONT:
398 idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume;
399 idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute;
400 if (idx == -1)
401 {
402 /* HDA codecs workaround */
403 idx = pHandle->controls[OSS_MIXER_FRONT].idxVolume;
404 idxMute = pHandle->controls[OSS_MIXER_FRONT].idxMute;
405 }
406 break;
407 case OSS32_MIX_VOLUME_MASTER_REAR: //TODO:
408 idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume;
409 idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute;
410 break;
411 case OSS32_MIX_VOLUME_PCM:
412 idx = pHandle->controls[OSS_MIXER_PCM].idxVolume;
413 idxMute = pHandle->controls[OSS_MIXER_PCM].idxMute;
414 if (idx == -1)
415 {
416 /* HDA codecs workaround */
417 idx = pHandle->controls[OSS_MIXER_FRONT].idxVolume;
418 idxMute = pHandle->controls[OSS_MIXER_FRONT].idxMute;
419 }
420 break;
421 case OSS32_MIX_VOLUME_MIDI:
422 idx = pHandle->controls[OSS_MIXER_SYNTH].idxVolume;
423 idxMute = pHandle->controls[OSS_MIXER_SYNTH].idxMute;
424 break;
425 case OSS32_MIX_VOLUME_LINEIN:
426 idx = pHandle->controls[OSS_MIXER_LINE].idxVolume;
427 idxMute = pHandle->controls[OSS_MIXER_LINE].idxMute;
428 break;
429 case OSS32_MIX_VOLUME_MIC:
430 idx = pHandle->controls[OSS_MIXER_MIC].idxVolume;
431 idxMute = pHandle->controls[OSS_MIXER_MIC].idxMute;
432 break;
433 case OSS32_MIX_VOLUME_CD:
434 idx = pHandle->controls[OSS_MIXER_CD].idxVolume;
435 idxMute = pHandle->controls[OSS_MIXER_CD].idxMute;
436 break;
437 case OSS32_MIX_VOLUME_SPDIF:
438 idx = pHandle->controls[OSS_MIXER_DIGITAL1].idxVolume;
439 idxMute = pHandle->controls[OSS_MIXER_DIGITAL1].idxMute;
440 break;
441 case OSS32_MIX_VOLUME_VIDEO:
442 idx = pHandle->controls[OSS_MIXER_VIDEO].idxVolume;
443 idxMute = pHandle->controls[OSS_MIXER_VIDEO].idxMute;
444 break;
445 case OSS32_MIX_VOLUME_PCSPEAKER:
446 idx = pHandle->controls[OSS_MIXER_PCSPEAKER].idxVolume;
447 idxMute = pHandle->controls[OSS_MIXER_PCSPEAKER].idxMute;
448 break;
449 case OSS32_MIX_VOLUME_PHONE:
450 idx = pHandle->controls[OSS_MIXER_PHONEOUT].idxVolume;
451 idxMute = pHandle->controls[OSS_MIXER_PHONEOUT].idxMute;
452 break;
453 case OSS32_MIX_VOLUME_HEADPHONE:
454 idx = pHandle->controls[OSS_MIXER_HEADPHONE].idxVolume;
455 idxMute = pHandle->controls[OSS_MIXER_HEADPHONE].idxMute;
456 break;
457 case OSS32_MIX_VOLUME_SPEAKER:
458 idx = pHandle->controls[OSS_MIXER_SPEAKER].idxVolume;
459 idxMute = pHandle->controls[OSS_MIXER_SPEAKER].idxMute;
460 break;
461 case OSS32_MIX_VOLUME_AUX:
462 idx = pHandle->controls[OSS_MIXER_LINE1].idxVolume;
463 idxMute = pHandle->controls[OSS_MIXER_LINE1].idxMute;
464 break;
465 case OSS32_MIX_VOLUME_CAPTURE:
466 idx = pHandle->controls[OSS_MIXER_IGAIN].idxVolume;
467 idxMute = pHandle->controls[OSS_MIXER_IGAIN].idxMute;
468 break;
469
470 default:
471 DebugInt3();
472 ret = OSSERR_INVALID_PARAMETER;
473 goto fail;
474 }
475 if(idx == -1) {
476 rprintf(("Unknown control %d", line));
477 ret = OSSERR_INVALID_PARAMETER;
478 goto fail;
479 }
480
481 if(idxMute != -1 && volume != 0) {
482 //disable mute
483 pElem->id.numid = pHandle->pids[idxMute].numid;
484 pElem->indirect = 0;
485
486 pElem->value.integer.value[0] = TRUE; //switch, not mute control (inversed)
487 pElem->value.integer.value[1] = TRUE;
488 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
489 }
490 //request information about mixer control
491 pElemInfo->id.numid = pHandle->pids[idx].numid;
492 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
493 if(ret) {
494 ret = UNIXToOSSError(ret);
495 DebugInt3();
496 goto fail;
497 }
498 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
499 ret = OSSERR_INVALID_PARAMETER;
500 DebugInt3();
501 goto fail;
502 }
503 pElem->id.numid = pHandle->pids[idx].numid;
504 pElem->indirect = 0;
505
506 lVol = ConvertVolume(GET_VOLUME_L(volume), pElemInfo->value.integer.max);
507 pElem->value.integer.value[0] = lVol;
508
509 if(pElemInfo->count > 1) { //stereo
510 rVol = ConvertVolume(GET_VOLUME_R(volume), pElemInfo->value.integer.max);
511 pElem->value.integer.value[1] = rVol;
512 }
513
514 dprintf(("OSS32_MixSetVolume of %s streamid %X to (%d,%d)(%d,%d) caps %d",
515 pHandle->pids[idx].name, (ULONG)pHandle,
516 GET_VOLUME_L(volume), GET_VOLUME_R(volume), lVol, rVol, pElemInfo->value.integer.max));
517
518#if 1
519 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
520#else
521 // looking for more, then one opened streams to prevent of muting active stream
522 cnt = 0;
523 for (idx=0; idx < 8*256; idx++)
524 if (opened_handles[idx].handle != 0)
525 cnt++;
526
527 dprintf(("OSS32_MixSetVolume old cnt=%X line=%x lVol=%x rVol=%x", cnt, line, lVol, rVol));
528 // if (((cnt == 1 && (lVol==0 && rVol==0)) || (lVol>0 && rVol>0)) ||
529 if (cnt == 1 || line != OSS32_MIX_VOLUME_PCM)
530 {
531 dprintf(("OSS32_MixSetVolume Ioctl"));
532 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
533
534 if(idxMute != -1 && volume == 0) {
535 //enable mute
536 pElem->id.numid = pHandle->pids[idxMute].numid;
537 pElem->indirect = 0;
538
539 pElem->value.integer.value[0] = FALSE; //switch, not mute control (inversed)
540 pElem->value.integer.value[1] = FALSE;
541 dprintf(("OSS32_MixSetVolume Ioctl mute"));
542 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
543 }
544 }
545#endif
546
547 kfree(pElem);
548 pElem = NULL;
549 if(ret) {
550 rprintf(("OSS32_MixSetVolume ret=%x", ret));
551 DebugInt3();
552 return UNIXToOSSError(ret);
553 }
554 return OSSERR_SUCCESS;
555
556fail:
557 if(pElem) kfree(pElem);
558 return ret;
559}
560//******************************************************************************
561//******************************************************************************
562OSSRET OSS32_MixSetProperty(OSSSTREAMID streamid, ULONG ulLine, ULONG ulValue)
563{
564 mixerhandle *pHandle = (mixerhandle *)streamid;
565 struct snd_ctl_elem_value *pElem = NULL;
566 struct snd_ctl_elem_info *pElemInfo;
567 int ret, idx = -1, lVol, rVol = 0, j, i;
568
569 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
570 DebugInt3();
571 return OSSERR_INVALID_STREAMID;
572 }
573 //set operation to non-blocking
574 pHandle->file.f_flags = O_NONBLOCK;
575
576 //too big to put on the stack
577 pElem = (struct snd_ctl_elem_value *)kmalloc(sizeof(struct snd_ctl_elem_value) + sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
578 if(pElem == NULL) {
579 DebugInt3();
580 return OSSERR_OUT_OF_MEMORY;
581 }
582 pElemInfo = (struct snd_ctl_elem_info *)(pElem+1);
583
584 switch(ulLine) {
585 case OSS32_MIX_INPUTSRC:
586 idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom;
587 //is this capture source supported by the hardware??
588 if(!(pHandle->reccaps & OSS32_MIX_FLAG(ulValue))) {
589 DebugInt3();
590 ret = OSSERR_INVALID_PARAMETER;
591 goto fail;
592 }
593 if(pHandle->rectype == RECTYPE_SELECTOR) {//input source selector
594 //set left and right capture source
595 pElem->value.enumerated.item[0] = pHandle->idxRecCaps[ulValue];
596 pElem->value.enumerated.item[1] = pHandle->idxRecCaps[ulValue];
597 }
598 else {//capture switch for each input source
599 //first turn off all capture switches...
600 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++)
601 {
602 if(pHandle->idxRecCaps[j] != -1) {
603 idx = pHandle->idxRecCaps[j];
604
605 //request information about mixer control
606 pElemInfo->id.numid = pHandle->pids[idx].numid;
607 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
608 if(ret) {
609 ret = UNIXToOSSError(ret);
610 DebugInt3();
611 goto fail;
612 }
613 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN) {
614 ret = OSSERR_INVALID_PARAMETER;
615 DebugInt3();
616 goto fail;
617 }
618
619 pElem->id.numid = pHandle->pids[idx].numid;
620 pElem->indirect = 0;
621 for(i=0;i<pElemInfo->count;i++) {
622 pElem->value.integer.value[i] = 0;
623 }
624
625 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
626 if(ret) {
627 ret = UNIXToOSSError(ret);
628 DebugInt3();
629 goto fail;
630 }
631 }
632 }
633 //request information about mixer control
634 pElemInfo->id.numid = pHandle->pids[idx].numid;
635 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
636 if(ret) {
637 ret = UNIXToOSSError(ret);
638 DebugInt3();
639 goto fail;
640 }
641
642 //and enable the capture switch for the selected input source
643 idx = pHandle->idxRecCaps[ulValue];
644 for(i=0;i<pElemInfo->count;i++) {
645 pElem->value.integer.value[i] = 1;
646 }
647 }
648
649 break;
650
651 case OSS32_MIX_SWITCH_MICBOOST:
652 idx = pHandle->controls[OSS_MIXER_MIC].idxCustom;
653 if(idx == -1) {
654 DebugInt3();
655 ret = OSSERR_INVALID_PARAMETER;
656 goto fail;
657 }
658 //set mic switch value (on/off)
659 pElem->value.integer.value[0] = ulValue;
660 break;
661
662 case OSS32_MIX_LEVEL_BASS:
663 idx = pHandle->controls[OSS_MIXER_BASS].idxVolume;
664 goto levelcontinue;
665 case OSS32_MIX_LEVEL_TREBLE:
666 idx = pHandle->controls[OSS_MIXER_TREBLE].idxVolume;
667 goto levelcontinue;
668 case OSS32_MIX_LEVEL_3DCENTER:
669 idx = pHandle->controls[OSS_MIXER_3DCENTER].idxVolume;
670 goto levelcontinue;
671 case OSS32_MIX_LEVEL_3DDEPTH:
672 idx = pHandle->controls[OSS_MIXER_3DDEPTH].idxVolume;
673levelcontinue:
674
675 if(idx == -1) {//supported?
676 DebugInt3();
677 ret = OSSERR_INVALID_PARAMETER;
678 goto fail;
679 }
680 //request information about mixer control
681 pElemInfo->id.numid = pHandle->pids[idx].numid;
682 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
683 if(ret) {
684 ret = UNIXToOSSError(ret);
685 DebugInt3();
686 goto fail;
687 }
688 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
689 ret = OSSERR_INVALID_PARAMETER;
690 DebugInt3();
691 goto fail;
692 }
693 lVol = ConvertVolume(GET_VOLUME_L(ulValue), pElemInfo->value.integer.max);
694 pElem->value.integer.value[0] = lVol;
695
696 if(pElemInfo->count > 1) { //stereo
697 rVol = ConvertVolume(GET_VOLUME_R(ulValue), pElemInfo->value.integer.max);
698 pElem->value.integer.value[1] = rVol;
699 }
700 break;
701
702 default:
703 DebugInt3();
704 ret = OSSERR_INVALID_PARAMETER;
705 goto fail;
706 }
707 pElem->id.numid = pHandle->pids[idx].numid;
708 pElem->indirect = 0;
709
710 dprintf(("OSS32_MixSetProperty of %s to %x", pHandle->pids[idx].name, ulValue));
711 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
712
713 kfree(pElem);
714 pElem = NULL;
715 if(ret) {
716 DebugInt3();
717 return UNIXToOSSError(ret);
718 }
719 return OSSERR_SUCCESS;
720
721fail:
722 if(pElem) kfree(pElem);
723 return ret;
724}
725//******************************************************************************
726//******************************************************************************
727OSSRET OSS32_MixGetProperty(OSSSTREAMID streamid, ULONG line, ULONG *pValue)
728{
729 mixerhandle *pHandle = (mixerhandle *)streamid;
730 int ret;
731
732 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
733 DebugInt3();
734 return OSSERR_INVALID_STREAMID;
735 }
736 //set operation to non-blocking
737 pHandle->file.f_flags = O_NONBLOCK;
738
739 return OSSERR_NOT_SUPPORTED;
740}
741//******************************************************************************
742//******************************************************************************
743ULONG OSSToALSAVolume(ULONG OSSVolIdx)
744{
745 switch(OSSVolIdx) {
746 case OSS_MIXER_VOLUME:
747 return OSS32_MIX_VOLUME_MASTER_FRONT;
748#if 0
749 case OSS_MIXER_VOLUME: //TODO:
750 return OSS32_MIX_VOLUME_MASTER_REAR;
751#endif
752 case OSS_MIXER_PCM:
753 return OSS32_MIX_VOLUME_PCM;
754 case OSS_MIXER_SYNTH:
755 return OSS32_MIX_VOLUME_MIDI;
756 case OSS_MIXER_LINE:
757 return OSS32_MIX_VOLUME_LINEIN;
758 case OSS_MIXER_MIC:
759 return OSS32_MIX_VOLUME_MIC;
760 case OSS_MIXER_CD:
761 return OSS32_MIX_VOLUME_CD;
762 case OSS_MIXER_DIGITAL1:
763 return OSS32_MIX_VOLUME_SPDIF;
764 case OSS_MIXER_VIDEO:
765 return OSS32_MIX_VOLUME_VIDEO;
766 case OSS_MIXER_PCSPEAKER:
767 return OSS32_MIX_VOLUME_PCSPEAKER;
768 case OSS_MIXER_PHONEOUT:
769 return OSS32_MIX_VOLUME_PHONE;
770 case OSS_MIXER_IGAIN:
771 return OSS32_MIX_VOLUME_CAPTURE;
772 case OSS_MIXER_TREBLE:
773 return OSS32_MIX_LEVEL_TREBLE;
774 case OSS_MIXER_BASS:
775 return OSS32_MIX_LEVEL_BASS;
776 case OSS_MIXER_HEADPHONE:
777 return OSS32_MIX_VOLUME_HEADPHONE;
778 case OSS_MIXER_SPEAKER:
779 return OSS32_MIX_VOLUME_SPEAKER;
780 case OSS_MIXER_LINE1:
781 return OSS32_MIX_VOLUME_AUX;
782 }
783 return -1;
784}
785//******************************************************************************
786//******************************************************************************
787OSSRET OSS32_MixQueryCaps(OSSSTREAMID streamid, POSS32_MIXCAPS pCaps)
788{
789 mixerhandle *pHandle = (mixerhandle *)streamid;
790 int i;
791
792 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
793 DebugInt3();
794 return OSSERR_INVALID_STREAMID;
795 }
796
797 strncpy(pCaps->name, pHandle->info.mixername, sizeof(pCaps->name));
798 pCaps->fuCtrlCaps = 0;
799 pCaps->fuRecCaps = 0;
800
801 for(i=0;i<OSS_MIXER_NRDEVICES;i++)
802 {
803 if(pHandle->controls[i].idxVolume != -1) {
804 ULONG volidx = OSSToALSAVolume(i);
805 if(volidx != -1)
806 pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(volidx);
807 }
808 }
809
810 //if it has a capture source control or the card has capture route switches,
811 //then we support intput source selection
812 if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1 ||
813 pHandle->rectype == RECTYPE_SWITCH)
814 {
815 pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(OSS32_MIX_INPUTSRC);
816 pCaps->fuRecCaps = pHandle->reccaps;
817 }
818 return OSSERR_SUCCESS;
819}
820//******************************************************************************
821//******************************************************************************
822OSSRET OSS32_MixQueryName(ULONG deviceid, char *pszMixerName, ULONG cbMixerName)
823{
824 mixerhandle *pHandle = NULL;
825 int ret, i, j;
826
827 if(alsa_fops == NULL)
828 return OSSERR_NO_DEVICE_AVAILABLE;
829
830 pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL);
831 if(pHandle == NULL) {
832 ret = OSSERR_OUT_OF_MEMORY;
833 goto failure;
834 }
835 memset(pHandle, 0, sizeof(mixerhandle));
836
837 //set operation to non-blocking
838 pHandle->file.f_flags = O_NONBLOCK;
839
840 //setup pointers in file structure (used internally by ALSA)
841 pHandle->file.f_dentry = &pHandle->d_entry;
842 pHandle->file.f_dentry->d_inode = &pHandle->inode;
843
844 pHandle->file.f_mode = FMODE_WRITE;
845 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
846
847 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
848 if(ret) {
849 goto failure;
850 }
851 //retrieve mixer information
852 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
853 SNDRV_CTL_IOCTL_CARD_INFO,
854 (ULONG)&pHandle->info);
855 if(ret) {
856 goto failure;
857 }
858
859 strncpy(pszMixerName, pHandle->info.mixername, cbMixerName);
860
861 pHandle->file.f_flags = O_NONBLOCK;
862 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
863 if(ret) {
864 goto failure;
865 }
866 kfree(pHandle);
867 return OSSERR_SUCCESS;
868
869failure:
870 if(pHandle) {
871 kfree(pHandle);
872 }
873 DebugInt3();
874 return OSSERR_OUT_OF_MEMORY;
875}
876//******************************************************************************
877//******************************************************************************
878OSSRET OSS32_QueryNames(ULONG deviceid, char *pszDeviceName, ULONG cbDeviceName,
879 char *pszMixerName, ULONG cbMixerName, BOOL fLongName)
880{
881 mixerhandle *pHandle = NULL;
882 int ret, i, j;
883
884 if(alsa_fops == NULL) {
885 ret = OSSERR_NO_DEVICE_AVAILABLE;
886 printk("ret = OSSERR_NO_DEVICE_AVAILABLE\n");
887 goto failure;
888 }
889
890 pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL);
891 if(pHandle == NULL) {
892 ret = OSSERR_OUT_OF_MEMORY;
893 goto failure;
894 }
895 memset(pHandle, 0, sizeof(mixerhandle));
896
897 //set operation to non-blocking
898 pHandle->file.f_flags = O_NONBLOCK;
899
900 //setup pointers in file structure (used internally by ALSA)
901 pHandle->file.f_dentry = &pHandle->d_entry;
902 pHandle->file.f_dentry->d_inode = &pHandle->inode;
903
904 pHandle->file.f_mode = FMODE_WRITE;
905 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
906
907 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
908 if(ret) {
909 printk("open ret = %i\n", ret);
910 goto failure;
911 }
912 //retrieve mixer information
913 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
914 SNDRV_CTL_IOCTL_CARD_INFO,
915 (ULONG)&pHandle->info);
916 if(ret) {
917 printk("ioctl ret = %i\n", ret);
918 goto failure;
919 }
920
921 if(pszDeviceName) {
922 if(fLongName == TRUE) {
923 strncpy(pszDeviceName, pHandle->info.longname, cbDeviceName);
924 }
925 else strncpy(pszDeviceName, pHandle->info.name, cbDeviceName);
926 }
927 if(pszMixerName) {
928 strncpy(pszMixerName, pHandle->info.mixername, cbMixerName);
929 }
930
931// printk("Card: %s with mixer %s\n",pszDeviceName, pszMixerName);
932
933 pHandle->file.f_flags = O_NONBLOCK;
934 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
935 if(ret) {
936 printk("release ret = %i\n", ret);
937 goto failure;
938 }
939 kfree(pHandle);
940 return OSSERR_SUCCESS;
941
942failure:
943 if(pHandle) {
944 kfree(pHandle);
945 }
946 DebugInt3();
947 printk("OSS32_QueryNames() ret = %i\n", ret);
948 return OSSERR_OUT_OF_MEMORY;
949}
950//******************************************************************************
951//******************************************************************************
952
Note: See TracBrowser for help on using the repository browser.