summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_userdev/oss_userdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drv/oss_userdev/oss_userdev.c')
-rw-r--r--kernel/drv/oss_userdev/oss_userdev.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/kernel/drv/oss_userdev/oss_userdev.c b/kernel/drv/oss_userdev/oss_userdev.c
new file mode 100644
index 0000000..c026ff3
--- /dev/null
+++ b/kernel/drv/oss_userdev/oss_userdev.c
@@ -0,0 +1,352 @@
+/*
+ * Purpose: Kernel space support module for user land audio/mixer drivers
+ *
+ */
+/*
+ *
+ * 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_userdev_cfg.h"
+#include <oss_userdev_exports.h>
+#include "userdev.h"
+
+oss_device_t *userdev_osdev = NULL;
+static int client_dev = -1, server_dev = -1; /* Control devces */
+
+char *userdev_client_devnode = "/dev/oss/oss_userdev0/client";
+char *userdev_server_devnode = "/dev/oss/oss_userdev0/server";
+
+/*
+ * Global device lists and the mutex that protects them.
+ */
+oss_mutex_t userdev_global_mutex;
+
+/*
+ * The oss_userdev driver creates new device pairs on-demand. All device
+ * pairs that are not in use will be kept in the userdev_free_device_list
+ * (linked) list. If this list contains any entries then they will be
+ * reused whenever a new device pair is required.
+ */
+userdev_devc_t *userdev_free_device_list = NULL;
+
+/*
+ * Linked list for device pairs that have a server attached. These device
+ * pairs are available for the clients.
+ */
+userdev_devc_t *userdev_active_device_list = NULL;
+
+/*ARGSUSED*/
+static int
+userdev_server_redirect (int dev, int mode, int open_flags)
+{
+/*
+ * Purpose: This entry point is used to create new userdev instances and to redirect clients to them.
+ */
+ int server_engine;
+
+
+ if ((server_engine=usrdev_find_free_device_pair()) >= 0)
+ {
+ userdev_devc_t *devc = audio_engines[server_engine]->devc;
+
+ userdev_reinit_instance(devc);
+ return server_engine;
+ }
+
+ return userdev_create_device_pair();
+}
+
+/*ARGSUSED*/
+static int
+userdev_client_redirect (int dev, int mode, int open_flags)
+{
+/*
+ * Purpose: This entry point is used to create new userdev instances and to redirect clients to them.
+ */
+
+ userdev_devc_t *devc;
+ oss_native_word flags;
+
+ uid_t uid;
+
+ uid = oss_get_procinfo(OSS_GET_PROCINFO_UID);
+
+ MUTEX_ENTER_IRQDISABLE(userdev_global_mutex, flags);
+ devc=userdev_active_device_list;
+
+ while (devc != NULL)
+ {
+ int ok=1;
+
+ switch (devc->match_method)
+ {
+ case UD_MATCH_UID:
+ if (devc->match_key != uid) /* Wrong UID */
+ ok=0;
+ break;
+ }
+
+ if (ok)
+ {
+ MUTEX_EXIT_IRQRESTORE(userdev_global_mutex, flags);
+ return devc->client_portc.audio_dev;
+ }
+
+ devc = devc->next_instance;
+ }
+
+ MUTEX_EXIT_IRQRESTORE(userdev_global_mutex, flags);
+ return OSS_EIO;
+}
+
+/*
+ * Dummy audio driver entrypoint functions.
+ *
+ * Functionality of the control device is handled by userdev_[client|server]_redirect().
+ * The other entry points are not used for any purpose but the audio core
+ * framework expects to see them.
+ */
+/*ARGSUSED*/
+static int
+userdev_control_set_rate (int dev, int arg)
+{
+ /* Dumy routine - Not actually used */
+ return 48000;
+}
+
+/*ARGSUSED*/
+static short
+userdev_control_set_channels (int dev, short arg)
+{
+ /* Dumy routine - Not actually used */
+ return 2;
+}
+
+/*ARGSUSED*/
+static unsigned int
+userdev_control_set_format (int dev, unsigned int arg)
+{
+ /* Dumy routine - Not actually used */
+ return AFMT_S16_NE;
+}
+
+static void
+userdev_control_reset (int dev)
+{
+ /* Dumy routine - Not actually used */
+}
+
+/*ARGSUSED*/
+static int
+userdev_control_open (int dev, int mode, int open_flags)
+{
+ /* Dumy routine - Not actually used */
+ return OSS_EIO;
+}
+
+/*ARGSUSED*/
+static void
+userdev_control_close (int dev, int mode)
+{
+ /* Dumy routine - Not actually used */
+}
+
+/*ARGSUSED*/
+static int
+userdev_control_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
+{
+ /* Dumy routine - Not actually used */
+ return OSS_EINVAL;
+}
+
+/*ARGSUSED*/
+static void
+userdev_control_output_block (int dev, oss_native_word buf, int count, int fragsize,
+ int intrflag)
+{
+ /* Dumy routine - Not actually used */
+}
+
+/*ARGSUSED*/
+static void
+userdev_control_start_input (int dev, oss_native_word buf, int count, int fragsize,
+ int intrflag)
+{
+ /* Dumy routine - Not actually used */
+}
+
+/*ARGSUSED*/
+static int
+userdev_control_prepare_for_input (int dev, int bsize, int bcount)
+{
+ /* Dumy routine - Not actually used */
+ return OSS_EIO;
+}
+
+/*ARGSUSED*/
+static int
+userdev_control_prepare_for_output (int dev, int bsize, int bcount)
+{
+ /* Dumy routine - Not actually used */
+ return OSS_EIO;
+}
+
+static audiodrv_t userdev_server_control_driver = {
+ userdev_control_open,
+ userdev_control_close,
+ userdev_control_output_block,
+ userdev_control_start_input,
+ userdev_control_ioctl,
+ userdev_control_prepare_for_input,
+ userdev_control_prepare_for_output,
+ userdev_control_reset,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* trigger */
+ userdev_control_set_rate,
+ userdev_control_set_format,
+ userdev_control_set_channels,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ userdev_server_redirect
+};
+
+static audiodrv_t userdev_client_control_driver = {
+ userdev_control_open,
+ userdev_control_close,
+ userdev_control_output_block,
+ userdev_control_start_input,
+ userdev_control_ioctl,
+ userdev_control_prepare_for_input,
+ userdev_control_prepare_for_output,
+ userdev_control_reset,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* trigger */
+ userdev_control_set_rate,
+ userdev_control_set_format,
+ userdev_control_set_channels,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ userdev_client_redirect
+};
+
+static void
+attach_control_device(void)
+{
+/*
+ * Create the control device files that are used to create client/server
+ * device pairs and to redirect access to them.
+ */
+ userdev_devc_t *devc = (userdev_devc_t*)0xdeadcafe; /* This should never get referenced */
+
+ if ((client_dev = oss_install_audiodev_with_devname (OSS_AUDIO_DRIVER_VERSION,
+ userdev_osdev,
+ userdev_osdev,
+ "User space audio device client side",
+ &userdev_client_control_driver,
+ sizeof (audiodrv_t),
+ ADEV_AUTOMODE, AFMT_S16_NE, devc, -1,
+ "client")) < 0)
+ {
+ return;
+ }
+ userdev_server_devnode = audio_engines[server_dev]->devnode;
+ audio_engines[client_dev]->vmix_mixer=NULL;
+
+ if ((server_dev = oss_install_audiodev_with_devname (OSS_AUDIO_DRIVER_VERSION,
+ userdev_osdev,
+ userdev_osdev,
+ "User space audio device server side",
+ &userdev_server_control_driver,
+ sizeof (audiodrv_t),
+ ADEV_AUTOMODE, AFMT_S16_NE, devc, -1,
+ "server")) < 0)
+ {
+ return;
+ }
+ audio_engines[server_dev]->caps |= PCM_CAP_HIDDEN;
+ audio_engines[server_dev]->vmix_mixer=NULL;
+ userdev_client_devnode = audio_engines[client_dev]->devnode;
+}
+
+int
+oss_userdev_attach (oss_device_t * osdev)
+{
+ userdev_osdev = osdev;
+
+ osdev->devc = NULL;
+ MUTEX_INIT (osdev, userdev_global_mutex, MH_DRV);
+
+ oss_register_device (osdev, "User space audio driver subsystem");
+
+ attach_control_device();
+
+ return 1;
+}
+
+int
+oss_userdev_detach (oss_device_t * osdev)
+{
+ userdev_devc_t *devc;
+
+ if (oss_disable_device (osdev) < 0)
+ return 0;
+
+ devc = userdev_free_device_list;
+
+ while (devc != NULL)
+ {
+ userdev_devc_t *next = devc->next_instance;
+
+ userdev_delete_device_pair(devc);
+
+ devc = next;
+ }
+
+ oss_unregister_device (osdev);
+
+ MUTEX_CLEANUP(userdev_global_mutex);
+
+ return 1;
+}