source: roaraudio/libroaross/libroaross.c @ 6048:f37c7f362422

Last change on this file since 6048:f37c7f362422 was 6048:f37c7f362422, checked in by phi, 9 years ago

seems NetBSD now also uses va-function for the _oss_ioctl() alias.

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