source: roaraudio/libroaross/libroaross.c @ 3850:ecd08ece4a31

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

use of roar_mm_*()

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