source: roaraudio/libroaross/libroaross.c @ 3778:1c21eee2b90d

Last change on this file since 3778:1c21eee2b90d was 3778:1c21eee2b90d, checked in by phi, 14 years ago

added fcntl()

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