source: roaraudio/libroaross/libroaross.c @ 3871:dc9be2b6eef2

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

added support for creat()

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