source: roaraudio/libroaross/libroaross.c @ 3951:e96f68ad3c68

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

only test for O_ASYNC if OS has a O_ASYNC

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