patch-2.3.16 linux/drivers/sbus/audio/audio.c
Next file: linux/drivers/sbus/audio/cs4231.c
Previous file: linux/drivers/sbus/audio/amd7930.c
Back to the patch index
Back to the overall index
- Lines: 432
- Date:
Tue Aug 31 11:25:33 1999
- Orig file:
v2.3.15/linux/drivers/sbus/audio/audio.c
- Orig date:
Fri Aug 6 11:58:00 1999
diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
@@ -1,12 +1,12 @@
/*
* drivers/sbus/audio/audio.c
*
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
- * Copyright (C) 1997,1998 Derrick J. Brashear (shadow@dementia.org)
- * Copyright (C) 1997 Brent Baccala (baccala@freesoft.org)
+ * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ * Copyright 1997,1998,1999 Derrick J. Brashear (shadow@dementia.org)
+ * Copyright 1997 Brent Baccala (baccala@freesoft.org)
*
* Mixer code adapted from code contributed by and
- * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz)
+ * Copyright 1998 Michael Mraka (michael@fi.muni.cz)
* and with fixes from Michael Shuey (shuey@ecn.purdue.edu)
* The mixer code cheats; Sparc hardware doesn't generally allow independent
* line control, and this fakes it badly.
@@ -40,11 +40,17 @@
#undef __AUDIO_DEBUG
#define __AUDIO_ERROR
#undef __AUDIO_TRACE
+#undef __AUDIO_OSSDEBUG
#ifdef __AUDIO_DEBUG
#define dprintk(x) printk x
#else
#define dprintk(x)
#endif
+#ifdef __AUDIO_OSSDEBUG
+#define oprintk(x) printk x
+#else
+#define oprintk(x)
+#endif
#ifdef __AUDIO_ERROR
#define eprintk(x) printk x
#else
@@ -117,10 +123,12 @@
* TODO: Make number of input/output buffers tunable parameters
*/
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x202ff
init_waitqueue_head(&drv->open_wait);
init_waitqueue_head(&drv->output_write_wait);
init_waitqueue_head(&drv->output_drain_wait);
init_waitqueue_head(&drv->input_read_wait);
+#endif
drv->num_output_buffers = 8;
drv->output_buffer_size = (4096 * 2);
@@ -269,6 +277,7 @@
* If status & 2, a buffer was claimed for DMA and is still in use.
*
* The playing_count for non-DMA hardware should never be non-zero.
+ * Value of status for non-DMA hardware should always be 1.
*/
if (status & 1) {
if (drv->playing_count)
@@ -305,15 +314,16 @@
/* If we got back a buffer, see if anyone wants to write to it */
if ((status & 1) || ((drv->output_count + drv->playing_count)
- < drv->num_output_buffers))
+ < drv->num_output_buffers)) {
wake_up_interruptible(&drv->output_write_wait);
+ }
/* If the output queue is empty, shut down the driver. */
if ((drv->output_count < 1) && (drv->playing_count < 1)) {
kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
/* Stop the lowlevel driver from outputing. */
- drv->ops->stop_output(drv);
+ /* drv->ops->stop_output(drv); Should not be necessary -- DJB 5/25/98 */
drv->output_active = 0;
/* Wake up any waiting writers or syncers and return. */
@@ -638,8 +648,11 @@
{
struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
SPARCAUDIO_DEVICE_SHIFT)];
- unsigned long i = 0, j = 0;
- unsigned int k;
+ unsigned long i = 0, j = 0, l = 0, m = 0;
+ unsigned int k = 0;
+
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ drv->mixer_modify_counter++;
if(cmd == SOUND_MIXER_INFO) {
audio_device_t tmp;
@@ -651,9 +664,7 @@
memset(&info, 0, sizeof(info));
strncpy(info.id, tmp.name, sizeof(info.id));
strncpy(info.name, "Sparc Audio", sizeof(info.name));
-
- /* XXX do this right... */
- info.modify_counter = 0;
+ info.modify_counter = drv->mixer_modify_counter;
if(copy_to_user((char *)arg, &info, sizeof(info)))
retval = -EFAULT;
@@ -665,74 +676,130 @@
switch (cmd) {
case SOUND_MIXER_WRITE_RECLEV:
- case SOUND_MIXER_WRITE_MIC:
- case SOUND_MIXER_WRITE_CD:
- case SOUND_MIXER_WRITE_LINE:
- case SOUND_MIXER_WRITE_IMIX:
if(COPY_IN(arg, k))
return -EFAULT;
- tprintk(("setting input volume (0x%x)", k));
+ iretry:
+ oprintk(("setting input volume (0x%x)", k));
if (drv->ops->get_input_channels)
j = drv->ops->get_input_channels(drv);
- if (j == 1) {
- i = s_to_m(k);
- tprintk((" for mono to %d\n", i));
- if (drv->ops->set_input_volume)
- drv->ops->set_input_volume(drv, i);
- if (drv->ops->get_input_volume)
- i = drv->ops->get_input_volume(drv);
- i = m_to_s(i);
- } else {
- i = s_to_g(k);
- j = s_to_b(k);
- tprintk((" for stereo to to %d (bal %d)\n", i, j));
- if (drv->ops->set_input_volume)
- drv->ops->set_input_volume(drv, i);
- if (drv->ops->get_input_volume)
- i = drv->ops->get_input_volume(drv);
- if (drv->ops->set_input_balance)
- drv->ops->set_input_balance(drv, j);
- if (drv->ops->get_input_balance)
- j = drv->ops->get_input_balance(drv);
- i = b_to_s(i,j);
- }
+ if (drv->ops->get_input_volume)
+ l = drv->ops->get_input_volume(drv);
+ if (drv->ops->get_input_balance)
+ m = drv->ops->get_input_balance(drv);
+ i = OSS_TO_GAIN(k);
+ j = OSS_TO_BAL(k);
+ oprintk((" for stereo to to %d (bal %d):", i, j));
+ if (drv->ops->set_input_volume)
+ drv->ops->set_input_volume(drv, i);
+ if (drv->ops->set_input_balance)
+ drv->ops->set_input_balance(drv, j);
+ case SOUND_MIXER_READ_RECLEV:
+ if (drv->ops->get_input_volume)
+ i = drv->ops->get_input_volume(drv);
+ if (drv->ops->get_input_balance)
+ j = drv->ops->get_input_balance(drv);
+ oprintk((" got (0x%x)\n", BAL_TO_OSS(i,j)));
+ i = BAL_TO_OSS(i,j);
+ /* Try to be reasonable about volume changes */
+ if ((cmd == SOUND_MIXER_WRITE_RECLEV) && (i != k) &&
+ (i == BAL_TO_OSS(l,m)))
+ {
+ k += (OSS_LEFT(k) > OSS_LEFT(i)) ? 256 : -256;
+ k += (OSS_RIGHT(k) > OSS_RIGHT(i)) ? 1 : -1;
+ oprintk((" try 0x%x\n", k));
+ goto iretry;
+ }
return COPY_OUT(arg, i);
- case SOUND_MIXER_WRITE_PCM:
case SOUND_MIXER_WRITE_VOLUME:
- case SOUND_MIXER_WRITE_SPEAKER:
if(COPY_IN(arg, k))
return -EFAULT;
- tprintk(("setting output volume (0x%x)", k));
+ if (drv->ops->get_output_muted && drv->ops->set_output_muted) {
+ i = drv->ops->get_output_muted(drv);
+ if ((k == 0) || ((i == 0) && (OSS_LEFT(k) < 100)))
+ drv->ops->set_output_muted(drv, 1);
+ else
+ drv->ops->set_output_muted(drv, 0);
+ }
+ case SOUND_MIXER_READ_VOLUME:
+ if (drv->ops->get_output_muted)
+ i = drv->ops->get_output_muted(drv);
+ k = 0x6464 * (1 - i);
+ return COPY_OUT(arg, k);
+ case SOUND_MIXER_WRITE_PCM:
+ if(COPY_IN(arg, k))
+ return -EFAULT;
+ oretry:
+ oprintk(("setting output volume (0x%x)\n", k));
if (drv->ops->get_output_channels)
j = drv->ops->get_output_channels(drv);
- if (j == 1) {
- i = s_to_m(k);
- tprintk((" for mono to %d\n", i));
- if (drv->ops->set_output_volume)
- drv->ops->set_output_volume(drv, i);
- if (drv->ops->get_output_volume)
- i = drv->ops->get_output_volume(drv);
- i = m_to_s(i);
- } else {
- i = s_to_g(k);
- j = s_to_b(k);
- tprintk((" for stereo to to %d (bal %d)\n", i, j));
- if (drv->ops->set_output_volume)
- drv->ops->set_output_volume(drv, i);
- if (drv->ops->get_output_volume)
- i = drv->ops->get_output_volume(drv);
- if (drv->ops->set_output_balance)
- drv->ops->set_output_balance(drv, j);
- if (drv->ops->get_output_balance)
- j = drv->ops->get_output_balance(drv);
- i = b_to_s(i,j);
- }
+ if (drv->ops->get_output_volume)
+ l = drv->ops->get_output_volume(drv);
+ if (drv->ops->get_output_balance)
+ m = drv->ops->get_output_balance(drv);
+ oprintk((" started as (0x%x)\n", BAL_TO_OSS(l,m)));
+ i = OSS_TO_GAIN(k);
+ j = OSS_TO_BAL(k);
+ oprintk((" for stereo to %d (bal %d)\n", i, j));
+ if (drv->ops->set_output_volume)
+ drv->ops->set_output_volume(drv, i);
+ if (drv->ops->set_output_balance)
+ drv->ops->set_output_balance(drv, j);
+ case SOUND_MIXER_READ_PCM:
+ if (drv->ops->get_output_volume)
+ i = drv->ops->get_output_volume(drv);
+ if (drv->ops->get_output_balance)
+ j = drv->ops->get_output_balance(drv);
+ oprintk((" got 0x%x\n", BAL_TO_OSS(i,j)));
+ i = BAL_TO_OSS(i,j);
+ /* Try to be reasonable about volume changes */
+ if ((cmd == SOUND_MIXER_WRITE_PCM) && (i != k) &&
+ (i == BAL_TO_OSS(l,m)))
+ {
+ k += (OSS_LEFT(k) > OSS_LEFT(i)) ? 256 : -256;
+ k += (OSS_RIGHT(k) > OSS_RIGHT(i)) ? 1 : -1;
+ oprintk((" try 0x%x\n", k));
+ goto oretry;
+ }
return COPY_OUT(arg, i);
+ case SOUND_MIXER_READ_SPEAKER:
+ k = OSS_PORT_AUDIO(drv, AUDIO_SPEAKER);
+ return COPY_OUT(arg, k);
+ case SOUND_MIXER_READ_MIC:
+ k = OSS_IPORT_AUDIO(drv, AUDIO_MICROPHONE);
+ return COPY_OUT(arg, k);
+ case SOUND_MIXER_READ_CD:
+ k = OSS_IPORT_AUDIO(drv, AUDIO_CD);
+ return COPY_OUT(arg, k);
+ case SOUND_MIXER_READ_LINE:
+ k = OSS_IPORT_AUDIO(drv, AUDIO_LINE_IN);
+ return COPY_OUT(arg, k);
+ case SOUND_MIXER_READ_LINE1:
+ k = OSS_PORT_AUDIO(drv, AUDIO_HEADPHONE);
+ return COPY_OUT(arg, k);
+ case SOUND_MIXER_READ_LINE2:
+ k = OSS_PORT_AUDIO(drv, AUDIO_LINE_OUT);
+ return COPY_OUT(arg, k);
+
+ case SOUND_MIXER_WRITE_MIC:
+ case SOUND_MIXER_WRITE_CD:
+ case SOUND_MIXER_WRITE_LINE:
+ case SOUND_MIXER_WRITE_LINE1:
+ case SOUND_MIXER_WRITE_LINE2:
+ case SOUND_MIXER_WRITE_SPEAKER:
+ if(COPY_IN(arg, k))
+ return -EFAULT;
+ OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_LINE, AUDIO_LINE_IN, k);
+ OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_MIC, AUDIO_MICROPHONE, k);
+ OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_CD, AUDIO_CD, k);
+
+ OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_SPEAKER, AUDIO_SPEAKER, k);
+ OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE1, AUDIO_HEADPHONE, k);
+ OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE2, AUDIO_LINE_OUT, k);
+ return COPY_OUT(arg, k);
case SOUND_MIXER_READ_RECSRC:
if (drv->ops->get_input_port)
i = drv->ops->get_input_port(drv);
/* only one should ever be selected */
- if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */
if (i & AUDIO_CD) j = SOUND_MASK_CD;
if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE;
if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC;
@@ -744,11 +811,10 @@
if(COPY_IN(arg, k))
return -EFAULT;
/* only one should ever be selected */
- if (k & SOUND_MASK_IMIX) j = AUDIO_ANALOG_LOOPBACK;
if (k & SOUND_MASK_CD) j = AUDIO_CD;
if (k & SOUND_MASK_LINE) j = AUDIO_LINE_IN;
if (k & SOUND_MASK_MIC) j = AUDIO_MICROPHONE;
- tprintk(("setting inport to %d\n", j));
+ oprintk(("setting inport to %d\n", j));
i = drv->ops->set_input_port(drv, j);
return COPY_OUT(arg, i);
@@ -759,7 +825,6 @@
if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
if (i & AUDIO_CD) j |= SOUND_MASK_CD;
- if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */
return COPY_OUT(arg, j);
case SOUND_MIXER_READ_CAPS: /* mixer capabilities */
@@ -767,62 +832,27 @@
return COPY_OUT(arg, i);
case SOUND_MIXER_READ_DEVMASK: /* all supported devices */
- case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */
if (drv->ops->get_input_ports)
i = drv->ops->get_input_ports(drv);
/* what do we support? */
if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
if (i & AUDIO_CD) j |= SOUND_MASK_CD;
- if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */
if (drv->ops->get_output_ports)
i = drv->ops->get_output_ports(drv);
if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER;
- if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */
- if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE;
-
+ if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE1;
+ if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE2;
+
j |= SOUND_MASK_VOLUME;
-
+
+ case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */
+ j |= SOUND_MASK_PCM|SOUND_MASK_RECLEV;
+
if (cmd == SOUND_MIXER_READ_STEREODEVS)
j &= ~(MONO_DEVICES);
return COPY_OUT(arg, j);
- case SOUND_MIXER_READ_PCM:
- case SOUND_MIXER_READ_SPEAKER:
- case SOUND_MIXER_READ_VOLUME:
- if (drv->ops->get_output_channels)
- j = drv->ops->get_output_channels(drv);
- if (j == 1) {
- if (drv->ops->get_output_volume)
- i = drv->ops->get_output_volume(drv);
- i = m_to_s(i);
- } else {
- if (drv->ops->get_output_volume)
- i = drv->ops->get_output_volume(drv);
- if (drv->ops->get_output_balance)
- j = drv->ops->get_output_balance(drv);
- i = b_to_s(i,j);
- }
- return COPY_OUT(arg, i);
- case SOUND_MIXER_READ_RECLEV:
- case SOUND_MIXER_READ_MIC:
- case SOUND_MIXER_READ_CD:
- case SOUND_MIXER_READ_LINE:
- case SOUND_MIXER_READ_IMIX:
- if (drv->ops->get_input_channels)
- j = drv->ops->get_input_channels(drv);
- if (j == 1) {
- if (drv->ops->get_input_volume)
- i = drv->ops->get_input_volume(drv);
- i = m_to_s(i);
- } else {
- if (drv->ops->get_input_volume)
- i = drv->ops->get_input_volume(drv);
- if (drv->ops->get_input_balance)
- j = drv->ops->get_input_balance(drv);
- i = b_to_s(i,j);
- }
- return COPY_OUT(arg, i);
default:
return -EINVAL;
}
@@ -881,6 +911,10 @@
case SPARCAUDIO_DSP_MINOR:
case SPARCAUDIO_AUDIO_MINOR:
case SPARCAUDIO_AUDIOCTL_MINOR:
+ /* According to the OSS prog int, you can mixer ioctl /dev/dsp */
+ if (_IOC_TYPE(cmd) == 'M')
+ return sparcaudio_mixer_ioctl(inode,
+ file, cmd, (unsigned int *)arg);
switch (cmd) {
case I_GETSIG:
case I_GETSIG_SOLARIS:
@@ -1997,6 +2031,36 @@
return -ENXIO;
}
+ /* From the dbri driver:
+ * SunOS 5.5.1 audio(7I) man page says:
+ * "Upon the initial open() of the audio device, the driver
+ * will reset the data format of the device to the default
+ * state of 8-bit, 8KHz, mono u-law data."
+ *
+ * Of course, we only do this for /dev/audio, and assume
+ * OSS semantics on /dev/dsp
+ */
+
+ if ((minor & 0xf) == SPARCAUDIO_AUDIO_MINOR) {
+ if (file->f_mode & FMODE_WRITE) {
+ if (drv->ops->set_output_channels)
+ drv->ops->set_output_channels(drv, 1);
+ if (drv->ops->set_output_encoding)
+ drv->ops->set_output_encoding(drv, AUDIO_ENCODING_ULAW);
+ if (drv->ops->set_output_rate)
+ drv->ops->set_output_rate(drv, 8000);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (drv->ops->set_input_channels)
+ drv->ops->set_input_channels(drv, 1);
+ if (drv->ops->set_input_encoding)
+ drv->ops->set_input_encoding(drv, AUDIO_ENCODING_ULAW);
+ if (drv->ops->set_input_rate)
+ drv->ops->set_input_rate(drv, 8000);
+ }
+ }
+
MOD_INC_USE_COUNT;
/* Success! */
@@ -2098,7 +2162,7 @@
#ifdef MODULE
int init_module(void)
#else
-__initfunc(int sparcaudio_init(void))
+int __init sparcaudio_init(void)
#endif
{
#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)