source: roaraudio/libroaross/libroaross.c @ 5381:430b1d26e12d

Last change on this file since 5381:430b1d26e12d was 5381:430b1d26e12d, checked in by phi, 12 years ago

updated copyright years

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