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
RevLine 
[3138]1//libroaross.c:
2
3/*
[5961]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2014
[3138]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[3138]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"
[3261]37#include "libroarlight/libroarlight.h"
[3138]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>
[3139]60#include <dlfcn.h>
[3778]61#include <stdarg.h>
[3139]62
63#if defined(RTLD_NEXT)
64#define REAL_LIBC RTLD_NEXT
65#else
66#define REAL_LIBC ((void *) -1L)
67#endif
[3138]68
[3164]69#ifndef ENOTSUP
70#define ENOTSUP ENOSYS
71#endif
72
[3873]73#ifndef O_DIRECTORY
74#define O_DIRECTORY 0
75#endif
76
[3892]77#ifndef O_DIRECT
78#define O_DIRECT 0
79#endif
80
[3872]81#ifndef O_LARGEFILE
82#define O_LARGEFILE 0
83#endif
84
85#ifndef O_NOATIME
86#define O_NOATIME 0
87#endif
88
[3868]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
[3166]92#if defined(ROAR_OS_NETBSD) && defined(ioctl)
93#define IOCTL_IS_ALIAS
94#endif
95
[3167]96#ifdef ROAR_OS_FREEBSD
[3891]97#define _VA_ARGS_MODE_T int
98#else
99#define _VA_ARGS_MODE_T mode_t
[3167]100#endif
101
[3890]102#ifdef ROAR_OS_FREEBSD
103#define _CREAT_ARG_PATHNAME path
104#else
105#define _CREAT_ARG_PATHNAME pathname
106#endif
107
[3169]108#ifdef ROAR_OS_NETBSD
[6048]109#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, ...))
[3171]110#define map_args int __fd = fd; unsigned long int __request = com
[6048]111#define va_argp
112#define ioctl_lastarg com
[3180]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
[3169]118#else
119#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
[3171]120#define map_args void * argp
[3169]121#define va_argp
[3180]122#define ioctl_lastarg __request
[3169]123#endif
124
[3153]125#define OSS_VOLUME_SCALE 100
126
[3138]127#define _MAX_POINTER  8
128
[3140]129// handle type:
[3663]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 */
[3666]137#define HT_STATIC     7 /* Static file */
[3140]138
[3138]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;
[3140]149 int type;
[3780]150 int sysio_flags;
[3140]151 struct roar_stream    stream;
152 struct roar_vio_calls stream_vio;
[3144]153 int                   stream_dir;
[3140]154 int                   stream_opened;
[3178]155 size_t                stream_buffersize;
156 size_t                readc, writec;
[3246]157 size_t                pos;
[3666]158 union {
159  struct {
160   char * data;
161   size_t len;
162  } sf;
163 } userdata;
[3138]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);
[3166]171#ifndef IOCTL_IS_ALIAS
[3146]172 int     (*ioctl)(int d, int request, ...);
[3166]173#endif
[3246]174 off_t   (*lseek)(int fildes, off_t offset, int whence);
[3264]175 FILE   *(*fopen)(const char *path, const char *mode);
[3657]176 int     (*dup)(int oldfd);
177 int     (*dup2)(int oldfd, int newfd);
[3771]178 int     (*select)(int nfds, fd_set *readfds, fd_set *writefds,
179                   fd_set *exceptfds, struct timeval *timeout);
[3778]180 int     (*fcntl)(int fd, int cmd, ...);
[3782]181 int     (*access)(const char *pathname, int mode);
[3866]182 int     (*open64)(const char *__file, int __oflag, ...);
[3890]183 int     (*creat)(const char *_CREAT_ARG_PATHNAME, mode_t mode);
[4633]184#ifndef __clang__
[3880]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);
[4633]188#endif
[3138]189} _os;
190
[3150]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
[3140]217static struct pointer {
[3138]218 int fh;
219 struct handle * handle;
220} _ptr[_MAX_POINTER];
221
[3662]222
[3666]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
[3662]244static struct devices {
245  char * prefix;
246  int type;
[3666]247  size_t len;
248  void * userdata;
[3870]249  struct handle * (*open)(const char * file, int flags, mode_t mode, struct devices * ptr);
[3662]250} _device_list[] = {
[4008]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},
[3870]279 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat, NULL},
[3662]280#ifdef ROAR_DEFAULT_OSS_DEV
[3870]281 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL, NULL},
[3662]282#endif
[4380]283#ifdef ROAR_DEFAULT_OSS_MIX_DEV
284 {ROAR_DEFAULT_OSS_MIX_DEV, HT_MIXER, 0, NULL, NULL},
285#endif
[3870]286 {NULL, HT_NONE, 0, NULL, NULL},
[3662]287};
288
[3849]289
290static int _update_nonblock (struct handle * handle);
291
[3138]292static void _init_os (void) {
293 memset(&_os, 0, sizeof(_os));
[3139]294
[3775]295 // if call roar_dl_getsym() here all applications will segfaul.
296 // why?
297
[3772]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");
[3166]302#ifndef IOCTL_IS_ALIAS
[3772]303 _os.ioctl  = dlsym(REAL_LIBC, "ioctl");
[3166]304#endif
[3772]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");
[3778]310 _os.fcntl  = dlsym(REAL_LIBC, "fcntl");
[3782]311 _os.access = dlsym(REAL_LIBC, "access");
[3866]312 _os.open64 = dlsym(REAL_LIBC, "open64");
[3871]313 _os.creat  = dlsym(REAL_LIBC, "creat");
[4633]314#ifndef __clang__
[3880]315 _os.stat   = dlsym(REAL_LIBC, "stat");
316 _os.fstat  = dlsym(REAL_LIBC, "fstat");
317 _os.lstat  = dlsym(REAL_LIBC, "lstat");
[4633]318#endif
[3138]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();
[3771]335  roar_vio_select(NULL, 0, NULL, NULL);
[3138]336  inited++;
337 }
338}
339
[3157]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
[3138]372static int _open_dummy (void) {
373 int p[2];
374
[4078]375 ROAR_DBG("_open_dummy(void) = ?");
376
[3138]377 if ( pipe(p) == -1 )
378  return -1;
379
380 close(p[1]);
381
[4078]382 ROAR_DBG("_open_dummy(void) = %i", p[0]);
[3138]383 return p[0];
384}
385
[5754]386static struct session * _open_session (const char * server, const char * name) {
[3652]387 struct session * ses = &_session;
[5754]388 int new_session = roar_env_get("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
[3652]389
[3183]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
[3652]393 if ( new_session ) {
[3850]394  ses = roar_mm_malloc(sizeof(struct session));
[3652]395  if ( ses == NULL )
396   return NULL;
397
398  memset(ses, 0, sizeof(struct session));
399 }
400
401 if ( ses->refc == 0 ) {
[3138]402
403  if ( name == NULL )
[5754]404   name = roar_env_get("ROAR_OSS_CLIENT_NAME");
[3500]405
406  if ( name == NULL )
[3138]407   name = "libroaross client";
408
[3652]409  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
410   if ( new_session )
[3850]411    roar_mm_free(ses);
[3652]412
[3138]413   return NULL;
[3652]414  }
[3157]415
[3652]416  _find_volume_sid(ses);
[3184]417
[3652]418  if ( !new_session ) {
[5754]419   if ( roar_env_get("ROAR_OSS_KEEP_SESSION") != NULL )
[3652]420    ses->refc++;
421  }
[3143]422 }
[3138]423
[3652]424 ses->refc++;
[3183]425
[3652]426 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
427 return ses;
[3138]428}
429
430static void _close_session(struct session * session) {
431 if ( session == NULL )
432  return;
433
434 session->refc--;
435
[3144]436 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
437
[3138]438 if ( session->refc == 0 ) {
439  roar_disconnect(&(session->con));
440 }
[3652]441
442 if ( session != &_session )
[3850]443  roar_mm_free(session);
[3138]444}
445
[3140]446static struct handle * _open_handle(struct session * session) {
447 struct handle * handle;
448
[3183]449 ROAR_DBG("_open_handle(session=%p) = ?", session);
450
[3140]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;
[3666]458
459 if ( session != NULL )
460  session->refc++; // TODO: better warp this
461
[3140]462 handle->type = HT_NONE;
[3144]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);
[3140]465
[3183]466 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
[3140]467 return handle;
468}
469
470static void _close_handle(struct handle * handle) {
[3664]471 int need_close = 0;
472
[3140]473 if (handle == NULL)
474  return;
475
476 handle->refc--;
477
[3144]478 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
479
[3140]480 if ( handle->refc == 0 ) {
[3664]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 )
[3140]492   roar_vio_close(&(handle->stream_vio));
493
[3664]494  if ( handle->session != NULL ) {
495   handle->session->refc--;
[3144]496
[3664]497   _close_session(handle->session);
498  }
[3144]499
[3140]500  roar_mm_free(handle);
501 }
502}
503
[4078]504static struct pointer * _get_pointer_by_fh_or_new (int fh) {
[3140]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
[4078]515static struct pointer * _get_pointer_by_fh (int fh) {
516 if ( fh == -1 )
[3140]517  return NULL;
518
[4078]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);
[3140]529  return NULL;
[4078]530 }
531
532 if ( (ret->fh = _open_dummy()) == -1 ) {
533  ROAR_DBG("_open_pointer(handle=%p) = NULL", handle);
534  return NULL;
535 }
[3140]536
537 ret->handle = handle;
538
[4078]539 ROAR_DBG("_open_pointer(handle=%p) = %p", handle, ret);
540
[3140]541 return ret;
542}
543
[3657]544static struct pointer * _attach_pointer(struct handle * handle, int fh) {
[4078]545 struct pointer * ret = _get_pointer_by_fh_or_new(-1);
[3657]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
[3140]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}
[3138]570
571// -------------------------------------
[3870]572// central function to find device:
573// -------------------------------------
574
575static struct devices * _get_device (const char * pathname) {
[4008]576 size_t len, pathlen;
[3870]577 int i;
[4008]578 int qm_match;
[3870]579
[4007]580 ROAR_DBG("_get_device(pathname='%s') = ?", pathname);
581
[4008]582 pathlen = strlen(pathname);
583
[3870]584 for (i = 0; _device_list[i].prefix != NULL; i++) {
585  len = strlen(_device_list[i].prefix);
586
[4008]587  qm_match = 0;
588
[3870]589  if ( _device_list[i].prefix[len-1] == '*' ) {
590   len--;
[4008]591  } else if ( _device_list[i].prefix[len-1] == '?' ) {
592   qm_match = 1;
593   len--;
[3870]594  } else {
595   len++;
596  }
[4008]597
[3870]598  if ( !strncmp(pathname, _device_list[i].prefix, len) ) {
[4008]599   if ( !qm_match || pathlen == (len + 1) )
600    return &(_device_list[i]);
[3870]601  }
602 }
603
[4007]604 ROAR_DBG("_get_device(pathname='%s') = NULL", pathname);
[3870]605 return NULL;
606}
607
608// -------------------------------------
[3142]609// central open function:
610// -------------------------------------
611
612static int _open_file (const char *pathname, int flags) {
[3143]613 struct session * session;
614 struct handle  * handle;
615 struct pointer * pointer;
[3662]616 struct devices * ptr = NULL;
[3143]617
[3665]618 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
619
[3777]620/*
621 * Flags we ignore:
622 * O_DIRECT, O_APPEND, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_TRUNC
623 */
624
[4081]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
[3951]633#ifdef O_ASYNC
[3777]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 }
[3951]639#endif
[3777]640
[4487]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);
[3777]653  errno = EINVAL;
654  return -1;
655 }
656
[4007]657 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
658
[3666]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  }
[3143]666 }
667
[3870]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;
[3143]685 }
686
[3868]687 switch (flags & _O_PARA_DIR) {
[3145]688  case O_RDONLY:
[3244]689    switch (ptr->type) {
690     case HT_WAVEFORM:
[5543]691       handle->stream_dir = ROAR_DIR_RECORD;
[3244]692      break;
693     case HT_MIDI:
694       handle->stream_dir = ROAR_DIR_MIDI_OUT;
695      break;
[3246]696     case HT_DMX:
697       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
698      break;
[3665]699     case HT_MIXER:
[3666]700     case HT_STATIC:
[3665]701      break;
[3248]702     default:
[3665]703       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3248]704       return -1;
[3244]705    }
[3145]706   break;
707  case O_WRONLY:
[3244]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;
[3246]715     case HT_DMX:
716       handle->stream_dir = ROAR_DIR_LIGHT_IN;
717      break;
[3666]718     case HT_MIXER:
719     case HT_STATIC:
720      break;
[3248]721     default:
[3665]722       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3248]723       return -1;
[3244]724    }
[3145]725   break;
726  case O_RDWR:
[3244]727    switch (ptr->type) {
728     case HT_WAVEFORM:
[5543]729       handle->stream_dir = ROAR_DIR_RECPLAY;
[3244]730      break;
[3666]731     case HT_MIXER:
732     case HT_STATIC:
733      break;
[3248]734     default:
[3665]735       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3248]736       return -1;
[3244]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;
[3145]751   break;
[3261]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;
[3666]758  case HT_STATIC:
759    handle->userdata.sf.len      = ptr->len;
760    handle->userdata.sf.data     = ptr->userdata;
761   break;
[3145]762 }
763
[4078]764 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
765
[3143]766 if ( (pointer = _open_pointer(handle)) == NULL ) {
767  _close_handle(handle);
[3665]768  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3143]769  return -1;
770 }
771
[3665]772 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
773
[3143]774 return pointer->fh;
[3142]775}
776
777// -------------------------------------
[3952]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
[4964]797 if ( roar_vio_clear_calls(&(handle->stream_vio)) == -1 ) {
[3953]798  _close_handle(handle);
799  return -1;
800 }
801
[3952]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// -------------------------------------
[3144]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,
[5289]831                                     handle->stream_dir,
832                                     -1 /* TODO: Find better way to select mixer ID. */
[3144]833                                    ) == -1 )
834  return -1;
835
836 handle->stream_opened++;
837
[3150]838 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
839
[3849]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
[3144]875 return 0;
876}
877
878// -------------------------------------
[3147]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
[3148]935  default:
[3229]936    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
[3148]937    errno = ENOSYS;
938    return -1;
939   break;
[3147]940 }
941
[3148]942 return 0;
[3147]943}
944
[3149]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
[3147]974// -------------------------------------
[3150]975// mixer ioctls:
976// -------------------------------------
977
[3158]978static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
[3159]979 mixer_info * info;
[3150]980 int channels;
981 struct roar_mixer_settings mixer;
[3155]982 int o_w    =  0;
[3150]983 int o_sid  = -1;
[3158]984 int * ip   = vp;
[3165]985#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
986 char * name = NULL;
987#endif
[3150]988
[3165]989#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
[3150]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
[3159]1000//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
[3152]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;
[3156]1005  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
1006  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
[3152]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;
[3156]1013//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
1014  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
[3152]1015/*
1016  case :     name = "";     break;
[3156]1017  case :     name = "";     break;
[3152]1018*/
[3150]1019 }
1020 if ( name != NULL ) {
[3656]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);
[3150]1023  errno = ENOSYS;
1024  return -1;
1025 }
[3165]1026#endif
[3150]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
[3177]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;
[3150]1066 }
1067 if ( o_sid != -1 ) {
1068  // set/get volume
1069  if ( o_w ) {
[3536]1070   mixer.scale    = OSS_VOLUME_SCALE;
1071   mixer.mixer[0] = ( *ip       & 0xFF);
1072   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
[5236]1073   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2, ROAR_SET_VOL_UNMAPPED) == -1 ) {
[3156]1074    errno = EIO;
[3150]1075    return -1;
1076   }
1077   return 0;
1078  } else {
1079   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
[3156]1080    errno = EIO;
[3150]1081    return -1;
1082   }
[3153]1083   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
[3150]1084   return 0;
1085  }
1086 }
1087
1088 switch (req) {
[3155]1089  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
[3150]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 )
[3156]1106#if 0
[3150]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;
[3156]1112#endif
[3150]1113
1114    return 0;
1115   break;
[3153]1116  case SOUND_MIXER_READ_RECMASK:
[3154]1117  case SOUND_MIXER_READ_RECSRC:
[3153]1118    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
1119    return 0;
1120   break;
[3154]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;
[3156]1129  case SOUND_MIXER_READ_CAPS:
1130    *ip = 0;
1131    return 0;
1132   break;
[3159]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;
[3150]1140 }
1141
[3656]1142 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
[3156]1143// _os.ioctl(-1, req, ip);
[3656]1144 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
[3150]1145 errno = ENOSYS;
1146 return -1;
1147}
1148
1149// -------------------------------------
[3178]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// -------------------------------------
[3138]1163// emulated functions follow:
1164// -------------------------------------
1165
1166int     open(const char *pathname, int flags, ...) {
[3142]1167 int     ret;
1168 mode_t  mode = 0;
[3138]1169 va_list args;
1170
1171 _init();
1172
[3261]1173 if ( pathname == NULL ) {
1174  errno = EFAULT;
1175  return -1;
1176 }
1177
1178 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
[3142]1179 ret = _open_file(pathname, flags);
1180
1181 switch (ret) {
1182  case -2:       // continue as normal, use _op.open()
[4081]1183    ROAR_DBG("open(pathname='%s', flags=%x, ...): is not handled by us, pass to kernel\n", pathname, flags);
[3142]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
[3138]1193 if (flags & O_CREAT) {
1194  va_start(args, flags);
[3891]1195  mode = va_arg(args, _VA_ARGS_MODE_T);
[3138]1196  va_end(args);
1197 }
1198
1199 return _os.open(pathname, flags, mode);
1200}
1201
[3866]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
[4081]1214 ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = ?", __file, __oflag);
[3866]1215 ret = _open_file(__file, __oflag);
1216
1217 switch (ret) {
1218  case -2:       // continue as normal, use _op.open()
[4081]1219    ROAR_DBG("open64(__file='%s', __oflags=%x, ...): not for us, passing to kernel", __file, __oflag);
[3866]1220   break;
1221  case -1:       // pass error to caller
1222    return -1;
1223   break;
1224  default:       // return successfully opened pointer to caller
[4081]1225    ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = %i", __file, __oflag, ret);
[3866]1226    return ret;
1227   break;
1228 }
1229
1230 if (__oflag & O_CREAT) {
1231  va_start(args, __oflag);
[3891]1232  mode = va_arg(args, _VA_ARGS_MODE_T);
[3866]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
[3138]1247int     close(int fd) {
[3140]1248 struct pointer * pointer;
[3138]1249 _init();
1250
[3140]1251 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1252  _close_pointer(pointer);
1253  return 0;
1254 }
1255
[3138]1256 return _os.close(fd);
1257}
1258
1259ssize_t write(int fd, const void *buf, size_t count) {
[3261]1260 struct roar_roardmx_message roardmxmsg;
[3140]1261 struct pointer * pointer;
[3178]1262 ssize_t ret;
[3639]1263 size_t i;
[3140]1264
[3138]1265 _init();
1266
[3140]1267 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
[3655]1268  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
[3261]1269  switch (pointer->handle->type) {
[3664]1270   case HT_STREAM: // handle stream specific stuff
[3261]1271     if ( pointer->handle->stream_opened == 0 ) {
1272      if ( _open_stream(pointer->handle) == -1 ) {
1273       errno = EIO;
1274       return -1;
1275      }
1276     }
[3664]1277   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
[3261]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;
[3664]1283   case HT_DMX: // DMX need specal handling as we need to convert the protocol
[3261]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;
[3664]1313   default: // we don't know what to do with other types
[3261]1314     errno = EINVAL;
[3140]1315     return -1;
[3261]1316    break;
[3140]1317  }
1318 }
1319
[3138]1320 return _os.write(fd, buf, count);
1321}
1322
1323ssize_t read(int fd, void *buf, size_t count) {
[3140]1324 struct pointer * pointer;
[3178]1325 ssize_t ret;
[3140]1326
[3138]1327 _init();
1328
[3140]1329 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
[3666]1330  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1331
[3664]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;
[3666]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;
[3664]1358   default:
1359     errno = EINVAL;
[3140]1360     return -1;
[3664]1361    break;
[3140]1362  }
1363 }
1364
[3138]1365 return _os.read(fd, buf, count);
1366}
1367
[3246]1368off_t lseek(int fildes, off_t offset, int whence) {
1369 struct pointer * pointer;
[3666]1370 ssize_t tmp;
[3246]1371
1372 _init();
1373
1374 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
[3664]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;
[3666]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;
[3664]1426   default:
1427     errno = EINVAL;
1428     return -1;
1429    break;
[3246]1430  }
1431 }
1432
1433 return _os.lseek(fildes, offset, whence);
1434}
1435
[3169]1436IOCTL() {
1437 map_args;
[3147]1438 struct pointer * pointer;
1439 struct handle  * handle;
[3169]1440 int * ip = NULL;
[3655]1441 size_t tmp;
[3176]1442 audio_buf_info * bi;
[3178]1443 count_info     * ci;
[3229]1444#ifdef __FIXME__
1445 char * nosys_reqname = NULL;
1446#endif
[3169]1447#ifdef va_argp
[3146]1448 va_list args;
[3169]1449#endif
[3146]1450
1451 _init();
1452
[4079]1453 ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
[3148]1454
[3169]1455#ifdef va_argp
[3180]1456 va_start (args, ioctl_lastarg);
[3146]1457 argp = va_arg (args, void *);
1458 va_end (args);
[3169]1459#endif
[3146]1460
[4079]1461// ROAR_DBG("ioctl(fh=%i, request=%i, ...) = ?", __fd, __request);
[4077]1462
[4079]1463 ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
[3148]1464
[3147]1465 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
[3148]1466  ip = argp;
[3656]1467//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
[3229]1468#ifdef __FIXME__
[4079]1469  switch (__request) {
[3792]1470   case SOUND_PCM_READ_RATE: nosys_reqname     = "SOUND_PCM_READ_RATE";     break;
[3229]1471   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
[3792]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;
[3654]1485   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
[3229]1486/*
1487   case : nosys_reqname = ""; break;
1488   case : nosys_reqname = ""; break;
1489   case : nosys_reqname = ""; break;
1490*/
1491  }
1492#endif
[3147]1493  switch ((handle = pointer->handle)->type) {
1494   case HT_STREAM:
1495     switch (__request) {
1496      case SNDCTL_DSP_RESET:
1497      case SNDCTL_DSP_POST:
[3654]1498      case SNDCTL_DSP_SYNC: // ignore for the moment.
[3162]1499      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
[3654]1500      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
[3175]1501        return 0;
[3147]1502       break;
[4853]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;
[3147]1507      case SNDCTL_DSP_SPEED:
1508        handle->stream.info.rate = *ip;
[3656]1509        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
[3147]1510        return 0;
1511       break;
1512      case SNDCTL_DSP_CHANNELS:
1513        handle->stream.info.channels = *ip;
[3656]1514        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
[3147]1515        return 0;
1516       break;
[3160]1517      case SNDCTL_DSP_STEREO:
1518        handle->stream.info.channels = *ip ? 2 : 1;
1519        return 0;
1520       break;
[3161]1521      case SNDCTL_DSP_GETBLKSIZE:
[3178]1522        *ip = _get_stream_buffersize(handle);
[3161]1523        return 0;
1524       break;
[3147]1525      case SNDCTL_DSP_SETFMT:
[3656]1526        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
[3147]1527        return _ioctl_stream_format(handle, *ip);
1528       break;
[3148]1529      case SNDCTL_DSP_GETFMTS:
[3656]1530//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
[3149]1531        *ip = _ioctl_stream_format_list();
[3148]1532        return 0;
1533       break;
[3176]1534      case SNDCTL_DSP_GETOSPACE:
1535      case SNDCTL_DSP_GETISPACE:
1536        bi = argp;
1537        memset(bi, 0, sizeof(*bi));
[3178]1538        bi->bytes      = _get_stream_buffersize(handle);
[3176]1539        bi->fragments  = 1;
1540        bi->fragsize   = bi->bytes;
1541        bi->fragstotal = 1;
1542        return 0;
1543       break;
[3178]1544      case SNDCTL_DSP_GETOPTR:
[3655]1545        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
[3178]1546        ci = argp;
1547        memset(ci, 0, sizeof(*ci));
1548        ci->bytes  = handle->writec;
[3655]1549        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1550        ci->ptr    = ci->bytes % tmp;
[3178]1551        return 0;
1552       break;
1553      case SNDCTL_DSP_GETIPTR:
1554        ci = argp;
1555        memset(ci, 0, sizeof(*ci));
1556        ci->bytes  = handle->readc;
[3655]1557        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1558        ci->ptr    = ci->bytes % tmp;
[3178]1559        return 0;
1560       break;
[3177]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
[3864]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
[3147]1576      default:
[3229]1577#ifdef __FIXME__
[3656]1578        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
[3229]1579#else
[3656]1580        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
[3229]1581#endif
[3147]1582        errno = ENOSYS;
1583        return -1;
1584     }
1585    break;
1586   case HT_MIXER:
[3158]1587     return _ioctl_mixer(handle, __request, argp);
[3147]1588    break;
1589   default:
[3656]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);
[3147]1592     errno = EINVAL;
1593     return -1;
1594    break;
1595  }
1596 }
1597
[3166]1598#ifdef IOCTL_IS_ALIAS
1599 errno = ENOSYS;
1600 return -1;
1601#else
[4081]1602 ROAR_DBG("ioctl(__fd=%i, __request=0x%lX, argp=%p): not for us, passing to kernel", __fd, (long unsigned int) __request, argp);
[3146]1603 return _os.ioctl(__fd, __request, argp);
[3166]1604#endif
[3146]1605}
1606
[3657]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}
[3264]1648
[3771]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;
[3774]1653 struct pointer * pointer;
1654 struct handle  * handle;
[3771]1655 ssize_t ret;
1656 size_t num = 0;
[3773]1657 size_t idx;
[3771]1658 int i;
1659 int i_r, i_w, i_e;
1660 int max_index = -1;
[3773]1661 static volatile int is_critical = 0;
[3771]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...
[3774]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   }
[3771]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);
[4226]1769
1770  if ( ret == 0 ) {
1771   if ( readfds != NULL ) {
1772    FD_ZERO(readfds);
1773   }
1774   if ( writefds != NULL ) {
1775    FD_ZERO(writefds);
1776   }
[4227]1777   if ( exceptfds != NULL ) {
[4226]1778    FD_ZERO(exceptfds);
1779   }
1780  }
1781
[3771]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
[3778]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;
[3780]1824 int ret   = -1;
1825 int diff;
[3778]1826
[3779]1827 _init();
1828
[3781]1829 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...) = ?", fd, cmd);
1830
[3778]1831 switch (cmd) {
1832  case F_DUPFD:
1833  case F_SETFD:
1834  case F_SETFL:
1835  case F_SETOWN:
[3872]1836#ifdef F_SETSIG
[3778]1837  case F_SETSIG:
[3872]1838#endif
1839#ifdef F_SETLEASE
[3778]1840  case F_SETLEASE:
[3872]1841#endif
1842#ifdef F_NOTIFY
[3778]1843  case F_NOTIFY:
[3872]1844#endif
[3778]1845    type = LONG;
1846   break;
1847  case F_GETFD:
1848  case F_GETFL:
1849  case F_GETOWN:
[3872]1850#ifdef F_GETSIG
[3778]1851  case F_GETSIG:
[3872]1852#endif
1853#ifdef F_GETLEASE
[3778]1854  case F_GETLEASE:
[3872]1855#endif
[3778]1856    type = NONE;
1857   break;
1858  case F_GETLK:
1859  case F_SETLK:
1860  case F_SETLKW:
[4081]1861#ifdef F_GETLK64
[4121]1862#if F_GETLK64 != F_GETLK
[4081]1863  case F_GETLK64:
1864#endif
[4121]1865#endif
[4081]1866#ifdef F_SETLK64
[4121]1867#if F_SETLK64 != F_SETLK
[4081]1868  case F_SETLK64:
1869#endif
[4121]1870#endif
[4081]1871#ifdef F_SETLKW64
[4121]1872#if F_SETLKW64 != F_SETLKW
[4081]1873  case F_SETLKW64:
1874#endif
[4121]1875#endif
[3778]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 ) {
[4081]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);
[3778]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:
[3781]1916     ROAR_DBG("fcntl(fd=%i, cmd=%i): fd is true sysio, pass call to kernel", fd, cmd);
[3778]1917     return _os.fcntl(fd, cmd);
1918    break;
1919   case LONG:
[3781]1920     ROAR_DBG("fcntl(fd=%i, cmd=%i, arg=%li): fd is true sysio, pass call to kernel", fd, cmd, argl);
[3778]1921     return _os.fcntl(fd, cmd, argl);
1922    break;
1923   case POINTER:
[3781]1924     ROAR_DBG("fcntl(fd=%i, cmd=%i, lock=%p): fd is true sysio, pass call to kernel", fd, cmd, vp);
[3778]1925     return _os.fcntl(fd, cmd, vp);
1926    break;
1927   default: /* make compiler happy */
1928    break;
1929  }
1930 }
1931
[3781]1932 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...): fd is true pointer, handle internaly", fd, cmd);
1933
[3780]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;
[3868]1961    diff &= (int)~(int)_O_PARA_DIR;
1962    diff &= (int)~(int)_O_PARA_IGN;
[3849]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
[3780]1973    if ( diff == 0 ) { // only flags changed we ignore anyway.
[3849]1974     pointer->handle->sysio_flags  = (int)argl;
[3780]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;
[3778]2001}
2002
[3782]2003int access(const char *pathname, int mode) {
[3783]2004 struct devices * ptr = NULL;
[3782]2005
2006 _init();
2007
[3870]2008 if ( (ptr = _get_device(pathname)) != NULL ) {
[3783]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
[3782]2027 return _os.access(pathname, mode);
2028}
2029
[3890]2030int creat(const char *_CREAT_ARG_PATHNAME, mode_t mode) {
[3871]2031 _init();
2032
[3890]2033 if ( _get_device(_CREAT_ARG_PATHNAME) != NULL ) {
[3871]2034  errno = EEXIST;
2035  return -1;
2036 }
2037
[3890]2038 return _os.creat(_CREAT_ARG_PATHNAME, mode);
[3871]2039}
2040
[3264]2041// -------------------------------------
[3880]2042// emulated *stat*() functions follow:
2043// -------------------------------------
2044
[4633]2045#ifndef __clang__
[3880]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}
[4633]2081#endif
[3880]2082
2083// -------------------------------------
[3264]2084// emulated stdio functions follow:
2085// -------------------------------------
2086
2087//roar_vio_to_stdio
2088
[3667]2089static int _vio_close    (struct roar_vio_calls * vio) {
2090 int ret = 0;
[5234]2091 int fh = -1;
[3667]2092
[5234]2093 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_GET_FH, &fh) != -1 )
2094  if ( fh != -1 )
2095   ret = close(fh);
[3667]2096
2097 roar_mm_free(vio);
2098
2099 return ret;
2100}
2101
[3264]2102FILE *fopen(const char *path, const char *mode) {
[3667]2103 struct roar_vio_calls * vio;
[3264]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
[3265]2118 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
[3264]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()
[4081]2147    ROAR_DBG("fopen(path='%s', mode='%s'): not for us, passing to libc", path, mode);
[3264]2148   break;
2149  case -1:       // pass error to caller
2150    return NULL;
2151   break;
2152  default:       // return successfully opened pointer to caller
[4080]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
[3667]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
[5234]2161    roar_vio_open_fh(vio, ret);
[3667]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    }
[4080]2170#endif
[3264]2171   break;
2172 }
2173
2174 return _os.fopen(path, mode);
2175}
2176
[3879]2177// -------------------------------------
2178// RoarAudio plugin functions follow:
2179// -------------------------------------
2180
2181ROAR_DL_PLUGIN_START(libroaross) {
2182 _init();
2183} ROAR_DL_PLUGIN_END
2184
[3138]2185#endif
2186
2187//ll
Note: See TracBrowser for help on using the repository browser.