source: GPL/branches/uniaud-2.0/lib32/soundmixer.c@ 304

Last change on this file since 304 was 84, checked in by vladest, 19 years ago

SB code update
HDA code update
Some other updates

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