blob: e6602e70a8ec335085df5c76930d8214e90d133f [file] [log] [blame]
Eric Pouech31c28661999-03-22 14:50:38 +00001/* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
Alexandre Julliard491502b1997-11-01 19:08:16 +00003/*
4 * Sample MIXER Wine Driver for Linux
5 *
Eric Pouech31c28661999-03-22 14:50:38 +00006 * Copyright 1997 Marcus Meissner
Eric Pouech54e4ba01999-05-03 09:26:48 +00007 * 1999 Eric Pouech
Alexandre Julliard491502b1997-11-01 19:08:16 +00008 */
9
Alexandre Julliard491502b1997-11-01 19:08:16 +000010#include <stdlib.h>
David Luyeree517e81999-02-28 12:27:56 +000011#include <string.h>
Alexandre Julliard491502b1997-11-01 19:08:16 +000012#include <unistd.h>
13#include <fcntl.h>
14#include <sys/ioctl.h>
Jim Aston2e1cafa1999-03-14 16:35:05 +000015#include "windef.h"
Alexandre Julliard491502b1997-11-01 19:08:16 +000016#include "user.h"
17#include "driver.h"
Eric Pouech37c02171999-09-05 16:44:38 +000018#include "mmddk.h"
19#include "oss.h"
Eric Pouech54e4ba01999-05-03 09:26:48 +000020#include "debugtools.h"
Alexandre Julliard491502b1997-11-01 19:08:16 +000021
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000022DEFAULT_DEBUG_CHANNEL(mmaux)
23
Eric Pouech31c28661999-03-22 14:50:38 +000024#ifdef HAVE_OSS
Alexandre Julliard491502b1997-11-01 19:08:16 +000025#define MIXER_DEV "/dev/mixer"
26
Eric Pouech31c28661999-03-22 14:50:38 +000027#define WINE_MIXER_MANUF_ID 0xAA
Eric Pouech54e4ba01999-05-03 09:26:48 +000028#define WINE_MIXER_PRODUCT_ID 0x55
Eric Pouech31c28661999-03-22 14:50:38 +000029#define WINE_MIXER_VERSION 0x0100
30#define WINE_MIXER_NAME "WINE OSS Mixer"
31
Eric Pouech54e4ba01999-05-03 09:26:48 +000032#define WINE_CHN_MASK(_x) (1L << (_x))
33#define WINE_CHN_SUPPORTS(_c, _x) ((_c) & WINE_CHN_MASK(_x))
34#define WINE_MIXER_MASK (WINE_CHN_MASK(SOUND_MIXER_VOLUME) | \
35 WINE_CHN_MASK(SOUND_MIXER_BASS) | \
36 WINE_CHN_MASK(SOUND_MIXER_TREBLE) | \
37 WINE_CHN_MASK(SOUND_MIXER_SYNTH) | \
38 WINE_CHN_MASK(SOUND_MIXER_PCM) | \
39 WINE_CHN_MASK(SOUND_MIXER_LINE) | \
40 WINE_CHN_MASK(SOUND_MIXER_MIC) | \
41 WINE_CHN_MASK(SOUND_MIXER_CD))
42
Alexandre Julliard491502b1997-11-01 19:08:16 +000043/**************************************************************************
Eric Pouech54e4ba01999-05-03 09:26:48 +000044 * MIX_GetVal [internal]
45 */
46static BOOL MIX_GetVal(int chn, int* val)
47{
48 int mixer;
49 BOOL ret = FALSE;
50
51 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
52 /* FIXME: ENXIO => no mixer installed */
53 WARN("mixer device not available !\n");
54 } else {
55 if (ioctl(mixer, MIXER_READ(chn), val) >= 0) {
Eric Pouechb343fa81999-05-24 08:16:31 +000056 TRACE("Reading %x on %d\n", *val, chn);
Eric Pouech54e4ba01999-05-03 09:26:48 +000057 ret = TRUE;
58 }
59 close(mixer);
60 }
61 return ret;
62}
63
64/**************************************************************************
65 * MIX_SetVal [internal]
66 */
67static BOOL MIX_SetVal(int chn, int* val)
68{
69 int mixer;
70 BOOL ret = FALSE;
71
72 TRACE("Writing %x on %d\n", *val, chn);
73
74 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
75 /* FIXME: ENXIO => no mixer installed */
76 WARN("mixer device not available !\n");
77 } else {
78 if (ioctl(mixer, MIXER_WRITE(chn), val) >= 0) {
79 ret = TRUE;
80 }
81 close(mixer);
82 }
83 return ret;
84}
85
86/**************************************************************************
87 * MIX_GetDevCaps [internal]
Alexandre Julliard491502b1997-11-01 19:08:16 +000088 */
Eric Pouech31c28661999-03-22 14:50:38 +000089static DWORD MIX_GetDevCaps(WORD wDevID, LPMIXERCAPSA lpCaps, DWORD dwSize)
Alexandre Julliard491502b1997-11-01 19:08:16 +000090{
Eric Pouech54e4ba01999-05-03 09:26:48 +000091 int mixer, mask;
92
93 TRACE("(%04X, %p, %lu);\n", wDevID, lpCaps, dwSize);
94
95 if (wDevID != 0) return MMSYSERR_BADDEVICEID;
96 if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
97
98 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
99 /* FIXME: ENXIO => no mixer installed */
100 WARN("mixer device not available !\n");
101 return MMSYSERR_NOTENABLED;
102 }
103 lpCaps->wMid = WINE_MIXER_MANUF_ID;
104 lpCaps->wPid = WINE_MIXER_PRODUCT_ID;
105 lpCaps->vDriverVersion = WINE_MIXER_VERSION;
106 strcpy(lpCaps->szPname, WINE_MIXER_NAME);
107 if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &mask) == -1) {
Alexandre Julliard491502b1997-11-01 19:08:16 +0000108 close(mixer);
Eric Pouech54e4ba01999-05-03 09:26:48 +0000109 perror("ioctl mixer SOUND_MIXER_DEVMASK");
110 return MMSYSERR_NOTENABLED;
111 }
112
113 /* FIXME: can the Linux Mixer differ between multiple mixer targets ? */
114 lpCaps->cDestinations = 1;
115 lpCaps->fdwSupport = 0; /* No bits defined yet */
116
117 close(mixer);
118 return MMSYSERR_NOERROR;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000119}
120
Alexandre Julliard491502b1997-11-01 19:08:16 +0000121static char *sdlabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
122static char *sdnames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
Eric Pouechc11b1671999-02-13 12:38:09 +0000123
Eric Pouech54e4ba01999-05-03 09:26:48 +0000124/**************************************************************************
125 * MIX_GetLineInfoFromIndex [internal]
126 */
Eric Pouech31c28661999-03-22 14:50:38 +0000127static void MIX_GetLineInfoFromIndex(LPMIXERLINEA lpMl, int devmask, DWORD idx)
Eric Pouechc11b1671999-02-13 12:38:09 +0000128{
Eric Pouech54e4ba01999-05-03 09:26:48 +0000129 strcpy(lpMl->szShortName, sdlabels[idx]);
130 strcpy(lpMl->szName, sdnames[idx]);
131 lpMl->dwLineID = idx;
132 lpMl->dwDestination = 0; /* index for speakers */
133 lpMl->cConnections = 1;
134 lpMl->cControls = 1;
135 switch (idx) {
136 case SOUND_MIXER_SYNTH:
137 lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
138 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
139 break;
140 case SOUND_MIXER_CD:
141 lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
142 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
143 break;
144 case SOUND_MIXER_LINE:
145 lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
146 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
147 break;
148 case SOUND_MIXER_MIC:
149 lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
150 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
151 break;
152 case SOUND_MIXER_PCM:
153 lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
154 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
155 break;
156 default:
157 ERR("Index %ld not handled.\n", idx);
158 break;
159 }
Eric Pouechc11b1671999-02-13 12:38:09 +0000160}
Alexandre Julliard491502b1997-11-01 19:08:16 +0000161
162/**************************************************************************
Eric Pouech54e4ba01999-05-03 09:26:48 +0000163 * MIX_GetLineInfo [internal]
Alexandre Julliard491502b1997-11-01 19:08:16 +0000164 */
Eric Pouech31c28661999-03-22 14:50:38 +0000165static DWORD MIX_GetLineInfo(WORD wDevID, LPMIXERLINEA lpMl, DWORD fdwInfo)
Alexandre Julliard491502b1997-11-01 19:08:16 +0000166{
Eric Pouech54e4ba01999-05-03 09:26:48 +0000167 int mixer, i, j;
168 int devmask, stereomask;
169 BOOL isDst = FALSE;
170 DWORD ret = MMSYSERR_NOERROR;
171
172 TRACE("(%04X, %p, %lu);\n", wDevID, lpMl, fdwInfo);
173 if (lpMl == NULL || lpMl->cbStruct != sizeof(*lpMl))
174 return MMSYSERR_INVALPARAM;
175 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
176 return MMSYSERR_NOTENABLED;
177
178 if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
179 close(mixer);
180 perror("ioctl mixer SOUND_MIXER_DEVMASK");
181 return MMSYSERR_NOTENABLED;
182 }
183 devmask &= WINE_MIXER_MASK;
184 if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereomask) == -1) {
185 close(mixer);
186 perror("ioctl mixer SOUND_MIXER_STEREODEVS");
187 return MMSYSERR_NOTENABLED;
188 }
189 stereomask &= WINE_MIXER_MASK;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000190
Eric Pouech54e4ba01999-05-03 09:26:48 +0000191#if 0
192 int recsrc, recmask;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000193
Eric Pouech54e4ba01999-05-03 09:26:48 +0000194 if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) {
195 close(mixer);
196 perror("ioctl mixer SOUND_MIXER_RECSRC");
197 return MMSYSERR_NOTENABLED;
198 }
Eric Pouechc11b1671999-02-13 12:38:09 +0000199
Eric Pouech54e4ba01999-05-03 09:26:48 +0000200 if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
201 close(mixer);
202 perror("ioctl mixer SOUND_MIXER_RECMASK");
203 return MMSYSERR_NOTENABLED;
204 }
205#endif
206
207 /* FIXME: set all the variables correctly... the lines below
208 * are very wrong...
209 */
210 lpMl->fdwLine = MIXERLINE_LINEF_ACTIVE;
211 lpMl->cChannels = 1;
212 lpMl->dwUser = 0;
213 lpMl->cControls = 1;
214
215 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
216 case MIXER_GETLINEINFOF_DESTINATION:
217 TRACE("DESTINATION (%08lx)\n", lpMl->dwDestination);
218 /* FIXME: Linux doesn't seem to support multiple outputs?
219 * So we have only one output type: Speaker.
Alexandre Julliard491502b1997-11-01 19:08:16 +0000220 */
Eric Pouech54e4ba01999-05-03 09:26:48 +0000221 lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
222 lpMl->dwSource = 0xFFFFFFFF;
223 lpMl->dwLineID = SOUND_MIXER_VOLUME;
224 strncpy(lpMl->szShortName, sdlabels[SOUND_MIXER_VOLUME], MIXER_SHORT_NAME_CHARS);
225 strncpy(lpMl->szName, sdnames[SOUND_MIXER_VOLUME], MIXER_LONG_NAME_CHARS);
226
227 /* we have all connections found in the devmask */
228 lpMl->cConnections = 0;
229 for (j = 1; j < SOUND_MIXER_NRDEVICES; j++)
230 if (WINE_CHN_SUPPORTS(devmask, j))
231 lpMl->cConnections++;
232 if (stereomask & WINE_CHN_MASK(SOUND_MIXER_VOLUME))
233 lpMl->cChannels++;
234 break;
235 case MIXER_GETLINEINFOF_SOURCE:
236 TRACE("SOURCE (%08lx)\n", lpMl->dwSource);
237 i = lpMl->dwSource;
238 for (j = 1; j < SOUND_MIXER_NRDEVICES; j++) {
239 if (WINE_CHN_SUPPORTS(devmask, j) && (i-- == 0))
Alexandre Julliard491502b1997-11-01 19:08:16 +0000240 break;
Eric Pouech54e4ba01999-05-03 09:26:48 +0000241 }
242 if (j >= SOUND_MIXER_NRDEVICES)
243 return MIXERR_INVALLINE;
244 if (WINE_CHN_SUPPORTS(stereomask, j))
245 lpMl->cChannels++;
246 MIX_GetLineInfoFromIndex(lpMl, devmask, j);
247 break;
248 case MIXER_GETLINEINFOF_LINEID:
249 TRACE("LINEID (%08lx)\n", lpMl->dwLineID);
250 if (lpMl->dwLineID >= SOUND_MIXER_NRDEVICES)
251 return MIXERR_INVALLINE;
252 if (WINE_CHN_SUPPORTS(stereomask, lpMl->dwLineID))
253 lpMl->cChannels++;
254 MIX_GetLineInfoFromIndex(lpMl, devmask, lpMl->dwLineID);
255 break;
256 case MIXER_GETLINEINFOF_COMPONENTTYPE:
257 TRACE("COMPONENT TYPE (%08lx)\n", lpMl->dwComponentType);
258
259 switch (lpMl->dwComponentType) {
260 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
261 i = SOUND_MIXER_VOLUME;
262 lpMl->dwDestination = 0;
263 lpMl->dwSource = 0xFFFFFFFF;
264 isDst = TRUE;
265 break;
266 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
267 i = SOUND_MIXER_SYNTH;
268 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
269 break;
270 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
271 i = SOUND_MIXER_CD;
272 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
273 break;
274 case MIXERLINE_COMPONENTTYPE_SRC_LINE:
275 i = SOUND_MIXER_LINE;
276 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
277 break;
278 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
279 i = SOUND_MIXER_MIC;
280 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
281 break;
282 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
283 i = SOUND_MIXER_PCM;
284 lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
285 break;
286 default:
287 FIXME("Unhandled component type (%08lx)\n", lpMl->dwComponentType);
288 return MMSYSERR_INVALPARAM;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000289 }
Eric Pouech31c28661999-03-22 14:50:38 +0000290
Eric Pouech54e4ba01999-05-03 09:26:48 +0000291 if (WINE_CHN_SUPPORTS(devmask, i)) {
292 strcpy(lpMl->szShortName, sdlabels[i]);
293 strcpy(lpMl->szName, sdnames[i]);
294 lpMl->dwLineID = i;
295 }
296 if (WINE_CHN_SUPPORTS(stereomask, i))
297 lpMl->cChannels++;
298 lpMl->cConnections = 0;
299 if (isDst) {
300 for (j = 1; j < SOUND_MIXER_NRDEVICES; j++) {
301 if (WINE_CHN_SUPPORTS(devmask, j)) {
302 lpMl->cConnections++;
303 }
304 }
305 }
306 break;
307 case MIXER_GETLINEINFOF_TARGETTYPE:
308 FIXME("_TARGETTYPE not implemented yet.\n");
309 break;
310 default:
311 WARN("Unknown flag (%08lx)\n", fdwInfo & MIXER_GETLINEINFOF_QUERYMASK);
312 break;
313 }
314
315 lpMl->Target.dwType = MIXERLINE_TARGETTYPE_AUX;
316 lpMl->Target.dwDeviceID = 0xFFFFFFFF;
317 lpMl->Target.wMid = WINE_MIXER_MANUF_ID;
318 lpMl->Target.wPid = WINE_MIXER_PRODUCT_ID;
319 lpMl->Target.vDriverVersion = WINE_MIXER_VERSION;
320 strcpy(lpMl->Target.szPname, WINE_MIXER_NAME);
321
322 close(mixer);
323 return ret;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000324}
325
326/**************************************************************************
327 * MIX_GetLineInfo [internal]
328 */
Eric Pouech31c28661999-03-22 14:50:38 +0000329static DWORD MIX_Open(WORD wDevID, LPMIXEROPENDESC lpMod, DWORD flags)
Alexandre Julliard491502b1997-11-01 19:08:16 +0000330{
Eric Pouech54e4ba01999-05-03 09:26:48 +0000331 TRACE("(%04X, %p, %lu);\n", wDevID, lpMod, flags);
332 if (lpMod == NULL) return MMSYSERR_INVALPARAM;
333 /* hmm. We don't keep the mixer device open. So just pretend it works */
334 return MMSYSERR_NOERROR;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000335}
336
Eric Pouech54e4ba01999-05-03 09:26:48 +0000337/**************************************************************************
338 * MIX_GetLineControls [internal]
339 */
Eric Pouech31c28661999-03-22 14:50:38 +0000340static DWORD MIX_GetLineControls(WORD wDevID, LPMIXERLINECONTROLSA lpMlc, DWORD flags)
341{
Eric Pouech54e4ba01999-05-03 09:26:48 +0000342 LPMIXERCONTROLA mc;
Eric Pouech31c28661999-03-22 14:50:38 +0000343
Eric Pouech54e4ba01999-05-03 09:26:48 +0000344 TRACE("(%04X, %p, %lu): stub!\n", wDevID, lpMlc, flags);
345
346 if (lpMlc == NULL) return MMSYSERR_INVALPARAM;
347 if (lpMlc->cbStruct < sizeof(*lpMlc) ||
348 lpMlc->cbmxctrl < sizeof(MIXERCONTROLA))
349 return MMSYSERR_INVALPARAM;
Eric Pouech31c28661999-03-22 14:50:38 +0000350
Eric Pouech54e4ba01999-05-03 09:26:48 +0000351 switch (flags & MIXER_GETLINECONTROLSF_QUERYMASK) {
352 case MIXER_GETLINECONTROLSF_ALL:
353 TRACE("line=%08lx GLCF_ALL (%ld)\n", lpMlc->dwLineID, lpMlc->cControls);
354 if (lpMlc->cControls != 1)
355 return MMSYSERR_INVALPARAM;
356 break;
357 case MIXER_GETLINECONTROLSF_ONEBYID:
358 TRACE("line=%08lx GLCF_ONEBYID (%lx)\n", lpMlc->dwLineID, lpMlc->u.dwControlID);
359 if (lpMlc->u.dwControlID != 0)
360 return MMSYSERR_INVALPARAM;
361 break;
362 case MIXER_GETLINECONTROLSF_ONEBYTYPE:
363 TRACE("line=%08lx GLCF_ONEBYTYPE (%lx)\n", lpMlc->dwLineID, lpMlc->u.dwControlType);
364 if ((lpMlc->u.dwControlType & MIXERCONTROL_CT_CLASS_MASK) != MIXERCONTROL_CT_CLASS_FADER)
365 return MMSYSERR_INVALPARAM;
366 break;
367 default:
Eric Pouechb343fa81999-05-24 08:16:31 +0000368 ERR("Unknown flag %08lx\n", flags & MIXER_GETLINECONTROLSF_QUERYMASK);
Eric Pouech54e4ba01999-05-03 09:26:48 +0000369 return MMSYSERR_INVALPARAM;
370 }
371 TRACE("Returning volume control\n");
372 /* currently, OSS only provides 1 control per line
373 * so one by id == one by type == all
374 */
375 mc = lpMlc->pamxctrl;
376 mc->cbStruct = sizeof(MIXERCONTROLA);
377 /* since we always have a single control per line, we'll use for controlID the lineID */
378 mc->dwControlID = lpMlc->dwLineID;
379 mc->dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
380 mc->fdwControl = 0;
381 mc->cMultipleItems = 0;
382 strncpy(mc->szShortName, "Vol", MIXER_SHORT_NAME_CHARS);
383 strncpy(mc->szName, "Volume", MIXER_LONG_NAME_CHARS);
384 memset(&mc->Bounds, 0, sizeof(mc->Bounds));
385 /* CONTROLTYPE_VOLUME uses the MIXER_CONTROLDETAILS_UNSIGNED struct,
386 * [0, 100] is the range supported by OSS
387 * FIXME: sounds like MIXERCONTROL_CONTROLTYPE_VOLUME is always between 0 and 65536...
388 * look at conversions done in (Get|Set)ControlDetails to stay in [0, 100] range
389 */
Patrik Stridvall32b43251999-09-14 07:52:16 +0000390 mc->Bounds.s1.dwMinimum = 0;
391 mc->Bounds.s1.dwMaximum = 100;
Eric Pouech54e4ba01999-05-03 09:26:48 +0000392 memset(&mc->Metrics, 0, sizeof(mc->Metrics));
393 mc->Metrics.cSteps = 0;
394 return MMSYSERR_NOERROR;
Eric Pouech31c28661999-03-22 14:50:38 +0000395}
Eric Pouech54e4ba01999-05-03 09:26:48 +0000396
397/**************************************************************************
398 * MIX_GetControlDetails [internal]
399 */
400static DWORD MIX_GetControlDetails(WORD wDevID, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
401{
402 DWORD ret = MMSYSERR_NOTSUPPORTED;
403
Eric Pouechb343fa81999-05-24 08:16:31 +0000404 TRACE("(%04X, %p, %lu)\n", wDevID, lpmcd, fdwDetails);
Eric Pouech54e4ba01999-05-03 09:26:48 +0000405
406 if (lpmcd == NULL) return MMSYSERR_INVALPARAM;
407
408 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
409 case MIXER_GETCONTROLDETAILSF_VALUE:
410 TRACE("GCD VALUE (%08lx)\n", lpmcd->dwControlID);
411 {
412 LPMIXERCONTROLDETAILS_UNSIGNED mcdu;
413 int val;
414
415 /* ControlID == LineID == OSS mixer channel */
416 /* return value is 00RL (4 bytes)... */
417 if (!MIX_GetVal(lpmcd->dwControlID, &val))
418 return MMSYSERR_INVALPARAM;
419
420 switch (lpmcd->cChannels) {
421 case 1:
422 /* mono... so R = L */
423 mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)lpmcd->paDetails;
424 mcdu->dwValue = (LOBYTE(LOWORD(val)) * 65536L) / 100;
425 break;
426 case 2:
427 /* stereo, left is paDetails[0] */
428 mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 0 * lpmcd->cbDetails);
429 mcdu->dwValue = (LOBYTE(LOWORD(val)) * 65536L) / 100;
430 mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 1 * lpmcd->cbDetails);
431 mcdu->dwValue = (HIBYTE(LOWORD(val)) * 65536L) / 100;
432 break;
433 default:
434 WARN("Unknown cChannels (%ld)\n", lpmcd->cChannels);
435 return MMSYSERR_INVALPARAM;
436 }
437 TRACE("=> %08lx\n", mcdu->dwValue);
438 }
439 ret = MMSYSERR_NOERROR;
440 break;
441 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
442 FIXME("NIY\n");
443 break;
444 default:
Eric Pouechb343fa81999-05-24 08:16:31 +0000445 WARN("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK);
Eric Pouech54e4ba01999-05-03 09:26:48 +0000446 }
447 return ret;
448}
449
450/**************************************************************************
451 * MIX_SetControlDetails [internal]
452 */
453static DWORD MIX_SetControlDetails(WORD wDevID, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
454{
455 DWORD ret = MMSYSERR_NOTSUPPORTED;
Eric Pouechb343fa81999-05-24 08:16:31 +0000456
457 TRACE("(%04X, %p, %lu)\n", wDevID, lpmcd, fdwDetails);
Eric Pouech54e4ba01999-05-03 09:26:48 +0000458
459 if (lpmcd == NULL) return MMSYSERR_INVALPARAM;
460
461 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
462 case MIXER_GETCONTROLDETAILSF_VALUE:
463 TRACE("GCD VALUE (%08lx)\n", lpmcd->dwControlID);
464 {
465 LPMIXERCONTROLDETAILS_UNSIGNED mcdu;
466 int val;
467
468 /* val should contain 00RL */
469 switch (lpmcd->cChannels) {
470 case 1:
471 /* mono... so R = L */
472 mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)lpmcd->paDetails;
473 TRACE("Setting RL to %08ld\n", mcdu->dwValue);
474 val = 0x101 * ((mcdu->dwValue * 100) >> 16);
475 break;
476 case 2:
477 /* stereo, left is paDetails[0] */
478 mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 0 * lpmcd->cbDetails);
479 TRACE("Setting L to %08ld\n", mcdu->dwValue);
480 val = ((mcdu->dwValue * 100) >> 16);
481 mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 1 * lpmcd->cbDetails);
482 TRACE("Setting R to %08ld\n", mcdu->dwValue);
483 val += ((mcdu->dwValue * 100) >> 16) << 8;
484 break;
485 default:
486 WARN("Unknown cChannels (%ld)\n", lpmcd->cChannels);
487 return MMSYSERR_INVALPARAM;
488 }
489
490 /* ControlID == LineID == OSS mixer channel */
491 if (!MIX_SetVal(lpmcd->dwControlID, &val))
492 return MMSYSERR_INVALPARAM;
493 }
494 ret = MMSYSERR_NOERROR;
495 break;
496 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
497 FIXME("NIY\n");
498 break;
499 default:
500 WARN("Unknown GetControlDetails flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK);
501 }
502 return MMSYSERR_NOTSUPPORTED;
503}
504
505#endif /* HAVE_OSS */
Eric Pouech31c28661999-03-22 14:50:38 +0000506
Alexandre Julliard491502b1997-11-01 19:08:16 +0000507/**************************************************************************
508 * mixMessage [sample driver]
509 */
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000510DWORD WINAPI mixMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
Eric Pouech54e4ba01999-05-03 09:26:48 +0000511 DWORD dwParam1, DWORD dwParam2)
Alexandre Julliard491502b1997-11-01 19:08:16 +0000512{
Eric Pouech54e4ba01999-05-03 09:26:48 +0000513 TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
514 wDevID, wMsg, dwUser, dwParam1, dwParam2);
515
Eric Pouech31c28661999-03-22 14:50:38 +0000516#ifdef HAVE_OSS
Eric Pouech54e4ba01999-05-03 09:26:48 +0000517 switch(wMsg) {
518 case MXDM_GETDEVCAPS:
519 return MIX_GetDevCaps(wDevID, (LPMIXERCAPSA)dwParam1, dwParam2);
520 case MXDM_GETLINEINFO:
521 return MIX_GetLineInfo(wDevID, (LPMIXERLINEA)dwParam1, dwParam2);
522 case MXDM_GETNUMDEVS:
523 TRACE("return 1;\n");
524 return 1;
525 case MXDM_OPEN:
526 return MIX_Open(wDevID, (LPMIXEROPENDESC)dwParam1, dwParam2);
527 case MXDM_CLOSE:
528 return MMSYSERR_NOERROR;
529 case MXDM_GETLINECONTROLS:
530 return MIX_GetLineControls(wDevID, (LPMIXERLINECONTROLSA)dwParam1, dwParam2);
531 case MXDM_GETCONTROLDETAILS:
532 return MIX_GetControlDetails(wDevID, (LPMIXERCONTROLDETAILS)dwParam1, dwParam2);
533 case MXDM_SETCONTROLDETAILS:
534 return MIX_SetControlDetails(wDevID, (LPMIXERCONTROLDETAILS)dwParam1, dwParam2);
535 default:
536 WARN("unknown message %d!\n", wMsg);
537 }
538 return MMSYSERR_NOTSUPPORTED;
539#else
540 return MMSYSERR_NOTENABLED;
Eric Pouech31c28661999-03-22 14:50:38 +0000541#endif
Alexandre Julliard491502b1997-11-01 19:08:16 +0000542}
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000543
Eric Pouech31c28661999-03-22 14:50:38 +0000544