2
* Purpose: Client/server audio device pair for oss_userdev
4
* This file implements the actual client/server device pair. There will be
5
* separate oss_userdev instance for each process that has opened the
10
* This file is part of Open Sound System.
12
* Copyright (C) 4Front Technologies 1996-2008.
14
* This this source file is released under GPL v2 license (no other versions).
15
* See the COPYING file included in the main directory of this source
16
* distribution for the license terms and conditions.
20
#include "oss_userdev_cfg.h"
21
#include <oss_userdev_exports.h>
23
static void userdev_free_device_pair (userdev_devc_t *devc);
25
extern int userdev_visible_clientnodes;
28
transfer_audio (userdev_portc_t * server_portc, dmap_t * dmap_from,
31
int l = dmap_from->fragment_size;
32
unsigned char *fromp, *top;
34
if (dmap_to->fragment_size != l)
36
cmn_err (CE_WARN, "Fragment size mismatch (%d != %d)\n",
37
dmap_to->fragment_size, l);
39
/* Perform emergency stop */
40
server_portc->input_triggered = 0;
41
server_portc->output_triggered = 0;
42
server_portc->peer->input_triggered = 0;
43
server_portc->peer->output_triggered = 0;
48
dmap_from->dmabuf + (dmap_from->byte_counter % dmap_from->bytes_in_use);
49
top = dmap_to->dmabuf + (dmap_to->byte_counter % dmap_to->bytes_in_use);
51
memcpy (top, fromp, l);
56
handle_input (userdev_portc_t * server_portc)
58
userdev_portc_t *client_portc = server_portc->peer;
60
if (client_portc->output_triggered)
62
transfer_audio (server_portc,
63
audio_engines[client_portc->audio_dev]->dmap_out,
64
audio_engines[server_portc->audio_dev]->dmap_in);
65
oss_audio_outputintr (client_portc->audio_dev, 0);
68
oss_audio_inputintr (server_portc->audio_dev, 0);
72
handle_output (userdev_portc_t * server_portc)
74
userdev_portc_t *client_portc = server_portc->peer;
76
if (client_portc->input_triggered)
78
transfer_audio (server_portc,
79
audio_engines[server_portc->audio_dev]->dmap_out,
80
audio_engines[client_portc->audio_dev]->dmap_in);
81
oss_audio_inputintr (client_portc->audio_dev, 0);
84
oss_audio_outputintr (server_portc->audio_dev, 0);
91
* This timer callback routine will get called 100 times/second. It handles
92
* movement of audio data between the client and server sides.
94
userdev_portc_t *server_portc = pc;
95
userdev_devc_t *devc = server_portc->devc;
96
int tmout = devc->poll_ticks;
101
devc->timeout_id = 0; /* No longer valid */
103
if (server_portc->input_triggered)
104
handle_input (server_portc);
106
if (server_portc->output_triggered)
107
handle_output (server_portc);
109
/* Retrigger timer callback */
110
if (server_portc->input_triggered || server_portc->output_triggered)
111
devc->timeout_id = timeout (userdev_cb, server_portc, tmout);
115
userdev_check_input (int dev)
117
userdev_portc_t *portc = audio_engines[dev]->portc;
118
if (!portc->peer->output_triggered)
120
return OSS_ECONNRESET;
126
userdev_check_output (int dev)
128
userdev_portc_t *portc = audio_engines[dev]->portc;
130
if (!portc->peer->input_triggered)
132
return OSS_ECONNRESET;
135
if (portc->peer->open_mode == 0)
141
setup_sample_format (userdev_portc_t * portc)
144
userdev_devc_t *devc = portc->devc;
145
int fragsize, frame_size;
147
frame_size = devc->channels * devc->fmt_bytes;
151
fragsize = (devc->rate * frame_size * devc->poll_ticks) / OSS_HZ; /* Number of bytes/fragment */
152
devc->rate = fragsize * 100 / frame_size;
154
/* Setup the server side */
155
adev = audio_engines[portc->audio_dev];
156
adev->min_block = adev->max_block = fragsize;
158
/* Setup the client side */
159
adev = audio_engines[portc->peer->audio_dev];
160
adev->min_block = adev->max_block = fragsize;
162
adev->max_rate = adev->min_rate = devc->rate;
163
adev->iformat_mask = devc->fmt;
164
adev->oformat_mask = devc->fmt;
165
adev->xformat_mask = devc->fmt;
166
adev->min_channels = adev->max_channels = devc->channels;
170
userdev_server_set_rate (int dev, int arg)
172
userdev_portc_t *portc = audio_engines[dev]->portc;
173
userdev_devc_t *devc = audio_engines[dev]->devc;
174
adev_t *client_adev = audio_engines[portc->peer->audio_dev];
179
if (portc->peer->input_triggered || portc->peer->output_triggered)
187
/* Force the sample rate to be multiple of 100 */
188
arg = (arg / 100) * 100;
192
client_adev->min_rate = arg;
193
client_adev->max_rate = arg;
195
setup_sample_format (portc);
197
return devc->rate = arg;
202
userdev_client_set_rate (int dev, int arg)
204
userdev_devc_t *devc = audio_engines[dev]->devc;
210
userdev_server_set_channels (int dev, short arg)
212
userdev_portc_t *portc = audio_engines[dev]->portc;
213
userdev_devc_t *devc = audio_engines[dev]->devc;
214
adev_t *client_adev = audio_engines[portc->peer->audio_dev];
217
return devc->channels;
219
if (portc->peer->input_triggered || portc->peer->output_triggered)
220
return devc->channels;
224
if (arg > MAX_CHANNELS)
227
devc->channels = arg;
228
client_adev->min_channels=client_adev->max_channels=arg;
230
setup_sample_format (portc);
232
return devc->channels;
237
userdev_client_set_channels (int dev, short arg)
239
userdev_devc_t *devc = audio_engines[dev]->devc;
241
return devc->channels; /* Server side channels */
245
userdev_server_set_format (int dev, unsigned int arg)
247
userdev_devc_t *devc = audio_engines[dev]->devc;
248
userdev_portc_t *portc = audio_engines[dev]->portc;
249
adev_t *client_adev = audio_engines[portc->peer->audio_dev];
254
if (portc->peer->input_triggered || portc->peer->output_triggered)
267
default: /* Unsupported format */
275
client_adev->oformat_mask = arg;
276
client_adev->iformat_mask = arg;
278
setup_sample_format (portc);
285
userdev_client_set_format (int dev, unsigned int arg)
287
userdev_devc_t *devc = audio_engines[dev]->devc;
289
return devc->fmt; /* Server side sample format */
292
static void userdev_trigger (int dev, int state);
295
userdev_reset (int dev)
297
userdev_trigger (dev, 0);
302
userdev_server_open (int dev, int mode, int open_flags)
304
userdev_portc_t *portc = audio_engines[dev]->portc;
305
userdev_devc_t *devc = audio_engines[dev]->devc;
306
oss_native_word flags;
308
if (portc == NULL || portc->peer == NULL)
311
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
313
if (portc->open_mode)
315
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
319
portc->open_mode = mode;
321
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
330
userdev_client_open (int dev, int mode, int open_flags)
332
userdev_portc_t *portc = audio_engines[dev]->portc;
333
userdev_devc_t *devc = audio_engines[dev]->devc;
334
oss_native_word flags;
336
if (portc == NULL || portc->peer == NULL)
339
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
341
if (portc->open_mode)
343
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
347
portc->open_mode = mode;
350
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
355
wipe_audio_buffers(userdev_devc_t *devc)
358
* Write silence to the audio buffers when only one of the sides
359
* is open. This prevents the device from looping the last fragments
360
* written to the device.
364
dmap = audio_engines[devc->client_portc.audio_dev]->dmap_out;
365
if (dmap != NULL && dmap->dmabuf != NULL)
366
memset(dmap->dmabuf, 0, dmap->buffsize);
368
dmap = audio_engines[devc->client_portc.audio_dev]->dmap_in;
369
if (dmap != NULL && dmap->dmabuf != NULL)
370
memset(dmap->dmabuf, 0, dmap->buffsize);
372
dmap = audio_engines[devc->server_portc.audio_dev]->dmap_out;
373
if (dmap != NULL && dmap->dmabuf != NULL)
374
memset(dmap->dmabuf, 0, dmap->buffsize);
376
dmap = audio_engines[devc->server_portc.audio_dev]->dmap_in;
377
if (dmap != NULL && dmap->dmabuf != NULL)
378
memset(dmap->dmabuf, 0, dmap->buffsize);
383
userdev_server_close (int dev, int mode)
385
userdev_portc_t *portc = audio_engines[dev]->portc;
386
userdev_devc_t *devc = audio_engines[dev]->devc;
387
oss_native_word flags;
390
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
391
portc->open_mode = 0;
393
/* Stop the client side because there is no server */
394
portc->peer->input_triggered = 0;
395
portc->peer->output_triggered = 0;
396
open_count = --devc->open_count;
399
userdev_free_device_pair (devc);
401
wipe_audio_buffers(devc);
402
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
407
userdev_client_close (int dev, int mode)
409
userdev_portc_t *portc = audio_engines[dev]->portc;
410
userdev_devc_t *devc = audio_engines[dev]->devc;
411
oss_native_word flags;
414
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
415
portc->open_mode = 0;
417
open_count = --devc->open_count;
420
userdev_free_device_pair (devc);
422
wipe_audio_buffers(devc);
424
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
429
userdev_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
433
case SNDCTL_GETLABEL:
436
* Return an empty string so that this feature can be tested.
437
* Complete functionality is to be implemented later.
439
oss_label_t *s = (oss_label_t *) arg;
440
memset (s, 0, sizeof (oss_label_t));
448
* Return an empty string so that this feature can be tested.
449
* Complete functionality is to be implemented later.
451
oss_longname_t *s = (oss_longname_t *) arg;
452
memset (s, 0, sizeof (oss_longname_t));
462
set_adev_name(int dev, const char *name)
464
adev_t *adev = audio_engines[dev];
466
strcpy(adev->name, name);
468
#ifdef CONFIG_OSS_VMIX
469
if (adev->vmix_mixer != NULL)
470
vmix_change_devnames(adev->vmix_mixer, name);
476
create_instance(int dev, userdev_create_t *crea)
478
userdev_devc_t *devc = audio_engines[dev]->devc;
481
devc->match_method = crea->match_method;
482
devc->match_key = crea->match_key;
483
devc->create_flags = crea->flags;
485
devc->poll_ticks = (crea->poll_interval * OSS_HZ) / 1000;
487
if (devc->poll_ticks < 1)
488
devc->poll_ticks = 1;
490
crea->poll_interval = (1000*devc->poll_ticks) / OSS_HZ;
492
if (crea->poll_interval<1)
493
crea->poll_interval = 1;
495
crea->name[sizeof(crea->name)-1]=0; /* Overflow protectgion */
497
sprintf(tmp_name, "%s (server)", crea->name);
499
set_adev_name (devc->client_portc.audio_dev, crea->name);
500
set_adev_name (devc->server_portc.audio_dev, tmp_name);
502
strcpy(crea->devnode, audio_engines[devc->client_portc.audio_dev]->devnode);
508
userdev_set_control (int dev, int ctl, unsigned int cmd, int value)
510
userdev_devc_t *devc = mixer_devs[dev]->devc;
512
if (ctl < 0 || ctl >= USERDEV_MAX_MIXERS)
515
if (cmd == SNDCTL_MIX_READ)
517
return devc->mixer_values[ctl];
520
devc->mixer_values[ctl] = value;
521
devc->modify_counter++;
528
userdev_server_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
532
case USERDEV_CREATE_INSTANCE:
534
userdev_create_t *crea = (userdev_create_t *)arg;
536
return create_instance(dev, crea);
540
case USERDEV_GET_CLIENTCOUNT:
542
userdev_devc_t *devc = audio_engines[dev]->devc;
544
return *arg = (devc->client_portc.open_mode != 0);
549
* Mixer related ioctl calls
552
case USERDEV_CREATE_MIXGROUP:
554
userdev_devc_t *devc = audio_engines[dev]->devc;
555
userdev_mixgroup_t *grp=(userdev_mixgroup_t*)arg;
558
grp->name[sizeof(grp->name)-1]=0; /* Buffer overflow protection */
559
if ((group=mixer_ext_create_group(devc->mixer_dev, grp->parent, grp->name))<0)
566
case USERDEV_CREATE_MIXCTL:
568
userdev_devc_t *devc = audio_engines[dev]->devc;
569
userdev_mixctl_t *c=(userdev_mixctl_t*)arg;
573
c->name[sizeof(c->name)-1]=0; /* Buffer overflow protection */
575
if (c->index < 0 || c->index >= USERDEV_MAX_MIXERS)
578
if ((ctl = mixer_ext_create_control (devc->mixer_dev,
589
ext = mixer_find_ext (devc->mixer_dev, ctl);
591
ext->minvalue = c->offset;
592
ext->control_no= c->control_no;
593
ext->rgbcolor = c->rgbcolor;
595
if (c->type == MIXT_ENUM)
597
memcpy(ext->enum_present, c->enum_present, sizeof(ext->enum_present));
598
mixer_ext_set_strings (devc->mixer_dev, ctl, c->enum_choises, 0);
605
case USERDEV_GET_MIX_CHANGECOUNT:
607
userdev_devc_t *devc = audio_engines[dev]->devc;
609
return *arg = devc->modify_counter;
613
case USERDEV_SET_MIXERS:
615
userdev_devc_t *devc = audio_engines[dev]->devc;
617
memcpy(devc->mixer_values, arg, sizeof(devc->mixer_values));
618
mixer_devs[devc->mixer_dev]->modify_counter++;
619
//cmn_err(CE_CONT, "Set %08x %08x\n", devc->mixer_values[0], devc->mixer_values[1]);
624
case USERDEV_GET_MIXERS:
626
userdev_devc_t *devc = audio_engines[dev]->devc;
628
memcpy(arg, devc->mixer_values, sizeof(devc->mixer_values));
635
return userdev_ioctl(dev, cmd, arg);
640
userdev_output_block (int dev, oss_native_word buf, int count, int fragsize,
647
userdev_start_input (int dev, oss_native_word buf, int count, int fragsize,
653
userdev_trigger (int dev, int state)
655
userdev_portc_t *portc = audio_engines[dev]->portc;
656
userdev_devc_t *devc = audio_engines[dev]->devc;
658
if (portc->open_mode & OPEN_READ) /* Handle input */
660
portc->input_triggered = !!(state & OPEN_READ);
663
if (portc->open_mode & OPEN_WRITE) /* Handle output */
665
portc->output_triggered = !!(state & OPEN_WRITE);
668
if (portc->output_triggered || portc->input_triggered) /* Something is going on */
670
int tmout = devc->poll_ticks;
675
if (portc->port_type != PT_SERVER)
676
portc = portc->peer; /* Switch to the server side */
678
if (portc->output_triggered || portc->input_triggered) /* Something is going on */
679
if (devc->timeout_id == 0)
681
devc->timeout_id = timeout (userdev_cb, portc, tmout);
686
if (portc->port_type == PT_SERVER)
687
if (devc->timeout_id != 0)
689
untimeout (devc->timeout_id);
690
devc->timeout_id = 0;
697
userdev_server_prepare_for_input (int dev, int bsize, int bcount)
699
oss_native_word flags;
701
userdev_portc_t *portc = audio_engines[dev]->portc;
702
userdev_devc_t *devc = audio_engines[dev]->devc;
704
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
705
portc->input_triggered = 0;
706
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
713
userdev_server_prepare_for_output (int dev, int bsize, int bcount)
715
oss_native_word flags;
717
userdev_portc_t *portc = audio_engines[dev]->portc;
718
userdev_devc_t *devc = audio_engines[dev]->devc;
720
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
721
portc->output_triggered = 0;
722
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
729
userdev_client_prepare_for_input (int dev, int bsize, int bcount)
731
oss_native_word flags;
732
userdev_portc_t *portc = audio_engines[dev]->portc;
733
userdev_devc_t *devc = audio_engines[dev]->devc;
735
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
736
portc->input_triggered = 0;
737
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
744
userdev_client_prepare_for_output (int dev, int bsize, int bcount)
746
oss_native_word flags;
747
userdev_portc_t *portc = audio_engines[dev]->portc;
748
userdev_devc_t *devc = audio_engines[dev]->devc;
750
MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
751
portc->output_triggered = 0;
752
MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
759
userdev_alloc_buffer (int dev, dmap_t * dmap, int direction)
761
#define MY_BUFFSIZE (64*1024)
762
if (dmap->dmabuf != NULL)
764
dmap->dmabuf_phys = 0; /* Not mmap() capable */
765
dmap->dmabuf = KERNEL_MALLOC (MY_BUFFSIZE);
766
if (dmap->dmabuf == NULL)
768
dmap->buffsize = MY_BUFFSIZE;
775
userdev_free_buffer (int dev, dmap_t * dmap, int direction)
777
if (dmap->dmabuf == NULL)
779
KERNEL_FREE (dmap->dmabuf);
787
userdev_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
794
userdev_ioctl_override (int dev, unsigned int cmd, ioctl_arg arg)
797
* Purpose of this ioctl override function is to intercept mixer
798
* ioctl calls made on the client side and to hide everything
799
* outside the userdev instance from the application.
801
* Note that this ioctl is related with the client side audio device. However
802
* if /dev/mixer points to this (audio) device then all mixer acess will
803
* be redirected too. Also the vmix driver will redirect mixer/system ioctl
804
* calls to this function.
807
userdev_devc_t *devc = audio_engines[dev]->devc;
808
adev_t *adev = audio_engines[devc->client_portc.audio_dev];
812
case SNDCTL_MIX_NRMIX:
816
case SNDCTL_MIX_NREXT:
817
*arg = devc->mixer_dev;
818
return OSS_EAGAIN; /* Continue with the default handler */
824
* Fake SNDCTL_SYSINFO to report just one mixer device which is
825
* the one associated with the client.
827
oss_sysinfo *info = (oss_sysinfo *) arg;
830
if ((err=oss_mixer_ext(dev, OSS_DEV_DSP_ENGINE, cmd, arg))<0)
834
* Hide all non-oss_userdev devices
836
strcpy (info->product, "OSS (userdev)");
840
for (i = 0; i < 8; i++)
841
info->openedaudio[i] = 0;
847
case SNDCTL_MIXERINFO:
849
oss_mixerinfo *info = (oss_mixerinfo *) arg;
851
info->dev = devc->mixer_dev; /* Redirect to oss_userdev mixer */
853
if ((err=oss_mixer_ext(dev, OSS_DEV_DSP_ENGINE, cmd, arg))<0)
856
strcpy(info->name, adev->name);
857
info->card_number = 0;
861
case SNDCTL_AUDIOINFO:
862
case SNDCTL_AUDIOINFO_EX:
864
oss_audioinfo *info = (oss_audioinfo *) arg;
866
info->dev = devc->client_portc.audio_dev;
868
cmd = SNDCTL_ENGINEINFO;
870
if ((err=oss_mixer_ext(dev, OSS_DEV_DSP_ENGINE, cmd, arg))<0)
873
info->card_number = 0;
877
case SNDCTL_CARDINFO:
879
oss_card_info *info = (oss_card_info *) arg;
881
info->card = adev->card_number; /* Redirect to oss_userdev0 */
883
if ((err=oss_mixer_ext(dev, OSS_DEV_DSP_ENGINE, cmd, arg))<0)
890
case SNDCTL_MIX_EXTINFO:
892
oss_mixext *ext = (oss_mixext*)arg;
894
ext->dev = devc->mixer_dev;
896
if ((err=oss_mixer_ext(dev, OSS_DEV_DSP_ENGINE, cmd, arg))<0)
899
if (ext->type == MIXT_DEVROOT)
901
oss_mixext_root *root = (oss_mixext_root *) ext->data;
902
strncpy(root->name, adev->name, 48);
910
case SNDCTL_MIX_READ:
911
case SNDCTL_MIX_WRITE:
913
oss_mixer_value *ent = (oss_mixer_value*)arg;
915
ent->dev = devc->mixer_dev;
917
return OSS_EAGAIN; /* Redirect */
926
static audiodrv_t userdev_server_driver = {
928
userdev_server_close,
929
userdev_output_block,
931
userdev_server_ioctl,
932
userdev_server_prepare_for_input,
933
userdev_server_prepare_for_output,
940
userdev_server_set_rate,
941
userdev_server_set_format,
942
userdev_server_set_channels,
946
userdev_check_output,
947
userdev_alloc_buffer,
951
NULL /* userdev_get_buffer_pointer */
954
static audiodrv_t userdev_client_driver = {
956
userdev_client_close,
957
userdev_output_block,
960
userdev_client_prepare_for_input,
961
userdev_client_prepare_for_output,
968
userdev_client_set_rate,
969
userdev_client_set_format,
970
userdev_client_set_channels,
974
userdev_check_output,
975
userdev_alloc_buffer,
979
NULL, // userdev_get_buffer_pointer
980
NULL, // userdev_calibrate_speed
981
NULL, // userdev_sync_control
982
NULL, // userdev_prepare_to_stop
983
NULL, // userdev_get_input_pointer
984
NULL, // userdev_get_output_pointer
985
NULL, // userdev_bind
986
NULL, // userdev_setup_fragments
987
NULL, // userdev_redirect
988
userdev_ioctl_override
992
userdev_mixer_ioctl (int dev, int audiodev, unsigned int cmd, ioctl_arg arg)
995
if (cmd == SOUND_MIXER_READ_CAPS)
996
return *arg = SOUND_CAP_NOLEGACY;
999
if (cmd == SOUND_MIXER_READ_DEVMASK ||
1000
cmd == SOUND_MIXER_READ_RECMASK || cmd == SOUND_MIXER_READ_RECSRC)
1003
if (cmd == SOUND_MIXER_READ_VOLUME || cmd == SOUND_MIXER_READ_PCM)
1004
return *arg = 100 | (100 << 8);
1005
if (cmd == SOUND_MIXER_WRITE_VOLUME || cmd == SOUND_MIXER_WRITE_PCM)
1006
return *arg = 100 | (100 << 8);
1011
static mixer_driver_t userdev_mixer_driver = {
1016
install_server (userdev_devc_t * devc)
1018
userdev_portc_t *portc = &devc->server_portc;
1022
ADEV_STEREOONLY | ADEV_16BITONLY | ADEV_VIRTUAL |
1023
ADEV_FIXEDRATE | ADEV_SPECIAL | ADEV_HIDDEN | ADEV_DUPLEX;
1025
memset (portc, 0, sizeof (*portc));
1028
portc->port_type = PT_SERVER;
1030
if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
1033
"User space audio device server side",
1034
&userdev_server_driver,
1035
sizeof (audiodrv_t),
1036
opts, SUPPORTED_FORMATS, devc, -1)) < 0)
1041
audio_engines[adev]->portc = portc;
1042
audio_engines[adev]->min_rate = 5000;
1043
audio_engines[adev]->max_rate = MAX_RATE;
1044
audio_engines[adev]->min_channels = 1;
1045
audio_engines[adev]->max_channels = MAX_CHANNELS;
1046
audio_engines[adev]->vmix_mixer=NULL;
1047
strcpy(audio_engines[adev]->devnode, userdev_server_devnode);
1049
portc->audio_dev = adev;
1055
null_mixer_init(int de)
1061
userdev_create_mixer(userdev_devc_t * devc)
1063
if ((devc->mixer_dev = oss_install_mixer (OSS_MIXER_DRIVER_VERSION,
1066
"OSS userdev mixer",
1067
&userdev_mixer_driver,
1068
sizeof (mixer_driver_t), devc)) < 0)
1070
devc->mixer_dev = -1;
1073
mixer_ext_set_init_fn (devc->mixer_dev, null_mixer_init, USERDEV_MAX_MIXERS*2);
1077
install_client (userdev_devc_t * devc)
1079
userdev_portc_t *portc = &devc->client_portc;
1083
ADEV_STEREOONLY | ADEV_16BITONLY | ADEV_VIRTUAL | ADEV_DUPLEX |
1084
ADEV_FIXEDRATE | ADEV_SPECIAL | ADEV_LOOP;
1086
memset (portc, 0, sizeof (*portc));
1088
userdev_create_mixer(devc);
1091
portc->port_type = PT_CLIENT;
1093
if (!userdev_visible_clientnodes && !(devc->create_flags & USERDEV_F_VMIX_PRIVATENODE))
1095
opts |= ADEV_HIDDEN;
1098
if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
1101
"User space audio device",
1102
&userdev_client_driver,
1103
sizeof (audiodrv_t),
1104
opts, SUPPORTED_FORMATS, devc, -1)) < 0)
1109
if (!userdev_visible_clientnodes) /* Invisible client device nodes */
1110
strcpy(audio_engines[adev]->devnode, userdev_client_devnode);
1112
audio_engines[adev]->portc = portc;
1113
audio_engines[adev]->mixer_dev = devc->mixer_dev;
1114
audio_engines[adev]->min_rate = 5000;
1115
audio_engines[adev]->max_rate = MAX_RATE;
1116
audio_engines[adev]->min_channels = 1;
1117
audio_engines[adev]->max_channels = MAX_CHANNELS;
1119
portc->audio_dev = adev;
1120
#ifdef CONFIG_OSS_VMIX
1121
vmix_attach_audiodev(devc->osdev, adev, -1, 0);
1128
userdev_create_device_pair(void)
1130
int client_engine, server_engine;
1131
userdev_devc_t *devc;
1132
oss_native_word flags;
1134
if ((devc=PMALLOC(userdev_osdev, sizeof (*devc))) == NULL)
1136
memset(devc, 0, sizeof(*devc));
1138
devc->osdev = userdev_osdev;
1139
MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV);
1143
devc->fmt = AFMT_S16_NE;
1144
devc->fmt_bytes = 2;
1146
devc->poll_ticks = 10;
1148
if ((server_engine=install_server (devc)) < 0)
1149
return server_engine;
1151
if ((client_engine=install_client (devc)) < 0)
1152
return client_engine;
1154
devc->client_portc.peer = &devc->server_portc;
1155
devc->server_portc.peer = &devc->client_portc;
1158
* Insert the device to the list of available devices
1160
MUTEX_ENTER_IRQDISABLE(userdev_global_mutex, flags);
1161
devc->next_instance = userdev_active_device_list;
1162
userdev_active_device_list = devc;
1163
MUTEX_EXIT_IRQRESTORE(userdev_global_mutex, flags);
1165
return server_engine;
1169
userdev_free_device_pair (userdev_devc_t *devc)
1171
oss_native_word flags;
1173
set_adev_name(devc->client_portc.audio_dev, "User space audio device");
1174
set_adev_name(devc->server_portc.audio_dev, "User space audio device server side");
1176
MUTEX_ENTER_IRQDISABLE(userdev_global_mutex, flags);
1178
devc->match_method = 0;
1179
devc->match_key = 0;
1182
* Add to the free device pair list.
1184
devc->next_instance = userdev_free_device_list;
1185
userdev_free_device_list = devc;
1188
* Remove the device pair from the active device list.
1191
if (userdev_active_device_list == devc) /* First device in the list */
1193
userdev_active_device_list = userdev_active_device_list->next_instance;
1197
userdev_devc_t *this = userdev_active_device_list, *prev = NULL;
1199
while (this != NULL)
1203
prev->next_instance = this->next_instance; /* Remove */
1208
this = this->next_instance;
1211
MUTEX_EXIT_IRQRESTORE(userdev_global_mutex, flags);
1215
userdev_reinit_instance(userdev_devc_t *devc)
1217
if (devc->mixer_dev < 0)
1220
mixer_ext_rebuild_all (devc->mixer_dev, null_mixer_init, USERDEV_MAX_MIXERS*2);
1224
userdev_delete_device_pair(userdev_devc_t *devc)
1230
MUTEX_CLEANUP(devc->mutex);
1234
usrdev_find_free_device_pair(void)
1236
oss_native_word flags;
1237
userdev_devc_t *devc;
1239
MUTEX_ENTER_IRQDISABLE(userdev_global_mutex, flags);
1241
if (userdev_free_device_list != NULL)
1243
devc = userdev_free_device_list;
1244
userdev_free_device_list = userdev_free_device_list->next_instance;
1246
devc->next_instance = userdev_active_device_list;
1247
userdev_active_device_list = devc;
1249
MUTEX_EXIT_IRQRESTORE(userdev_global_mutex, flags);
1250
return devc->server_portc.audio_dev;
1252
MUTEX_EXIT_IRQRESTORE(userdev_global_mutex, flags);