summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_sadasupport
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drv/oss_sadasupport')
-rw-r--r--kernel/drv/oss_sadasupport/.config3
-rw-r--r--kernel/drv/oss_sadasupport/.devices1
-rw-r--r--kernel/drv/oss_sadasupport/.name1
-rw-r--r--kernel/drv/oss_sadasupport/.params0
-rw-r--r--kernel/drv/oss_sadasupport/oss_sadasupport.c1277
-rw-r--r--kernel/drv/oss_sadasupport/oss_sadasupport.man26
-rw-r--r--kernel/drv/oss_sadasupport/sadasupport_sol9.h187
7 files changed, 1495 insertions, 0 deletions
diff --git a/kernel/drv/oss_sadasupport/.config b/kernel/drv/oss_sadasupport/.config
new file mode 100644
index 0000000..c8e8442
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/.config
@@ -0,0 +1,3 @@
+bus=STREAMS
+targetos=SunOS
+depends=SADA
diff --git a/kernel/drv/oss_sadasupport/.devices b/kernel/drv/oss_sadasupport/.devices
new file mode 100644
index 0000000..236f38f
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/.devices
@@ -0,0 +1 @@
+oss_sadasupport OSSAUDIOS SADA emulation layer for OSS
diff --git a/kernel/drv/oss_sadasupport/.name b/kernel/drv/oss_sadasupport/.name
new file mode 100644
index 0000000..c311b6a
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/.name
@@ -0,0 +1 @@
+SADA emulation layer for OSS
diff --git a/kernel/drv/oss_sadasupport/.params b/kernel/drv/oss_sadasupport/.params
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/.params
diff --git a/kernel/drv/oss_sadasupport/oss_sadasupport.c b/kernel/drv/oss_sadasupport/oss_sadasupport.c
new file mode 100644
index 0000000..43f5226
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/oss_sadasupport.c
@@ -0,0 +1,1277 @@
+/*
+ * Purpose: Support for the legacy (SADA) /dev/audio interfaces of Solaris
+ *
+ * Description:
+ * This driver serves as a bridge between the OSS audio drivers and the
+ * native audio support framework of Solaris.
+ *
+ * **** This driver supports only one device instance ****
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+
+#include "oss_sadasupport_cfg.h"
+#include <oss_pci.h>
+#include <sys/note.h>
+#include <sys/audioio.h>
+#include <sys/audio.h>
+#include <sys/audiovar.h>
+#include <sys/audio/audio_trace.h>
+#include <sys/audio/audio_support.h>
+#include <sys/audio/audio_src.h>
+#include <sys/mixer.h>
+#include <sys/audio/audio_mixer.h>
+#ifdef SOL9
+#include <sys/audio/am_src1.h>
+#else
+#include <sys/sunldi.h>
+#endif
+
+int sadasupport_rate = 48000;
+
+static int do_byteswap = 0;
+
+#ifdef SOL9
+extern am_ad_src_entry_t am_src1;
+#else
+extern am_ad_src_entry_t am_src2;
+#endif
+
+#define AUDIOS_DEV_NAME "SUNW,oss"
+#define AUDIOS_DEV_CONFIG "onboard1"
+#define AUDIOS_DEV_VERSION "a"
+#define AUDIOS_NAME "oss"
+#define AUDIOS_IDNUM (0x6175)
+#define AUDIOS_MINPACKET (0)
+#define AUDIOS_MAXPACKET (1*1024)
+#define AUDIOS_HIWATER (64*1024)
+#define AUDIOS_LOWATER (32*1024)
+#define AUDIOS_BUFFSIZE (8*1024)
+
+#define AUDIOS_SAMPR5510 (5510)
+#define AUDIOS_SAMPR6620 (6620)
+#define AUDIOS_SAMPR8000 (8000)
+#define AUDIOS_SAMPR9600 (9600)
+#define AUDIOS_SAMPR11025 (11025)
+#define AUDIOS_SAMPR12000 (12000)
+#define AUDIOS_SAMPR16000 (16000)
+#define AUDIOS_SAMPR18900 (18900)
+#define AUDIOS_SAMPR22050 (22050)
+#define AUDIOS_SAMPR24000 (24000)
+#define AUDIOS_SAMPR27420 (27420)
+#define AUDIOS_SAMPR32000 (32000)
+#define AUDIOS_SAMPR33075 (33075)
+#define AUDIOS_SAMPR37800 (37800)
+#define AUDIOS_SAMPR44100 (44100)
+#define AUDIOS_SAMPR48000 (48000)
+
+#define AUDIOS_DEFAULT_SR AUDIOS_SAMPR8000
+#define AUDIOS_DEFAULT_CH AUDIO_CHANNELS_MONO
+#define AUDIOS_DEFAULT_PREC AUDIO_PRECISION_8
+#define AUDIOS_DEFAULT_ENC AUDIO_ENCODING_ULAW
+#define AUDIOS_DEFAULT_PGAIN (AUDIO_MAX_GAIN * 3 / 4)
+#define AUDIOS_DEFAULT_RGAIN (127)
+#define AUDIOS_DEFAULT_MONITOR_GAIN (0)
+#define AUDIOS_DEFAULT_BAL AUDIO_MID_BALANCE
+
+/*
+ * Entry point routine prototypes
+ */
+static int sadasupport_open (queue_t * q, dev_t * devp, int flag, int sflag,
+ cred_t * credp);
+static int sadasupport_close (queue_t * q, int flag, cred_t * credp);
+static int sadasupport_ad_set_config (audiohdl_t, int, int, int, int, int);
+static int sadasupport_ad_set_format (audiohdl_t, int, int, int, int, int,
+ int);
+static int sadasupport_ad_start_play (audiohdl_t, int);
+static void sadasupport_ad_pause_play (audiohdl_t, int);
+static void sadasupport_ad_stop_play (audiohdl_t, int);
+static int sadasupport_ad_start_record (audiohdl_t, int);
+static void sadasupport_ad_stop_record (audiohdl_t, int);
+
+/* now, only support stereo */
+static uint_t sadasupport_channels[] = {
+ AUDIO_CHANNELS_STEREO,
+ 0
+};
+
+static am_ad_cap_comb_t sadasupport_combinations[] = {
+ {AUDIO_PRECISION_16, AUDIO_ENCODING_LINEAR},
+ {0}
+};
+
+static uint_t sadasupport_mixer_srs[] = {
+ AUDIOS_SAMPR8000, AUDIOS_SAMPR48000, 0
+};
+
+#ifdef SOL9
+/* don't filter the higher sample rates, this causes the high to be lost */
+static am_ad_src1_info_t sadasupport_play_sample_rates_info[] = {
+ {AUDIOS_SAMPR8000, AUDIOS_SAMPR48000, 2, /* up 6, down 1 */
+ 3, (2 | AM_SRC1_FILTER), 0, 0, 1, 1, 0, 0, 3},
+ {AUDIOS_SAMPR9600, AUDIOS_SAMPR48000, 1, /* up 5, down 1 */
+ (5 | AM_SRC1_FILTER), 0, 0, 0, 1, 0, 0, 0, 3},
+ {AUDIOS_SAMPR11025, AUDIOS_SAMPR48000, 3, /* up 640, down 147 */
+ 10, 8, (8 | AM_SRC1_FILTER), 0, 7, 7, 3, 0, 3},
+ {AUDIOS_SAMPR12000, AUDIOS_SAMPR48000, 1, /* up 4, down 1 */
+ (4 | AM_SRC1_FILTER), 0, 0, 0, 1, 0, 0, 0, 3},
+ {AUDIOS_SAMPR16000, AUDIOS_SAMPR48000, 1, /* up 3, down 1 */
+ (3 | AM_SRC1_FILTER), 0, 0, 0, 1, 0, 0, 0, 3},
+ {AUDIOS_SAMPR18900, AUDIOS_SAMPR48000, 3, /* up 160, down 63 */
+ 8, 5, (4 | AM_SRC1_FILTER), 0, 7, 3, 3, 0, 3},
+ {AUDIOS_SAMPR22050, AUDIOS_SAMPR48000, 3, /* up 320, down 147 */
+ 10, 8, (4 | AM_SRC1_FILTER), 0, 7, 7, 3, 0, 3},
+ {AUDIOS_SAMPR24000, AUDIOS_SAMPR48000, 1, /* up 2, down 1 */
+ (2 | AM_SRC1_FILTER), 0, 0, 0, 1, 0, 0, 0, 3},
+ {AUDIOS_SAMPR32000, AUDIOS_SAMPR48000, 1, /* up 3, down 2 */
+ (3 | AM_SRC1_FILTER), 0, 0, 0, 2, 0, 0, 0, 3},
+ {AUDIOS_SAMPR33075, AUDIOS_SAMPR48000, 4, /* up 640, down 441 */
+ 8, 5, 4, 4, 7, 7, 3, 3, 3},
+ {AUDIOS_SAMPR37800, AUDIOS_SAMPR48000, 3, /* up 80, down 63 */
+ 5, 4, 4, 0, 7, 3, 3, 0, 3},
+ {AUDIOS_SAMPR44100, AUDIOS_SAMPR48000, 3, /* up 160, down 147 */
+ 8, 5, 4, 0, 7, 7, 3, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR48000, 1, /* up 1, down 1 */
+ 1, 0, 0, 0, 1, 0, 0, 0, 3},
+ {0}
+};
+
+static am_ad_src1_info_t sadasupport_record_sample_rates_info[] = {
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR8000, 1, /* up 1, down 6 */
+ 1, 0, 0, 0, 6, 0, 0, 0, 0},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR9600, 1, /* up 1, down 5 */
+ 1, 0, 0, 0, 5, 0, 0, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR11025, 3, /* up 147, down 640 */
+ 7, 7, (3 | AM_SRC1_FILTER), 0, 10, 8, 8, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR12000, 1, /* up 1, down 4 */
+ 1, 0, 0, 0, 4, 0, 0, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR16000, 1, /* up 1, down 3 */
+ 1, 0, 0, 0, 3, 0, 0, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR18900, 3, /* up 63, down 160 */
+ 7, 3, (3 | AM_SRC1_FILTER), 0, 8, 5, 4, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR22050, 3, /* up 147, down 320 */
+ 7, 7, (3 | AM_SRC1_FILTER), 0, 10, 8, 4, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR24000, 1, /* up 1, down 2 */
+ 1, 0, 0, 0, 2, 0, 0, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR32000, 1, /* up 2, down 3 */
+ (2 | AM_SRC1_FILTER), 0, 0, 0, 3, 0, 0, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR33075, 4, /* up 441, down 640 */
+ 7, 7, 3, 3, 8, 5, 4, 4, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR37800, 3, /* up 63, down 80 */
+ 7, 3, 3, 0, 5, 4, 4, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR44100, 3, /* up 147, down 160 */
+ 7, 7, 3, 0, 8, 5, 4, 0, 3},
+ {AUDIOS_SAMPR48000, AUDIOS_SAMPR48000, 3, /* up 1, down 1 */
+ 1, 0, 0, 0, 1, 0, 0, 0, 3},
+ {0}
+};
+#endif
+
+#if 0
+static uint_t sadasupport_compat_srs[] = {
+ AUDIOS_SAMPR5510, AUDIOS_SAMPR6620, AUDIOS_SAMPR8000,
+ AUDIOS_SAMPR9600, AUDIOS_SAMPR11025, AUDIOS_SAMPR12000,
+ AUDIOS_SAMPR16000, AUDIOS_SAMPR18900, AUDIOS_SAMPR22050,
+ AUDIOS_SAMPR24000, AUDIOS_SAMPR27420, AUDIOS_SAMPR32000,
+ AUDIOS_SAMPR33075, AUDIOS_SAMPR37800, AUDIOS_SAMPR44100,
+ AUDIOS_SAMPR48000, 0
+};
+#endif
+
+static am_ad_sample_rates_t sadasupport_mixer_sample_rates = {
+ MIXER_SRS_FLAG_SR_LIMITS,
+ sadasupport_mixer_srs
+};
+
+#if 0
+static am_ad_sample_rates_t sadasupport_compat_sample_rates = {
+ MIXER_SRS_FLAG_SR_NOT_LIMITS,
+ sadasupport_compat_srs
+};
+#endif
+
+typedef struct
+{
+ oss_device_t *osdev;
+ kmutex_t inst_lock;
+
+/*
+ * Fields related with the OSS audio device
+ */
+
+ volatile int audio_busy;
+ int audio_mode;
+ int oss_audiodev;
+ int play_frag;
+ int rec_frag;
+ int start_flags;
+ int sample_rate;
+ int mute; /* Play silence if mute is set */
+
+/*
+ * Fields related with the audiosup and mixer modules.
+ */
+ audiohdl_t audio_handle;
+ am_ad_info_t ad_info; /* audio device info state */
+ uint16_t vol_bits_mask; /* bits used to ctrl volume */
+
+ audio_info_t audios_defaults; /* default state for dev */
+ audio_device_t audios_dev_info; /* audio device info state */
+#ifndef SOL9
+ ldi_handle_t lh;
+ ldi_ident_t li;
+#endif
+} sadasupport_devc;
+
+static sadasupport_devc *devc = NULL;
+static struct fileinfo tmp_file = { 0 };
+
+static am_ad_entry_t sadasupport_entry = {
+ NULL, /* ad_setup() */
+ NULL, /* ad_teardown() */
+ sadasupport_ad_set_config, /* ad_set_config() */
+ sadasupport_ad_set_format, /* ad_set_format() */
+ sadasupport_ad_start_play, /* ad_start_play() */
+ sadasupport_ad_pause_play, /* ad_pause_play() */
+ sadasupport_ad_stop_play, /* ad_stop_play() */
+ sadasupport_ad_start_record, /* ad_start_record() */
+ sadasupport_ad_stop_record, /* ad_stop_record() */
+ NULL, /* ad_ioctl() */
+ NULL /* ad_iocdata() */
+};
+
+/*
+ * STREAMS structures
+ */
+
+/* STREAMS driver id and limit value struct */
+static struct module_info sadasupport_modinfo = {
+ AUDIOS_IDNUM, /* module ID number */
+ AUDIOS_NAME, /* module name */
+ AUDIOS_MINPACKET, /* minimum packet size */
+ AUDIOS_MAXPACKET, /* maximum packet size */
+ AUDIOS_HIWATER, /* high water mark */
+ AUDIOS_LOWATER, /* low water mark */
+};
+
+/* STREAMS queue processing procedures structures */
+/* read queue */
+static struct qinit sadasupport_rqueue = {
+ audio_sup_rput, /* put procedure */
+ audio_sup_rsvc, /* service procedure */
+ sadasupport_open, /* open procedure */
+ sadasupport_close, /* close procedure */
+ NULL, /* unused */
+ &sadasupport_modinfo, /* module parameters */
+ NULL /* module statistics */
+};
+
+/* write queue */
+static struct qinit sadasupport_wqueue = {
+ audio_sup_wput, /* write procedure */
+ audio_sup_wsvc, /* service procedure */
+ NULL, /* open procedure */
+ NULL, /* close procedure */
+ NULL, /* unused */
+ &sadasupport_modinfo, /* module parameters */
+ NULL /* module statistics */
+};
+
+/* STREAMS entity declaration structure */
+struct streamtab oss_sadasupport_str_info = {
+ &sadasupport_rqueue, /* read queue */
+ &sadasupport_wqueue, /* write queue */
+ NULL, /* mux lower read queue */
+ NULL, /* mux lower write queue */
+};
+
+/*ARGSUSED*/
+static void
+input_callback (int dev, int parm)
+{
+ dmap_p dmap;
+ adev_p adev;
+ unsigned char *buf;
+ int samples, i;
+ oss_native_word flags;
+
+ adev = audio_engines[dev];
+ dmap = adev->dmap_in;
+
+ if (dmap->dmabuf == NULL)
+ {
+ cmn_err (CE_WARN, "Dmabuf==NULL\n");
+ return;
+ }
+
+ MUTEX_ENTER (dmap->mutex, flags);
+
+ samples = dmap->fragment_size / 2; /* Number of 16 bit samples */
+
+ buf = dmap->dmabuf + devc->rec_frag * dmap->fragment_size;
+
+ if (dmap->nfrags == 0)
+ {
+ cmn_err (CE_WARN, "Nfrags==0\n");
+ MUTEX_EXIT (dmap->mutex, flags);
+ return;
+ }
+
+ devc->rec_frag = (devc->rec_frag + 1) % dmap->nfrags;
+ dmap->user_counter += dmap->fragment_size;
+ MUTEX_EXIT (dmap->mutex, flags);
+
+ /* Perform byte swapping (if necessary) */
+ if (do_byteswap)
+ for (i = 0; i < samples * 2; i += 2)
+ {
+ unsigned char tmp;
+
+ tmp = buf[i];
+ buf[i] = buf[i + 1];
+ buf[i + 1] = tmp;
+ }
+ am_send_audio (devc->audio_handle, buf, AUDIO_NO_CHANNEL, samples);
+
+}
+
+static int fill_play_buf (sadasupport_devc * devc);
+
+/*ARGSUSED*/
+static void
+output_callback (int dev, int parm)
+{
+ fill_play_buf (devc);
+}
+
+static int
+setup_device (sadasupport_devc * devc)
+{
+ int fmt = AFMT_S16_NE;
+ int ch = 2;
+ int rate = devc->sample_rate;
+ int mode;
+
+ devc->mute = 0; /* Unmute every time the device gets opened */
+
+ mode = 0;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_COOKEDMODE,
+ (ioctl_arg) & mode);
+
+#if 0
+ int frag;
+
+ //frag=0x0002000d; /* Two 8k fragments */
+ frag = 0x0008000a; /* 1k fragments */
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETFRAGMENT,
+ (ioctl_arg) & frag);
+#endif
+
+ do_byteswap = 0;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETFMT,
+ (ioctl_arg) & fmt);
+ if (fmt != AFMT_S16_NE)
+ {
+ fmt = AFMT_S16_OE;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETFMT,
+ (ioctl_arg) & fmt);
+ if (fmt != AFMT_S16_OE)
+ {
+ cmn_err (CE_WARN, "Internal error (format=%x)\n", fmt);
+ return AUDIO_FAILURE;
+ }
+ do_byteswap = 1;
+ }
+
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_CHANNELS,
+ (ioctl_arg) & ch);
+ if (ch != 2)
+ {
+ cmn_err (CE_WARN, "Internal error (channels=%d)\n", ch);
+ return AUDIO_FAILURE;
+ }
+
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SPEED,
+ (ioctl_arg) & rate);
+ if (rate != devc->sample_rate)
+ {
+/*
+ * Disabling SADA mixing/src may cause problems if the application wants
+ * to use rate that is not supported by the device itself. In that case
+ * we need to switch to the rate returned by the device.
+ */
+ cmn_err (CE_WARN, "Returned sample rate %d is different than requested %d)\n", rate,
+ devc->sample_rate);
+ cmn_err (CE_CONT, "Switching to %d\n", rate);
+ devc->sample_rate = rate;
+ // return AUDIO_FAILURE;
+ }
+
+ return AUDIO_SUCCESS;
+}
+
+#ifndef SOL9
+static int
+sadasupport_open (queue_t * q, dev_t * devp, int flag, int sflag,
+ cred_t * credp)
+{
+ int retval, i;
+ int devnum;
+ int dev = *devp;
+ char *cmd;
+ unsigned int bl_flags = 0;
+ int oss_mode = 0;
+
+ DDB (cmn_err
+ (CE_CONT, "sadasupport_open(dev=%x, flag=%x, sflag=%x)\n",
+ dev, flag, sflag));
+
+ if (devc == NULL)
+ return EIO;
+
+ oss_mode = OPEN_READWRITE;
+
+ mutex_enter (&devc->inst_lock);
+
+ if (devc->audio_busy++ == 0)
+ {
+ oss_audioinfo ai;
+ int err;
+
+ mutex_exit (&devc->inst_lock);
+
+ tmp_file.acc_flags = 0;
+ tmp_file.mode = oss_mode;
+
+ devc->audio_mode = tmp_file.mode;
+
+ DDB (cmn_err (CE_CONT, "Opening /dev/dsp (mode=%x)\n", tmp_file.mode));
+
+ if (ldi_ident_from_dev (dev, &devc->li) != 0)
+ {
+ cmn_err (CE_WARN, "ldi_ident_from_dev failed\n");
+ devc->audio_busy--;
+ return EIO;
+ }
+
+ if ((err =
+ ldi_open_by_name ("/dev/dsp", FWRITE | FREAD, credp, &devc->lh,
+ devc->li)) != 0)
+ {
+ cmn_err (CE_WARN,
+ "ldi_open_by_name(\"/dev/dsp\") failed, errno=%d\n", err);
+ devc->audio_busy--;
+ return -err;
+ }
+
+ ai.dev = -1;
+ if ((err =
+ ldi_ioctl (devc->lh, SNDCTL_ENGINEINFO, (intptr_t) & ai, FKIOCTL,
+ credp, &retval)) != 0)
+ {
+ ldi_close (devc->lh, FREAD | FWRITE, credp);
+ ldi_ident_release (devc->li);
+ cmn_err (CE_WARN, "ldi_ioctl(SNDCTL_AUDIOINFO) failed, err=%d\n",
+ err);
+ devc->audio_busy--;
+ return err;
+ }
+
+ devnum = ai.dev;
+
+ DDB (cmn_err
+ (CE_CONT, "Opened OSS audio engine %d:%s\n", devnum, ai.name));
+
+ if (devnum < 0 || devnum >= num_audio_engines)
+ {
+ cmn_err (CE_WARN, "OSS audio engine number %d is out of range.\n",
+ devnum);
+ ldi_close (devc->lh, FREAD | FWRITE, credp);
+ ldi_ident_release (devc->li);
+ devc->audio_busy--;
+ return ENXIO;
+ }
+
+ devc->oss_audiodev = devnum;
+
+ if (tmp_file.mode & OPEN_READ)
+ audio_engines[devnum]->dmap_in->audio_callback = input_callback;
+ if (tmp_file.mode & OPEN_WRITE)
+ audio_engines[devnum]->dmap_out->audio_callback = output_callback;
+ strcpy (audio_engines[devnum]->cmd, "SADA");
+ strcpy (audio_engines[devnum]->label, "SADA");
+ audio_engines[devnum]->pid = 0;
+
+ if ((retval = setup_device (devc)) != AUDIO_SUCCESS)
+ {
+ cmn_err (CE_NOTE, "setup_device failed\n");
+ mutex_enter (&devc->inst_lock);
+ if (--devc->audio_busy == 0)
+ {
+ ldi_close (devc->lh, FREAD | FWRITE, credp);
+ ldi_ident_release (devc->li);
+ mutex_exit (&devc->inst_lock);
+ }
+ else
+ mutex_exit (&devc->inst_lock);
+
+ return EIO;
+ }
+ }
+ else
+ {
+ if (oss_mode & ~devc->audio_mode)
+ {
+ cmn_err (CE_NOTE, "Conflicting access modes\n");
+
+ if (--devc->audio_busy == 0)
+ {
+ mutex_exit (&devc->inst_lock);
+ ldi_close (devc->lh, FREAD | FWRITE, credp);
+ ldi_ident_release (devc->li);
+ return EBUSY;
+ }
+
+ mutex_exit (&devc->inst_lock);
+ return EBUSY;
+ }
+
+ mutex_exit (&devc->inst_lock);
+
+ }
+
+ DDB (cmn_err (CE_CONT, "Open count %d\n", devc->audio_busy));
+
+ DDB (cmn_err
+ (CE_CONT, "audio_sup_open(q=%p, dev=%x, flag=%x, sflag=%x)\n", q, dev,
+ flag, sflag));
+ if ((retval = audio_sup_open (q, devp, flag, sflag, credp)) != 0)
+ {
+ cmn_err (CE_NOTE, "audio_sup_open() returned %d\n", retval);
+ mutex_enter (&devc->inst_lock);
+ if (--devc->audio_busy == 0)
+ {
+ mutex_exit (&devc->inst_lock);
+ ldi_close (devc->lh, FREAD | FWRITE, credp);
+ ldi_ident_release (devc->li);
+ }
+ else
+ mutex_exit (&devc->inst_lock);
+ }
+
+ return retval;
+}
+
+static int
+sadasupport_close (queue_t * q, int flag, cred_t * credp)
+{
+ int retval, count;
+
+ DDB (cmn_err (CE_CONT, "sadasupport_close(q=%p, flag=%x)\n", q, flag));
+
+ if (!devc->audio_busy)
+ cmn_err (CE_WARN, "Close while not busy.\n");
+
+ retval = audio_sup_close (q, flag, credp);
+
+ mutex_enter (&devc->inst_lock);
+ count = --devc->audio_busy;
+ mutex_exit (&devc->inst_lock);
+
+ DDB (cmn_err (CE_CONT, "Open count (close) %d\n", count));
+ if (count == 0)
+ {
+ DDB (cmn_err
+ (CE_CONT, "Closing OSS audiodev %d\n", devc->oss_audiodev));
+ ldi_close (devc->lh, FREAD | FWRITE, credp);
+ ldi_ident_release (devc->li);
+ devc->audio_mode = 0;
+ }
+
+ return retval;
+}
+#else
+#include "sadasupport_sol9.h"
+#endif
+
+static void
+set_port (sadasupport_devc * devc, int dir, int port)
+{
+ int recdev = SOUND_MASK_MIC;
+
+ if (dir == AUDIO_PLAY) /* Don't support this */
+ return;
+
+ switch (port)
+ {
+ case AUDIO_MICROPHONE:
+ recdev = SOUND_MASK_MIC;
+ break;
+ case AUDIO_LINE_IN:
+ recdev = SOUND_MASK_LINE;
+ break;
+ case AUDIO_CD:
+ recdev = SOUND_MASK_CD;
+ break;
+ }
+
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SOUND_MIXER_WRITE_RECSRC,
+ (ioctl_arg) & recdev);
+ /* Let's hope that worked */
+}
+
+static void
+set_gain (sadasupport_devc * devc, int dir, int gain, int channel)
+{
+ int cmd;
+ int val;
+
+ if (gain < 0)
+ gain = 0;
+ if (gain > 255)
+ gain = 255;
+
+ gain = (gain * 100) / 255;
+
+ if (dir == AUDIO_PLAY)
+ cmd = SNDCTL_DSP_GETPLAYVOL;
+ else
+ cmd = SNDCTL_DSP_GETRECVOL;
+
+ if (oss_audio_ioctl (devc->oss_audiodev, NULL, cmd, (ioctl_arg) & val) < 0)
+ return;
+
+ switch (channel)
+ {
+ case 0: /* Left channel */
+ val = (val & 0xff00) | gain;
+ break;
+
+ case 1: /* Right channel */
+ val = (val & 0x00ff) | (gain << 8);
+ break;
+ }
+
+ if (dir == AUDIO_PLAY)
+ cmd = SNDCTL_DSP_SETPLAYVOL;
+ else
+ cmd = SNDCTL_DSP_SETRECVOL;
+
+ oss_audio_ioctl (devc->oss_audiodev, NULL, cmd, (ioctl_arg) & val);
+}
+
+/*ARGSUSED*/
+static void
+set_monitor_gain (sadasupport_devc * devc, int gain)
+{
+ /* NOP. SADA applications are not allowed to change monitor gain. */
+}
+
+/*ARGSUSED*/
+static int
+sadasupport_ad_set_config (audiohdl_t ahandle, int stream, int command,
+ int dir, int arg1, int arg2)
+{
+/*
+ * We do not support most gain settings. They are incompatible with the way
+ * how OSS 4.0 (and later) works.
+ */
+
+#if 0
+ typedef struct
+ {
+ uint_t cmd;
+ char *name;
+ } cmds_t;
+
+ static const cmds_t cmds[] = {
+ {AM_SET_GAIN, "AM_SET_GAIN"},
+ {AM_SET_GAIN_BAL, "AM_SET_GAIN_BAL"},
+ {AM_SET_PORT, "AM_SET_PORT"},
+ {AM_SET_MONITOR_GAIN, "AM_SET_MONITOR_GAIN"},
+ {AM_OUTPUT_MUTE, "AM_OUTPUT_MUTE"},
+ {AM_MONO_MIC, "AM_MONO_MIC"},
+ {AM_MIC_BOOST, "AM_MIC_BOOST"},
+ {AM_BASS_BOOST, "AM_BASS_BOOST"},
+ {AM_MID_BOOST, "AM_MID_BOOST"},
+ {AM_TREBLE_BOOST, "AM_TREBLE_BOOST"},
+ {AM_LOUDNESS, "AM_LOUDNESS"},
+ {AM_SET_DIAG_MODE, "AM_SET_DIAG_MODE"},
+ {0, NULL}
+ };
+#endif
+
+ if (devc->audio_mode == 0)
+ return AUDIO_SUCCESS;
+
+ switch (command)
+ {
+ case AM_SET_PORT:
+ set_port (devc, dir, arg1);
+ break;
+
+ case AM_SET_GAIN_BAL:
+ return AUDIO_FAILURE;
+ break;
+
+ case AM_SET_GAIN:
+ set_gain (devc, dir, arg1, arg2);
+ break;
+
+ case AM_SET_MONITOR_GAIN:
+ set_monitor_gain (devc, arg1);
+ break;
+
+ case AM_OUTPUT_MUTE:
+ devc->mute = arg1;
+ break;
+
+ default:
+#if 0
+ int i;
+
+ cmn_err (CE_CONT,
+ "sadasupport_ad_set_config(stream=%d, cmd=%x, dir=%d, arg1=%x, arg2=%x)\n",
+ stream, command, dir, arg1, arg2);
+
+ for (i = 0; cmds[i].cmd != 0; i++)
+ if (cmds[i].cmd == command)
+ {
+ cmn_err (CE_CONT, " Unsupported mixer command =%s\n",
+ cmds[i].name);
+ break;
+ }
+#endif
+ break;
+ }
+ return AUDIO_SUCCESS;
+}
+
+/*ARGSUSED*/
+static int
+sadasupport_ad_set_format (audiohdl_t ahandle, int stream, int dir,
+ int sample_rate, int channels, int precision,
+ int encoding)
+{
+
+ DDB (cmn_err (CE_CONT,
+ "sadasupport_ad_set_format(stream=%d, dir=%d, sr=%d, ch=%d, prec=%d, enc=%d)\n",
+ stream, dir, sample_rate, channels, precision, encoding));
+
+ if (precision != AUDIO_PRECISION_16)
+ {
+ cmn_err (CE_WARN, "Sample size must be 16 bits.\n");
+ return AUDIO_FAILURE;
+ }
+
+ if (channels != AUDIO_CHANNELS_STEREO)
+ {
+ cmn_err (CE_WARN, "Channels must be stereo.\n");
+ return AUDIO_FAILURE;
+ }
+
+ if (encoding != AUDIO_ENCODING_LINEAR)
+ {
+ cmn_err (CE_WARN, "Channels must be stereo.\n");
+ return AUDIO_FAILURE;
+ }
+
+ devc->sample_rate = sample_rate;
+
+ return AUDIO_SUCCESS;
+}
+
+static int
+fill_play_buf (sadasupport_devc * devc)
+{
+ int rs;
+ int dev;
+ dmap_p dmap;
+ adev_p adev;
+ unsigned char *buf;
+ int samples, i;
+ oss_native_word flags;
+
+ dev = devc->oss_audiodev;
+
+ adev = audio_engines[dev];
+ dmap = adev->dmap_out;
+
+ if (dmap->dmabuf == NULL)
+ {
+ cmn_err (CE_WARN, "Dmabuf==NULL\n");
+ return AUDIO_FAILURE;
+ }
+
+ MUTEX_ENTER (dmap->mutex, flags);
+
+ samples = dmap->fragment_size / 2; /* Number of 16 bit samples */
+
+ buf = dmap->dmabuf + devc->play_frag * dmap->fragment_size;
+
+ if (dmap->nfrags == 0)
+ {
+ cmn_err (CE_WARN, "Nfrags==0\n");
+ MUTEX_EXIT (dmap->mutex, flags);
+ return AUDIO_FAILURE;
+ }
+
+ rs = am_get_audio (devc->audio_handle, buf, AUDIO_NO_CHANNEL, samples);
+
+ if (devc->mute || rs == 0) /* Device paused or muted */
+ {
+ memset (buf, 0, dmap->fragment_size);
+ }
+ else
+ {
+ /* Perform byte swapping (if necessary) */
+ if (do_byteswap)
+ for (i = 0; i < samples * 2; i += 2)
+ {
+ unsigned char tmp;
+
+ tmp = buf[i];
+ buf[i] = buf[i + 1];
+ buf[i + 1] = tmp;
+ }
+ }
+
+ devc->play_frag = (devc->play_frag + 1) % dmap->nfrags;
+ dmap->user_counter += dmap->fragment_size;
+ MUTEX_EXIT (dmap->mutex, flags);
+
+ return rs;
+}
+
+/*ARGSUSED*/
+static int
+sadasupport_ad_start_play (audiohdl_t ahandle, int stream)
+{
+ int dev;
+ dmap_p dmap;
+ adev_p adev;
+
+ dev = devc->oss_audiodev;
+
+ if (dev < 0 || dev >= num_audio_engines)
+ {
+ cmn_err (CE_CONT, "Bad oss_audiodev %d\n", dev);
+ return AUDIO_FAILURE;
+ }
+
+ adev = audio_engines[dev];
+ dmap = adev->dmap_out;
+
+ mutex_enter (&devc->inst_lock);
+/*
+ * Already playing?
+ */
+ if (devc->start_flags & PCM_ENABLE_OUTPUT)
+ {
+ mutex_exit (&devc->inst_lock);
+ return 0; /* All buffers are full at this moment */
+ }
+
+ DDB (cmn_err (CE_CONT, "sadasupport_ad_start_play(stream=%d)\n", stream));
+
+/*
+ * Skip the first fragment (fill with silence) to avoid underruns
+ */
+ devc->play_frag = 1;
+ dmap->user_counter = dmap->fragment_size;
+
+/*
+ * Trigger the play engine
+ */
+ dmap->dma_mode = PCM_ENABLE_OUTPUT;
+ devc->start_flags &= ~PCM_ENABLE_OUTPUT;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETTRIGGER,
+ (ioctl_arg) & devc->start_flags);
+ devc->start_flags |= PCM_ENABLE_OUTPUT;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETTRIGGER,
+ (ioctl_arg) & devc->start_flags);
+
+ //dmap->user_counter += dmap->fragment_size;
+ devc->audios_defaults.play.buffer_size = dmap->fragment_size;
+ devc->ad_info.ad_play.ad_bsize = dmap->fragment_size;
+
+ mutex_exit (&devc->inst_lock);
+ return fill_play_buf (devc);
+}
+
+/*ARGSUSED*/
+static void
+sadasupport_ad_stop_play (audiohdl_t ahandle, int stream)
+{
+ DDB (cmn_err (CE_CONT, "sadasupport_ad_stop_play (stream=%d)\n", stream));
+ mutex_enter (&devc->inst_lock);
+ devc->start_flags &= ~PCM_ENABLE_OUTPUT;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETTRIGGER,
+ (ioctl_arg) & devc->start_flags);
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_HALT_OUTPUT,
+ (ioctl_arg) NULL);
+ mutex_exit (&devc->inst_lock);
+}
+
+static void
+sadasupport_ad_pause_play (audiohdl_t ahandle, int stream)
+{
+ DDB (cmn_err (CE_CONT, "sadasupport_ad_pause_play\n"));
+
+ sadasupport_ad_stop_play (ahandle, stream);
+}
+
+/*ARGSUSED*/
+static int
+sadasupport_ad_start_record (audiohdl_t ahandle, int stream)
+{
+ int dev;
+ dmap_p dmap;
+ adev_p adev;
+
+ dev = devc->oss_audiodev;
+
+ if (dev < 0 || dev >= num_audio_engines)
+ {
+ cmn_err (CE_CONT, "Bad oss_audiodev %d\n", dev);
+ return AUDIO_FAILURE;
+ }
+
+ mutex_enter (&devc->inst_lock);
+ adev = audio_engines[dev];
+ dmap = adev->dmap_in;
+
+/*
+ * Already Recording?
+ */
+ if (devc->start_flags & PCM_ENABLE_INPUT)
+ {
+ mutex_exit (&devc->inst_lock);
+ return AUDIO_SUCCESS; /* All buffers are full at this moment */
+ }
+
+ DDB (cmn_err (CE_CONT, "sadasupport_ad_start_record(stream=%d)\n", stream));
+
+/*
+ * Skip the first fragment (fill with silence) to avoid underruns
+ */
+ devc->rec_frag = 0;
+ dmap->user_counter = 0;
+
+/*
+ * Trigger the rec engine
+ */
+ dmap->dma_mode = PCM_ENABLE_INPUT;
+ devc->start_flags &= ~PCM_ENABLE_INPUT;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETTRIGGER,
+ (ioctl_arg) & devc->start_flags);
+ devc->start_flags |= PCM_ENABLE_INPUT;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETTRIGGER,
+ (ioctl_arg) & devc->start_flags);
+
+ devc->audios_defaults.record.buffer_size = dmap->fragment_size;
+ devc->ad_info.ad_record.ad_bsize = dmap->fragment_size;
+
+ mutex_exit (&devc->inst_lock);
+ return AUDIO_SUCCESS;
+}
+
+/*ARGSUSED*/
+static void
+sadasupport_ad_stop_record (audiohdl_t ahandle, int stream)
+{
+ DDB (cmn_err (CE_CONT, "sadasupport_ad_stop_record(stream=%d)\n", stream));
+ mutex_enter (&devc->inst_lock);
+ devc->start_flags &= ~PCM_ENABLE_INPUT;
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_SETTRIGGER,
+ (ioctl_arg) & devc->start_flags);
+ oss_audio_ioctl (devc->oss_audiodev, NULL, SNDCTL_DSP_HALT_INPUT,
+ (ioctl_arg) NULL);
+ mutex_exit (&devc->inst_lock);
+}
+
+static int
+sadasupport_init_state (sadasupport_devc * devc, dev_info_t * dip)
+{
+ int rints = 175;
+ int pints = 175;
+ int cdrom;
+ int mode;
+
+ devc->vol_bits_mask = 5;
+
+ cdrom = ddi_prop_get_int (DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "cdrom", 0);
+
+ /* get the mode from the .conf file */
+ if (ddi_prop_get_int (DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "mixer-mode", 1))
+ {
+ mode = AM_MIXER_MODE;
+ }
+ else
+ {
+ mode = AM_COMPAT_MODE;
+ }
+
+ /* fill in the device default state */
+ devc->audios_defaults.play.sample_rate = AUDIOS_DEFAULT_SR;
+ devc->audios_defaults.play.channels = AUDIOS_DEFAULT_CH;
+ devc->audios_defaults.play.precision = AUDIOS_DEFAULT_PREC;
+ devc->audios_defaults.play.encoding = AUDIOS_DEFAULT_ENC;
+ devc->audios_defaults.play.gain = AUDIOS_DEFAULT_PGAIN;
+ devc->audios_defaults.play.port = AUDIO_SPEAKER | AUDIO_LINE_OUT;
+ devc->audios_defaults.play.avail_ports = AUDIO_SPEAKER | AUDIO_LINE_OUT;
+ devc->audios_defaults.play.mod_ports = AUDIO_SPEAKER | AUDIO_LINE_OUT;
+ devc->audios_defaults.play.buffer_size = AUDIOS_BUFFSIZE;
+ devc->audios_defaults.play.balance = AUDIOS_DEFAULT_BAL;
+
+ devc->audios_defaults.record.sample_rate = AUDIOS_DEFAULT_SR;
+ devc->audios_defaults.record.channels = AUDIOS_DEFAULT_CH;
+ devc->audios_defaults.record.precision = AUDIOS_DEFAULT_PREC;
+ devc->audios_defaults.record.encoding = AUDIOS_DEFAULT_ENC;
+ devc->audios_defaults.record.gain = AUDIOS_DEFAULT_PGAIN;
+ devc->audios_defaults.record.port = AUDIO_MICROPHONE;
+ devc->audios_defaults.record.avail_ports =
+ AUDIO_MICROPHONE | AUDIO_LINE_IN | AUDIO_CD;
+ devc->audios_defaults.record.mod_ports =
+ AUDIO_MICROPHONE | AUDIO_LINE_IN | AUDIO_CD;
+ devc->audios_defaults.record.buffer_size = AUDIOS_BUFFSIZE;
+ devc->audios_defaults.record.balance = AUDIOS_DEFAULT_BAL;
+
+ devc->audios_defaults.monitor_gain = AUDIOS_DEFAULT_MONITOR_GAIN;
+ devc->audios_defaults.output_muted = B_FALSE;
+ devc->audios_defaults.ref_cnt = B_FALSE;
+ devc->audios_defaults.hw_features =
+ AUDIO_HWFEATURE_DUPLEX | AUDIO_HWFEATURE_PLAY |
+ AUDIO_HWFEATURE_IN2OUT | AUDIO_HWFEATURE_RECORD;
+ devc->audios_defaults.sw_features = AUDIO_SWFEATURE_MIXER;
+
+ if (cdrom)
+ {
+ devc->audios_defaults.record.avail_ports |= AUDIO_CD;
+ devc->audios_defaults.record.mod_ports |= AUDIO_CD;
+ }
+
+#if 0
+ devc->audios_psample_rate = devc->audios_defaults.play.sample_rate;
+ devc->audios_pchannels = devc->audios_defaults.play.channels;
+ devc->audios_pprecision = devc->audios_defaults.play.precision;
+ devc->audios_csample_rate = devc->audios_defaults.record.sample_rate;
+ devc->audios_cchannels = devc->audios_defaults.record.channels;
+ devc->audios_cprecision = devc->audios_defaults.record.precision;
+#endif
+
+ /*
+ * fill in the ad_info structure
+ */
+ devc->ad_info.ad_mode = mode;
+ devc->ad_info.ad_int_vers = AM_VERSION;
+ devc->ad_info.ad_add_mode = NULL;
+ devc->ad_info.ad_codec_type = AM_TRAD_CODEC;
+ devc->ad_info.ad_defaults = &devc->audios_defaults;
+ devc->ad_info.ad_play_comb = sadasupport_combinations;
+ devc->ad_info.ad_rec_comb = sadasupport_combinations;
+ devc->ad_info.ad_entry = &sadasupport_entry;
+ devc->ad_info.ad_dev_info = &devc->audios_dev_info;
+ devc->ad_info.ad_diag_flags = AM_DIAG_INTERNAL_LOOP;
+ devc->ad_info.ad_diff_flags =
+ AM_DIFF_SR | AM_DIFF_CH | AM_DIFF_PREC | AM_DIFF_ENC;
+ devc->ad_info.ad_assist_flags = AM_ASSIST_MIC;
+ devc->ad_info.ad_misc_flags = AM_MISC_RP_EXCL | AM_MISC_MONO_DUP;
+ devc->ad_info.ad_translate_flags =
+ AM_MISC_8_P_TRANSLATE | AM_MISC_8_R_TRANSLATE;
+ devc->ad_info.ad_num_mics = 1;
+
+ /* play capabilities */
+ devc->ad_info.ad_play.ad_mixer_srs = sadasupport_mixer_sample_rates;
+
+ devc->ad_info.ad_play.ad_compat_srs = sadasupport_mixer_sample_rates;
+
+#ifdef SOL9
+ devc->ad_info.ad_play.ad_conv = &am_src1;
+ devc->ad_info.ad_play.ad_sr_info = sadasupport_play_sample_rates_info;
+#else
+ devc->ad_info.ad_play.ad_conv = &am_src2;
+ devc->ad_info.ad_play.ad_sr_info = NULL;
+#endif
+ devc->ad_info.ad_play.ad_chs = sadasupport_channels;
+ devc->ad_info.ad_play.ad_int_rate = pints;
+ devc->ad_info.ad_play.ad_max_chs = 32;
+ devc->ad_info.ad_play.ad_bsize = AUDIOS_BUFFSIZE;
+
+ /* record capabilities */
+ devc->ad_info.ad_record.ad_mixer_srs = sadasupport_mixer_sample_rates;
+ devc->ad_info.ad_record.ad_compat_srs = sadasupport_mixer_sample_rates;
+#ifdef SOL9
+ devc->ad_info.ad_record.ad_conv = &am_src1;
+ devc->ad_info.ad_record.ad_sr_info = sadasupport_record_sample_rates_info;
+#else
+ devc->ad_info.ad_record.ad_conv = &am_src2;
+ devc->ad_info.ad_record.ad_sr_info = NULL;
+#endif
+ devc->ad_info.ad_record.ad_chs = sadasupport_channels;
+ devc->ad_info.ad_record.ad_int_rate = rints;
+ devc->ad_info.ad_record.ad_max_chs = 32;
+ devc->ad_info.ad_record.ad_bsize = AUDIOS_BUFFSIZE;
+
+ /* fill in device info strings */
+ (void) strcpy (devc->audios_dev_info.name, AUDIOS_DEV_NAME);
+ (void) strcpy (devc->audios_dev_info.config, AUDIOS_DEV_CONFIG);
+ (void) strcpy (devc->audios_dev_info.version, AUDIOS_DEV_VERSION);
+
+#if 0
+ devc->play_buf_size = AUDIOS_SAMPR48000 * AUDIO_CHANNELS_STEREO *
+ (AUDIO_PRECISION_16 >> AUDIO_PRECISION_SHIFT) / pints;
+ devc->play_buf_size += AUDIOS_MOD_SIZE -
+ (devc->play_buf_size % AUDIOS_MOD_SIZE);
+ devc->record_buf_size = AUDIOS_SAMPR48000 * AUDIO_CHANNELS_STEREO *
+ (AUDIO_PRECISION_16 >> AUDIO_PRECISION_SHIFT) / rints;
+ devc->record_buf_size += AUDIOS_MOD_SIZE -
+ (devc->record_buf_size % AUDIOS_MOD_SIZE);
+#endif
+ return (AUDIO_SUCCESS);
+
+} /* sadasupport_init_state */
+
+int
+oss_sadasupport_attach (oss_device_t * osdev)
+{
+#ifndef SOL9
+ audio_sup_reg_data_t data;
+#endif
+ int instance;
+ /* extern struct cb_ops ossdrv_streams_cb_ops; */
+
+ sadasupport_mixer_srs[1] = sadasupport_rate; /* Set the maximum rate */
+
+ instance = ddi_get_instance (osdev->dip);
+
+ DDB (cmn_err (CE_CONT, "sadasupport_attach\n"));
+
+ if (devc != NULL)
+ {
+ cmn_err (CE_WARN, "Multiple instances are not permitted\n");
+ return 0;
+ }
+
+ devc = PMALLOC (osdev, sizeof (*devc));
+ devc->osdev = osdev;
+ devc->oss_audiodev = -1;
+ devc->start_flags = 0;
+ mutex_init (&devc->inst_lock, NULL, MUTEX_DRIVER, NULL);
+
+ osdev->devc = devc;
+
+#ifdef SOL9
+ if ((devc->audio_handle =
+ audio_sup_attach (osdev->dip, DDI_ATTACH)) == NULL)
+ {
+ audio_sup_log (NULL, CE_WARN,
+ "!%s%d: attach() audio_sup_attach () failed",
+ DRIVER_NICK, instance);
+ return 0;
+ }
+ DDB (cmn_err (CE_CONT, "audio_sup_attach() OK, handle=%p\n",
+ devc->audio_handle));
+#else
+ data.asrd_version = AUDIOSUP_VERSION;
+ data.asrd_key = NULL;
+
+ if ((devc->audio_handle = audio_sup_register (osdev->dip, &data)) == NULL)
+ {
+ audio_sup_log (NULL, CE_WARN,
+ "!%s%d: attach() audio_sup_register() failed",
+ DRIVER_NICK, instance);
+ return 0;
+ }
+ DDB (cmn_err (CE_CONT, "audio_sup_register() OK, handle=%x\n",
+ devc->audio_handle));
+#endif
+ /* Save private data */
+ audio_sup_set_private (devc->audio_handle, devc);
+
+ if ((sadasupport_init_state (devc, osdev->dip)) != AUDIO_SUCCESS)
+ {
+ audio_sup_log (devc->audio_handle, CE_WARN,
+ "!attach() init state structure failed");
+ return 0;
+ }
+
+ /* call the mixer attach() routine */
+ if (am_attach (devc->audio_handle, DDI_ATTACH, &devc->ad_info) !=
+ AUDIO_SUCCESS)
+ {
+ audio_sup_log (devc->audio_handle, CE_WARN,
+ "!attach() am_attach() failed");
+ return 0;
+ }
+
+ oss_register_device (osdev, "SADA compatibility layer");
+ ddi_report_dev (osdev->dip);
+
+/*
+ * Take a copy of the callback options and replace the open/close
+ * entry points with our own version.
+ */
+
+ return 1;
+}
+
+int
+oss_sadasupport_detach (oss_device_t * osdev)
+{
+ /* int instance; */
+ sadasupport_devc *devc = osdev->devc;
+
+ if (devc != NULL && devc->audio_busy)
+ return 0;
+
+ /* instance = ddi_get_instance (osdev->dip); */
+
+#if 0
+ /* stop DMA engines */
+ mutex_enter (&devc->inst_lock);
+ sadasupport_stop_dma (devc);
+ mutex_exit (&devc->inst_lock);
+
+ /* remove the interrupt handler */
+ ddi_remove_intr (dip, 0, devc->intr_iblock);
+
+ /* free DMA memory */
+ sadasupport_free_sample_buf (devc, &devc->play_buf);
+ sadasupport_free_sample_buf (devc, &devc->record_buf);
+
+ /* free the kernel statistics structure */
+ if (devc->audios_ksp)
+ {
+ kstat_delete (devc->audios_ksp);
+ }
+#endif
+ /* detach audio mixer */
+ (void) am_detach (devc->audio_handle, DDI_DETACH);
+
+ /*
+ * call the audio support module's detach routine to remove this
+ * driver completely from the audio driver architecture.
+ */
+#ifdef SOL9
+ (void) audio_sup_detach (devc->audio_handle, DDI_DETACH);
+#else
+ (void) audio_sup_unregister (devc->audio_handle);
+#endif
+ mutex_destroy (&devc->inst_lock);
+ devc = NULL;
+
+ return 1;
+}
diff --git a/kernel/drv/oss_sadasupport/oss_sadasupport.man b/kernel/drv/oss_sadasupport/oss_sadasupport.man
new file mode 100644
index 0000000..4cce53e
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/oss_sadasupport.man
@@ -0,0 +1,26 @@
+NAME
+oss_sadasupport - Open Sound System to Sun "devaudio" converter driver.
+
+DESCRIPTION
+Open Sound System driver Solaris "devaudio" or "SADA" compatibility.
+This driver is a shim driver between SADA's audio core and amsrc2 (mixer)
+and the OSS audio core. Currently playback, recording and mixer controls
+of SADA/devaudio are supported by this driver. This driver essentially
+translates between SADA audio and OSS audio. It relies on SADA to keep
+track of complete audio information and then takes that information and
+translates it into OSS API. This way, OSS drivers can achieve a 99.9%
+emulation of SADA APIs.
+
+OPTIONS
+No configuration options defined for the current version.
+
+KNOWN PROBLEMS
+Mixer volume control (/dev/audioctl) emulation is very limited. It is only
+possible to change the playback volume. Use native OSS mixers such as
+ossxmix(1) for volume control and control panel functions.
+
+FILES
+CONFIGFILEPATH/oss_sadasupport.conf Device configuration file
+
+AUTHOR
+4Front Technologies
diff --git a/kernel/drv/oss_sadasupport/sadasupport_sol9.h b/kernel/drv/oss_sadasupport/sadasupport_sol9.h
new file mode 100644
index 0000000..6bf7518
--- /dev/null
+++ b/kernel/drv/oss_sadasupport/sadasupport_sol9.h
@@ -0,0 +1,187 @@
+/*
+ * Purpose: Solaris 9 compatible version of sadasupport_open/close
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+static int
+sadasupport_open (queue_t * q, dev_t * devp, int flag, int sflag,
+ cred_t * credp)
+{
+ int retval, i;
+ int tmpdev;
+ int dev = *devp;
+ char *cmd;
+ unsigned int bl_flags = 0;
+ int oss_mode = 0;
+#ifndef SOL9
+ extern void oss_forceload_drivers (int dev, cred_t * cred_p);
+#endif
+
+ DDB (cmn_err
+ (CE_CONT, "sadasupport_open(q=%x, dev=%x, flag=%x, sflag=%x)\n", q,
+ dev, flag, sflag));
+
+ cmd = oss_get_procname ();
+ DDB (cmn_err (CE_CONT, "Command %s\n", cmd));
+
+ if (devc == NULL)
+ return EIO;
+
+ oss_mode = OPEN_READWRITE;
+
+ mutex_enter (&devc->inst_lock);
+
+ if (devc->audio_busy++ == 0)
+ {
+ mutex_exit (&devc->inst_lock);
+
+ tmp_file.acc_flags = 0;
+ tmp_file.mode = oss_mode;
+
+ tmpdev = 0;
+ devc->audio_mode = tmp_file.mode;
+#if 0
+ DDB (cmn_err (CE_CONT, "Opening OSS audio device file %d (mode=%x)\n",
+ devc->masterdev, tmp_file.mode));
+
+ if (devc->masterdev >= 0 && devc->masterdev < num_audio_devfiles)
+#endif
+ {
+ /* Open /dev/dsp# */
+ tmp_file.mode = oss_mode = OPEN_READ | OPEN_WRITE;
+ if ((retval =
+ oss_audio_open_devfile (0, OSS_DEV_DSP,
+ &tmp_file, 1, OF_DEVAUDIO,
+ &tmpdev)) < 0)
+ {
+ mutex_enter (&devc->inst_lock);
+ devc->audio_busy = 0;
+ mutex_exit (&devc->inst_lock);
+ return -retval;
+ }
+ }
+#if 0
+ else
+
+ {
+ /* Open /dev/dsp */
+
+ if ((retval =
+ oss_open_vdsp (0, OSS_DEV_VDSP, &tmp_file, 1, OF_DEVAUDIO,
+ &tmpdev)) < 0)
+ {
+ mutex_enter (&devc->inst_lock);
+ devc->audio_busy = 0;
+ mutex_exit (&devc->inst_lock);
+ return -retval;
+ }
+ }
+#endif
+ DDB (cmn_err
+ (CE_CONT, "Opened OSS audio engine %d, minor=%d\n", retval,
+ tmpdev));
+
+ devc->oss_audiodev = retval;
+
+ if (tmp_file.mode & OPEN_READ)
+ audio_engines[retval]->dmap_in->audio_callback = input_callback;
+ if (tmp_file.mode & OPEN_WRITE)
+ audio_engines[retval]->dmap_out->audio_callback = output_callback;
+ strcpy (audio_engines[retval]->cmd, "SADA");
+ strcpy (audio_engines[retval]->label, "SADA");
+ audio_engines[retval]->pid = 0;
+
+ if ((retval = setup_device (devc)) != AUDIO_SUCCESS)
+ {
+ cmn_err (CE_NOTE, "setup_device failed\n");
+ mutex_enter (&devc->inst_lock);
+ if (--devc->audio_busy == 0)
+ {
+ mutex_exit (&devc->inst_lock);
+ oss_audio_release (devc->oss_audiodev, &tmp_file);
+ }
+ else
+ mutex_exit (&devc->inst_lock);
+
+ return EIO;
+ }
+ }
+ else
+ {
+ if (oss_mode & ~devc->audio_mode)
+ {
+ cmn_err (CE_NOTE, "Conflicting access modes\n");
+
+ if (--devc->audio_busy == 0)
+ {
+ mutex_exit (&devc->inst_lock);
+ oss_audio_release (devc->oss_audiodev, &tmp_file);
+ return EBUSY;
+ }
+
+ mutex_exit (&devc->inst_lock);
+ return EBUSY;
+ }
+
+ mutex_exit (&devc->inst_lock);
+
+ }
+
+ DDB (cmn_err (CE_CONT, "Open count %d\n", devc->audio_busy));
+
+ DDB (cmn_err
+ (CE_CONT, "audio_sup_open(q=%x, dev=%x, flag=%x, sflag=%x)\n", q, dev,
+ flag, sflag));
+ if ((retval = audio_sup_open (q, devp, flag, sflag, credp)) != 0)
+ {
+ cmn_err (CE_NOTE, "audio_sup_open() returned %d\n", retval);
+ mutex_enter (&devc->inst_lock);
+ if (--devc->audio_busy == 0)
+ {
+ mutex_exit (&devc->inst_lock);
+ oss_audio_release (devc->oss_audiodev, &tmp_file);
+ }
+ else
+ mutex_exit (&devc->inst_lock);
+ }
+
+ return retval;
+}
+
+static int
+sadasupport_close (queue_t * q, int flag, cred_t * credp)
+{
+ int retval, count;
+
+ DDB (cmn_err (CE_CONT, "sadasupport_close(q=%x, flag=%x)\n", q, flag));
+
+ if (!devc->audio_busy)
+ cmn_err (CE_WARN, "Close while not busy.\n");
+
+ retval = audio_sup_close (q, flag, credp);
+
+ mutex_enter (&devc->inst_lock);
+ count = --devc->audio_busy;
+ mutex_exit (&devc->inst_lock);
+
+ DDB (cmn_err (CE_CONT, "Open count (close) %d\n", count));
+ if (count == 0)
+ {
+ DDB (cmn_err
+ (CE_CONT, "Closing OSS audiodev %d\n", devc->oss_audiodev));
+ oss_audio_release (devc->oss_audiodev, &tmp_file);
+ devc->audio_mode = 0;
+ }
+
+ return retval;
+}