source: roaraudio/libroaross/libroaross.c @ 3868:41e42a0a5c97

Last change on this file since 3868:41e42a0a5c97 was 3868:41e42a0a5c97, checked in by phi, 14 years ago

use symbilic names

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