source: GPL/trunk/lib32/sound.c@ 76

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

Latest ALSA patches
HDA patches
Patch for Intel from Rudy's
Fixes locks on NM256 chipsets
Fixes PM on Maestro3 chipsets

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