summaryrefslogtreecommitdiffstats
path: root/drivers/sbus/audio/audio.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /drivers/sbus/audio/audio.c
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'drivers/sbus/audio/audio.c')
-rw-r--r--drivers/sbus/audio/audio.c682
1 files changed, 434 insertions, 248 deletions
diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c
index ba9563449..ab14e2767 100644
--- a/drivers/sbus/audio/audio.c
+++ b/drivers/sbus/audio/audio.c
@@ -2,6 +2,12 @@
* drivers/sbus/audio/audio.c
*
* Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org)
+ * Copyright (C) 1997 Brent Baccala (baccala@freesoft.org)
+ *
+ * Mixer code adapted from code contributed by and
+ * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz)
+ *
*
* This is the audio midlayer that sits between the VFS character
* devices and the low-level audio hardware device drivers.
@@ -21,8 +27,9 @@
#include <linux/init.h>
#include <linux/soundcard.h>
#include <asm/uaccess.h>
+#include <asm/pgtable.h>
-#include "audio.h"
+#include <asm/audioio.h>
/*
@@ -47,17 +54,18 @@ int register_sparcaudio_driver(struct sparcaudio_driver *drv)
/* Setup the circular queues of output and input buffers
*
* Each buffer is a single page, but output buffers might
- * be partially filled (by a write with count < PAGE_SIZE),
+ * be partially filled (by a write with count < 4096),
* so each output buffer also has a paired output size.
*
* Input buffers, on the other hand, always fill completely,
- * so we don't need input counts - each contains PAGE_SIZE
+ * so we don't need input counts - each contains 4096
* bytes of audio data.
*
* TODO: Make number of input/output buffers tunable parameters
*/
drv->num_output_buffers = 32;
+ drv->playing_count = 0;
drv->output_front = 0;
drv->output_rear = 0;
drv->output_count = 0;
@@ -74,6 +82,7 @@ int register_sparcaudio_driver(struct sparcaudio_driver *drv)
/* Setup the circular queue of input buffers. */
drv->num_input_buffers = 32;
+ drv->recording_count = 0;
drv->input_front = 0;
drv->input_rear = 0;
drv->input_count = 0;
@@ -143,28 +152,25 @@ int unregister_sparcaudio_driver(struct sparcaudio_driver *drv)
return 0;
}
-static void sparcaudio_output_done_task(void * arg)
+void sparcaudio_output_done(struct sparcaudio_driver * drv, int reclaim)
{
- struct sparcaudio_driver *drv = (struct sparcaudio_driver *)arg;
- unsigned long flags;
+ /* Reclaim a buffer unless it's still in the DMA pipe */
+ if (reclaim) {
+ if (drv->output_count > 0)
+ drv->output_count--;
+ else
+ if (drv->playing_count > 0)
+ drv->playing_count--;
+ } else
+ drv->playing_count++;
- save_and_cli(flags);
- drv->ops->start_output(drv,
- drv->output_buffers[drv->output_front],
- drv->output_sizes[drv->output_front]);
- drv->output_active = 1;
- restore_flags(flags);
-}
-
-void sparcaudio_output_done(struct sparcaudio_driver * drv)
-{
/* Point the queue after the "done" buffer. */
drv->output_size -= drv->output_sizes[drv->output_front];
drv->output_front = (drv->output_front + 1) % drv->num_output_buffers;
- drv->output_count--;
/* If the output queue is empty, shutdown the driver. */
if (drv->output_count == 0) {
+ if (drv->playing_count == 0) {
/* Stop the lowlevel driver from outputing. */
drv->ops->stop_output(drv);
drv->output_active = 0;
@@ -173,19 +179,17 @@ void sparcaudio_output_done(struct sparcaudio_driver * drv)
wake_up_interruptible(&drv->output_write_wait);
wake_up_interruptible(&drv->output_drain_wait);
return;
+ }
}
- /* Otherwise, queue a task to give the driver the next buffer. */
- drv->tqueue.next = NULL;
- drv->tqueue.sync = 0;
- drv->tqueue.routine = sparcaudio_output_done_task;
- drv->tqueue.data = drv;
+ /* If we got back a buffer, see if anyone wants to write to it */
+ if (reclaim || ((drv->output_count + drv->playing_count)
+ < drv->num_output_buffers))
+ wake_up_interruptible(&drv->output_write_wait);
+
+ drv->ops->start_output(drv, drv->output_buffers[drv->output_front],
+ drv->output_sizes[drv->output_front]);
- queue_task(&drv->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-
- /* Wake up any tasks that are waiting. */
- wake_up_interruptible(&drv->output_write_wait);
}
void sparcaudio_input_done(struct sparcaudio_driver * drv)
@@ -202,7 +206,7 @@ void sparcaudio_input_done(struct sparcaudio_driver * drv)
} else {
/* Otherwise, give the driver the next buffer. */
drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
- PAGE_SIZE);
+ 4096);
}
/* Wake up any tasks that are waiting. */
@@ -234,7 +238,7 @@ static ssize_t sparcaudio_read(struct file * file,
return -EINTR;
}
- bytes_to_copy = PAGE_SIZE - driver->input_offset;
+ bytes_to_copy = 4096 - driver->input_offset;
if (bytes_to_copy > count)
bytes_to_copy = count;
@@ -242,7 +246,7 @@ static ssize_t sparcaudio_read(struct file * file,
bytes_to_copy, -EFAULT);
driver->input_offset += bytes_to_copy;
- if (driver->input_offset >= PAGE_SIZE) {
+ if (driver->input_offset >= 4096) {
driver->input_rear = (driver->input_rear + 1) % driver->num_input_buffers;
driver->input_count--;
driver->input_offset = 0;
@@ -263,11 +267,11 @@ static void sparcaudio_sync_output(struct sparcaudio_driver * driver)
/* If the low-level driver is not active, activate it. */
save_and_cli(flags);
- if (! driver->output_active) {
- driver->ops->start_output(driver,
- driver->output_buffers[driver->output_front],
- driver->output_sizes[driver->output_front]);
- driver->output_active = 1;
+ if ((!driver->output_active) && (driver->output_count > 0)) {
+ driver->ops->start_output(driver,
+ driver->output_buffers[driver->output_front],
+ driver->output_sizes[driver->output_front]);
+ driver->output_active = 1;
}
restore_flags(flags);
}
@@ -277,59 +281,184 @@ static ssize_t sparcaudio_write(struct file * file, const char *buf,
{
int bytes_written = 0, bytes_to_copy;
- /* Ensure that we have something to write. */
- if (count < 1) {
- sparcaudio_sync_output(driver);
- return 0;
- }
+ if (! file->f_mode & FMODE_WRITE)
+ return -EINVAL;
/* Loop until all output is written to device. */
while (count > 0) {
- /* Check to make sure that an output buffer is available. */
- /* If not, make valiant attempt */
- if (driver->output_count == driver->num_output_buffers)
- sparcaudio_reorganize_buffers(driver);
-
- if (driver->output_count == driver->num_output_buffers) {
- /* We need buffers, so... */
- sparcaudio_sync_output(driver);
- interruptible_sleep_on(&driver->output_write_wait);
- if (signal_pending(current))
- return bytes_written > 0 ? bytes_written : -EINTR;
+ /* Check to make sure that an output buffer is available. */
+ /* If not, make valiant attempt */
+ if (driver->num_output_buffers ==
+ (driver->output_count + driver->playing_count))
+ sparcaudio_reorganize_buffers(driver);
+
+ if (driver->num_output_buffers ==
+ (driver->output_count + driver->playing_count)) {
+ /* We need buffers, so... */
+ sparcaudio_sync_output(driver);
+ interruptible_sleep_on(&driver->output_write_wait);
+ if (signal_pending(current))
+ return bytes_written > 0 ? bytes_written : -EINTR;
}
- /* Determine how much we can copy in this iteration. */
- bytes_to_copy = count;
- if (bytes_to_copy > PAGE_SIZE)
- bytes_to_copy = PAGE_SIZE;
+ /* No buffers were freed. Go back to sleep */
+ if (driver->num_output_buffers ==
+ (driver->output_count + driver->playing_count))
+ continue;
+
+ /* Determine how much we can copy in this iteration. */
+ bytes_to_copy = count;
+ if (bytes_to_copy > 4096)
+ bytes_to_copy = 4096;
- copy_from_user_ret(driver->output_buffers[driver->output_rear],
+ copy_from_user_ret(driver->output_buffers[driver->output_rear],
buf, bytes_to_copy, -EFAULT);
- /* Update the queue pointers. */
- buf += bytes_to_copy;
- count -= bytes_to_copy;
- bytes_written += bytes_to_copy;
- driver->output_sizes[driver->output_rear] = bytes_to_copy;
- driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers;
- driver->output_count++;
- driver->output_size += bytes_to_copy;
-
- /* Activate the driver if more than page of data is waiting. */
- if (driver->output_size > 4096)
- sparcaudio_sync_output(driver);
+ /* Update the queue pointers. */
+ buf += bytes_to_copy;
+ count -= bytes_to_copy;
+ bytes_written += bytes_to_copy;
+ driver->output_sizes[driver->output_rear] = bytes_to_copy;
+ driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers;
+ driver->output_count++;
+ driver->output_size += bytes_to_copy;
}
+ sparcaudio_sync_output(driver);
/* Return the number of bytes written to the caller. */
return bytes_written;
}
+#define COPY_IN(arg, get) get_user(get, (int *)arg)
+#define COPY_OUT(arg, ret) put_user(ret, (int *)arg)
+
+/* Add these in as new devices are supported. Belongs in audioio.h, actually */
+#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_VOLUME)
+#define MONO_DEVICES (SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SPEAKER | SOUND_MASK_MIC)
+
+static inline int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int i = 0, j = 0;
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ /* For any missing routines, pretend we changed things anyhow for now */
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_VOLUME:
+ if (driver->ops->get_output_channels)
+ j = driver->ops->get_output_channels(driver);
+ COPY_IN(arg, i);
+ if (j == 1) {
+ i = s_to_m(i);
+ if (driver->ops->set_output_volume)
+ driver->ops->set_output_volume(driver, i * 255/100);
+ if (driver->ops->get_output_volume)
+ i = driver->ops->get_output_volume(driver);
+ i = m_to_s(i);
+ } else {
+ /* there should be stuff here which calculates balance and
+ volume on a stereo device. will do it eventually */
+ i = s_to_g(i);
+ if (driver->ops->set_output_volume)
+ driver->ops->set_output_volume(driver, i * 255/100);
+ if (driver->ops->get_output_volume)
+ i = driver->ops->get_output_volume(driver);
+ j = s_to_b(i);
+ if (driver->ops->set_output_balance)
+ driver->ops->set_output_balance(driver, j);
+ if (driver->ops->get_output_balance)
+ j = driver->ops->get_output_balance(driver);
+ i = b_to_s(i,j);
+ }
+ return COPY_OUT(arg, i);
+ default:
+ /* Play like we support other things */
+ return COPY_OUT(arg, i);
+ }
+ } else {
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ if (driver->ops->get_input_port)
+ i = driver->ops->get_input_port(driver);
+ /* 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;
+
+ return COPY_OUT(arg, j);
+
+ case SOUND_MIXER_RECMASK:
+ if (driver->ops->get_input_ports)
+ i = driver->ops->get_input_ports(driver);
+ /* 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; /* ? */
+
+ return COPY_OUT(arg, j);
+
+ case SOUND_MIXER_CAPS: /* mixer capabilities */
+ i = SOUND_CAP_EXCL_INPUT;
+ return COPY_OUT(arg, i);
+
+ case SOUND_MIXER_DEVMASK: /* all supported devices */
+ case SOUND_MIXER_STEREODEVS: /* what supports stereo */
+ if (driver->ops->get_input_ports)
+ i = driver->ops->get_input_ports(driver);
+ /* 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 (driver->ops->get_output_ports)
+ i = driver->ops->get_output_ports(driver);
+ 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;
+
+ j |= SOUND_MASK_VOLUME;
+
+ if ((cmd & 0xff) == SOUND_MIXER_STEREODEVS)
+ j &= ~(MONO_DEVICES);
+ return COPY_OUT(arg, j);
+
+ case SOUND_MIXER_VOLUME:
+ if (driver->ops->get_output_channels)
+ j = driver->ops->get_output_channels(driver);
+ if (j == 1) {
+ if (driver->ops->get_output_volume)
+ i = driver->ops->get_output_volume(driver);
+ i = m_to_s(i);
+ } else {
+ /* there should be stuff here which calculates balance and
+ volume on a stereo device. will do it eventually */
+ if (driver->ops->get_output_volume)
+ i = driver->ops->get_output_volume(driver);
+ if (driver->ops->get_output_balance)
+ j = driver->ops->get_output_balance(driver);
+ i = b_to_s(i,j);
+ }
+ return COPY_OUT(arg, i);
+
+ default:
+ /* Play like we support other things */
+ return COPY_OUT(arg, i);
+ }
+ }
+}
+
static int sparcaudio_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int retval = 0;
struct audio_info ainfo;
+ if (((cmd >> 8) & 0xff) == 'M') {
+ return sparcaudio_mixer_ioctl(inode, file, cmd, arg);
+ }
+
switch (cmd) {
case SNDCTL_DSP_SYNC:
case AUDIO_DRAIN:
@@ -339,6 +468,40 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
}
break;
+ case AUDIO_FLUSH:
+ if (driver->output_active && (file->f_mode & FMODE_WRITE)) {
+ wake_up_interruptible(&driver->output_write_wait);
+ driver->ops->stop_output(driver);
+ driver->output_active = 0;
+ driver->output_front = 0;
+ driver->output_rear = 0;
+ driver->output_count = 0;
+ driver->output_size = 0;
+ driver->playing_count = 0;
+ }
+ if (driver->input_active && (file->f_mode & FMODE_READ)) {
+ wake_up_interruptible(&driver->input_read_wait);
+ driver->ops->stop_input(driver);
+ driver->input_active = 0;
+ driver->input_front = 0;
+ driver->input_rear = 0;
+ driver->input_count = 0;
+ driver->recording_count = 0;
+ }
+ if ((file->f_mode & FMODE_READ) &&
+ !(driver->flags & SDF_OPEN_READ)) {
+ driver->ops->start_input(driver,
+ driver->input_buffers[driver->input_front],
+ 4096);
+ driver->input_active = 1;
+ }
+ if ((file->f_mode & FMODE_WRITE) &&
+ !(driver->flags & SDF_OPEN_WRITE)) {
+ sparcaudio_sync_output(driver);
+ }
+ break;
+
+
case AUDIO_GETDEV:
if (driver->ops->sunaudio_getdev) {
audio_device_t tmp;
@@ -349,18 +512,17 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
} else
retval = -EINVAL;
- printk(KERN_INFO "sparcaudio_ioctl: AUDIO_GETDEV\n");
break;
case AUDIO_GETDEV_SUNOS:
if (driver->ops->sunaudio_getdev_sunos) {
int tmp=driver->ops->sunaudio_getdev_sunos(driver);
- copy_to_user_ret((int *)arg, &tmp, sizeof(tmp), -EFAULT);
+ if (put_user(tmp, (int *)arg))
+ retval = -EFAULT;
} else
retval = -EINVAL;
- printk(KERN_INFO "sparcaudio_ioctl: AUDIO_GETDEV_SUNOS\n");
break;
case AUDIO_GETINFO:
@@ -388,7 +550,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
if (driver->ops->get_input_ports)
ainfo.record.avail_ports =
driver->ops->get_input_ports(driver);
- ainfo.record.buffer_size = PAGE_SIZE;
+ ainfo.record.buffer_size = 4096;
ainfo.record.samples = 0;
ainfo.record.eof = 0;
ainfo.record.pause = 0;
@@ -422,7 +584,8 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
if (driver->ops->get_output_ports)
ainfo.play.avail_ports =
driver->ops->get_output_ports(driver);
- ainfo.play.buffer_size = PAGE_SIZE;
+ /* This is not defined in the play context in Solaris */
+ ainfo.play.buffer_size = 0;
ainfo.play.samples = 0;
ainfo.play.eof = 0;
ainfo.play.pause = 0;
@@ -430,7 +593,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
ainfo.play.waiting = waitqueue_active(&driver->open_wait);
if (driver->ops->get_output_balance)
ainfo.play.balance =
- driver->ops->get_output_balance(driver);
+ (unsigned char)driver->ops->get_output_balance(driver);
ainfo.play.minordev = 4;
ainfo.play.open = 1;
ainfo.play.active = driver->output_active;
@@ -441,9 +604,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
if (driver->ops->get_output_muted)
ainfo.output_muted =
- driver->ops->get_output_muted(driver);
-
- printk("sparcaudio_ioctl: AUDIO_GETINFO\n");
+ (unsigned char)driver->ops->get_output_muted(driver);
copy_to_user_ret((struct audio_info *)arg, &ainfo,
sizeof(ainfo), -EFAULT);
@@ -452,7 +613,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
case AUDIO_SETINFO:
{
- audio_info_t curinfo;
+ audio_info_t curinfo, newinfo;
copy_from_user_ret(&ainfo, (audio_info_t *) arg, sizeof(audio_info_t), -EFAULT);
@@ -531,61 +692,56 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
break;
}
- curinfo.record.encoding = (Modify(ainfo.record.encoding) ?
- ainfo.record.encoding :
- driver->ops->get_input_encoding(driver));
- curinfo.record.sample_rate = (Modify(ainfo.record.sample_rate) ?
- ainfo.record.sample_rate :
- driver->ops->get_input_rate(driver));
- curinfo.record.precision = (Modify(ainfo.record.precision) ?
- ainfo.record.precision :
- driver->ops->get_input_precision(driver));
- curinfo.record.channels = (Modify(ainfo.record.channels) ?
- ainfo.record.channels :
- driver->ops->get_input_channels(driver));
- switch (curinfo.record.encoding) {
+ curinfo.record.encoding = driver->ops->get_input_encoding(driver);
+ curinfo.record.sample_rate = driver->ops->get_input_rate(driver);
+ curinfo.record.precision = driver->ops->get_input_precision(driver);
+ curinfo.record.channels = driver->ops->get_input_channels(driver);
+ newinfo.record.encoding = Modify(ainfo.record.encoding) ?
+ ainfo.record.encoding : curinfo.record.encoding;
+ newinfo.record.sample_rate = Modify(ainfo.record.sample_rate)?
+ ainfo.record.sample_rate : curinfo.record.sample_rate;
+ newinfo.record.precision = Modify(ainfo.record.precision) ?
+ ainfo.record.precision : curinfo.record.precision;
+ newinfo.record.channels = Modify(ainfo.record.channels) ?
+ ainfo.record.channels : curinfo.record.channels;
+
+ switch (newinfo.record.encoding) {
case AUDIO_ENCODING_ALAW:
case AUDIO_ENCODING_ULAW:
- if (Modify(ainfo.record.precision) &&
- ainfo.record.precision != 8) {
- retval = -EINVAL;
- break;
- }
- if (Modify(ainfo.record.channels) &&
- ainfo.record.channels != 1) {
- retval = -EINVAL;
- break;
- }
- break;
- case AUDIO_ENCODING_LINEAR:
- case AUDIO_ENCODING_LINEARLE:
- if (Modify(ainfo.record.precision) &&
- ainfo.record.precision != 16) {
- retval = -EINVAL;
- break;
- }
- if (Modify(ainfo.record.channels) &&
- (ainfo.record.channels != 1 &&
- ainfo.record.channels != 2))
- {
- retval = -EINVAL;
- break;
- }
- break;
- case AUDIO_ENCODING_LINEAR8:
- if (Modify(ainfo.record.precision) &&
- ainfo.record.precision != 8) {
- retval = -EINVAL;
- break;
- }
- if (Modify(ainfo.record.channels) &&
- (ainfo.record.channels != 1 &&
- ainfo.record.channels != 2))
- {
- retval = -EINVAL;
- break;
- }
- }
+ if (newinfo.record.precision != 8) {
+ retval = -EINVAL;
+ break;
+ }
+ if (newinfo.record.channels != 1) {
+ retval = -EINVAL;
+ break;
+ }
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ case AUDIO_ENCODING_LINEARLE:
+ if (newinfo.record.precision != 16) {
+ retval = -EINVAL;
+ break;
+ }
+ if (newinfo.record.channels != 1 &&
+ newinfo.record.channels != 2)
+ {
+ retval = -EINVAL;
+ break;
+ }
+ break;
+ case AUDIO_ENCODING_LINEAR8:
+ if (newinfo.record.precision != 8) {
+ retval = -EINVAL;
+ break;
+ }
+ if (newinfo.record.channels != 1 &&
+ newinfo.record.channels != 2)
+ {
+ retval = -EINVAL;
+ break;
+ }
+ }
if (retval < 0)
break;
@@ -604,61 +760,56 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
break;
}
- curinfo.play.encoding = (Modify(ainfo.play.encoding) ?
- ainfo.play.encoding :
- driver->ops->get_output_encoding(driver));
- curinfo.play.sample_rate = (Modify(ainfo.play.sample_rate) ?
- ainfo.play.sample_rate :
- driver->ops->get_output_rate(driver));
- curinfo.play.precision = (Modify(ainfo.play.precision) ?
- ainfo.play.precision :
- driver->ops->get_output_precision(driver));
- curinfo.play.channels = (Modify(ainfo.play.channels) ?
- ainfo.play.channels :
- driver->ops->get_output_channels(driver));
- switch (curinfo.play.encoding) {
+ curinfo.play.encoding = driver->ops->get_output_encoding(driver);
+ curinfo.play.sample_rate = driver->ops->get_output_rate(driver);
+ curinfo.play.precision = driver->ops->get_output_precision(driver);
+ curinfo.play.channels = driver->ops->get_output_channels(driver);
+ newinfo.play.encoding = Modify(ainfo.play.encoding) ?
+ ainfo.play.encoding : curinfo.play.encoding;
+ newinfo.play.sample_rate = Modify(ainfo.play.sample_rate) ?
+ ainfo.play.sample_rate : curinfo.play.sample_rate;
+ newinfo.play.precision = Modify(ainfo.play.precision) ?
+ ainfo.play.precision : curinfo.play.precision;
+ newinfo.play.channels = Modify(ainfo.play.channels) ?
+ ainfo.play.channels : curinfo.play.channels;
+
+ switch (newinfo.play.encoding) {
case AUDIO_ENCODING_ALAW:
case AUDIO_ENCODING_ULAW:
- if (Modify(ainfo.play.precision) &&
- ainfo.play.precision != 8) {
- retval = -EINVAL;
- break;
- }
- if (Modify(ainfo.play.channels) &&
- ainfo.play.channels != 1) {
- retval = -EINVAL;
- break;
- }
- break;
- case AUDIO_ENCODING_LINEAR:
- case AUDIO_ENCODING_LINEARLE:
- if (Modify(ainfo.play.precision) &&
- ainfo.play.precision != 16) {
- retval = -EINVAL;
- break;
- }
- if (Modify(ainfo.play.channels) &&
- (ainfo.play.channels != 1 &&
- ainfo.play.channels != 2))
- {
- retval = -EINVAL;
- break;
- }
- break;
- case AUDIO_ENCODING_LINEAR8:
- if (Modify(ainfo.play.precision) &&
- ainfo.play.precision != 8) {
- retval = -EINVAL;
- break;
- }
- if (Modify(ainfo.play.channels) &&
- (ainfo.play.channels != 1 &&
- ainfo.play.channels != 2))
- {
- retval = -EINVAL;
- break;
- }
- }
+ if (newinfo.play.precision != 8) {
+ retval = -EINVAL;
+ break;
+ }
+ if (newinfo.play.channels != 1) {
+ retval = -EINVAL;
+ break;
+ }
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ case AUDIO_ENCODING_LINEARLE:
+ if (newinfo.play.precision != 16) {
+ retval = -EINVAL;
+ break;
+ }
+ if (newinfo.play.channels != 1 &&
+ newinfo.play.channels != 2)
+ {
+ retval = -EINVAL;
+ break;
+ }
+ break;
+ case AUDIO_ENCODING_LINEAR8:
+ if (newinfo.play.precision != 8) {
+ retval = -EINVAL;
+ break;
+ }
+ if (newinfo.play.channels != 1 &&
+ newinfo.play.channels != 2)
+ {
+ retval = -EINVAL;
+ break;
+ }
+ }
if (retval < 0)
break;
@@ -686,8 +837,20 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
}
}
+ /* Maybe this should be a routine instead of a macro */
+#define IF_SET_DO(x,y) if ((x) && Modify(y)) x(driver, y)
+#define IF_SETC_DO(x,y) if ((x) && Modifyc(y)) x(driver, y)
+ IF_SETC_DO(driver->ops->set_input_balance, (int)ainfo.record.balance);
+ IF_SETC_DO(driver->ops->set_output_balance, (int)ainfo.play.balance);
+ IF_SET_DO(driver->ops->set_input_volume, ainfo.record.gain);
+ IF_SET_DO(driver->ops->set_output_volume, ainfo.play.gain);
+ IF_SET_DO(driver->ops->set_input_port, ainfo.record.port);
+ IF_SET_DO(driver->ops->set_output_port, ainfo.play.port);
+ IF_SET_DO(driver->ops->set_monitor_volume, ainfo.monitor_gain);
+ IF_SETC_DO(driver->ops->set_output_muted, (int)ainfo.output_muted);
+#undef IF_SET_DO
+#undef IF_SETC_DO
- printk("sparcaudio_ioctl: AUDIO_SETINFO\n");
break;
}
@@ -696,8 +859,6 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file,
retval = driver->ops->ioctl(inode,file,cmd,arg,driver);
else {
retval = -EINVAL;
-
- printk("sparcaudio_ioctl: 0x%x\n", cmd);
}
}
@@ -725,77 +886,83 @@ static struct file_operations sparcaudioctl_fops = {
static int sparcaudio_open(struct inode * inode, struct file * file)
{
- int err;
-
- /* A low-level audio driver must exist. */
- if (!driver)
- return -ENODEV;
-
- if (MINOR(inode->i_rdev) == 5) {
-
- file->f_op = &sparcaudioctl_fops;
-
- MOD_INC_USE_COUNT;
-
- return 0;
- }
-
- /* We only support minor #4 (/dev/audio) right now. */
- if (MINOR(inode->i_rdev) != 4)
- return -ENXIO;
-
- /* If the driver is busy, then wait to get through. */
- retry_open:
+ int minor = MINOR(inode->i_rdev);
+ int err;
+
+ /* A low-level audio driver must exist. */
+ if (!driver)
+ return -ENODEV;
+
+ switch (minor) {
+ case SPARCAUDIO_AUDIOCTL_MINOR:
+ file->f_op = &sparcaudioctl_fops;
+ break;
+
+ case SPARCAUDIO_DSP16_MINOR:
+ case SPARCAUDIO_DSP_MINOR:
+ case SPARCAUDIO_AUDIO_MINOR:
+ /* If the driver is busy, then wait to get through. */
+ retry_open:
if (file->f_mode & FMODE_READ && driver->flags & SDF_OPEN_READ) {
- if (file->f_flags & O_NONBLOCK)
- return -EBUSY;
-
- interruptible_sleep_on(&driver->open_wait);
- if (signal_pending(current))
- return -EINTR;
- goto retry_open;
+ if (file->f_flags & O_NONBLOCK)
+ return -EBUSY;
+
+ interruptible_sleep_on(&driver->open_wait);
+ if (signal_pending(current))
+ return -EINTR;
+ goto retry_open;
}
if (file->f_mode & FMODE_WRITE && driver->flags & SDF_OPEN_WRITE) {
- if (file->f_flags & O_NONBLOCK)
- return -EBUSY;
-
- interruptible_sleep_on(&driver->open_wait);
- if (signal_pending(current))
- return -EINTR;
- goto retry_open;
+ if (file->f_flags & O_NONBLOCK)
+ return -EBUSY;
+
+ interruptible_sleep_on(&driver->open_wait);
+ if (signal_pending(current))
+ return -EINTR;
+ goto retry_open;
}
+ /* Allow the low-level driver to initialize itself. */
+ if (driver->ops->open) {
+ err = driver->ops->open(inode,file,driver);
+ if (err < 0)
+ return err;
+ }
+
/* Mark the driver as locked for read and/or write. */
if (file->f_mode & FMODE_READ) {
- driver->input_offset = 0;
- driver->input_front = 0;
- driver->input_rear = 0;
- driver->input_count = 0;
- driver->ops->start_input(driver, driver->input_buffers[driver->input_front],
- PAGE_SIZE);
- driver->input_active = 1;
- driver->flags |= SDF_OPEN_READ;
+ driver->input_offset = 0;
+ driver->input_front = 0;
+ driver->input_rear = 0;
+ driver->input_count = 0;
+ driver->recording_count = 0;
+ driver->ops->start_input(driver, driver->input_buffers[driver->input_front],
+ 4096);
+ driver->input_active = 1;
+ driver->flags |= SDF_OPEN_READ;
}
if (file->f_mode & FMODE_WRITE) {
- driver->output_size = 0;
- driver->output_front = 0;
- driver->output_rear = 0;
- driver->output_count = 0;
- driver->output_active = 0;
- driver->flags |= SDF_OPEN_WRITE;
+ driver->playing_count = 0;
+ driver->output_size = 0;
+ driver->output_front = 0;
+ driver->output_rear = 0;
+ driver->output_count = 0;
+ driver->output_active = 0;
+ driver->flags |= SDF_OPEN_WRITE;
}
-
- /* Allow the low-level driver to initialize itself. */
- if (driver->ops->open) {
- err = driver->ops->open(inode,file,driver);
- if (err < 0)
- return err;
- }
-
- MOD_INC_USE_COUNT;
-
- /* Success! */
- return 0;
+ break;
+ case SPARCAUDIO_MIXER_MINOR:
+ file->f_op = &sparcaudioctl_fops;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ MOD_INC_USE_COUNT;
+
+ /* Success! */
+ return 0;
}
static int sparcaudio_release(struct inode * inode, struct file * file)
@@ -876,3 +1043,22 @@ void cleanup_module(void)
unregister_chrdev(SOUND_MAJOR, "sparcaudio");
}
#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */