source: roaraudio/libroaross/libroaross.c @ 3866:5ca375b5e98c

Last change on this file since 3866:5ca375b5e98c was 3866:5ca375b5e98c, checked in by phi, 14 years ago

added open64()

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