source: roaraudio/libroaross/libroaross.c @ 3783:9d56be5fbe0f

Last change on this file since 3783:9d56be5fbe0f was 3783:9d56be5fbe0f, checked in by phi, 14 years ago

allow access() on internal files

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