source: roaraudio/libroaross/libroaross.c @ 3780:d463fa7a8ba9

Last change on this file since 3780:d463fa7a8ba9 was 3780:d463fa7a8ba9, checked in by phi, 14 years ago

added some very basic support for fcntl()

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