source: roaraudio/libroaross/libroaross.c @ 3775:3fe8c77c0208

Last change on this file since 3775:3fe8c77c0208 was 3775:3fe8c77c0208, checked in by phi, 14 years ago

added comments

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