source: roaraudio/libroaross/libroaross.c @ 3891:b46eba7707b2

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

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