source: roaraudio/libroaross/libroaross.c @ 3890:bbf415110a11

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

use support creat() on FreeBSD

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