source: roaraudio/libroaross/libroaross.c @ 3870:a1987a5a6824

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

use more general API, support tailing star in filenames

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