source: roaraudio/libroaross/libroaross.c @ 3880:0a3a7d8ca0f2

Last change on this file since 3880:0a3a7d8ca0f2 was 3880:0a3a7d8ca0f2, checked in by phi, 14 years ago

dummy implemented stat(), fstat(), lstat()

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