source: roaraudio/libroaross/libroaross.c @ 3777:cfa215d2654d

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

handle some flags

File size: 42.4 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/*
497 * Flags we ignore:
498 * O_DIRECT, O_APPEND, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_TRUNC
499 */
500
501 if ( flags & O_ASYNC ) {
502  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // not supported O_ASYNC", pathname, flags);
503  errno = ENOSYS;
504  return -1;
505 }
506
507 if ( (flags & O_DIRECTORY) || (flags & O_EXCL) ) {
508  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // invalid flags (O_DIRECTORY or O_EXCL)", pathname, flags);
509  errno = EINVAL;
510  return -1;
511 }
512
513 for (i = 0; _device_list[i].prefix != NULL; i++) {
514  if ( !strcmp(pathname, _device_list[i].prefix) ) {
515   ptr = &(_device_list[i]);
516  }
517 }
518
519 if ( ptr == NULL )
520  return -2;
521
522 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
523  session = NULL;
524 } else {
525  if ( (session = _open_session(NULL, NULL)) == NULL ) {
526   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
527   return -1;
528  }
529 }
530
531 if ( (handle = _open_handle(session)) == NULL ) {
532  _close_session(session);
533  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
534  return -1;
535 }
536
537 handle->type       = ptr->type;
538 handle->stream_dir = -1;
539
540 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
541  case O_RDONLY:
542    switch (ptr->type) {
543     case HT_WAVEFORM:
544       handle->stream_dir = ROAR_DIR_MONITOR;
545      break;
546     case HT_MIDI:
547       handle->stream_dir = ROAR_DIR_MIDI_OUT;
548      break;
549     case HT_DMX:
550       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
551      break;
552     case HT_MIXER:
553     case HT_STATIC:
554      break;
555     default:
556       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
557       return -1;
558    }
559   break;
560  case O_WRONLY:
561    switch (ptr->type) {
562     case HT_WAVEFORM:
563       handle->stream_dir = ROAR_DIR_PLAY;
564      break;
565     case HT_MIDI:
566       handle->stream_dir = ROAR_DIR_MIDI_IN;
567      break;
568     case HT_DMX:
569       handle->stream_dir = ROAR_DIR_LIGHT_IN;
570      break;
571     case HT_MIXER:
572     case HT_STATIC:
573      break;
574     default:
575       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
576       return -1;
577    }
578   break;
579  case O_RDWR:
580    switch (ptr->type) {
581     case HT_WAVEFORM:
582       handle->stream_dir = ROAR_DIR_BIDIR;
583      break;
584     case HT_MIXER:
585     case HT_STATIC:
586      break;
587     default:
588       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
589       return -1;
590    }
591   break;
592 }
593
594 switch (handle->type) {
595  case HT_WAVEFORM:
596    handle->type = HT_STREAM;
597   break;
598  case HT_MIDI:
599    handle->type = HT_STREAM;
600    handle->stream.info.rate     = 0;
601    handle->stream.info.bits     = ROAR_MIDI_BITS;
602    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
603    handle->stream.info.codec    = ROAR_CODEC_MIDI;
604   break;
605  case HT_DMX:
606    handle->stream.info.rate     = 0;
607    handle->stream.info.bits     = ROAR_LIGHT_BITS;
608    handle->stream.info.channels = 512;
609    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
610   break;
611  case HT_STATIC:
612    handle->userdata.sf.len      = ptr->len;
613    handle->userdata.sf.data     = ptr->userdata;
614   break;
615 }
616
617 if ( (pointer = _open_pointer(handle)) == NULL ) {
618  _close_handle(handle);
619  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
620  return -1;
621 }
622
623 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
624
625 return pointer->fh;
626}
627
628// -------------------------------------
629// open function for streams:
630// -------------------------------------
631
632static int _open_stream (struct handle * handle) {
633  // FIXME: this should be re-written much more cleanly:
634
635 if ( handle == NULL )
636  return -1;
637
638 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
639                                     &(handle->session->con), &(handle->stream),
640                                     handle->stream.info.rate,
641                                     handle->stream.info.channels,
642                                     handle->stream.info.bits,
643                                     handle->stream.info.codec,
644                                     handle->stream_dir
645                                    ) == -1 )
646  return -1;
647
648 handle->stream_opened++;
649
650 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
651
652 return 0;
653}
654
655// -------------------------------------
656// function to parse format:
657// -------------------------------------
658
659static int _ioctl_stream_format (struct handle * handle, int format) {
660 struct roar_audio_info * info = &(handle->stream.info);
661
662 switch (format) {
663  case AFMT_S8:
664    info->bits  = 8;
665    info->codec = ROAR_CODEC_PCM_S_LE;
666   break;
667  case AFMT_U8:
668    info->bits  = 8;
669    info->codec = ROAR_CODEC_PCM_U_LE;
670   break;
671  case AFMT_S16_BE:
672    info->bits  = 16;
673    info->codec = ROAR_CODEC_PCM_S_BE;
674   break;
675  case AFMT_S16_LE:
676    info->bits  = 16;
677    info->codec = ROAR_CODEC_PCM_S_LE;
678   break;
679  case AFMT_U16_BE:
680    info->bits  = 16;
681    info->codec = ROAR_CODEC_PCM_U_BE;
682   break;
683  case AFMT_U16_LE:
684    info->bits  = 16;
685    info->codec = ROAR_CODEC_PCM_U_LE;
686   break;
687#ifdef AFMT_S32_BE
688  case AFMT_S32_BE:
689    info->bits  = 32;
690    info->codec = ROAR_CODEC_PCM_S_BE;
691   break;
692#endif
693#ifdef AFMT_S32_LE
694  case AFMT_S32_LE:
695    info->bits  = 32;
696    info->codec = ROAR_CODEC_PCM_S_LE;
697   break;
698#endif
699  case AFMT_A_LAW:
700    info->bits  = 8;
701    info->codec = ROAR_CODEC_ALAW;
702   break;
703  case AFMT_MU_LAW:
704    info->bits  = 8;
705    info->codec = ROAR_CODEC_MULAW;
706   break;
707#ifdef AFMT_VORBIS
708  case AFMT_VORBIS:
709    info->codec = ROAR_CODEC_OGG_VORBIS;
710   break;
711#endif
712  default:
713    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
714    errno = ENOSYS;
715    return -1;
716   break;
717 }
718
719 return 0;
720}
721
722static inline int _ioctl_stream_format_list (void) {
723 int format = 0;
724
725 format |= AFMT_S8;
726 format |= AFMT_U8;
727
728 format |= AFMT_S16_BE;
729 format |= AFMT_S16_LE;
730
731 format |= AFMT_U16_BE;
732 format |= AFMT_U16_LE;
733
734#ifdef AFMT_S32_BE
735 format |= AFMT_S32_BE;
736#endif
737#ifdef AFMT_S32_LE
738 format |= AFMT_S32_LE;
739#endif
740
741 format |= AFMT_A_LAW;
742 format |= AFMT_MU_LAW;
743
744#ifdef AFMT_VORBIS
745 format |= AFMT_VORBIS;
746#endif
747
748 return format;
749}
750
751// -------------------------------------
752// mixer ioctls:
753// -------------------------------------
754
755static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
756 mixer_info * info;
757 int channels;
758 struct roar_mixer_settings mixer;
759 int o_w    =  0;
760 int o_sid  = -1;
761 int * ip   = vp;
762#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
763 char * name = NULL;
764#endif
765
766#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
767 switch (req) {
768#if 0
769  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
770  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
771  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
772  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
773  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
774  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
775  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
776#endif
777//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
778  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
779  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
780  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
781  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
782  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
783  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
784  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
785  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
786  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
787  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
788  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
789  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
790//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
791  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
792/*
793  case :     name = "";     break;
794  case :     name = "";     break;
795*/
796 }
797 if ( name != NULL ) {
798  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
799  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
800  errno = ENOSYS;
801  return -1;
802 }
803#endif
804
805 switch (req) {
806  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
807  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
808  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
809  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
810  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
811#if 0
812  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
813  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
814  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
815#endif
816  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
817  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
818  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
819  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
820  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
821#if 0
822  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
823  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
824  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
825#endif
826  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
827  case SOUND_MIXER_READ_PCM:
828    o_w = 0;
829    if ( handle->type == HT_STREAM ) {
830     o_sid = roar_stream_get_id(&(handle->stream));
831    } else {
832     o_sid = _mix_settings.sid.pcm;
833    }
834   break;
835  case SOUND_MIXER_WRITE_PCM:
836    o_w = 1;
837    if ( handle->type == HT_STREAM ) {
838     o_sid = roar_stream_get_id(&(handle->stream));
839    } else {
840     o_sid = _mix_settings.sid.pcm;
841    }
842   break;
843 }
844 if ( o_sid != -1 ) {
845  // set/get volume
846  if ( o_w ) {
847   mixer.scale    = OSS_VOLUME_SCALE;
848   mixer.mixer[0] = ( *ip       & 0xFF);
849   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
850   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
851    errno = EIO;
852    return -1;
853   }
854   return 0;
855  } else {
856   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
857    errno = EIO;
858    return -1;
859   }
860   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
861   return 0;
862  }
863 }
864
865 switch (req) {
866  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
867  case SOUND_MIXER_READ_DEVMASK:
868    *ip = 0;
869
870    if ( _mix_settings.sid.volume != -1 )
871     *ip |= SOUND_MASK_VOLUME;
872    if ( _mix_settings.sid.pcm != -1 )
873     *ip |= SOUND_MASK_PCM;
874    if ( _mix_settings.sid.line != -1 )
875     *ip |= SOUND_MASK_LINE;
876    if ( _mix_settings.sid.line1 != -1 )
877     *ip |= SOUND_MASK_LINE1;
878    if ( _mix_settings.sid.line2 != -1 )
879     *ip |= SOUND_MASK_LINE2;
880    if ( _mix_settings.sid.line3 != -1 )
881     *ip |= SOUND_MASK_LINE3;
882    if ( _mix_settings.sid.digital1 != -1 )
883#if 0
884     *ip |= SOUND_MASK_DIGITAL1;
885    if ( _mix_settings.sid.digital2 != -1 )
886     *ip |= SOUND_MASK_DIGITAL2;
887    if ( _mix_settings.sid.digital3 != -1 )
888     *ip |= SOUND_MASK_DIGITAL3;
889#endif
890
891    return 0;
892   break;
893  case SOUND_MIXER_READ_RECMASK:
894  case SOUND_MIXER_READ_RECSRC:
895    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
896    return 0;
897   break;
898  case SOUND_MIXER_WRITE_RECSRC:
899    if ( *ip == SOUND_MASK_VOLUME ) {
900     return  0;
901    } else {
902     errno = ENOTSUP;
903     return -1;
904    }
905   break;
906  case SOUND_MIXER_READ_CAPS:
907    *ip = 0;
908    return 0;
909   break;
910  case SOUND_MIXER_INFO:
911    info = vp;
912    memset(info, 0, sizeof(*info));
913    strcpy(info->id, "RoarAudio");
914    strcpy(info->name, "RoarAudio");
915    return 0;
916   break;
917 }
918
919 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
920// _os.ioctl(-1, req, ip);
921 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
922 errno = ENOSYS;
923 return -1;
924}
925
926// -------------------------------------
927// buffer size calculation:
928// -------------------------------------
929
930static size_t _get_stream_buffersize (struct handle * handle) {
931 if ( handle->stream_buffersize )
932  return handle->stream_buffersize;
933
934 return handle->stream_buffersize = handle->stream.info.rate     *
935                                    handle->stream.info.channels *
936                                    handle->stream.info.bits     / 800;
937}
938
939// -------------------------------------
940// emulated functions follow:
941// -------------------------------------
942
943int     open(const char *pathname, int flags, ...) {
944 int     ret;
945 mode_t  mode = 0;
946 va_list args;
947
948 _init();
949
950 if ( pathname == NULL ) {
951  errno = EFAULT;
952  return -1;
953 }
954
955 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
956 ret = _open_file(pathname, flags);
957
958 switch (ret) {
959  case -2:       // continue as normal, use _op.open()
960   break;
961  case -1:       // pass error to caller
962    return -1;
963   break;
964  default:       // return successfully opened pointer to caller
965    return ret;
966   break;
967 }
968
969 if (flags & O_CREAT) {
970  va_start(args, flags);
971  mode = va_arg(args, mode_t);
972  va_end(args);
973 }
974
975 return _os.open(pathname, flags, mode);
976}
977
978int     close(int fd) {
979 struct pointer * pointer;
980 _init();
981
982 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
983  _close_pointer(pointer);
984  return 0;
985 }
986
987 return _os.close(fd);
988}
989
990ssize_t write(int fd, const void *buf, size_t count) {
991 struct roar_roardmx_message roardmxmsg;
992 struct pointer * pointer;
993 ssize_t ret;
994 size_t i;
995
996 _init();
997
998 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
999  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
1000  switch (pointer->handle->type) {
1001   case HT_STREAM: // handle stream specific stuff
1002     if ( pointer->handle->stream_opened == 0 ) {
1003      if ( _open_stream(pointer->handle) == -1 ) {
1004       errno = EIO;
1005       return -1;
1006      }
1007     }
1008   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
1009     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
1010     if ( ret > 0 )
1011      pointer->handle->writec += ret;
1012     return ret;
1013    break;
1014   case HT_DMX: // DMX need specal handling as we need to convert the protocol
1015     if ( pointer->handle->stream_opened == 0 ) {
1016      if ( _open_stream(pointer->handle) == -1 ) {
1017       errno = EIO;
1018       return -1;
1019      }
1020     }
1021     if ( count > 0 ) {
1022      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
1023       errno = EIO;
1024       return -1;
1025      }
1026      for (i = 0; i < count; i++) {
1027       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1028#ifdef EMSGSIZE
1029        errno = EMSGSIZE;
1030#else
1031        errno = EIO;
1032#endif
1033        return -1;
1034       }
1035      }
1036      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1037       errno = EIO;
1038       return -1;
1039      }
1040     }
1041     pointer->handle->pos += count;
1042     return count;
1043    break;
1044   default: // we don't know what to do with other types
1045     errno = EINVAL;
1046     return -1;
1047    break;
1048  }
1049 }
1050
1051 return _os.write(fd, buf, count);
1052}
1053
1054ssize_t read(int fd, void *buf, size_t count) {
1055 struct pointer * pointer;
1056 ssize_t ret;
1057
1058 _init();
1059
1060 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1061  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1062
1063  switch (pointer->handle->type) {
1064   case HT_STREAM:
1065     if ( pointer->handle->stream_opened == 0 ) {
1066      if ( _open_stream(pointer->handle) == -1 ) {
1067       errno = EIO;
1068       return -1;
1069      }
1070     }
1071   case HT_VIO:
1072     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1073     if ( ret > 0 )
1074      pointer->handle->readc += ret;
1075     return ret;
1076    break;
1077   case HT_STATIC:
1078     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1079     ret = pointer->handle->pos + count; // calc the end of the read
1080
1081     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1082      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1083     }
1084
1085     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1086     pointer->handle->pos += count;
1087     return count;
1088    break;
1089   default:
1090     errno = EINVAL;
1091     return -1;
1092    break;
1093  }
1094 }
1095
1096 return _os.read(fd, buf, count);
1097}
1098
1099off_t lseek(int fildes, off_t offset, int whence) {
1100 struct pointer * pointer;
1101 ssize_t tmp;
1102
1103 _init();
1104
1105 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1106  switch (pointer->handle->type) {
1107   case HT_DMX:
1108     switch (whence) {
1109      case SEEK_SET:
1110        pointer->handle->pos  = offset;
1111       break;
1112      case SEEK_CUR:
1113        pointer->handle->pos += offset;
1114       break;
1115      case SEEK_END:
1116      default:
1117        errno = EINVAL;
1118        return -1;
1119       break;
1120     }
1121     return pointer->handle->pos;
1122    break;
1123   case HT_VIO:
1124     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1125    break;
1126   case HT_STATIC:
1127     switch (whence) {
1128      case SEEK_SET:
1129        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1130         errno = EINVAL;
1131         return -1;
1132        }
1133        pointer->handle->pos  = offset;
1134       break;
1135      case SEEK_CUR:
1136        tmp = pointer->handle->pos + offset;
1137        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1138         errno = EINVAL;
1139         return -1;
1140        }
1141        pointer->handle->pos = tmp;
1142       break;
1143      case SEEK_END:
1144        tmp = pointer->handle->userdata.sf.len + offset;
1145        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1146         errno = EINVAL;
1147         return -1;
1148        }
1149        pointer->handle->pos = tmp;
1150       break;
1151      default:
1152        errno = EINVAL;
1153        return -1;
1154       break;
1155     }
1156    break;
1157   default:
1158     errno = EINVAL;
1159     return -1;
1160    break;
1161  }
1162 }
1163
1164 return _os.lseek(fildes, offset, whence);
1165}
1166
1167IOCTL() {
1168 map_args;
1169 struct pointer * pointer;
1170 struct handle  * handle;
1171 int * ip = NULL;
1172 size_t tmp;
1173 audio_buf_info * bi;
1174 count_info     * ci;
1175#ifdef __FIXME__
1176 char * nosys_reqname = NULL;
1177#endif
1178#ifdef va_argp
1179 va_list args;
1180#endif
1181
1182 _init();
1183
1184// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1185
1186#ifdef va_argp
1187 va_start (args, ioctl_lastarg);
1188 argp = va_arg (args, void *);
1189 va_end (args);
1190#endif
1191
1192// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1193
1194 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1195  ip = argp;
1196//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1197#ifdef __FIXME__
1198  switch ((handle = pointer->handle)->type) {
1199   case SOUND_PCM_READ_RATE: nosys_reqname = "SOUND_PCM_READ_RATE"; break;
1200   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1201   case SOUND_PCM_READ_BITS: nosys_reqname = "SOUND_PCM_READ_BITS"; break;
1202   case SOUND_PCM_READ_FILTER: nosys_reqname = "SOUND_PCM_READ_FILTER"; break;
1203   case SNDCTL_COPR_RESET: nosys_reqname = "SNDCTL_COPR_RESET"; break;
1204   case SNDCTL_COPR_LOAD: nosys_reqname = "SNDCTL_COPR_LOAD"; break;
1205   case SNDCTL_COPR_HALT: nosys_reqname = "SNDCTL_COPR_HALT"; break;
1206   case SNDCTL_COPR_RDATA: nosys_reqname = "SNDCTL_COPR_RDATA"; break;
1207   case SNDCTL_COPR_RCODE: nosys_reqname = "SNDCTL_COPR_RCODE"; break;
1208   case SNDCTL_COPR_WDATA: nosys_reqname = "SNDCTL_COPR_WDATA"; break;
1209   case SNDCTL_COPR_WCODE: nosys_reqname = "SNDCTL_COPR_WCODE"; break;
1210   case SNDCTL_COPR_RUN: nosys_reqname = "SNDCTL_COPR_RUN"; break;
1211   case SNDCTL_COPR_SENDMSG: nosys_reqname = "SNDCTL_COPR_SENDMSG"; break;
1212   case SNDCTL_COPR_RCVMSG: nosys_reqname = "SNDCTL_COPR_RCVMSG"; break;
1213   case SNDCTL_DSP_GETCAPS: nosys_reqname = "SNDCTL_DSP_GETCAPS"; break;
1214   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1215/*
1216   case : nosys_reqname = ""; break;
1217   case : nosys_reqname = ""; break;
1218   case : nosys_reqname = ""; break;
1219*/
1220  }
1221#endif
1222  switch ((handle = pointer->handle)->type) {
1223   case HT_STREAM:
1224     switch (__request) {
1225      case SNDCTL_DSP_RESET:
1226      case SNDCTL_DSP_POST:
1227      case SNDCTL_DSP_SYNC: // ignore for the moment.
1228      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1229      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1230        return 0;
1231       break;
1232      case SNDCTL_DSP_SPEED:
1233        handle->stream.info.rate = *ip;
1234        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1235        return 0;
1236       break;
1237      case SNDCTL_DSP_CHANNELS:
1238        handle->stream.info.channels = *ip;
1239        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1240        return 0;
1241       break;
1242      case SNDCTL_DSP_STEREO:
1243        handle->stream.info.channels = *ip ? 2 : 1;
1244        return 0;
1245       break;
1246      case SNDCTL_DSP_GETBLKSIZE:
1247        *ip = _get_stream_buffersize(handle);
1248        return 0;
1249       break;
1250      case SNDCTL_DSP_SETFMT:
1251        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1252        return _ioctl_stream_format(handle, *ip);
1253       break;
1254      case SNDCTL_DSP_GETFMTS:
1255//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1256        *ip = _ioctl_stream_format_list();
1257        return 0;
1258       break;
1259      case SNDCTL_DSP_GETOSPACE:
1260      case SNDCTL_DSP_GETISPACE:
1261        bi = argp;
1262        memset(bi, 0, sizeof(*bi));
1263        bi->bytes      = _get_stream_buffersize(handle);
1264        bi->fragments  = 1;
1265        bi->fragsize   = bi->bytes;
1266        bi->fragstotal = 1;
1267        return 0;
1268       break;
1269      case SNDCTL_DSP_GETOPTR:
1270        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1271        ci = argp;
1272        memset(ci, 0, sizeof(*ci));
1273        ci->bytes  = handle->writec;
1274        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1275        ci->ptr    = ci->bytes % tmp;
1276        return 0;
1277       break;
1278      case SNDCTL_DSP_GETIPTR:
1279        ci = argp;
1280        memset(ci, 0, sizeof(*ci));
1281        ci->bytes  = handle->readc;
1282        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1283        ci->ptr    = ci->bytes % tmp;
1284        return 0;
1285       break;
1286#ifdef SNDCTL_DSP_GETPLAYVOL
1287      case SNDCTL_DSP_GETPLAYVOL:
1288        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1289       break;
1290#endif
1291#ifdef SNDCTL_DSP_SETPLAYVOL
1292      case SNDCTL_DSP_SETPLAYVOL:
1293        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1294       break;
1295#endif
1296      default:
1297#ifdef __FIXME__
1298        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1299#else
1300        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1301#endif
1302        errno = ENOSYS;
1303        return -1;
1304     }
1305    break;
1306   case HT_MIXER:
1307     return _ioctl_mixer(handle, __request, argp);
1308    break;
1309   default:
1310     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1311     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1312     errno = EINVAL;
1313     return -1;
1314    break;
1315  }
1316 }
1317
1318#ifdef IOCTL_IS_ALIAS
1319 errno = ENOSYS;
1320 return -1;
1321#else
1322 return _os.ioctl(__fd, __request, argp);
1323#endif
1324}
1325
1326int dup(int oldfd) {
1327 struct pointer * pointer;
1328 int ret;
1329
1330 _init();
1331
1332 ret = _os.dup(oldfd);
1333
1334 if (ret == -1)
1335  return -1;
1336
1337 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1338  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1339   _os.close(ret);
1340   return -1;
1341  }
1342 }
1343
1344 return ret;
1345}
1346
1347int dup2(int oldfd, int newfd) {
1348 struct pointer * pointer;
1349 int ret;
1350
1351 _init();
1352
1353 ret = _os.dup2(oldfd, newfd);
1354
1355 if (ret == -1)
1356  return -1;
1357
1358 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1359  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1360   _os.close(ret);
1361   return -1;
1362  }
1363 }
1364
1365 return ret;
1366}
1367
1368int select(int nfds, fd_set *readfds, fd_set *writefds,
1369           fd_set *exceptfds, struct timeval *timeout) {
1370 struct roar_vio_selecttv rtv;
1371 struct roar_vio_select * sv  = NULL;
1372 struct pointer * pointer;
1373 struct handle  * handle;
1374 ssize_t ret;
1375 size_t num = 0;
1376 size_t idx;
1377 int i;
1378 int i_r, i_w, i_e;
1379 int max_index = -1;
1380 static volatile int is_critical = 0;
1381
1382 _init();
1383
1384 if ( is_critical )
1385  return _os.select(nfds, readfds, writefds, exceptfds, timeout);
1386
1387 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = ?", nfds, readfds, writefds, exceptfds, timeout);
1388
1389 if ( nfds == 0 ) {
1390  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1391  return 0;
1392 }
1393
1394 if ( readfds == NULL && writefds == NULL && exceptfds == NULL ) {
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 ( timeout != NULL ) {
1400  rtv.sec = timeout->tv_sec;
1401  rtv.nsec = timeout->tv_usec*1000;
1402 }
1403
1404 // count number of handles:
1405 for (i = 0; i < nfds; i++) {
1406  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1407  if ( (readfds   != NULL && FD_ISSET(i, readfds  )) ||
1408       (writefds  != NULL && FD_ISSET(i, writefds )) ||
1409       (exceptfds != NULL && FD_ISSET(i, exceptfds))
1410     ) {
1411   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1412   num++;
1413   max_index = i;
1414  }
1415 }
1416
1417 if ( num == 0 ) {
1418  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1419  return 0;
1420 }
1421
1422 nfds = max_index + 1;
1423
1424 // create sv;
1425 sv = roar_mm_malloc(sizeof(struct roar_vio_select)*num);
1426 if ( sv == NULL ) {
1427  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1", nfds, readfds, writefds, exceptfds, timeout);
1428  return -1;
1429 }
1430
1431 memset(sv, 0, sizeof(struct roar_vio_select)*num);
1432
1433 for (i = 0, idx = 0; i < nfds; i++) {
1434  if ( idx >= num ) {
1435   roar_mm_free(sv);
1436   errno = EFAULT;
1437   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);
1438   return -1;
1439  }
1440  i_r = readfds   != NULL && FD_ISSET(i, readfds);
1441  i_w = writefds  != NULL && FD_ISSET(i, writefds);
1442  i_e = exceptfds != NULL && FD_ISSET(i, exceptfds);
1443
1444  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);
1445
1446  if ( i_r || i_w || i_e ) {
1447   // TODO: use VIO for pointers...
1448   if ( (pointer = _get_pointer_by_fh(i)) != NULL ) {
1449    handle = pointer->handle;
1450    sv[idx].vio     = NULL;
1451    sv[idx].fh      = -1;
1452    switch (handle->type) {
1453     case HT_DMX:
1454     case HT_STREAM:
1455       if ( ! handle->stream_opened ) {
1456        // implement this as statichly return OK
1457        errno = ENOSYS;
1458        return -1;
1459       }
1460     case HT_VIO:
1461       sv[idx].vio = &(handle->stream_vio);
1462      break;
1463     default: /* non supported type */
1464       errno = EINVAL;
1465       return -1;
1466      break;
1467    }
1468   } else {
1469    sv[idx].vio     = NULL;
1470    sv[idx].fh      = i;
1471   }
1472
1473   sv[idx].ud.si   = i;
1474   sv[idx].eventsq = (i_r ? ROAR_VIO_SELECT_READ   : 0) |
1475                     (i_w ? ROAR_VIO_SELECT_WRITE  : 0) |
1476                     (i_e ? ROAR_VIO_SELECT_EXCEPT : 0);
1477   idx++;
1478  }
1479 }
1480
1481 is_critical++;
1482 ret = roar_vio_select(sv, num, timeout == NULL ? NULL : &rtv, NULL);
1483 is_critical--;
1484
1485 if ( ret < 1 ) {
1486  roar_mm_free(sv);
1487  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1488  return ret;
1489 }
1490
1491 // update readfds, writefds, exceptfds:
1492 if ( readfds != NULL )
1493  FD_ZERO(readfds);
1494
1495 if ( writefds != NULL )
1496  FD_ZERO(writefds);
1497
1498 if ( exceptfds != NULL )
1499  FD_ZERO(exceptfds);
1500
1501 for (idx = 0; idx < num; idx++) {
1502  if ( sv[idx].eventsa == 0 )
1503   continue;
1504
1505  if ( sv[idx].eventsa & ROAR_VIO_SELECT_READ )
1506   if ( readfds != NULL )
1507    FD_SET(sv[idx].ud.si, readfds);
1508
1509  if ( sv[idx].eventsa & ROAR_VIO_SELECT_WRITE )
1510   if ( writefds != NULL )
1511    FD_SET(sv[idx].ud.si, writefds);
1512
1513  if ( sv[idx].eventsa & ROAR_VIO_SELECT_EXCEPT )
1514   if ( exceptfds != NULL )
1515    FD_SET(sv[idx].ud.si, exceptfds);
1516 }
1517
1518 roar_mm_free(sv);
1519
1520 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1521 return ret;
1522}
1523
1524// -------------------------------------
1525// emulated stdio functions follow:
1526// -------------------------------------
1527
1528//roar_vio_to_stdio
1529
1530static int _vio_close    (struct roar_vio_calls * vio) {
1531 int ret = 0;
1532
1533 if ( roar_vio_get_fh(vio) != -1 )
1534  ret = close(roar_vio_get_fh(vio));
1535
1536 roar_mm_free(vio);
1537
1538 return ret;
1539}
1540
1541FILE *fopen(const char *path, const char *mode) {
1542 struct roar_vio_calls * vio;
1543 FILE  * fr;
1544 int     ret;
1545 int     r = 0, w = 0;
1546 int     flags = 0;
1547 int     i;
1548 register char c;
1549
1550 _init();
1551
1552 if ( path == NULL || mode == NULL ) {
1553  errno = EFAULT;
1554  return NULL;
1555 }
1556
1557 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
1558
1559 for (i = 0; (c = mode[i]) != 0; i++) {
1560  switch (c) {
1561   case 'r': r = 1; break;
1562   case 'w': w = 1; break;
1563   case 'a': w = 1; break;
1564   case '+':
1565     r = 1;
1566     w = 1;
1567    break;
1568  }
1569 }
1570
1571 if ( r && w ) {
1572  flags = O_RDWR;
1573 } else if ( r ) {
1574  flags = O_RDONLY;
1575 } else if ( w ) {
1576  flags = O_WRONLY;
1577 } else {
1578  errno = EINVAL;
1579  return NULL;
1580 }
1581
1582 ret = _open_file(path, flags);
1583
1584 switch (ret) {
1585  case -2:       // continue as normal, use _op.open()
1586   break;
1587  case -1:       // pass error to caller
1588    return NULL;
1589   break;
1590  default:       // return successfully opened pointer to caller
1591    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
1592     return NULL; // errno should be set correctly by roar_mm_malloc().
1593    }
1594
1595    roar_vio_init_calls(vio);  // TODO: add error handling.
1596    roar_vio_set_fh(vio, ret); // TODO: add error handling.
1597    vio->close = _vio_close;
1598    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
1599     _vio_close(vio);
1600     errno = EIO;
1601     return NULL;
1602    } else {
1603     return fr;
1604    }
1605   break;
1606 }
1607
1608 return _os.fopen(path, mode);
1609}
1610
1611#endif
1612
1613//ll
Note: See TracBrowser for help on using the repository browser.