Allow 1% deviation from specified sampling rate for some soundcards.
[wine] / dlls / winmm / wineoss / mmaux.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Sample AUXILARY Wine Driver
4  *
5  * Copyright 1994 Martin Ayotte
6  */
7
8 #define EMULATE_SB16
9
10 #include "config.h"
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <sys/ioctl.h>
17 #include "windef.h"
18 #include "driver.h"
19 #include "mmddk.h"
20 #include "oss.h"
21 #include "debugtools.h"
22
23 DEFAULT_DEBUG_CHANNEL(mmaux)
24     
25 #ifdef HAVE_OSS
26
27 #define MIXER_DEV "/dev/mixer"
28     
29 static int      NumDev = 6;
30
31 /*-----------------------------------------------------------------------*/
32
33 static  int     AUXDRV_Init(void)
34 {
35     int mixer;
36
37     if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
38         WARN("mixer device not available !\n");
39         NumDev = 0;
40     } else {
41         close(mixer);
42         NumDev = 6;
43     }
44     return NumDev;
45 }
46
47 /**************************************************************************
48  *                              AUX_GetDevCaps                  [internal]
49  */
50 static DWORD AUX_GetDevCaps(WORD wDevID, LPAUXCAPSA lpCaps, DWORD dwSize)
51 {
52     int         mixer,volume;
53     
54     TRACE("(%04X, %p, %lu);\n", wDevID, lpCaps, dwSize);
55     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
56     if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
57         WARN("mixer device not available !\n");
58         return MMSYSERR_NOTENABLED;
59     }
60     if (ioctl(mixer, SOUND_MIXER_READ_LINE, &volume) == -1) {
61         close(mixer);
62         WARN("unable to read mixer !\n");
63         return MMSYSERR_NOTENABLED;
64     }
65     close(mixer);
66 #ifdef EMULATE_SB16
67     lpCaps->wMid = 0x0002;
68     lpCaps->vDriverVersion = 0x0200;
69     lpCaps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
70     switch (wDevID) {
71     case 0:
72         lpCaps->wPid = 0x0196;
73         strcpy(lpCaps->szPname, "SB16 Aux: Wave");
74         lpCaps->wTechnology = AUXCAPS_AUXIN;
75         break;
76     case 1:
77         lpCaps->wPid = 0x0197;
78         strcpy(lpCaps->szPname, "SB16 Aux: Midi Synth");
79         lpCaps->wTechnology = AUXCAPS_AUXIN;
80         break;
81     case 2:
82         lpCaps->wPid = 0x0191;
83         strcpy(lpCaps->szPname, "SB16 Aux: CD");
84         lpCaps->wTechnology = AUXCAPS_CDAUDIO;
85         break;
86     case 3:
87         lpCaps->wPid = 0x0192;
88         strcpy(lpCaps->szPname, "SB16 Aux: Line-In");
89         lpCaps->wTechnology = AUXCAPS_AUXIN;
90         break;
91     case 4:
92         lpCaps->wPid = 0x0193;
93         strcpy(lpCaps->szPname, "SB16 Aux: Mic");
94         lpCaps->wTechnology = AUXCAPS_AUXIN;
95         break;
96     case 5:
97         lpCaps->wPid = 0x0194;
98         strcpy(lpCaps->szPname, "SB16 Aux: Master");
99         lpCaps->wTechnology = AUXCAPS_AUXIN;
100         break;
101     }
102 #else
103     lpCaps->wMid = 0xAA;
104     lpCaps->wPid = 0x55;
105     lpCaps->vDriverVersion = 0x0100;
106     strcpy(lpCaps->szPname, "Generic Linux Auxiliary Driver");
107     lpCaps->wTechnology = AUXCAPS_CDAUDIO;
108     lpCaps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
109 #endif
110     return MMSYSERR_NOERROR;
111 }
112
113
114 /**************************************************************************
115  *                              AUX_GetVolume                   [internal]
116  */
117 static DWORD AUX_GetVolume(WORD wDevID, LPDWORD lpdwVol)
118 {
119     int         mixer, volume, left, right, cmd;
120     
121     TRACE("(%04X, %p);\n", wDevID, lpdwVol);
122     if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
123     if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
124         WARN("mixer device not available !\n");
125         return MMSYSERR_NOTENABLED;
126     }
127     switch(wDevID) {
128     case 0:
129         TRACE("SOUND_MIXER_READ_PCM !\n");
130         cmd = SOUND_MIXER_READ_PCM;
131         break;
132     case 1:
133         TRACE("SOUND_MIXER_READ_SYNTH !\n");
134         cmd = SOUND_MIXER_READ_SYNTH;
135         break;
136     case 2:
137         TRACE("SOUND_MIXER_READ_CD !\n");
138         cmd = SOUND_MIXER_READ_CD;
139         break;
140     case 3:
141         TRACE("SOUND_MIXER_READ_LINE !\n");
142         cmd = SOUND_MIXER_READ_LINE;
143         break;
144     case 4:
145         TRACE("SOUND_MIXER_READ_MIC !\n");
146         cmd = SOUND_MIXER_READ_MIC;
147         break;
148     case 5:
149         TRACE("SOUND_MIXER_READ_VOLUME !\n");
150         cmd = SOUND_MIXER_READ_VOLUME;
151         break;
152     default:
153         WARN("invalid device id=%04X !\n", wDevID);
154         return MMSYSERR_NOTENABLED;
155     }
156     if (ioctl(mixer, cmd, &volume) == -1) {
157         WARN("unable to read mixer !\n");
158         return MMSYSERR_NOTENABLED;
159     }
160     close(mixer);
161     left  = LOBYTE(LOWORD(volume));
162     right = HIBYTE(LOWORD(volume));
163     TRACE("left=%d right=%d !\n", left, right);
164     *lpdwVol = MAKELONG((left * 0xFFFFL) / 100, (right * 0xFFFFL) / 100);
165     return MMSYSERR_NOERROR;
166 }
167
168 /**************************************************************************
169  *                              AUX_SetVolume                   [internal]
170  */
171 static DWORD AUX_SetVolume(WORD wDevID, DWORD dwParam)
172 {
173     int         mixer;
174     int         volume, left, right;
175     int         cmd;
176     
177     TRACE("(%04X, %08lX);\n", wDevID, dwParam);
178     
179     left   = (LOWORD(dwParam) * 100) >> 16;
180     right  = (HIWORD(dwParam) * 100) >> 16;
181     volume = (right << 8) | left;
182     
183     if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
184         WARN("mixer device not available !\n");
185         return MMSYSERR_NOTENABLED;
186     }
187     
188     switch(wDevID) {
189     case 0:
190         TRACE("SOUND_MIXER_WRITE_PCM !\n");
191         cmd = SOUND_MIXER_WRITE_PCM;
192         break;
193     case 1:
194         TRACE("SOUND_MIXER_WRITE_SYNTH !\n");
195         cmd = SOUND_MIXER_WRITE_SYNTH;
196         break;
197     case 2:
198         TRACE("SOUND_MIXER_WRITE_CD !\n");
199         cmd = SOUND_MIXER_WRITE_CD;
200         break;
201     case 3:
202         TRACE("SOUND_MIXER_WRITE_LINE !\n");
203         cmd = SOUND_MIXER_WRITE_LINE;
204         break;
205     case 4:
206         TRACE("SOUND_MIXER_WRITE_MIC !\n");
207         cmd = SOUND_MIXER_WRITE_MIC;
208         break;
209     case 5:
210         TRACE("SOUND_MIXER_WRITE_VOLUME !\n");
211         cmd = SOUND_MIXER_WRITE_VOLUME;
212         break;
213     default:
214         WARN("invalid device id=%04X !\n", wDevID);
215         return MMSYSERR_NOTENABLED;
216     }
217     if (ioctl(mixer, cmd, &volume) == -1) {
218         WARN("unable to set mixer !\n");
219         return MMSYSERR_NOTENABLED;
220     }
221     close(mixer);
222     return MMSYSERR_NOERROR;
223 }
224
225 #endif
226
227 /**************************************************************************
228  *              OSS_auxMessage                          [sample driver]
229  */
230 DWORD WINAPI OSS_auxMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
231                             DWORD dwParam1, DWORD dwParam2)
232 {
233     TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n", 
234           wDevID, wMsg, dwUser, dwParam1, dwParam2);
235
236 #ifdef HAVE_OSS
237     switch (wMsg) {
238     case DRVM_INIT:
239         AUXDRV_Init();
240         /* fall thru */
241     case DRVM_EXIT:
242     case DRVM_ENABLE:
243     case DRVM_DISABLE:
244         /* FIXME: Pretend this is supported */
245         return 0;
246     case AUXDM_GETDEVCAPS:
247         return AUX_GetDevCaps(wDevID, (LPAUXCAPSA)dwParam1,dwParam2);
248     case AUXDM_GETNUMDEVS:
249         TRACE("return %d;\n", NumDev);
250         return NumDev;
251     case AUXDM_GETVOLUME:
252         return AUX_GetVolume(wDevID, (LPDWORD)dwParam1);
253     case AUXDM_SETVOLUME:
254         return AUX_SetVolume(wDevID, dwParam1);
255     default:
256         WARN("unknown message !\n");
257     }
258     return MMSYSERR_NOTSUPPORTED;
259 #else
260     return MMSYSERR_NOTENABLED;
261 #endif
262 }