summaryrefslogtreecommitdiff
path: root/kernel/framework/sndstat
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/framework/sndstat')
-rw-r--r--kernel/framework/sndstat/.config1
-rw-r--r--kernel/framework/sndstat/oss_sndstat.c693
2 files changed, 694 insertions, 0 deletions
diff --git a/kernel/framework/sndstat/.config b/kernel/framework/sndstat/.config
new file mode 100644
index 0000000..e44f78f
--- /dev/null
+++ b/kernel/framework/sndstat/.config
@@ -0,0 +1 @@
+targetcpu=any
diff --git a/kernel/framework/sndstat/oss_sndstat.c b/kernel/framework/sndstat/oss_sndstat.c
new file mode 100644
index 0000000..82f4ff5
--- /dev/null
+++ b/kernel/framework/sndstat/oss_sndstat.c
@@ -0,0 +1,693 @@
+/*
+ * Purpose: /dev/sndstat driver
+ *
+ * Description:
+ */
+/*
+ *
+ * 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_config.h>
+#include <midi_core.h>
+
+static char *sndstat_buf = NULL;
+static int sndstat_len, sndstat_ptr;
+static volatile int sndstat_busy = 0;
+int riptide_notice = 0; /* The Riptide driver will set this to 1 */
+
+/*
+ * All kind of status messages
+ */
+#define MAX_MESSAGE 50
+static char *messages[MAX_MESSAGE];
+static int nmessages; /* # of display messages (/dev/sndstat) */
+
+static int
+put_status (const char *s)
+{
+ int l = strlen (s);
+
+ if (sndstat_len + l >= 4000)
+ return 0;
+
+ memcpy (&sndstat_buf[sndstat_len], s, l);
+ sndstat_len += l;
+
+ return 1;
+}
+
+static int
+put_status_int (unsigned int val, int radix)
+{
+ char buf[11], *rx = "%d";
+
+ if (!val)
+ return put_status ("0");
+
+ if (radix == 16)
+ rx = "%x";
+ sprintf (buf, rx, val);
+
+ return put_status (buf);
+}
+
+static void
+init_status (void)
+{
+ /*
+ * Write the status information to the sndstat_buf and update sndstat_len.
+ * There is a limit of 4000 bytes for the data.
+ */
+
+ int i, p, missing_devs = 0;
+ int notify = 0;
+ extern char *oss_license_string;
+
+ sndstat_ptr = 0;
+
+ put_status ("OSS " OSS_VERSION_STRING);
+ put_status (oss_license_string);
+ put_status (" (C) 4Front Technologies 1996-2011\n");
+
+ if (riptide_notice)
+ put_status ("RipTide Driver (C) 2000, Conexant Systems, Inc.\n");
+
+#ifdef LICENSED_VERSION
+ oss_print_license (put_status, put_status_int);
+#endif
+
+#ifdef OSS_CONFIG_OPTIONS
+ put_status ("\nSource configration options: ");
+ put_status (OSS_CONFIG_OPTIONS);
+ put_status ("\n");
+#endif
+
+#ifdef OSS_HG_INFO
+ put_status ("\nHg revision: ");
+ put_status (OSS_HG_INFO);
+ put_status ("\n");
+#endif
+
+ if (nmessages > 0)
+ {
+ put_status ("\n");
+
+ for (i = 0; i < nmessages; i++)
+ {
+ if (!put_status (messages[i]))
+ return;
+ }
+
+ put_status ("\n");
+ }
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+ {
+#if defined(__FreeBSD__)
+ extern char version[];
+#endif
+
+ put_status ("Kernel: ");
+ put_status (version);
+ put_status ("\n");
+ }
+#endif
+
+#if 0
+/*
+ * This code is obsolete and not functional at this moment.
+ */
+ if (!put_status ("\nDevice objects:\n"))
+ return;
+
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ char tmp[256];
+
+ oss_get_cardinfo (i, tmp, sizeof (tmp) - 1);
+ if (!put_status (tmp))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+#endif
+
+ if (!put_status ("\nAudio devices:\n"))
+ return;
+
+ missing_devs = 0;
+
+ if (audio_devfiles != NULL)
+ for (i = 0; i < MAX_AUDIO_DEVFILES +100 && missing_devs < 40; i++)
+ {
+ int j, d;
+#if 0
+ if (i < num_audio_devfiles)
+ if (audio_devfiles[i]->card_number != cardno)
+ {
+ put_status (" \n");
+ cardno = audio_devfiles[i]->card_number;
+ }
+#endif
+/*
+ * New device numbering scheme may have /dev/dsp# devices in different
+ * order than the order of devices in audio_devices[]. Find the right device
+ * based on the adev->real_dev number. Note that device numbering may have
+ * holes if devices have been removed after running ossdevlinks -f last time.
+ */
+ d = -1;
+ for (j = 0; j < num_audio_devfiles; j++)
+ {
+ if (audio_devfiles[j]->real_dev == i)
+ {
+ if (j != i)
+ notify = 1;
+ d = audio_devfiles[j]->audio_devfile;
+ break;
+ }
+ }
+
+ if (d == -1)
+ {
+ missing_devs++;
+ continue;
+ }
+
+ if (missing_devs > 0) /* There is a hole in numbering */
+ for (j = i - missing_devs; j < i; j++)
+ {
+ notify = 1;
+ if (!put_status_int (j, 10))
+ return;
+ if (!put_status (": (Undefined or removed device)\n"))
+ return;
+ }
+ missing_devs = 0;
+
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!audio_devfiles[d]->enabled || audio_devfiles[d]->unloaded)
+ put_status ("(");
+
+ if (!put_status (audio_devfiles[d]->name))
+ return;
+ if (!audio_devfiles[d]->enabled || audio_devfiles[d]->unloaded)
+ put_status (")");
+
+ if ((audio_devfiles[d]->flags & ADEV_DUPLEX)
+ || (audio_devfiles[d]->flags & ADEV_NOINPUT)
+ || (audio_devfiles[d]->flags & ADEV_NOOUTPUT))
+ {
+ int nn = 0;
+
+ if (!put_status (" ("))
+ return;
+
+ if (audio_devfiles[d]->flags & ADEV_NOINPUT)
+ {
+ if (nn++)
+ put_status (",");
+ if (!put_status ("OUTPUT"))
+ return;
+ }
+
+ if (audio_devfiles[d]->flags & ADEV_NOOUTPUT)
+ {
+ if (nn++)
+ put_status (",");
+ if (!put_status ("INPUT"))
+ return;
+ }
+
+ if (audio_devfiles[d]->flags & ADEV_DUPLEX)
+ {
+ if (nn++)
+ put_status (",");
+ if (!put_status ("DUPLEX"))
+ return;
+ }
+ if (!put_status (")"))
+ return;
+ }
+
+ if (!put_status ("\n"))
+ return;
+
+ {
+ adev_t *adev = audio_devfiles[d];
+ int n = 0, single = 0;
+ if (adev->next_out == NULL)
+ single = 1;
+
+ while (adev != NULL)
+ {
+ if (adev->open_mode != 0)
+ {
+ if (i < 10)
+ {
+ if (!put_status (" "))
+ return;
+ }
+ else
+ {
+ if (!put_status (" "))
+ return;
+ }
+
+ if (single)
+ {
+ put_status ("Opened ");
+ if (adev->open_mode & OPEN_READ)
+ put_status ("IN");
+ if (adev->open_mode & OPEN_WRITE)
+ put_status ("OUT");
+ put_status (" by ");
+ }
+ else
+ {
+ put_status ("Engine ");
+ put_status_int (n + 1, 10);
+ put_status (" opened ");
+ if (adev->open_mode & OPEN_READ)
+ put_status ("IN");
+ if (adev->open_mode & OPEN_WRITE)
+ put_status ("OUT");
+ put_status (" by ");
+ }
+
+ if (adev->pid != -1 || *adev->label != 0)
+ {
+ if (*adev->label != 0)
+ {
+ if (!put_status (adev->label))
+ return;
+ if (!put_status ("/"))
+ return;
+ }
+
+ put_status_int (adev->pid, 10);
+ }
+ else
+ {
+ if (!put_status ("unknown application"))
+ return;
+ }
+
+ if (!put_status (" @ "))
+ return;
+ if (!put_status_int (adev->user_parms.rate, 10))
+ return;
+ if (!put_status ("/"))
+ return;
+ if (!put_status_int (adev->hw_parms.rate, 10))
+ return;
+ if (!put_status (" Hz"))
+ return;
+
+#if 1
+ if (!put_status (" Fragment: "))
+ return;
+
+ if (!put_status (audio_show_latency (adev->engine_num)))
+ return;
+#endif
+
+ if (!put_status ("\n"))
+ return;
+
+ if (*adev->song_name != 0)
+ {
+ if (i < 10)
+ {
+ if (!put_status (" "))
+ return;
+ }
+ else
+ {
+ if (!put_status (" "))
+ return;
+ }
+
+ if (!put_status ("Song name: "))
+ return;
+ if (!put_status (adev->song_name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+ }
+
+ adev = adev->next_out;
+ n++;
+ }
+ }
+ }
+
+#ifdef CONFIG_OSS_MIDI
+ if (!put_status ("\nMIDI devices:\n"))
+ return;
+
+ missing_devs = 0;
+ for (i = 0; i < MAX_MIDI_DEV * 2 && missing_devs < 16; i++)
+ {
+ int j, d = -1;
+
+ for (j = 0; j < num_mididevs; j++)
+ if (midi_devs[j]->real_dev == i)
+ {
+ d = j;
+ if (j != i)
+ notify = 1;
+ }
+
+ if (d == -1)
+ {
+ missing_devs++;
+ continue;
+ }
+
+ for (j = i - missing_devs; j < i; j++)
+ {
+ notify = 1;
+ if (!put_status_int (j, 10))
+ return;
+ if (!put_status (": (Unknown or removed device)\n"))
+ return;
+ }
+ missing_devs = 0;
+
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!midi_devs[d]->enabled || midi_devs[d]->unloaded)
+ put_status ("(");
+ if (!put_status (midi_devs[d]->name))
+ return;
+ if (!midi_devs[d]->enabled || midi_devs[d]->unloaded)
+ put_status (")");
+ if (!put_status ("\n"))
+ return;
+
+ if (midi_devs[d]->pid != -1)
+ {
+ if (i < 10)
+ {
+ if (!put_status (" "))
+ return;
+ }
+ else
+ {
+ if (!put_status (" "))
+ return;
+ }
+ if (!put_status ("Open by "))
+ return;
+ if (!put_status_int (midi_devs[d]->pid, 10))
+ return;
+ if (*midi_devs[d]->cmd != 0)
+ {
+ if (!put_status ("/"))
+ return;
+ if (!put_status (midi_devs[d]->cmd))
+ return;
+ }
+ if (!put_status ("\n"))
+ return;
+ if (midi_devs[d]->d->ioctl)
+ {
+ oss_longname_t song_name;
+
+ if (midi_devs[d]->d->ioctl (d, SNDCTL_GETSONG,
+ (ioctl_arg) song_name) >= 0
+ && *song_name != 0)
+ {
+ if (!put_status (" Song name: "))
+ return;
+ if (!put_status (song_name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+#if 0
+ /* TODO: No timer available at this moment */
+ if (!put_status ("\nTimers:\n"))
+ return;
+
+ for (i = 0; i < oss_num_timers; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (oss_timer_devs[i]->info.name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+#endif
+
+ if (!put_status ("\nMixers:\n"))
+ return;
+
+ missing_devs = 0;
+
+ for (i = 0; i < MAX_MIXER_DEV * 2 && missing_devs < 10; i++)
+ {
+ int j, d = -1;
+
+ for (j = 0; j < num_mixers; j++)
+ if (mixer_devs[j]->real_dev == i)
+ {
+ if (j != i)
+ notify = 1;
+ d = j;
+ }
+
+ if (d == -1)
+ {
+ missing_devs++;
+ continue;
+ }
+
+ for (j = i - missing_devs; j < i; j++)
+ {
+ notify = 1;
+ if (!put_status_int (j, 10))
+ return;
+ if (!put_status (": (Uninstalled or removed device\n"))
+ return;
+ }
+ missing_devs = 0;
+
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+
+ if (!mixer_devs[d]->enabled || mixer_devs[d]->unloaded)
+ if (!put_status ("("))
+ return;
+
+ if (!put_status (mixer_devs[d]->name))
+ return;
+
+ if (!mixer_devs[d]->enabled || mixer_devs[d]->unloaded)
+ if (!put_status (")"))
+ return;
+
+ if (!put_status ("\n"))
+ return;
+ }
+
+#if 1
+ p = 0;
+ for (i = 0; i < OSS_HISTORY_SIZE; i++)
+ if (*oss_history[i] != 0)
+ p++;
+
+ if (p > 0)
+#ifdef GET_PROCESS_UID
+ if (GET_PROCESS_UID () == 0)
+#endif
+ {
+ if (!put_status ("\nHistory:\n"))
+ return;
+
+ p = oss_history_p;
+
+ for (i = 0; i < OSS_HISTORY_SIZE; i++)
+ {
+ int ix = (p + i) % OSS_HISTORY_SIZE;
+
+ if (*oss_history[ix] == 0)
+ continue;
+
+ if (!put_status (oss_history[ix]))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+ }
+#endif
+#if 0
+ if (!put_status
+ ("\n\nNOTICE! This /dev/sndstat file is obsolete - use the ossinfo command instead\n"))
+ return;
+#endif
+ if (notify)
+ {
+ if (!put_status
+ ("\n\nWARNING! Legacy device numbering in /dev/sndstat is different from actual device numbering\n"))
+ return;
+ }
+
+ put_status ("\n\nNOTICE! Device numbers shown above may be wrong.\n");
+ put_status (" Use the ossinfo command to find out the correct device names.\n");
+
+ sndstat_buf[sndstat_len] = 0;
+}
+
+void
+store_msg (char *msg)
+{
+ char *s;
+
+ if (strlen (msg) > 100 || nmessages >= MAX_MESSAGE)
+ return;
+
+ s = PMALLOC (NULL, strlen (msg) + 1);
+ if (s == NULL)
+ {
+ return;
+ }
+ strcpy (s, msg);
+ messages[nmessages++] = s;
+}
+
+static int
+read_status (uio_t * buf, int count)
+{
+ /*
+ * Return at most 'count' bytes from the sndstat_buf.
+ */
+ int l, c;
+
+ l = count;
+ c = sndstat_len - sndstat_ptr;
+
+ if (l > c)
+ l = c;
+ if (l <= 0)
+ return 0;
+
+ if (uiomove (&sndstat_buf[sndstat_ptr], l, UIO_READ, buf) != 0)
+ return OSS_EFAULT;
+ sndstat_ptr += l;
+
+ return l;
+}
+
+/*ARGSUSED*/
+static int
+sndstat_open (int dev, int dev_class, struct fileinfo *file,
+ int recursive, int open_flags, int *redirect)
+{
+ /* TODO: Concurrency control */
+ if (sndstat_busy)
+ return OSS_EBUSY;
+ sndstat_busy = 1;
+
+ if ((sndstat_buf = KERNEL_MALLOC (4096)) == NULL)
+ {
+ sndstat_busy = 0;
+ return OSS_ENOMEM;
+ }
+
+ sndstat_len = 0;
+ init_status ();
+ sndstat_ptr = 0;
+
+ return 0;
+}
+
+/*ARGSUSED*/
+static void
+sndstat_close (int dev, struct fileinfo *file)
+{
+ KERNEL_FREE (sndstat_buf);
+ sndstat_buf = NULL;
+ sndstat_busy = 0;
+}
+
+/*ARGSUSED*/
+static int
+sndstat_read (int dev, struct fileinfo *file, uio_t * buf, int count)
+{
+ int l;
+ l = read_status (buf, count);
+ return l;
+}
+
+/*ARGSUSED*/
+static int
+sndstat_write (int dev, struct fileinfo *file, uio_t * buf, int count)
+{
+/*
+ * This dummy write routine will be used for some internal management purposes
+ * in the future. At this moment it just tells the osscore module that it
+ * should permit detaching itself.
+ */
+#ifdef sun
+ extern int oss_detach_enabled;
+ oss_detach_enabled = 1;
+ return count;
+#else
+ return OSS_EIO;
+#endif
+}
+
+/*ARGSUSED*/
+static int
+sndstat_ioctl (int dev, struct fileinfo *bogus,
+ unsigned int cmd, ioctl_arg arg)
+{
+ if (cmd == OSS_GETVERSION)
+ return *arg = OSS_VERSION;
+
+ return OSS_EINVAL;
+}
+
+static oss_cdev_drv_t sndstat_cdev_drv = {
+ sndstat_open,
+ sndstat_close,
+ sndstat_read,
+ sndstat_write,
+ sndstat_ioctl
+};
+
+void
+install_sndstat (oss_device_t * osdev)
+{
+ //static int already_installed=0;
+
+ // if (!already_installed++) // TODO: Is it necessaary to prevent loading sndstat multiple times?
+ oss_install_chrdev (osdev, "sndstat", OSS_DEV_STATUS, 0, &sndstat_cdev_drv,
+ 0);
+}