source: GPL/lib32/sound.c.old@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

File size: 39.4 KB
Line 
1/* $Id: sound.c,v 1.2 2003/08/08 15:09:03 vladest 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 <osspci.h>
37#include <stacktoflat.h>
38#include <stdlib.h>
39#include "soundoss.h"
40
41#undef samples_to_bytes
42#undef bytes_to_samples
43#define samples_to_bytes(a) ((a*pHandle->doublesamplesize)/2)
44#define bytes_to_samples(a) (pHandle->doublesamplesize ? ((a*2)/pHandle->doublesamplesize) : a)
45
46struct file_operations oss_devices[OSS32_MAX_DEVICES] = {0};
47struct file_operations *alsa_fops = NULL;
48int pcm_instances = 0;
49int pcm_device = 0;
50
51//OSS32 to ALSA datatype conversion table
52static OSSToALSADataType[OSS32_PCM_MAX_FORMATS] = {
53/* OSS32_PCM_FORMAT_S8 */ SNDRV_PCM_FORMAT_S8, //signed 8 bits sample
54/* OSS32_PCM_FORMAT_U8 */ SNDRV_PCM_FORMAT_U8, //unsigned 8 bits sample
55/* OSS32_PCM_FORMAT_S16_LE */ SNDRV_PCM_FORMAT_S16_LE, //signed 16 bits sample (little endian/Intel)
56/* OSS32_PCM_FORMAT_S16_BE */ SNDRV_PCM_FORMAT_S16_BE, //signed 16 bits sample (big endian/Motorola)
57/* OSS32_PCM_FORMAT_U16_LE */ SNDRV_PCM_FORMAT_U16_LE, //unsigned 16 bits sample (little endian/Intel)
58/* OSS32_PCM_FORMAT_U16_BE */ SNDRV_PCM_FORMAT_U16_BE, //unsigned 16 bits sample (big endian/Motorola)
59/* OSS32_PCM_FORMAT_S24_LE */ SNDRV_PCM_FORMAT_S24_LE, //signed 24 bits sample (little endian/Intel)
60/* OSS32_PCM_FORMAT_S24_BE */ SNDRV_PCM_FORMAT_S24_BE, //signed 24 bits sample (big endian/Motorola)
61/* OSS32_PCM_FORMAT_U24_LE */ SNDRV_PCM_FORMAT_U24_LE, //unsigned 24 bits sample (little endian/Intel)
62/* OSS32_PCM_FORMAT_U24_BE */ SNDRV_PCM_FORMAT_U24_BE, //unsigned 24 bits sample (big endian/Motorola)
63/* OSS32_PCM_FORMAT_S32_LE */ SNDRV_PCM_FORMAT_S32_LE, //signed 32 bits sample (little endian/Intel)
64/* OSS32_PCM_FORMAT_S32_BE */ SNDRV_PCM_FORMAT_S32_BE, //signed 32 bits sample (big endian/Motorola)
65/* OSS32_PCM_FORMAT_U32_LE */ SNDRV_PCM_FORMAT_U32_LE, //unsigned 32 bits sample (little endian/Intel)
66/* OSS32_PCM_FORMAT_U32_BE */ SNDRV_PCM_FORMAT_U32_BE, //unsigned 32 bits sample (big endian/Motorola)
67/* OSS32_PCM_FORMAT_MULAW */ SNDRV_PCM_FORMAT_MU_LAW, //8 bps (compressed 16 bits sample)
68/* OSS32_PCM_FORMAT_ALAW */ SNDRV_PCM_FORMAT_A_LAW, //8 bps (compressed 16 bits sample)
69/* OSS32_PCM_FORMAT_ADPCM */ SNDRV_PCM_FORMAT_IMA_ADPCM, //4 bps (compressed 16 bits sample)
70/* OSS32_PCM_FORMAT_MPEG */ SNDRV_PCM_FORMAT_MPEG, //AC3?
71};
72
73//******************************************************************************
74//******************************************************************************
75int register_chrdev(unsigned int version, const char *name, struct file_operations *fsop)
76{
77 if(!strcmp(name, "alsa")) {
78 alsa_fops = fsop;
79 }
80 return 0;
81}
82//******************************************************************************
83//******************************************************************************
84int unregister_chrdev(unsigned int version, const char *name)
85{
86 if(!strcmp(name, "alsa")) {
87 alsa_fops = NULL;
88 }
89 return 0;
90}
91//******************************************************************************
92//******************************************************************************
93int register_sound_special(struct file_operations *fops, int unit)
94{
95 if(fops == NULL) return -1;
96
97 memcpy(&oss_devices[OSS32_SPECIALID], fops, sizeof(struct file_operations));
98 return OSS32_SPECIALID;
99}
100//******************************************************************************
101//******************************************************************************
102int register_sound_mixer(struct file_operations *fops, int dev)
103{
104 if(fops == NULL) return -1;
105
106 memcpy(&oss_devices[OSS32_MIXERID], fops, sizeof(struct file_operations));
107 return OSS32_MIXERID;
108}
109//******************************************************************************
110//******************************************************************************
111int register_sound_midi(struct file_operations *fops, int dev)
112{
113 if(fops == NULL) return -1;
114
115 memcpy(&oss_devices[OSS32_MIDIID], fops, sizeof(struct file_operations));
116 return OSS32_MIDIID;
117}
118//******************************************************************************
119//******************************************************************************
120int register_sound_dsp(struct file_operations *fops, int dev)
121{
122 if(fops == NULL) return -1;
123
124 memcpy(&oss_devices[OSS32_DSPID], fops, sizeof(struct file_operations));
125 return OSS32_DSPID;
126}
127//******************************************************************************
128//******************************************************************************
129int register_sound_synth(struct file_operations *fops, int dev)
130{
131 if(fops == NULL) return -1;
132
133 memcpy(&oss_devices[OSS32_SYNTHID], fops, sizeof(struct file_operations));
134 return OSS32_SYNTHID;
135}
136//******************************************************************************
137//******************************************************************************
138void unregister_sound_special(int unit)
139{
140 memset(&oss_devices[OSS32_SPECIALID], 0, sizeof(struct file_operations));
141}
142//******************************************************************************
143//******************************************************************************
144void unregister_sound_mixer(int unit)
145{
146 memset(&oss_devices[OSS32_MIXERID], 0, sizeof(struct file_operations));
147}
148//******************************************************************************
149//******************************************************************************
150void unregister_sound_midi(int unit)
151{
152 memset(&oss_devices[OSS32_MIDIID], 0, sizeof(struct file_operations));
153}
154//******************************************************************************
155//******************************************************************************
156void unregister_sound_dsp(int unit)
157{
158 memset(&oss_devices[OSS32_DSPID], 0, sizeof(struct file_operations));
159}
160//******************************************************************************
161//******************************************************************************
162void unregister_sound_synth(int unit)
163{
164 memset(&oss_devices[OSS32_SYNTHID], 0, sizeof(struct file_operations));
165}
166//******************************************************************************
167//******************************************************************************
168OSSRET UNIXToOSSError(int unixerror)
169{
170 switch(unixerror) {
171 case 0:
172 return OSSERR_SUCCESS;
173 case -ENOMEM:
174 return OSSERR_OUT_OF_MEMORY;
175 case -ENODEV:
176 return OSSERR_NO_DEVICE_AVAILABLE;
177 case -ENOTTY:
178 case -EINVAL:
179 return OSSERR_INVALID_PARAMETER;
180 case -EAGAIN:
181 return OSSERR_AGAIN; //????
182 case -ENXIO:
183 return OSSERR_IO_ERROR;
184 case -EBUSY:
185 return OSSERR_BUSY;
186 case -EPERM:
187 return OSSERR_ACCESS_DENIED; //??
188 case -EPIPE:
189 case -EBADFD:
190 return OSSERR_ACCESS_DENIED; //??
191 default:
192 dprintf(("Unknown error %d", (unixerror > 0) ? unixerror : -unixerror));
193 return OSSERR_UNKNOWN;
194 }
195}
196//******************************************************************************
197//ALSA to OSS32 datatype conversion
198//******************************************************************************
199int ALSAToOSSDataType(ULONG ALSADataType)
200{
201 switch(ALSADataType)
202 {
203 case SNDRV_PCM_FORMAT_S8:
204 return OSS32_CAPS_PCM_FORMAT_S8; //signed 8 bits sample
205 case SNDRV_PCM_FORMAT_U8:
206 return OSS32_CAPS_PCM_FORMAT_U8; //unsigned 8 bits sample
207 case SNDRV_PCM_FORMAT_S16_LE:
208 return OSS32_CAPS_PCM_FORMAT_S16_LE; //signed 16 bits sample (little endian/Intel)
209 case SNDRV_PCM_FORMAT_S16_BE:
210 return OSS32_CAPS_PCM_FORMAT_S16_BE; //signed 16 bits sample (big endian/Motorola)
211 case SNDRV_PCM_FORMAT_U16_LE:
212 return OSS32_CAPS_PCM_FORMAT_U16_LE; //unsigned 16 bits sample (little endian/Intel)
213 case SNDRV_PCM_FORMAT_U16_BE:
214 return OSS32_CAPS_PCM_FORMAT_U16_BE; //unsigned 16 bits sample (big endian/Motorola)
215 case SNDRV_PCM_FORMAT_S24_LE:
216 return OSS32_CAPS_PCM_FORMAT_S24_LE; //signed 24 bits sample (little endian/Intel)
217 case SNDRV_PCM_FORMAT_S24_BE:
218 return OSS32_CAPS_PCM_FORMAT_S24_BE; //signed 24 bits sample (big endian/Motorola)
219 case SNDRV_PCM_FORMAT_U24_LE:
220 return OSS32_CAPS_PCM_FORMAT_U24_LE; //unsigned 24 bits sample (little endian/Intel)
221 case SNDRV_PCM_FORMAT_U24_BE:
222 return OSS32_CAPS_PCM_FORMAT_U24_BE; //unsigned 16 bits sample (big endian/Motorola)
223 case SNDRV_PCM_FORMAT_S32_LE:
224 return OSS32_CAPS_PCM_FORMAT_S32_LE; //signed 32 bits sample (little endian/Intel)
225 case SNDRV_PCM_FORMAT_S32_BE:
226 return OSS32_CAPS_PCM_FORMAT_S32_BE; //signed 32 bits sample (big endian/Motorola)
227 case SNDRV_PCM_FORMAT_U32_LE:
228 return OSS32_CAPS_PCM_FORMAT_U32_LE; //unsigned 32 bits sample (little endian/Intel)
229 case SNDRV_PCM_FORMAT_U32_BE:
230 return OSS32_CAPS_PCM_FORMAT_U32_BE; //unsigned 32 bits sample (big endian/Motorola)
231 case SNDRV_PCM_FORMAT_MU_LAW:
232 return OSS32_CAPS_PCM_FORMAT_MULAW; //8 bps (compressed 16 bits sample)
233 case SNDRV_PCM_FORMAT_A_LAW:
234 return OSS32_CAPS_PCM_FORMAT_ALAW; //8 bps (compressed 16 bits sample)
235 case SNDRV_PCM_FORMAT_IMA_ADPCM:
236 return OSS32_CAPS_PCM_FORMAT_ADPCM; //4 bps (compressed 16 bits sample)
237 case SNDRV_PCM_FORMAT_MPEG:
238 return OSS32_CAPS_PCM_FORMAT_MPEG; //AC3?
239 default:
240 DebugInt3();
241 return -1;
242 }
243}
244//******************************************************************************
245//******************************************************************************
246ULONG ALSAToOSSRateFlags(ULONG fuRates)
247{
248 ULONG fuOSSRates = 0;
249
250 if(fuRates & SNDRV_PCM_RATE_5512) {
251 fuOSSRates |= OSS32_CAPS_PCM_RATE_5512;
252 }
253 if(fuRates & SNDRV_PCM_RATE_8000) {
254 fuOSSRates |= OSS32_CAPS_PCM_RATE_8000;
255 }
256 if(fuRates & SNDRV_PCM_RATE_11025) {
257 fuOSSRates |= OSS32_CAPS_PCM_RATE_11025;
258 }
259 if(fuRates & SNDRV_PCM_RATE_16000) {
260 fuOSSRates |= OSS32_CAPS_PCM_RATE_16000;
261 }
262 if(fuRates & SNDRV_PCM_RATE_22050) {
263 fuOSSRates |= OSS32_CAPS_PCM_RATE_22050;
264 }
265 if(fuRates & SNDRV_PCM_RATE_32000) {
266 fuOSSRates |= OSS32_CAPS_PCM_RATE_32000;
267 }
268 if(fuRates & SNDRV_PCM_RATE_44100) {
269 fuOSSRates |= OSS32_CAPS_PCM_RATE_44100;
270 }
271 if(fuRates & SNDRV_PCM_RATE_48000) {
272 fuOSSRates |= OSS32_CAPS_PCM_RATE_48000;
273 }
274 if(fuRates & SNDRV_PCM_RATE_64000) {
275 fuOSSRates |= OSS32_CAPS_PCM_RATE_64000;
276 }
277 if(fuRates & SNDRV_PCM_RATE_88200) {
278 fuOSSRates |= OSS32_CAPS_PCM_RATE_88200;
279 }
280 if(fuRates & SNDRV_PCM_RATE_96000) {
281 fuOSSRates |= OSS32_CAPS_PCM_RATE_96000;
282 }
283 if(fuRates & SNDRV_PCM_RATE_176400) {
284 fuOSSRates |= OSS32_CAPS_PCM_RATE_176400;
285 }
286 if(fuRates & SNDRV_PCM_RATE_192000) {
287 fuOSSRates |= OSS32_CAPS_PCM_RATE_192000;
288 }
289 if(fuRates & SNDRV_PCM_RATE_CONTINUOUS) {
290 fuOSSRates |= OSS32_CAPS_PCM_RATE_CONTINUOUS;
291 }
292
293 //TODO:
294 if(fuRates & SNDRV_PCM_RATE_KNOT) {
295 DebugInt3();
296 }
297//#define OSS32_CAPS_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
298
299 return fuOSSRates;
300}
301//******************************************************************************
302//******************************************************************************
303OSSRET OSS32_QueryDevCaps(ULONG deviceid, POSS32_DEVCAPS pDevCaps)
304{
305 OSSSTREAMID streamid = 0;
306 soundhandle *pHandle;
307 snd_pcm_info_t *pcminfo = NULL;
308 snd_pcm_hw_params_t *params;
309 int ret, fmt, i;
310 ULONG format_mask;
311 snd_mask_t *mask;
312
313#ifdef DEBUG
314 dprintf(("vladest: OSS32_QueryDevCaps"));
315#endif
316 //these structures are too big to put on the stack
317 pcminfo = (snd_pcm_info_t *)kmalloc(sizeof(snd_pcm_info_t)+sizeof(snd_pcm_hw_params_t), GFP_KERNEL);
318 if(pcminfo == NULL) {
319 DebugInt3();
320 return OSSERR_OUT_OF_MEMORY;
321 }
322 params = (snd_pcm_hw_params_t *)(pcminfo+1);
323
324 pDevCaps->nrDevices = nrCardsDetected;
325 pDevCaps->ulCaps = OSS32_CAPS_WAVE_PLAYBACK | OSS32_CAPS_WAVE_CAPTURE;
326
327 //query wave in & out caps
328 for(i=0;i<2;i++)
329 {
330 PWAVE_CAPS pWaveCaps = (i == 0) ? &pDevCaps->waveOutCaps : &pDevCaps->waveInCaps;
331
332 ret = OSS32_WaveOpen(deviceid, (i == 0) ? OSS32_STREAM_WAVEOUT : OSS32_STREAM_WAVEIN, &streamid,0);
333 if(ret != OSSERR_SUCCESS)
334 {
335 DebugInt3();
336 goto fail;
337 }
338 pHandle = (soundhandle *)streamid;
339 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
340 ret = OSSERR_INVALID_STREAMID;
341 goto fail;
342 }
343 //set operation to non-blocking
344 pHandle->file.f_flags = O_NONBLOCK;
345
346 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_INFO, (ULONG)pcminfo);
347 if(ret != 0) {
348 ret = UNIXToOSSError(ret);
349 goto fail;
350 }
351 if(i == 0) {//only need to do this once
352 if(pcminfo->name[0]) {
353 strncpy(pDevCaps->szDeviceName, pcminfo->name, sizeof(pDevCaps->szDeviceName));
354 }
355 else strncpy(pDevCaps->szDeviceName, pcminfo->id, sizeof(pDevCaps->szDeviceName));
356 }
357 pWaveCaps->nrStreams = pcminfo->subdevices_count;
358
359 //get all hardware parameters
360 _snd_pcm_hw_params_any(params);
361 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_HW_REFINE, (ULONG)params);
362 if(ret != 0) {
363 ret = UNIXToOSSError(ret);
364 goto fail;
365 }
366
367 pWaveCaps->ulMinChannels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min;
368 pWaveCaps->ulMaxChannels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max;
369 pWaveCaps->ulChanFlags = 0;
370 if(pWaveCaps->ulMinChannels == 1) {
371 pWaveCaps->ulChanFlags |= OSS32_CAPS_PCM_CHAN_MONO;
372 }
373 if(pWaveCaps->ulMaxChannels >= 2) {
374 pWaveCaps->ulChanFlags |= OSS32_CAPS_PCM_CHAN_STEREO;
375 }
376 if(pWaveCaps->ulMaxChannels >= 4) {
377 pWaveCaps->ulChanFlags |= OSS32_CAPS_PCM_CHAN_QUAD;
378 }
379 if(pWaveCaps->ulMaxChannels >= 6) {
380 pWaveCaps->ulChanFlags |= OSS32_CAPS_PCM_CHAN_5_1;
381 }
382
383 pWaveCaps->ulMinRate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min;
384 pWaveCaps->ulMaxRate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max;
385
386 mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_RATE_MASK);
387 pWaveCaps->ulRateFlags = mask->bits[0];
388 //SNDRV_PCM_RATE_48000; // temp hack
389 //hw_param_mask_old(params, SNDRV_PCM_HW_PARAM_RATE_MASK);
390
391 pWaveCaps->ulRateFlags = ALSAToOSSRateFlags(pWaveCaps->ulRateFlags);
392
393 pWaveCaps->ulDataFormats = 0;
394
395 mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
396 format_mask = mask->bits[0];
397// hw_param_mask_old(params, SNDRV_PCM_HW_PARAM_FORMAT);
398// mask->bits;
399 //hw_param_mask_old(params, SNDRV_PCM_HW_PARAM_FORMAT);
400 for(fmt=0;fmt<32;fmt++)
401 {
402 if(format_mask & (1 << fmt))
403 {
404 int f = ALSAToOSSDataType(fmt);
405 if (f >= 0)
406 pWaveCaps->ulDataFormats |= f;
407 }
408 }
409
410 OSS32_WaveClose(streamid);
411 streamid = 0;
412
413 }
414
415 //Check support for MPU401, FM & Wavetable MIDI
416 if(OSS32_MidiOpen(deviceid, OSS32_STREAM_MPU401_MIDIOUT, &streamid) == OSSERR_SUCCESS)
417 {
418 pDevCaps->ulCaps |= OSS32_CAPS_MPU401_PLAYBACK;
419 OSS32_MidiClose(streamid);
420 streamid = 0;
421 }
422 if(OSS32_MidiOpen(deviceid, OSS32_STREAM_MPU401_MIDIIN, &streamid) == OSSERR_SUCCESS)
423 {
424 pDevCaps->ulCaps |= OSS32_CAPS_MPU401_CAPTURE;
425 OSS32_MidiClose(streamid);
426 streamid = 0;
427 }
428 if(OSS32_MidiOpen(deviceid, OSS32_STREAM_FM_MIDIOUT, &streamid) == OSSERR_SUCCESS)
429 {
430 pDevCaps->ulCaps |= OSS32_CAPS_FMSYNTH_PLAYBACK;
431 OSS32_MidiClose(streamid);
432 streamid = 0;
433 }
434 if(OSS32_MidiOpen(deviceid, OSS32_STREAM_WAVETABLE_MIDIOUT, &streamid) == OSSERR_SUCCESS)
435 {
436 pDevCaps->ulCaps |= OSS32_CAPS_WAVETABLE_PLAYBACK;
437 OSS32_MidiClose(streamid);
438 streamid = 0;
439 }
440 if(OSS32_MixQueryName(deviceid, &pDevCaps->szMixerName, sizeof(pDevCaps->szMixerName)) != OSSERR_SUCCESS) {
441 DebugInt3();
442 goto fail;
443 }
444
445 kfree(pcminfo);
446 streamid = 0;
447
448
449 return OSSERR_SUCCESS;
450
451fail:
452#ifdef DEBUG
453 dprintf(("vladest: OSS32_QueryDevCaps failed"));
454#endif
455 DebugInt3();
456 if(streamid) OSS32_WaveClose(streamid);
457 if(pcminfo) kfree(pcminfo);
458
459 return ret;
460}
461//******************************************************************************
462//******************************************************************************
463OSSRET OSS32_WaveOpen(ULONG deviceid, ULONG streamtype, OSSSTREAMID *pStreamId, int pcm)
464{
465 soundhandle *pHandle;
466 int ret;
467
468#ifdef DEBUG
469 dprintf(("vladest: OSS32_WaveOpen"));
470#endif
471
472 *pStreamId = 0;
473
474 if(alsa_fops == NULL) {
475 DebugInt3();
476#ifdef DEBUG
477 dprintf(("vladest: OSS32_WaveOpen: no devices"));
478#endif
479
480 return OSSERR_NO_DEVICE_AVAILABLE;
481 }
482
483 pHandle = kmalloc(sizeof(soundhandle), GFP_KERNEL);
484 if(pHandle == NULL) {
485 DebugInt3();
486 return OSSERR_OUT_OF_MEMORY;
487 }
488 memset(pHandle, 0, sizeof(soundhandle));
489
490 //set operation to non-blocking
491 pHandle->file.f_flags = O_NONBLOCK;
492
493 //setup pointers in file structure (used internally by ALSA)
494 pHandle->file.f_dentry = &pHandle->d_entry;
495 pHandle->file.f_dentry->d_inode = &pHandle->inode;
496
497 switch(streamtype) {
498 case OSS32_STREAM_WAVEOUT:
499 pHandle->file.f_mode = FMODE_WRITE;
500 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_PCM_PLAYBACK);
501 break;
502 case OSS32_STREAM_WAVEIN:
503 pHandle->file.f_mode = FMODE_READ;
504 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_PCM_CAPTURE);
505 break;
506 default:
507 DebugInt3();
508 kfree(pHandle);
509 return OSSERR_INVALID_PARAMETER;
510 }
511
512 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
513 if(ret) {
514 kfree(pHandle);
515 DebugInt3();
516 return UNIXToOSSError(ret);
517 }
518 pHandle->magic = MAGIC_WAVE_ALSA32;
519 *pStreamId = (ULONG)pHandle;
520 return OSSERR_SUCCESS;
521}
522//******************************************************************************
523//******************************************************************************
524OSSRET OSS32_WaveClose(OSSSTREAMID streamid)
525{
526 soundhandle *pHandle = (soundhandle *)streamid;
527 int ret;
528
529#ifdef DEBUG
530 dprintf(("vladest: OSS32_WaveClose"));
531#endif
532
533 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
534 DebugInt3();
535 return OSSERR_INVALID_STREAMID;
536 }
537 //set operation to non-blocking
538 pHandle->file.f_flags = O_NONBLOCK;
539
540 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
541 kfree(pHandle); //free handle data
542 if(ret) {
543 DebugInt3();
544 return UNIXToOSSError(ret);
545 }
546 return OSSERR_SUCCESS;
547}
548//******************************************************************************
549//******************************************************************************
550OSSRET OSS32_WavePrepare(OSSSTREAMID streamid)
551{
552 soundhandle *pHandle = (soundhandle *)streamid;
553 int ret;
554
555#ifdef DEBUG
556 dprintf(("vladest: OSS32_WavePrepare"));
557#endif
558
559 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
560 DebugInt3();
561#ifdef DEBUG
562 dprintf(("vladest: OSS32_WavePrepare: invalid streamID"));
563#endif
564
565 return OSSERR_INVALID_STREAMID;
566 }
567 //set operation to non-blocking
568 pHandle->file.f_flags = O_NONBLOCK;
569
570 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_PREPARE, 0);
571
572 return UNIXToOSSError(ret);;
573}
574//******************************************************************************
575//******************************************************************************
576OSSRET OSS32_WaveStart(OSSSTREAMID streamid)
577{
578 soundhandle *pHandle = (soundhandle *)streamid;
579 int ret;
580
581 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
582 DebugInt3();
583 return OSSERR_INVALID_STREAMID;
584 }
585 //set operation to non-blocking
586 pHandle->file.f_flags = O_NONBLOCK;
587
588 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_START, 0);
589
590 return UNIXToOSSError(ret);;
591}
592//******************************************************************************
593//******************************************************************************
594OSSRET OSS32_WaveStop(OSSSTREAMID streamid)
595{
596 soundhandle *pHandle = (soundhandle *)streamid;
597 int ret;
598
599 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
600 DebugInt3();
601 return OSSERR_INVALID_STREAMID;
602 }
603 //set operation to non-blocking
604 pHandle->file.f_flags = O_NONBLOCK;
605
606 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_DROP, 0);
607
608 return UNIXToOSSError(ret);;
609}
610//******************************************************************************
611//******************************************************************************
612OSSRET OSS32_WavePause(OSSSTREAMID streamid)
613{
614 soundhandle *pHandle = (soundhandle *)streamid;
615 int ret;
616
617 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
618 DebugInt3();
619 return OSSERR_INVALID_STREAMID;
620 }
621 //set operation to non-blocking
622 pHandle->file.f_flags = O_NONBLOCK;
623
624 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_PAUSE, 0);
625
626 return UNIXToOSSError(ret);;
627}
628//******************************************************************************
629//******************************************************************************
630OSSRET OSS32_WaveResume(OSSSTREAMID streamid)
631{
632 soundhandle *pHandle = (soundhandle *)streamid;
633 int ret;
634
635 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
636 DebugInt3();
637 return OSSERR_INVALID_STREAMID;
638 }
639 //set operation to non-blocking
640 pHandle->file.f_flags = O_NONBLOCK;
641
642 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_PAUSE, 1);
643
644 return UNIXToOSSError(ret);;
645}
646//******************************************************************************
647//******************************************************************************
648OSSRET OSS32_WaveSetHwParams(OSSSTREAMID streamid, OSS32_HWPARAMS *pHwParams)
649{
650 soundhandle *pHandle = (soundhandle *)streamid;
651 snd_pcm_hw_params_t params;
652 snd_pcm_sw_params_t swparams;
653 int ret, nrperiods, minnrperiods, maxnrperiods, samplesize;
654 ULONG bufsize, periodsize, minperiodsize, maxperiodsize;
655 ULONG periodbytes, minperiodbytes, maxperiodbytes;
656 BOOL fTryAgain = FALSE;
657
658#ifdef DEBUG
659 dprintf(("OSS32_WaveSetHwParams"));
660#endif
661 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
662#ifdef DEBUG
663 dprintf(("OSS32_WaveSetHwParams error. Invalid handle"));
664#endif
665 DebugInt3();
666 return OSSERR_INVALID_STREAMID;
667 }
668 if(pHwParams == NULL) {
669#ifdef DEBUG
670 dprintf(("OSS32_WaveSetHwParams error. params = NULL"));
671#endif
672 DebugInt3();
673 return OSSERR_INVALID_PARAMETER;
674 }
675 if(pHwParams->ulDataType >= OSS32_PCM_MAX_FORMATS) {
676#ifdef DEBUG
677 dprintf(("OSS32_WaveSetHwParams error. Too high PCM format"));
678#endif
679 DebugInt3();
680 return OSSERR_INVALID_PARAMETER;
681 }
682
683 //set operation to non-blocking
684 pHandle->file.f_flags = O_NONBLOCK;
685
686 //size of two samples (adpcm sample can be as small as 4 bits (mono), so take two)
687 samplesize = snd_pcm_format_size(OSSToALSADataType[pHwParams->ulDataType], 1);
688 pHandle->doublesamplesize = samplesize * 2;
689 pHandle->doublesamplesize *= pHwParams->ulNumChannels;
690 periodbytes = pHwParams->ulPeriodSize;
691 periodsize = bytes_to_samples(periodbytes);
692
693 //get all hardware parameters
694 _snd_pcm_hw_params_any(&params);
695 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS,
696 SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
697 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
698 pHwParams->ulBitsPerSample, 0);
699 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
700 pHwParams->ulBitsPerSample*pHwParams->ulNumChannels, 0);
701 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT,
702 OSSToALSADataType[pHwParams->ulDataType], 0);
703 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
704 pHwParams->ulNumChannels, 0);
705 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE,
706 pHwParams->ulSampleRate, 0);
707 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_HW_REFINE, (ULONG)__Stack32ToFlat(&params));
708 if(ret != 0) {
709#ifdef DEBUG
710 dprintf(("OSS32_WaveSetHwParams error %d in SNDRV_PCM_IOCTL_HW_REFINE ioctl.", ret));
711#endif
712 DebugInt3();
713 return UNIXToOSSError(ret);
714 }
715
716 //check period size against lower and upper boundaries
717 minperiodbytes = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
718 maxperiodbytes = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->max;
719 if(periodbytes < minperiodbytes) {
720 periodbytes = minperiodbytes;
721 }
722 else
723 if(periodbytes > maxperiodbytes) {
724 periodbytes = maxperiodbytes;
725 }
726
727 minperiodsize = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min;
728 maxperiodsize = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->max;
729 if(periodsize < minperiodsize) {
730 periodsize = minperiodsize;
731 }
732 else
733 if(periodsize > maxperiodsize) {
734 periodsize = maxperiodsize;
735 }
736
737 if(samples_to_bytes(periodsize) < periodbytes) {
738 periodbytes = samples_to_bytes(periodsize);
739 }
740 else
741 if(bytes_to_samples(periodbytes) < periodsize) {
742 periodsize = bytes_to_samples(periodbytes);
743 }
744
745 //make sure period size is a whole fraction of the buffer size
746 bufsize = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->max;
747 if(periodsize) {
748 nrperiods = bufsize/periodbytes;
749 }
750 else {
751#ifdef DEBUG
752 dprintf(("OSS32_WaveSetHwParams error. Invalid periodsize"));
753#endif
754 DebugInt3();
755 return OSSERR_INVALID_PARAMETER;
756 }
757 //check nr of periods against lower and upper boundaries
758 minnrperiods = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIODS)->min;
759 maxnrperiods = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIODS)->max;
760 if(nrperiods < minnrperiods) {
761 nrperiods = minnrperiods;
762 }
763 else
764 if(nrperiods > maxnrperiods) {
765 nrperiods = maxnrperiods;
766 }
767 //an odd nr of periods is not always a good thing (CMedia -> clicks during 8 bps playback),
768 //so we make sure it's an even number.
769 if(nrperiods == 1) {
770 DebugInt3();
771#ifdef DEBUG
772 dprintf(("OSS32_WaveSetHwParams error. Invalid number of periods"));
773#endif
774 return OSSERR_INVALID_PARAMETER;
775 }
776 nrperiods &= ~1;
777
778 //initialize parameter block & set sample rate, nr of channels and sample format, nr of periods,
779 //period size and buffer size
780tryagain:
781 _snd_pcm_hw_params_any(&params);
782 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS,
783 SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
784 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
785 pHwParams->ulBitsPerSample, 0);
786 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
787 pHwParams->ulBitsPerSample*pHwParams->ulNumChannels, 0);
788 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT,
789 OSSToALSADataType[pHwParams->ulDataType], 0);
790 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
791 pHwParams->ulNumChannels, 0);
792 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE,
793 pHwParams->ulSampleRate, 0);
794 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
795 periodsize, 0);
796 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
797 periodbytes, 0);
798 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIODS,
799 nrperiods, 0);
800 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
801 periodsize*nrperiods, 0);
802 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
803 periodbytes*nrperiods, 0);
804#ifdef DEBUG
805 dprintf(("Hardware parameters: sample rate %d, data type %d, channels %d, period size %d, periods %d",
806 pHwParams->ulSampleRate, pHwParams->ulDataType, pHwParams->ulNumChannels, periodsize, nrperiods));
807#endif
808 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_HW_PARAMS, (ULONG)__Stack32ToFlat(&params));
809 if(ret) {
810 if(fTryAgain == FALSE) {
811 minperiodsize = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min;
812 maxperiodsize = hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->max;
813 if(minperiodsize > maxperiodsize) {
814 //ALSA doesn't like the period size; try suggested one
815 periodsize = maxperiodsize;
816 periodbytes = samples_to_bytes(periodsize);
817 fTryAgain = TRUE;
818 goto tryagain;
819 }
820 }
821#ifdef DEBUG
822 dprintf(("OSS32_WaveSetHwParams error %d in SNDRV_PCM_IOCTL_HW_PARAMS ioctl.", ret));
823#endif
824 return UNIXToOSSError(ret);
825 }
826
827 //set silence threshold (all sizes in frames) (only needed for playback)
828 if(pHandle->file.f_mode == FMODE_WRITE)
829 {
830 swparams.avail_min = periodsize;
831 swparams.period_step = 1;
832 if(nrperiods <= 2) {
833 swparams.silence_size = (periodsize/2);
834 }
835 else {
836 swparams.silence_size = periodsize;
837 }
838 swparams.silence_threshold = swparams.silence_size;
839 swparams.sleep_min = 0;
840 swparams.start_threshold = 1;
841 swparams.stop_threshold = periodsize*nrperiods;
842 swparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
843 swparams.xfer_align = periodsize;
844
845 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_SW_PARAMS, (ULONG)__Stack32ToFlat(&swparams));
846 }
847#ifdef DEBUG
848 dprintf(("OSS32_WaveSetHwParams return %d after SNDRV_PCM_IOCTL_SW_PARAMS ioctl.", ret));
849#endif
850 return UNIXToOSSError(ret);
851}
852//******************************************************************************
853//******************************************************************************
854OSSRET OSS32_WaveAddBuffer(OSSSTREAMID streamid, ULONG buffer, ULONG size, ULONG *pTransferred, int pcm)
855{
856 soundhandle *pHandle = (soundhandle *)streamid;
857 snd_pcm_status_t status;
858 int ret;
859 LONG transferred;
860 ULONG position;
861
862 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
863 DebugInt3();
864 return OSSERR_INVALID_STREAMID;
865 }
866 if(pTransferred == NULL || buffer == 0 || size == 0) {
867 DebugInt3();
868 return OSSERR_INVALID_PARAMETER;
869 }
870
871 //set operation to non-blocking
872 pHandle->file.f_flags = O_NONBLOCK;
873
874 //first check how much room is left in the circular dma buffer
875 //this is done to make sure we don't block inside ALSA while trying to write
876 //more data than fits in the internal dma buffer.
877 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_STATUS, (ULONG)__Stack32ToFlat(&status));
878
879 if(ret) {
880 DebugInt3();
881 return UNIXToOSSError(ret);
882 }
883 size = min(size, samples_to_bytes(status.avail));
884 if(size == 0) {
885 dprintf2(("OSS32_WaveAddBuffer: no room left in hardware buffer!!"));
886 *pTransferred = 0;
887 return OSSERR_BUFFER_FULL;
888 }
889 dprintf2(("OSS32_WaveAddBuffer hw %x app %x avail %x, size %x", samples_to_bytes(status.hw_ptr), samples_to_bytes(status.appl_ptr), samples_to_bytes(status.avail), size));
890
891 transferred = 0;
892 switch(SNDRV_MINOR_DEVICE(MINOR(pHandle->inode.i_rdev)))
893 {
894 case SNDRV_MINOR_PCM_PLAYBACK:
895 while(TRUE) {
896 ret = pHandle->file.f_op->write(&pHandle->file, (char *)buffer, size, &pHandle->file.f_pos);
897 if(ret < 0) {
898 if(transferred > 0) {
899 dprintf(("OSS32_WaveAddBuffer failed on partial transfer %x %d; ret = %d", buffer, size, ret));
900
901 *pTransferred = transferred;
902 return OSSERR_SUCCESS;
903 }
904 dprintf(("OSS32_WaveAddBuffer failed when SNDRV_MINOR_PCM_PLAYBACK!!"));
905 DebugInt3();
906 return UNIXToOSSError(transferred);
907 }
908 if(ret == 0) {
909 break;
910 }
911 transferred += ret;
912
913 buffer += ret;
914 size -= ret;
915 if(size == 0) {
916 break;
917 }
918 }
919 break;
920 case SNDRV_MINOR_PCM_CAPTURE:
921 transferred = pHandle->file.f_op->read(&pHandle->file, (char *)buffer, size, &pHandle->file.f_pos);
922 break;
923 default:
924 DebugInt3();
925 return OSSERR_INVALID_PARAMETER;
926 }
927 if(ret < 0) {
928 dprintf(("OSS32_WaveAddBuffer failed when SNDRV_MINOR_PCM_CAPTURE!!"));
929 DebugInt3();
930 return UNIXToOSSError(transferred);
931 }
932
933 dprintf2(("OSS32_WaveAddBuffer: transferred %x bytes", transferred));
934 *pTransferred = transferred;
935
936 return OSSERR_SUCCESS;
937}
938//******************************************************************************
939//******************************************************************************
940OSSRET OSS32_WaveGetPosition(ULONG streamid, ULONG *pPosition)
941{
942 soundhandle *pHandle = (soundhandle *)streamid;
943 snd_pcm_status_t status;
944 int ret;
945 ULONG delta;
946
947 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
948 DebugInt3();
949 return OSSERR_INVALID_STREAMID;
950 }
951 if(pPosition == NULL) {
952 DebugInt3();
953 return OSSERR_INVALID_PARAMETER;
954 }
955
956 //set operation to non-blocking
957 pHandle->file.f_flags = O_NONBLOCK;
958
959 //Get the status of the stream
960 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_STATUS, (ULONG)__Stack32ToFlat(&status));
961
962 if(ret) {
963 DebugInt3();
964 return UNIXToOSSError(ret);
965 }
966
967 dprintf2(("OSS32_WaveGetPosition: hardware %x application %x", samples_to_bytes(status.hw_ptr), samples_to_bytes(status.appl_ptr)));
968 *pPosition = samples_to_bytes(status.hw_ptr); //return new hardware position
969 return OSSERR_SUCCESS;
970}
971//******************************************************************************
972//******************************************************************************
973OSSRET OSS32_WaveGetSpace(ULONG streamid, ULONG *pBytesAvail)
974{
975 soundhandle *pHandle = (soundhandle *)streamid;
976 snd_pcm_status_t status;
977 int ret;
978
979 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
980 DebugInt3();
981 return OSSERR_INVALID_STREAMID;
982 }
983 if(pBytesAvail == NULL) {
984 DebugInt3();
985 return OSSERR_INVALID_PARAMETER;
986 }
987
988 //set operation to non-blocking
989 pHandle->file.f_flags = O_NONBLOCK;
990
991 //Get the nr of bytes left in the audio buffer
992 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_STATUS, (ULONG)__Stack32ToFlat(&status));
993
994 if(ret) {
995 DebugInt3();
996 return UNIXToOSSError(ret);
997 }
998 *pBytesAvail = samples_to_bytes(status.avail);
999 return OSSERR_SUCCESS;
1000}
1001//******************************************************************************
1002//******************************************************************************
1003OSSRET OSS32_WaveSetVolume(OSSSTREAMID streamid, ULONG volume)
1004{
1005 soundhandle *pHandle = (soundhandle *)streamid;
1006 int ret;
1007 int leftvol, rightvol;
1008 snd_pcm_volume_t pcm_volume;
1009
1010 if(pHandle == NULL || pHandle->magic != MAGIC_WAVE_ALSA32) {
1011 DebugInt3();
1012 return OSSERR_INVALID_STREAMID;
1013 }
1014 //set operation to non-blocking
1015 pHandle->file.f_flags = O_NONBLOCK;
1016
1017 leftvol = GET_VOLUME_L(volume);
1018 rightvol = GET_VOLUME_R(volume);
1019
1020 pcm_volume.nrchannels = 4;
1021 pcm_volume.volume[SNDRV_PCM_VOL_FRONT_LEFT] = leftvol;
1022 pcm_volume.volume[SNDRV_PCM_VOL_FRONT_RIGHT] = rightvol;
1023 pcm_volume.volume[SNDRV_PCM_VOL_REAR_LEFT] = leftvol;
1024 pcm_volume.volume[SNDRV_PCM_VOL_REAR_RIGHT] = rightvol;
1025
1026 dprintf(("OSS32_WaveSetVolume %x to (%d,%d)", streamid, leftvol, rightvol));
1027 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_PCM_IOCTL_SETVOLUME, (ULONG)__Stack32ToFlat(&pcm_volume));
1028 return UNIXToOSSError(ret);
1029}
1030//******************************************************************************
1031//******************************************************************************
1032
Note: See TracBrowser for help on using the repository browser.