1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 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;
}
|