source: roaraudio/libroaross/libroaross.c @ 4380:9e0d335e4c4e

Last change on this file since 4380:9e0d335e4c4e was 4380:9e0d335e4c4e, checked in by phi, 14 years ago

some cleanup

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