diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/drv/oss_userdev/oss_userdev.c | |
download | oss4-1058def8e7827e56ce4a70afb4aeacb5dc44148f.tar.gz |
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/drv/oss_userdev/oss_userdev.c')
-rw-r--r-- | kernel/drv/oss_userdev/oss_userdev.c | 352 |
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; +} |