source: roaraudio/libroaross/libroaross.c @ 3879:6644eb2eda37

Last change on this file since 3879:6644eb2eda37 was 3879:6644eb2eda37, checked in by phi, 14 years ago

added roardl plugin init function (mostly dummy)

File size: 49.9 KB
Line 
1//libroaross.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "roaraudio.h"
37#include "libroarlight/libroarlight.h"
38
39#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
40#if defined(__OpenBSD__) || defined(__NetBSD__)
41#include <soundcard.h>
42#else
43#include <sys/soundcard.h>
44#endif
45#include <sys/ioctl.h>
46
47#ifdef ROAR_HAVE_H_SYS_TYPES
48#include <sys/types.h>
49#endif
50
51#ifdef ROAR_HAVE_H_FCNTL
52#include <fcntl.h>
53#endif
54
55#ifdef ROAR_HAVE_H_UNISTD
56#include <unistd.h>
57#endif
58
59#include <sys/stat.h>
60#include <dlfcn.h>
61#include <stdarg.h>
62
63#if defined(RTLD_NEXT)
64#define REAL_LIBC RTLD_NEXT
65#else
66#define REAL_LIBC ((void *) -1L)
67#endif
68
69#ifndef ENOTSUP
70#define ENOTSUP ENOSYS
71#endif
72
73#ifndef O_DIRECTORY
74#define O_DIRECTORY 0
75#endif
76
77#ifndef O_LARGEFILE
78#define O_LARGEFILE 0
79#endif
80
81#ifndef O_NOATIME
82#define O_NOATIME 0
83#endif
84
85#define _O_PARA_DIR (O_RDONLY|O_WRONLY|O_RDWR)
86#define _O_PARA_IGN (O_DIRECT|O_APPEND|O_LARGEFILE|O_NOATIME|O_NOCTTY|O_TRUNC)
87
88#if defined(ROAR_OS_NETBSD) && defined(ioctl)
89#define IOCTL_IS_ALIAS
90#endif
91
92#ifdef ROAR_OS_FREEBSD
93#define mode_t int
94#endif
95
96#ifdef ROAR_OS_NETBSD
97#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
98#define map_args int __fd = fd; unsigned long int __request = com
99#elif defined(ROAR_TARGET_CYGWIN)
100#define IOCTL() int ioctl (int __fd, int __cmd, ...)
101#define map_args unsigned long int __request = __cmd; void * argp
102#define va_argp
103#define ioctl_lastarg __cmd
104#else
105#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
106#define map_args void * argp
107#define va_argp
108#define ioctl_lastarg __request
109#endif
110
111#define OSS_VOLUME_SCALE 100
112
113#define _MAX_POINTER  8
114
115// handle type:
116#define HT_NONE       0 /* Unused object */
117#define HT_STREAM     1 /* Stream with no specal handling needed */
118#define HT_MIXER      2 /* Mixer device */
119#define HT_WAVEFORM   3 /* Waveform device */
120#define HT_MIDI       4 /* MIDI device */
121#define HT_DMX        5 /* DMX512/DMX4Linux device */
122#define HT_VIO        6 /* General VIO object */
123#define HT_STATIC     7 /* Static file */
124
125struct session {
126 int refc;
127 struct roar_connection con;
128};
129
130static struct session _session = {.refc = 0};
131
132struct handle {
133 int refc; // refrence counter
134 struct session * session;
135 int type;
136 int sysio_flags;
137 struct roar_stream    stream;
138 struct roar_vio_calls stream_vio;
139 int                   stream_dir;
140 int                   stream_opened;
141 size_t                stream_buffersize;
142 size_t                readc, writec;
143 size_t                pos;
144 union {
145  struct {
146   char * data;
147   size_t len;
148  } sf;
149 } userdata;
150};
151
152static struct {
153 int     (*open)(const char *pathname, int flags, mode_t mode);
154 int     (*close)(int fd);
155 ssize_t (*write)(int fd, const void *buf, size_t count);
156 ssize_t (*read)(int fd, void *buf, size_t count);
157#ifndef IOCTL_IS_ALIAS
158 int     (*ioctl)(int d, int request, ...);
159#endif
160 off_t   (*lseek)(int fildes, off_t offset, int whence);
161 FILE   *(*fopen)(const char *path, const char *mode);
162 int     (*dup)(int oldfd);
163 int     (*dup2)(int oldfd, int newfd);
164 int     (*select)(int nfds, fd_set *readfds, fd_set *writefds,
165                   fd_set *exceptfds, struct timeval *timeout);
166 int     (*fcntl)(int fd, int cmd, ...);
167 int     (*access)(const char *pathname, int mode);
168 int     (*open64)(const char *__file, int __oflag, ...);
169 int     (*creat)(const char *pathname, mode_t mode);
170} _os;
171
172static struct {
173 struct {
174  int volume;
175  int pcm;
176  int line;
177  int line1;
178  int line2;
179  int line3;
180  int digital1;
181  int digital2;
182  int digital3;
183 } sid;
184} _mix_settings = {
185                   .sid = {
186                           .volume   = -1,
187                           .pcm      = -1,
188                           .line     =  0,
189                           .line1    =  1,
190                           .line2    =  2,
191                           .line3    =  3,
192                           .digital1 =  1,
193                           .digital2 =  2,
194                           .digital3 =  3
195                          }
196                  };
197
198static struct pointer {
199 int fh;
200 struct handle * handle;
201} _ptr[_MAX_POINTER];
202
203
204static char _sf__dev_sndstat[] =
205 "Sound Driver:RoarAudio\n"
206 "Config options: 0\n"
207 "\n"
208 "Installed drivers:\n"
209 "Type 10: RoarAudio emulation\n"
210 "\n"
211 "Card config:\n"
212 "\n"
213 "Audio devices:\n"
214 "0: RoarAudio OSS emulation (DUPLEX)\n"
215 "\n"
216 "Midi devices:\n"
217 "0: RoarAudio OSS emulation MIDI\n"
218 "\n"
219 "Timers:\n"
220 "\n"
221 "Mixers:\n"
222 "0: RoarAudio OSS emulation Mixer\n"
223;
224
225static struct devices {
226  char * prefix;
227  int type;
228  size_t len;
229  void * userdata;
230  struct handle * (*open)(const char * file, int flags, mode_t mode, struct devices * ptr);
231} _device_list[] = {
232 {"/dev/dsp*",          HT_WAVEFORM,  0, NULL, NULL},
233 {"/dev/audio*",        HT_WAVEFORM,  0, NULL, NULL},
234 {"/dev/sound/dsp*",    HT_WAVEFORM,  0, NULL, NULL},
235 {"/dev/sound/audio*",  HT_WAVEFORM,  0, NULL, NULL},
236 {"/dev/mixer*",        HT_MIXER,     0, NULL, NULL},
237 {"/dev/sound/mixer*",  HT_MIXER,     0, NULL, NULL},
238 {"/dev/midi*",         HT_MIDI,      0, NULL, NULL},
239 {"/dev/rmidi*",        HT_MIDI,      0, NULL, NULL},
240 {"/dev/sound/midi*",   HT_MIDI,      0, NULL, NULL},
241 {"/dev/sound/rmidi*",  HT_MIDI,      0, NULL, NULL},
242 {"/dev/dmx*",          HT_DMX,       0, NULL, NULL},
243 {"/dev/misc/dmx*",     HT_DMX,       0, NULL, NULL},
244 {"/dev/dmxin*",        HT_DMX,       0, NULL, NULL},
245 {"/dev/misc/dmxin*",   HT_DMX,       0, NULL, NULL},
246 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat, NULL},
247#ifdef ROAR_DEFAULT_OSS_DEV
248 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL, NULL},
249#endif
250 {NULL, HT_NONE, 0, NULL, NULL},
251};
252
253
254static int _update_nonblock (struct handle * handle);
255
256static void _init_os (void) {
257 memset(&_os, 0, sizeof(_os));
258
259 // if call roar_dl_getsym() here all applications will segfaul.
260 // why?
261
262 _os.open   = dlsym(REAL_LIBC, "open");
263 _os.close  = dlsym(REAL_LIBC, "close");
264 _os.write  = dlsym(REAL_LIBC, "write");
265 _os.read   = dlsym(REAL_LIBC, "read");
266#ifndef IOCTL_IS_ALIAS
267 _os.ioctl  = dlsym(REAL_LIBC, "ioctl");
268#endif
269 _os.lseek  = dlsym(REAL_LIBC, "lseek");
270 _os.fopen  = dlsym(REAL_LIBC, "fopen");
271 _os.dup    = dlsym(REAL_LIBC, "dup");
272 _os.dup2   = dlsym(REAL_LIBC, "dup2");
273 _os.select = dlsym(REAL_LIBC, "select");
274 _os.fcntl  = dlsym(REAL_LIBC, "fcntl");
275 _os.access = dlsym(REAL_LIBC, "access");
276 _os.open64 = dlsym(REAL_LIBC, "open64");
277 _os.creat  = dlsym(REAL_LIBC, "creat");
278}
279
280static void _init_ptr (void) {
281 int i;
282
283 for (i = 0; i < _MAX_POINTER; i++) {
284  _ptr[i].fh = -1;
285 }
286}
287
288static void _init (void) {
289 static int inited = 0;
290
291 if ( !inited ) {
292  _init_os();
293  _init_ptr();
294  roar_vio_select(NULL, 0, NULL, NULL);
295  inited++;
296 }
297}
298
299static void _find_volume_sid (struct session * session) {
300 int i;
301 int num;
302 int id[ROAR_STREAMS_MAX];
303 struct roar_stream s;
304 char name[1024];
305
306 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
307
308 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
309  return;
310 }
311
312 for (i = 0; i < num; i++) {
313  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
314   continue;
315
316  if ( s.dir != ROAR_DIR_MIXING )
317   continue;
318
319  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
320   continue;
321
322  if ( !strcasecmp(name, "Waveform Mixer") ) {
323   _mix_settings.sid.volume = id[i];
324   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
325   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
326   return;
327  }
328 }
329}
330
331static int _open_dummy (void) {
332 int p[2];
333
334 if ( pipe(p) == -1 )
335  return -1;
336
337 close(p[1]);
338
339 return p[0];
340}
341
342static struct session * _open_session (char * server, char * name) {
343 struct session * ses = &_session;
344 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
345
346 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
347 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
348
349 if ( new_session ) {
350  ses = roar_mm_malloc(sizeof(struct session));
351  if ( ses == NULL )
352   return NULL;
353
354  memset(ses, 0, sizeof(struct session));
355 }
356
357 if ( ses->refc == 0 ) {
358
359  if ( name == NULL )
360   name = getenv("ROAR_OSS_CLIENT_NAME");
361
362  if ( name == NULL )
363   name = "libroaross client";
364
365  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
366   if ( new_session )
367    roar_mm_free(ses);
368
369   return NULL;
370  }
371
372  _find_volume_sid(ses);
373
374  if ( !new_session ) {
375   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
376    ses->refc++;
377  }
378 }
379
380 ses->refc++;
381
382 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
383 return ses;
384}
385
386static void _close_session(struct session * session) {
387 if ( session == NULL )
388  return;
389
390 session->refc--;
391
392 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
393
394 if ( session->refc == 0 ) {
395  roar_disconnect(&(session->con));
396 }
397
398 if ( session != &_session )
399  roar_mm_free(session);
400}
401
402static struct handle * _open_handle(struct session * session) {
403 struct handle * handle;
404
405 ROAR_DBG("_open_handle(session=%p) = ?", session);
406
407 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
408  return NULL;
409
410 memset(handle, 0, sizeof(struct handle));
411
412 handle->refc = 1;
413 handle->session = session;
414
415 if ( session != NULL )
416  session->refc++; // TODO: better warp this
417
418 handle->type = HT_NONE;
419 handle->stream_dir = ROAR_DIR_PLAY;
420 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
421
422 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
423 return handle;
424}
425
426static void _close_handle(struct handle * handle) {
427 int need_close = 0;
428
429 if (handle == NULL)
430  return;
431
432 handle->refc--;
433
434 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
435
436 if ( handle->refc == 0 ) {
437  switch (handle->type) {
438   case HT_VIO:
439     need_close = 1;
440    break;
441   case HT_STREAM:
442     if ( handle->stream_opened )
443      need_close = 1;
444    break;
445  }
446
447  if ( need_close )
448   roar_vio_close(&(handle->stream_vio));
449
450  if ( handle->session != NULL ) {
451   handle->session->refc--;
452
453   _close_session(handle->session);
454  }
455
456  roar_mm_free(handle);
457 }
458}
459
460static struct pointer * _get_pointer_by_fh (int fh) {
461 int i;
462
463 for (i = 0; i < _MAX_POINTER; i++) {
464  if ( _ptr[i].fh == fh )
465   return &(_ptr[i]);
466 }
467
468 return NULL;
469}
470
471static struct pointer * _open_pointer(struct handle * handle) {
472 struct pointer * ret = _get_pointer_by_fh(-1);
473
474 if ( ret == NULL )
475  return NULL;
476
477 if ( (ret->fh = _open_dummy()) == -1 )
478  return NULL;
479
480 ret->handle = handle;
481
482 return ret;
483}
484
485static struct pointer * _attach_pointer(struct handle * handle, int fh) {
486 struct pointer * ret = _get_pointer_by_fh(-1);
487
488 if ( ret == NULL )
489  return NULL;
490
491 if ( (ret->fh = fh) == -1 )
492  return NULL;
493
494 ret->handle = handle;
495
496 handle->refc++;
497
498 return ret;
499}
500
501static void _close_pointer(struct pointer * pointer) {
502 if ( pointer == NULL )
503  return;
504
505 _os.close(pointer->fh);
506
507 pointer->fh = -1;
508
509 _close_handle(pointer->handle);
510}
511
512// -------------------------------------
513// central function to find device:
514// -------------------------------------
515
516static struct devices * _get_device (const char * pathname) {
517 struct devices * ptr;
518 size_t len;
519 int i;
520
521 for (i = 0; _device_list[i].prefix != NULL; i++) {
522  len = strlen(_device_list[i].prefix);
523
524  if ( _device_list[i].prefix[len-1] == '*' ) {
525   len--;
526  } else {
527   len++;
528  }
529  if ( !strncmp(pathname, _device_list[i].prefix, len) ) {
530   ptr = &(_device_list[i]);
531  }
532 }
533
534 return NULL;
535}
536
537// -------------------------------------
538// central open function:
539// -------------------------------------
540
541static int _open_file (const char *pathname, int flags) {
542 struct session * session;
543 struct handle  * handle;
544 struct pointer * pointer;
545 struct devices * ptr = NULL;
546
547 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
548
549/*
550 * Flags we ignore:
551 * O_DIRECT, O_APPEND, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_TRUNC
552 */
553
554 if ( flags & O_ASYNC ) {
555  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // not supported O_ASYNC", pathname, flags);
556  errno = ENOSYS;
557  return -1;
558 }
559
560 if ( (flags & O_DIRECTORY) || (flags & O_EXCL) ) {
561  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // invalid flags (O_DIRECTORY or O_EXCL)", pathname, flags);
562  errno = EINVAL;
563  return -1;
564 }
565
566 if ( (ptr = _get_device(pathname)) == NULL )
567  return -2;
568
569 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
570  session = NULL;
571 } else {
572  if ( (session = _open_session(NULL, NULL)) == NULL ) {
573   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
574   return -1;
575  }
576 }
577
578 if ( ptr->open != NULL ) {
579  // TODO: Add support to pass mode (perms) to open.
580  if ( (handle = ptr->open(pathname, flags, 0000, ptr)) == NULL ) {
581   _close_session(session);
582   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
583   return -1;
584  }
585 } else {
586  if ( (handle = _open_handle(session)) == NULL ) {
587   _close_session(session);
588   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
589   return -1;
590  }
591
592  handle->type        = ptr->type;
593  handle->sysio_flags = flags;
594  handle->stream_dir  = -1;
595 }
596
597 switch (flags & _O_PARA_DIR) {
598  case O_RDONLY:
599    switch (ptr->type) {
600     case HT_WAVEFORM:
601       handle->stream_dir = ROAR_DIR_MONITOR;
602      break;
603     case HT_MIDI:
604       handle->stream_dir = ROAR_DIR_MIDI_OUT;
605      break;
606     case HT_DMX:
607       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
608      break;
609     case HT_MIXER:
610     case HT_STATIC:
611      break;
612     default:
613       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
614       return -1;
615    }
616   break;
617  case O_WRONLY:
618    switch (ptr->type) {
619     case HT_WAVEFORM:
620       handle->stream_dir = ROAR_DIR_PLAY;
621      break;
622     case HT_MIDI:
623       handle->stream_dir = ROAR_DIR_MIDI_IN;
624      break;
625     case HT_DMX:
626       handle->stream_dir = ROAR_DIR_LIGHT_IN;
627      break;
628     case HT_MIXER:
629     case HT_STATIC:
630      break;
631     default:
632       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
633       return -1;
634    }
635   break;
636  case O_RDWR:
637    switch (ptr->type) {
638     case HT_WAVEFORM:
639       handle->stream_dir = ROAR_DIR_BIDIR;
640      break;
641     case HT_MIXER:
642     case HT_STATIC:
643      break;
644     default:
645       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
646       return -1;
647    }
648   break;
649 }
650
651 switch (handle->type) {
652  case HT_WAVEFORM:
653    handle->type = HT_STREAM;
654   break;
655  case HT_MIDI:
656    handle->type = HT_STREAM;
657    handle->stream.info.rate     = 0;
658    handle->stream.info.bits     = ROAR_MIDI_BITS;
659    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
660    handle->stream.info.codec    = ROAR_CODEC_MIDI;
661   break;
662  case HT_DMX:
663    handle->stream.info.rate     = 0;
664    handle->stream.info.bits     = ROAR_LIGHT_BITS;
665    handle->stream.info.channels = 512;
666    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
667   break;
668  case HT_STATIC:
669    handle->userdata.sf.len      = ptr->len;
670    handle->userdata.sf.data     = ptr->userdata;
671   break;
672 }
673
674 if ( (pointer = _open_pointer(handle)) == NULL ) {
675  _close_handle(handle);
676  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
677  return -1;
678 }
679
680 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
681
682 return pointer->fh;
683}
684
685// -------------------------------------
686// open function for streams:
687// -------------------------------------
688
689static int _open_stream (struct handle * handle) {
690  // FIXME: this should be re-written much more cleanly:
691
692 if ( handle == NULL )
693  return -1;
694
695 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
696                                     &(handle->session->con), &(handle->stream),
697                                     handle->stream.info.rate,
698                                     handle->stream.info.channels,
699                                     handle->stream.info.bits,
700                                     handle->stream.info.codec,
701                                     handle->stream_dir
702                                    ) == -1 )
703  return -1;
704
705 handle->stream_opened++;
706
707 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
708
709 _update_nonblock(handle);
710
711 return 0;
712}
713
714// -------------------------------------
715// function to update O_NONBLOCK:
716// -------------------------------------
717
718static int _update_nonblock (struct handle * handle) {
719 int opened = 0;
720 int state  = handle->sysio_flags & O_NONBLOCK ? ROAR_SOCKET_NONBLOCK : ROAR_SOCKET_BLOCK;
721
722 switch (handle->type) {
723  case HT_NONE:
724  case HT_STATIC:
725  case HT_MIXER:
726    // we can ignore setting of nonblock flag here.
727    return 0;
728   break;
729  case HT_VIO:
730    opened = 1;
731   break;
732  case HT_STREAM:
733  case HT_WAVEFORM:
734  case HT_MIDI:
735  case HT_DMX:
736    opened = handle->stream_opened;
737   break;
738 }
739
740 if ( opened ) {
741  return roar_vio_nonblock(&(handle->stream_vio), state);
742 }
743
744 return 0;
745}
746
747// -------------------------------------
748// function to parse format:
749// -------------------------------------
750
751static int _ioctl_stream_format (struct handle * handle, int format) {
752 struct roar_audio_info * info = &(handle->stream.info);
753
754 switch (format) {
755  case AFMT_S8:
756    info->bits  = 8;
757    info->codec = ROAR_CODEC_PCM_S_LE;
758   break;
759  case AFMT_U8:
760    info->bits  = 8;
761    info->codec = ROAR_CODEC_PCM_U_LE;
762   break;
763  case AFMT_S16_BE:
764    info->bits  = 16;
765    info->codec = ROAR_CODEC_PCM_S_BE;
766   break;
767  case AFMT_S16_LE:
768    info->bits  = 16;
769    info->codec = ROAR_CODEC_PCM_S_LE;
770   break;
771  case AFMT_U16_BE:
772    info->bits  = 16;
773    info->codec = ROAR_CODEC_PCM_U_BE;
774   break;
775  case AFMT_U16_LE:
776    info->bits  = 16;
777    info->codec = ROAR_CODEC_PCM_U_LE;
778   break;
779#ifdef AFMT_S32_BE
780  case AFMT_S32_BE:
781    info->bits  = 32;
782    info->codec = ROAR_CODEC_PCM_S_BE;
783   break;
784#endif
785#ifdef AFMT_S32_LE
786  case AFMT_S32_LE:
787    info->bits  = 32;
788    info->codec = ROAR_CODEC_PCM_S_LE;
789   break;
790#endif
791  case AFMT_A_LAW:
792    info->bits  = 8;
793    info->codec = ROAR_CODEC_ALAW;
794   break;
795  case AFMT_MU_LAW:
796    info->bits  = 8;
797    info->codec = ROAR_CODEC_MULAW;
798   break;
799#ifdef AFMT_VORBIS
800  case AFMT_VORBIS:
801    info->codec = ROAR_CODEC_OGG_VORBIS;
802   break;
803#endif
804  default:
805    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
806    errno = ENOSYS;
807    return -1;
808   break;
809 }
810
811 return 0;
812}
813
814static inline int _ioctl_stream_format_list (void) {
815 int format = 0;
816
817 format |= AFMT_S8;
818 format |= AFMT_U8;
819
820 format |= AFMT_S16_BE;
821 format |= AFMT_S16_LE;
822
823 format |= AFMT_U16_BE;
824 format |= AFMT_U16_LE;
825
826#ifdef AFMT_S32_BE
827 format |= AFMT_S32_BE;
828#endif
829#ifdef AFMT_S32_LE
830 format |= AFMT_S32_LE;
831#endif
832
833 format |= AFMT_A_LAW;
834 format |= AFMT_MU_LAW;
835
836#ifdef AFMT_VORBIS
837 format |= AFMT_VORBIS;
838#endif
839
840 return format;
841}
842
843// -------------------------------------
844// mixer ioctls:
845// -------------------------------------
846
847static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
848 mixer_info * info;
849 int channels;
850 struct roar_mixer_settings mixer;
851 int o_w    =  0;
852 int o_sid  = -1;
853 int * ip   = vp;
854#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
855 char * name = NULL;
856#endif
857
858#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
859 switch (req) {
860#if 0
861  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
862  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
863  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
864  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
865  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
866  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
867  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
868#endif
869//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
870  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
871  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
872  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
873  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
874  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
875  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
876  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
877  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
878  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
879  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
880  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
881  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
882//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
883  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
884/*
885  case :     name = "";     break;
886  case :     name = "";     break;
887*/
888 }
889 if ( name != NULL ) {
890  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
891  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
892  errno = ENOSYS;
893  return -1;
894 }
895#endif
896
897 switch (req) {
898  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
899  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
900  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
901  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
902  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
903#if 0
904  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
905  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
906  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
907#endif
908  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
909  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
910  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
911  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
912  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
913#if 0
914  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
915  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
916  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
917#endif
918  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
919  case SOUND_MIXER_READ_PCM:
920    o_w = 0;
921    if ( handle->type == HT_STREAM ) {
922     o_sid = roar_stream_get_id(&(handle->stream));
923    } else {
924     o_sid = _mix_settings.sid.pcm;
925    }
926   break;
927  case SOUND_MIXER_WRITE_PCM:
928    o_w = 1;
929    if ( handle->type == HT_STREAM ) {
930     o_sid = roar_stream_get_id(&(handle->stream));
931    } else {
932     o_sid = _mix_settings.sid.pcm;
933    }
934   break;
935 }
936 if ( o_sid != -1 ) {
937  // set/get volume
938  if ( o_w ) {
939   mixer.scale    = OSS_VOLUME_SCALE;
940   mixer.mixer[0] = ( *ip       & 0xFF);
941   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
942   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
943    errno = EIO;
944    return -1;
945   }
946   return 0;
947  } else {
948   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
949    errno = EIO;
950    return -1;
951   }
952   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
953   return 0;
954  }
955 }
956
957 switch (req) {
958  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
959  case SOUND_MIXER_READ_DEVMASK:
960    *ip = 0;
961
962    if ( _mix_settings.sid.volume != -1 )
963     *ip |= SOUND_MASK_VOLUME;
964    if ( _mix_settings.sid.pcm != -1 )
965     *ip |= SOUND_MASK_PCM;
966    if ( _mix_settings.sid.line != -1 )
967     *ip |= SOUND_MASK_LINE;
968    if ( _mix_settings.sid.line1 != -1 )
969     *ip |= SOUND_MASK_LINE1;
970    if ( _mix_settings.sid.line2 != -1 )
971     *ip |= SOUND_MASK_LINE2;
972    if ( _mix_settings.sid.line3 != -1 )
973     *ip |= SOUND_MASK_LINE3;
974    if ( _mix_settings.sid.digital1 != -1 )
975#if 0
976     *ip |= SOUND_MASK_DIGITAL1;
977    if ( _mix_settings.sid.digital2 != -1 )
978     *ip |= SOUND_MASK_DIGITAL2;
979    if ( _mix_settings.sid.digital3 != -1 )
980     *ip |= SOUND_MASK_DIGITAL3;
981#endif
982
983    return 0;
984   break;
985  case SOUND_MIXER_READ_RECMASK:
986  case SOUND_MIXER_READ_RECSRC:
987    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
988    return 0;
989   break;
990  case SOUND_MIXER_WRITE_RECSRC:
991    if ( *ip == SOUND_MASK_VOLUME ) {
992     return  0;
993    } else {
994     errno = ENOTSUP;
995     return -1;
996    }
997   break;
998  case SOUND_MIXER_READ_CAPS:
999    *ip = 0;
1000    return 0;
1001   break;
1002  case SOUND_MIXER_INFO:
1003    info = vp;
1004    memset(info, 0, sizeof(*info));
1005    strcpy(info->id, "RoarAudio");
1006    strcpy(info->name, "RoarAudio");
1007    return 0;
1008   break;
1009 }
1010
1011 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
1012// _os.ioctl(-1, req, ip);
1013 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
1014 errno = ENOSYS;
1015 return -1;
1016}
1017
1018// -------------------------------------
1019// buffer size calculation:
1020// -------------------------------------
1021
1022static size_t _get_stream_buffersize (struct handle * handle) {
1023 if ( handle->stream_buffersize )
1024  return handle->stream_buffersize;
1025
1026 return handle->stream_buffersize = handle->stream.info.rate     *
1027                                    handle->stream.info.channels *
1028                                    handle->stream.info.bits     / 800;
1029}
1030
1031// -------------------------------------
1032// emulated functions follow:
1033// -------------------------------------
1034
1035int     open(const char *pathname, int flags, ...) {
1036 int     ret;
1037 mode_t  mode = 0;
1038 va_list args;
1039
1040 _init();
1041
1042 if ( pathname == NULL ) {
1043  errno = EFAULT;
1044  return -1;
1045 }
1046
1047 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
1048 ret = _open_file(pathname, flags);
1049
1050 switch (ret) {
1051  case -2:       // continue as normal, use _op.open()
1052   break;
1053  case -1:       // pass error to caller
1054    return -1;
1055   break;
1056  default:       // return successfully opened pointer to caller
1057    return ret;
1058   break;
1059 }
1060
1061 if (flags & O_CREAT) {
1062  va_start(args, flags);
1063  mode = va_arg(args, mode_t);
1064  va_end(args);
1065 }
1066
1067 return _os.open(pathname, flags, mode);
1068}
1069
1070int    open64(const char *__file, int __oflag, ...) {
1071 int     ret;
1072 mode_t  mode = 0;
1073 va_list args;
1074
1075 _init();
1076
1077 if ( __file == NULL ) {
1078  errno = EFAULT;
1079  return -1;
1080 }
1081
1082 ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = ?\n", __file, __oflag);
1083 ret = _open_file(__file, __oflag);
1084
1085 switch (ret) {
1086  case -2:       // continue as normal, use _op.open()
1087   break;
1088  case -1:       // pass error to caller
1089    return -1;
1090   break;
1091  default:       // return successfully opened pointer to caller
1092    return ret;
1093   break;
1094 }
1095
1096 if (__oflag & O_CREAT) {
1097  va_start(args, __oflag);
1098  mode = va_arg(args, mode_t);
1099  va_end(args);
1100 }
1101
1102 if ( _os.open64 != NULL ) {
1103  return _os.open64(__file, __oflag, mode);
1104 } else {
1105#ifdef O_LARGEFILE
1106  return _os.open(__file, __oflag | O_LARGEFILE, mode);
1107#else
1108  return _os.open(__file, __oflag, mode);
1109#endif
1110 }
1111}
1112
1113int     close(int fd) {
1114 struct pointer * pointer;
1115 _init();
1116
1117 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1118  _close_pointer(pointer);
1119  return 0;
1120 }
1121
1122 return _os.close(fd);
1123}
1124
1125ssize_t write(int fd, const void *buf, size_t count) {
1126 struct roar_roardmx_message roardmxmsg;
1127 struct pointer * pointer;
1128 ssize_t ret;
1129 size_t i;
1130
1131 _init();
1132
1133 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1134  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
1135  switch (pointer->handle->type) {
1136   case HT_STREAM: // handle stream specific stuff
1137     if ( pointer->handle->stream_opened == 0 ) {
1138      if ( _open_stream(pointer->handle) == -1 ) {
1139       errno = EIO;
1140       return -1;
1141      }
1142     }
1143   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
1144     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
1145     if ( ret > 0 )
1146      pointer->handle->writec += ret;
1147     return ret;
1148    break;
1149   case HT_DMX: // DMX need specal handling as we need to convert the protocol
1150     if ( pointer->handle->stream_opened == 0 ) {
1151      if ( _open_stream(pointer->handle) == -1 ) {
1152       errno = EIO;
1153       return -1;
1154      }
1155     }
1156     if ( count > 0 ) {
1157      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
1158       errno = EIO;
1159       return -1;
1160      }
1161      for (i = 0; i < count; i++) {
1162       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1163#ifdef EMSGSIZE
1164        errno = EMSGSIZE;
1165#else
1166        errno = EIO;
1167#endif
1168        return -1;
1169       }
1170      }
1171      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1172       errno = EIO;
1173       return -1;
1174      }
1175     }
1176     pointer->handle->pos += count;
1177     return count;
1178    break;
1179   default: // we don't know what to do with other types
1180     errno = EINVAL;
1181     return -1;
1182    break;
1183  }
1184 }
1185
1186 return _os.write(fd, buf, count);
1187}
1188
1189ssize_t read(int fd, void *buf, size_t count) {
1190 struct pointer * pointer;
1191 ssize_t ret;
1192
1193 _init();
1194
1195 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1196  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1197
1198  switch (pointer->handle->type) {
1199   case HT_STREAM:
1200     if ( pointer->handle->stream_opened == 0 ) {
1201      if ( _open_stream(pointer->handle) == -1 ) {
1202       errno = EIO;
1203       return -1;
1204      }
1205     }
1206   case HT_VIO:
1207     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1208     if ( ret > 0 )
1209      pointer->handle->readc += ret;
1210     return ret;
1211    break;
1212   case HT_STATIC:
1213     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1214     ret = pointer->handle->pos + count; // calc the end of the read
1215
1216     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1217      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1218     }
1219
1220     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1221     pointer->handle->pos += count;
1222     return count;
1223    break;
1224   default:
1225     errno = EINVAL;
1226     return -1;
1227    break;
1228  }
1229 }
1230
1231 return _os.read(fd, buf, count);
1232}
1233
1234off_t lseek(int fildes, off_t offset, int whence) {
1235 struct pointer * pointer;
1236 ssize_t tmp;
1237
1238 _init();
1239
1240 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1241  switch (pointer->handle->type) {
1242   case HT_DMX:
1243     switch (whence) {
1244      case SEEK_SET:
1245        pointer->handle->pos  = offset;
1246       break;
1247      case SEEK_CUR:
1248        pointer->handle->pos += offset;
1249       break;
1250      case SEEK_END:
1251      default:
1252        errno = EINVAL;
1253        return -1;
1254       break;
1255     }
1256     return pointer->handle->pos;
1257    break;
1258   case HT_VIO:
1259     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1260    break;
1261   case HT_STATIC:
1262     switch (whence) {
1263      case SEEK_SET:
1264        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1265         errno = EINVAL;
1266         return -1;
1267        }
1268        pointer->handle->pos  = offset;
1269       break;
1270      case SEEK_CUR:
1271        tmp = pointer->handle->pos + offset;
1272        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1273         errno = EINVAL;
1274         return -1;
1275        }
1276        pointer->handle->pos = tmp;
1277       break;
1278      case SEEK_END:
1279        tmp = pointer->handle->userdata.sf.len + offset;
1280        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1281         errno = EINVAL;
1282         return -1;
1283        }
1284        pointer->handle->pos = tmp;
1285       break;
1286      default:
1287        errno = EINVAL;
1288        return -1;
1289       break;
1290     }
1291    break;
1292   default:
1293     errno = EINVAL;
1294     return -1;
1295    break;
1296  }
1297 }
1298
1299 return _os.lseek(fildes, offset, whence);
1300}
1301
1302IOCTL() {
1303 map_args;
1304 struct pointer * pointer;
1305 struct handle  * handle;
1306 int * ip = NULL;
1307 size_t tmp;
1308 audio_buf_info * bi;
1309 count_info     * ci;
1310#ifdef __FIXME__
1311 char * nosys_reqname = NULL;
1312#endif
1313#ifdef va_argp
1314 va_list args;
1315#endif
1316
1317 _init();
1318
1319// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1320
1321#ifdef va_argp
1322 va_start (args, ioctl_lastarg);
1323 argp = va_arg (args, void *);
1324 va_end (args);
1325#endif
1326
1327// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1328
1329 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1330  ip = argp;
1331//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1332#ifdef __FIXME__
1333  switch ((handle = pointer->handle)->type) {
1334   case SOUND_PCM_READ_RATE: nosys_reqname     = "SOUND_PCM_READ_RATE";     break;
1335   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1336   case SOUND_PCM_READ_BITS: nosys_reqname     = "SOUND_PCM_READ_BITS";     break;
1337   case SOUND_PCM_READ_FILTER: nosys_reqname   = "SOUND_PCM_READ_FILTER";   break;
1338   case SNDCTL_COPR_RESET: nosys_reqname       = "SNDCTL_COPR_RESET";       break;
1339   case SNDCTL_COPR_LOAD: nosys_reqname        = "SNDCTL_COPR_LOAD";        break;
1340   case SNDCTL_COPR_HALT: nosys_reqname        = "SNDCTL_COPR_HALT";        break;
1341   case SNDCTL_COPR_RDATA: nosys_reqname       = "SNDCTL_COPR_RDATA";       break;
1342   case SNDCTL_COPR_RCODE: nosys_reqname       = "SNDCTL_COPR_RCODE";       break;
1343   case SNDCTL_COPR_WDATA: nosys_reqname       = "SNDCTL_COPR_WDATA";       break;
1344   case SNDCTL_COPR_WCODE: nosys_reqname       = "SNDCTL_COPR_WCODE";       break;
1345   case SNDCTL_COPR_RUN: nosys_reqname         = "SNDCTL_COPR_RUN";         break;
1346   case SNDCTL_COPR_SENDMSG: nosys_reqname     = "SNDCTL_COPR_SENDMSG";     break;
1347   case SNDCTL_COPR_RCVMSG: nosys_reqname      = "SNDCTL_COPR_RCVMSG";      break;
1348   case SNDCTL_DSP_GETCAPS: nosys_reqname      = "SNDCTL_DSP_GETCAPS";      break;
1349   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1350/*
1351   case : nosys_reqname = ""; break;
1352   case : nosys_reqname = ""; break;
1353   case : nosys_reqname = ""; break;
1354*/
1355  }
1356#endif
1357  switch ((handle = pointer->handle)->type) {
1358   case HT_STREAM:
1359     switch (__request) {
1360      case SNDCTL_DSP_RESET:
1361      case SNDCTL_DSP_POST:
1362      case SNDCTL_DSP_SYNC: // ignore for the moment.
1363      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1364      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1365        return 0;
1366       break;
1367      case SNDCTL_DSP_SPEED:
1368        handle->stream.info.rate = *ip;
1369        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1370        return 0;
1371       break;
1372      case SNDCTL_DSP_CHANNELS:
1373        handle->stream.info.channels = *ip;
1374        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1375        return 0;
1376       break;
1377      case SNDCTL_DSP_STEREO:
1378        handle->stream.info.channels = *ip ? 2 : 1;
1379        return 0;
1380       break;
1381      case SNDCTL_DSP_GETBLKSIZE:
1382        *ip = _get_stream_buffersize(handle);
1383        return 0;
1384       break;
1385      case SNDCTL_DSP_SETFMT:
1386        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1387        return _ioctl_stream_format(handle, *ip);
1388       break;
1389      case SNDCTL_DSP_GETFMTS:
1390//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1391        *ip = _ioctl_stream_format_list();
1392        return 0;
1393       break;
1394      case SNDCTL_DSP_GETOSPACE:
1395      case SNDCTL_DSP_GETISPACE:
1396        bi = argp;
1397        memset(bi, 0, sizeof(*bi));
1398        bi->bytes      = _get_stream_buffersize(handle);
1399        bi->fragments  = 1;
1400        bi->fragsize   = bi->bytes;
1401        bi->fragstotal = 1;
1402        return 0;
1403       break;
1404      case SNDCTL_DSP_GETOPTR:
1405        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1406        ci = argp;
1407        memset(ci, 0, sizeof(*ci));
1408        ci->bytes  = handle->writec;
1409        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1410        ci->ptr    = ci->bytes % tmp;
1411        return 0;
1412       break;
1413      case SNDCTL_DSP_GETIPTR:
1414        ci = argp;
1415        memset(ci, 0, sizeof(*ci));
1416        ci->bytes  = handle->readc;
1417        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1418        ci->ptr    = ci->bytes % tmp;
1419        return 0;
1420       break;
1421#ifdef SNDCTL_DSP_GETPLAYVOL
1422      case SNDCTL_DSP_GETPLAYVOL:
1423        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1424       break;
1425#endif
1426#ifdef SNDCTL_DSP_SETPLAYVOL
1427      case SNDCTL_DSP_SETPLAYVOL:
1428        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1429       break;
1430#endif
1431#ifdef SNDCTL_DSP_NONBLOCK
1432      case SNDCTL_DSP_NONBLOCK:
1433        return fcntl(__fd, F_SETFL, handle->sysio_flags|O_NONBLOCK);
1434       break;
1435#endif
1436      default:
1437#ifdef __FIXME__
1438        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1439#else
1440        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1441#endif
1442        errno = ENOSYS;
1443        return -1;
1444     }
1445    break;
1446   case HT_MIXER:
1447     return _ioctl_mixer(handle, __request, argp);
1448    break;
1449   default:
1450     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1451     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1452     errno = EINVAL;
1453     return -1;
1454    break;
1455  }
1456 }
1457
1458#ifdef IOCTL_IS_ALIAS
1459 errno = ENOSYS;
1460 return -1;
1461#else
1462 return _os.ioctl(__fd, __request, argp);
1463#endif
1464}
1465
1466int dup(int oldfd) {
1467 struct pointer * pointer;
1468 int ret;
1469
1470 _init();
1471
1472 ret = _os.dup(oldfd);
1473
1474 if (ret == -1)
1475  return -1;
1476
1477 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1478  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1479   _os.close(ret);
1480   return -1;
1481  }
1482 }
1483
1484 return ret;
1485}
1486
1487int dup2(int oldfd, int newfd) {
1488 struct pointer * pointer;
1489 int ret;
1490
1491 _init();
1492
1493 ret = _os.dup2(oldfd, newfd);
1494
1495 if (ret == -1)
1496  return -1;
1497
1498 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1499  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1500   _os.close(ret);
1501   return -1;
1502  }
1503 }
1504
1505 return ret;
1506}
1507
1508int select(int nfds, fd_set *readfds, fd_set *writefds,
1509           fd_set *exceptfds, struct timeval *timeout) {
1510 struct roar_vio_selecttv rtv;
1511 struct roar_vio_select * sv  = NULL;
1512 struct pointer * pointer;
1513 struct handle  * handle;
1514 ssize_t ret;
1515 size_t num = 0;
1516 size_t idx;
1517 int i;
1518 int i_r, i_w, i_e;
1519 int max_index = -1;
1520 static volatile int is_critical = 0;
1521
1522 _init();
1523
1524 if ( is_critical )
1525  return _os.select(nfds, readfds, writefds, exceptfds, timeout);
1526
1527 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = ?", nfds, readfds, writefds, exceptfds, timeout);
1528
1529 if ( nfds == 0 ) {
1530  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1531  return 0;
1532 }
1533
1534 if ( readfds == NULL && writefds == NULL && exceptfds == NULL ) {
1535  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1536  return 0;
1537 }
1538
1539 if ( timeout != NULL ) {
1540  rtv.sec = timeout->tv_sec;
1541  rtv.nsec = timeout->tv_usec*1000;
1542 }
1543
1544 // count number of handles:
1545 for (i = 0; i < nfds; i++) {
1546  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1547  if ( (readfds   != NULL && FD_ISSET(i, readfds  )) ||
1548       (writefds  != NULL && FD_ISSET(i, writefds )) ||
1549       (exceptfds != NULL && FD_ISSET(i, exceptfds))
1550     ) {
1551   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1552   num++;
1553   max_index = i;
1554  }
1555 }
1556
1557 if ( num == 0 ) {
1558  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1559  return 0;
1560 }
1561
1562 nfds = max_index + 1;
1563
1564 // create sv;
1565 sv = roar_mm_malloc(sizeof(struct roar_vio_select)*num);
1566 if ( sv == NULL ) {
1567  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1", nfds, readfds, writefds, exceptfds, timeout);
1568  return -1;
1569 }
1570
1571 memset(sv, 0, sizeof(struct roar_vio_select)*num);
1572
1573 for (i = 0, idx = 0; i < nfds; i++) {
1574  if ( idx >= num ) {
1575   roar_mm_free(sv);
1576   errno = EFAULT;
1577   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1 // i=%i, idx=%i, num=%i", nfds, readfds, writefds, exceptfds, timeout, i, (int)idx, (int)num);
1578   return -1;
1579  }
1580  i_r = readfds   != NULL && FD_ISSET(i, readfds);
1581  i_w = writefds  != NULL && FD_ISSET(i, writefds);
1582  i_e = exceptfds != NULL && FD_ISSET(i, exceptfds);
1583
1584  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, i_r=%i, i_w=%i, i_e=%i", nfds, readfds, writefds, exceptfds, timeout, i, i_r, i_w, i_e);
1585
1586  if ( i_r || i_w || i_e ) {
1587   // TODO: use VIO for pointers...
1588   if ( (pointer = _get_pointer_by_fh(i)) != NULL ) {
1589    handle = pointer->handle;
1590    sv[idx].vio     = NULL;
1591    sv[idx].fh      = -1;
1592    switch (handle->type) {
1593     case HT_DMX:
1594     case HT_STREAM:
1595       if ( ! handle->stream_opened ) {
1596        // implement this as statichly return OK
1597        errno = ENOSYS;
1598        return -1;
1599       }
1600     case HT_VIO:
1601       sv[idx].vio = &(handle->stream_vio);
1602      break;
1603     default: /* non supported type */
1604       errno = EINVAL;
1605       return -1;
1606      break;
1607    }
1608   } else {
1609    sv[idx].vio     = NULL;
1610    sv[idx].fh      = i;
1611   }
1612
1613   sv[idx].ud.si   = i;
1614   sv[idx].eventsq = (i_r ? ROAR_VIO_SELECT_READ   : 0) |
1615                     (i_w ? ROAR_VIO_SELECT_WRITE  : 0) |
1616                     (i_e ? ROAR_VIO_SELECT_EXCEPT : 0);
1617   idx++;
1618  }
1619 }
1620
1621 is_critical++;
1622 ret = roar_vio_select(sv, num, timeout == NULL ? NULL : &rtv, NULL);
1623 is_critical--;
1624
1625 if ( ret < 1 ) {
1626  roar_mm_free(sv);
1627  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1628  return ret;
1629 }
1630
1631 // update readfds, writefds, exceptfds:
1632 if ( readfds != NULL )
1633  FD_ZERO(readfds);
1634
1635 if ( writefds != NULL )
1636  FD_ZERO(writefds);
1637
1638 if ( exceptfds != NULL )
1639  FD_ZERO(exceptfds);
1640
1641 for (idx = 0; idx < num; idx++) {
1642  if ( sv[idx].eventsa == 0 )
1643   continue;
1644
1645  if ( sv[idx].eventsa & ROAR_VIO_SELECT_READ )
1646   if ( readfds != NULL )
1647    FD_SET(sv[idx].ud.si, readfds);
1648
1649  if ( sv[idx].eventsa & ROAR_VIO_SELECT_WRITE )
1650   if ( writefds != NULL )
1651    FD_SET(sv[idx].ud.si, writefds);
1652
1653  if ( sv[idx].eventsa & ROAR_VIO_SELECT_EXCEPT )
1654   if ( exceptfds != NULL )
1655    FD_SET(sv[idx].ud.si, exceptfds);
1656 }
1657
1658 roar_mm_free(sv);
1659
1660 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1661 return ret;
1662}
1663
1664int fcntl(int fd, int cmd, ...) {
1665 enum { NONE, UNKNOWN, LONG, POINTER } type = NONE;
1666 struct pointer * pointer;
1667 va_list ap;
1668 long argl = -1;
1669 void * vp = NULL;
1670 int ret   = -1;
1671 int diff;
1672
1673 _init();
1674
1675 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...) = ?", fd, cmd);
1676
1677 switch (cmd) {
1678  case F_DUPFD:
1679  case F_SETFD:
1680  case F_SETFL:
1681  case F_SETOWN:
1682#ifdef F_SETSIG
1683  case F_SETSIG:
1684#endif
1685#ifdef F_SETLEASE
1686  case F_SETLEASE:
1687#endif
1688#ifdef F_NOTIFY
1689  case F_NOTIFY:
1690#endif
1691    type = LONG;
1692   break;
1693  case F_GETFD:
1694  case F_GETFL:
1695  case F_GETOWN:
1696#ifdef F_GETSIG
1697  case F_GETSIG:
1698#endif
1699#ifdef F_GETLEASE
1700  case F_GETLEASE:
1701#endif
1702    type = NONE;
1703   break;
1704  case F_GETLK:
1705  case F_SETLK:
1706  case F_SETLKW:
1707    type = POINTER;
1708   break;
1709/*
1710  case F_EXLCK:
1711  case F_GETLK64:
1712  case F_SETLK64:
1713  case F_SETLKW64:
1714  case F_SHLCK:
1715  case F_LINUX_SPECIFIC_BASE:
1716  case F_INPROGRESS:
1717*/
1718  default:
1719    type = UNKNOWN;
1720 }
1721
1722 if ( type == UNKNOWN ) {
1723  errno = EINVAL;
1724  return -1;
1725 }
1726
1727 if ( type != NONE ) {
1728  va_start(ap, cmd);
1729  switch (type) {
1730   case LONG:
1731     argl = va_arg(ap, long);
1732    break;
1733   case POINTER:
1734     vp = va_arg(ap, void*);
1735    break;
1736   default: /* make compiler happy */
1737    break;
1738  }
1739  va_end(ap);
1740 }
1741
1742 if ( (pointer = _get_pointer_by_fh(fd)) == NULL ) {
1743  switch (type) {
1744   case NONE:
1745     ROAR_DBG("fcntl(fd=%i, cmd=%i): fd is true sysio, pass call to kernel", fd, cmd);
1746     return _os.fcntl(fd, cmd);
1747    break;
1748   case LONG:
1749     ROAR_DBG("fcntl(fd=%i, cmd=%i, arg=%li): fd is true sysio, pass call to kernel", fd, cmd, argl);
1750     return _os.fcntl(fd, cmd, argl);
1751    break;
1752   case POINTER:
1753     ROAR_DBG("fcntl(fd=%i, cmd=%i, lock=%p): fd is true sysio, pass call to kernel", fd, cmd, vp);
1754     return _os.fcntl(fd, cmd, vp);
1755    break;
1756   default: /* make compiler happy */
1757    break;
1758  }
1759 }
1760
1761 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...): fd is true pointer, handle internaly", fd, cmd);
1762
1763 switch (cmd) {
1764  case F_DUPFD:
1765    ret = _os.fcntl(fd, F_DUPFD, argl);
1766
1767    if ( ret != -1 ) {
1768     if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1769      _os.close(ret);
1770      ret = -1;
1771     }
1772    }
1773   break;
1774  case F_SETFD:
1775    if ( argl == 0 ) {
1776     ret = 0;
1777    } else {
1778     errno = ENOSYS;
1779     ret = -1;
1780    }
1781   break;
1782  case F_GETFD:
1783    ret = 0;
1784   break;
1785  case F_GETFL:
1786    ret = pointer->handle->sysio_flags;
1787   break;
1788  case F_SETFL:
1789    diff  = (int)argl ^ pointer->handle->sysio_flags;
1790    diff &= (int)~(int)_O_PARA_DIR;
1791    diff &= (int)~(int)_O_PARA_IGN;
1792
1793    if ( diff & O_NONBLOCK ) {
1794     diff -= O_NONBLOCK;
1795     pointer->handle->sysio_flags ^= O_NONBLOCK;
1796     if ( _update_nonblock(pointer->handle) == -1 ) {
1797      pointer->handle->sysio_flags ^= O_NONBLOCK;
1798      return -1;
1799     }
1800    }
1801
1802    if ( diff == 0 ) { // only flags changed we ignore anyway.
1803     pointer->handle->sysio_flags  = (int)argl;
1804     ret = 0;
1805    } else {
1806     errno = EINVAL;
1807     ret = -1;
1808    }
1809   break;
1810/* TODO: add support for those types:
1811  case F_SETFD:
1812  case F_SETOWN:
1813  case F_SETSIG:
1814  case F_SETLEASE:
1815  case F_NOTIFY:
1816  case F_GETOWN:
1817  case F_GETSIG:
1818  case F_GETLEASE:
1819  case F_GETLK:
1820  case F_SETLK:
1821  case F_SETLKW:
1822*/
1823  default:
1824    errno = ENOSYS;
1825    ret = -1;
1826   break;
1827 }
1828
1829 return ret;
1830}
1831
1832int access(const char *pathname, int mode) {
1833 struct devices * ptr = NULL;
1834
1835 _init();
1836
1837 if ( (ptr = _get_device(pathname)) != NULL ) {
1838  // the only flag we do not support is +x, which means
1839  // we need to reject all requets with X_OK.
1840  if ( mode & X_OK ) {
1841   errno = EACCES;
1842   return -1;
1843  }
1844
1845  // in addition HT_STATIC files do not support write (+w)
1846  // so we need to reject W_OK.
1847  if ( ptr->type == HT_STATIC && (mode & W_OK) ) {
1848   errno = EACCES;
1849   return -1;
1850  }
1851
1852  // Else the access is granted:
1853  return 0;
1854 }
1855
1856 return _os.access(pathname, mode);
1857}
1858
1859int creat(const char *pathname, mode_t mode) {
1860 _init();
1861
1862 if ( _get_device(pathname) != NULL ) {
1863  errno = EEXIST;
1864  return -1;
1865 }
1866
1867 return _os.creat(pathname, mode);
1868}
1869
1870// -------------------------------------
1871// emulated stdio functions follow:
1872// -------------------------------------
1873
1874//roar_vio_to_stdio
1875
1876static int _vio_close    (struct roar_vio_calls * vio) {
1877 int ret = 0;
1878
1879 if ( roar_vio_get_fh(vio) != -1 )
1880  ret = close(roar_vio_get_fh(vio));
1881
1882 roar_mm_free(vio);
1883
1884 return ret;
1885}
1886
1887FILE *fopen(const char *path, const char *mode) {
1888 struct roar_vio_calls * vio;
1889 FILE  * fr;
1890 int     ret;
1891 int     r = 0, w = 0;
1892 int     flags = 0;
1893 int     i;
1894 register char c;
1895
1896 _init();
1897
1898 if ( path == NULL || mode == NULL ) {
1899  errno = EFAULT;
1900  return NULL;
1901 }
1902
1903 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
1904
1905 for (i = 0; (c = mode[i]) != 0; i++) {
1906  switch (c) {
1907   case 'r': r = 1; break;
1908   case 'w': w = 1; break;
1909   case 'a': w = 1; break;
1910   case '+':
1911     r = 1;
1912     w = 1;
1913    break;
1914  }
1915 }
1916
1917 if ( r && w ) {
1918  flags = O_RDWR;
1919 } else if ( r ) {
1920  flags = O_RDONLY;
1921 } else if ( w ) {
1922  flags = O_WRONLY;
1923 } else {
1924  errno = EINVAL;
1925  return NULL;
1926 }
1927
1928 ret = _open_file(path, flags);
1929
1930 switch (ret) {
1931  case -2:       // continue as normal, use _op.open()
1932   break;
1933  case -1:       // pass error to caller
1934    return NULL;
1935   break;
1936  default:       // return successfully opened pointer to caller
1937    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
1938     return NULL; // errno should be set correctly by roar_mm_malloc().
1939    }
1940
1941    roar_vio_init_calls(vio);  // TODO: add error handling.
1942    roar_vio_set_fh(vio, ret); // TODO: add error handling.
1943    vio->close = _vio_close;
1944    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
1945     _vio_close(vio);
1946     errno = EIO;
1947     return NULL;
1948    } else {
1949     return fr;
1950    }
1951   break;
1952 }
1953
1954 return _os.fopen(path, mode);
1955}
1956
1957// -------------------------------------
1958// RoarAudio plugin functions follow:
1959// -------------------------------------
1960
1961ROAR_DL_PLUGIN_START(libroaross) {
1962 (void)para;
1963 _init();
1964} ROAR_DL_PLUGIN_END
1965
1966#endif
1967
1968//ll
Note: See TracBrowser for help on using the repository browser.