source: roaraudio/libroaross/libroaross.c @ 3872:51fe5bedbd0a

Last change on this file since 3872:51fe5bedbd0a was 3872:51fe5bedbd0a, checked in by phi, 14 years ago

become more portable

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