source: roaraudio/libroaross/libroaross.c @ 3771:8ff6830f66ee

Last change on this file since 3771:8ff6830f66ee was 3771:8ff6830f66ee, checked in by phi, 14 years ago

implemented select() using roar_vio_select() for sysio

File size: 41.3 KB
RevLine 
[3138]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[3138]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"
[3261]37#include "libroarlight/libroarlight.h"
[3138]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>
[3139]60#include <dlfcn.h>
61
62#if defined(RTLD_NEXT)
63#define REAL_LIBC RTLD_NEXT
64#else
65#define REAL_LIBC ((void *) -1L)
66#endif
[3138]67
[3164]68#ifndef ENOTSUP
69#define ENOTSUP ENOSYS
70#endif
71
[3166]72#if defined(ROAR_OS_NETBSD) && defined(ioctl)
73#define IOCTL_IS_ALIAS
74#endif
75
[3167]76#ifdef ROAR_OS_FREEBSD
77#define mode_t int
78#endif
79
[3169]80#ifdef ROAR_OS_NETBSD
81#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
[3171]82#define map_args int __fd = fd; unsigned long int __request = com
[3180]83#elif defined(ROAR_TARGET_CYGWIN)
84#define IOCTL() int ioctl (int __fd, int __cmd, ...)
85#define map_args unsigned long int __request = __cmd; void * argp
86#define va_argp
87#define ioctl_lastarg __cmd
[3169]88#else
89#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
[3171]90#define map_args void * argp
[3169]91#define va_argp
[3180]92#define ioctl_lastarg __request
[3169]93#endif
94
[3153]95#define OSS_VOLUME_SCALE 100
96
[3138]97#define _MAX_POINTER  8
98
[3140]99// handle type:
[3663]100#define HT_NONE       0 /* Unused object */
101#define HT_STREAM     1 /* Stream with no specal handling needed */
102#define HT_MIXER      2 /* Mixer device */
103#define HT_WAVEFORM   3 /* Waveform device */
104#define HT_MIDI       4 /* MIDI device */
105#define HT_DMX        5 /* DMX512/DMX4Linux device */
106#define HT_VIO        6 /* General VIO object */
[3666]107#define HT_STATIC     7 /* Static file */
[3140]108
[3138]109struct session {
110 int refc;
111 struct roar_connection con;
112};
113
114static struct session _session = {.refc = 0};
115
116struct handle {
117 int refc; // refrence counter
118 struct session * session;
[3140]119 int type;
120 struct roar_stream    stream;
121 struct roar_vio_calls stream_vio;
[3144]122 int                   stream_dir;
[3140]123 int                   stream_opened;
[3178]124 size_t                stream_buffersize;
125 size_t                readc, writec;
[3246]126 size_t                pos;
[3666]127 union {
128  struct {
129   char * data;
130   size_t len;
131  } sf;
132 } userdata;
[3138]133};
134
135static struct {
136 int     (*open)(const char *pathname, int flags, mode_t mode);
137 int     (*close)(int fd);
138 ssize_t (*write)(int fd, const void *buf, size_t count);
139 ssize_t (*read)(int fd, void *buf, size_t count);
[3166]140#ifndef IOCTL_IS_ALIAS
[3146]141 int     (*ioctl)(int d, int request, ...);
[3166]142#endif
[3246]143 off_t   (*lseek)(int fildes, off_t offset, int whence);
[3264]144 FILE   *(*fopen)(const char *path, const char *mode);
[3657]145 int     (*dup)(int oldfd);
146 int     (*dup2)(int oldfd, int newfd);
[3771]147 int     (*select)(int nfds, fd_set *readfds, fd_set *writefds,
148                   fd_set *exceptfds, struct timeval *timeout);
[3138]149} _os;
150
[3150]151static struct {
152 struct {
153  int volume;
154  int pcm;
155  int line;
156  int line1;
157  int line2;
158  int line3;
159  int digital1;
160  int digital2;
161  int digital3;
162 } sid;
163} _mix_settings = {
164                   .sid = {
165                           .volume   = -1,
166                           .pcm      = -1,
167                           .line     =  0,
168                           .line1    =  1,
169                           .line2    =  2,
170                           .line3    =  3,
171                           .digital1 =  1,
172                           .digital2 =  2,
173                           .digital3 =  3
174                          }
175                  };
176
[3140]177static struct pointer {
[3138]178 int fh;
179 struct handle * handle;
180} _ptr[_MAX_POINTER];
181
[3662]182
[3666]183static char _sf__dev_sndstat[] =
184 "Sound Driver:RoarAudio\n"
185 "Config options: 0\n"
186 "\n"
187 "Installed drivers:\n"
188 "Type 10: RoarAudio emulation\n"
189 "\n"
190 "Card config:\n"
191 "\n"
192 "Audio devices:\n"
193 "0: RoarAudio OSS emulation (DUPLEX)\n"
194 "\n"
195 "Midi devices:\n"
196 "0: RoarAudio OSS emulation MIDI\n"
197 "\n"
198 "Timers:\n"
199 "\n"
200 "Mixers:\n"
201 "0: RoarAudio OSS emulation Mixer\n"
202;
203
[3662]204static struct devices {
205  char * prefix;
206  int type;
[3666]207  size_t len;
208  void * userdata;
[3662]209} _device_list[] = {
[3666]210 {"/dev/dsp",           HT_WAVEFORM,  0, NULL},
211 {"/dev/audio",         HT_WAVEFORM,  0, NULL},
212 {"/dev/sound/dsp",     HT_WAVEFORM,  0, NULL},
213 {"/dev/sound/audio",   HT_WAVEFORM,  0, NULL},
214 {"/dev/mixer",         HT_MIXER,     0, NULL},
215 {"/dev/sound/mixer",   HT_MIXER,     0, NULL},
216 {"/dev/midi",          HT_MIDI,      0, NULL},
217 {"/dev/rmidi",         HT_MIDI,      0, NULL},
218 {"/dev/sound/midi",    HT_MIDI,      0, NULL},
219 {"/dev/sound/rmidi",   HT_MIDI,      0, NULL},
220 {"/dev/dmx",           HT_DMX,       0, NULL},
221 {"/dev/misc/dmx",      HT_DMX,       0, NULL},
222 {"/dev/dmxin",         HT_DMX,       0, NULL},
223 {"/dev/misc/dmxin",    HT_DMX,       0, NULL},
224 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat},
[3662]225#ifdef ROAR_DEFAULT_OSS_DEV
[3666]226 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL},
[3662]227#endif
[3666]228 {NULL, HT_NONE, 0, NULL},
[3662]229};
230
[3138]231static void _init_os (void) {
232 memset(&_os, 0, sizeof(_os));
[3139]233
234 _os.open  = dlsym(REAL_LIBC, "open");
235 _os.close = dlsym(REAL_LIBC, "close");
236 _os.write = dlsym(REAL_LIBC, "write");
237 _os.read  = dlsym(REAL_LIBC, "read");
[3166]238#ifndef IOCTL_IS_ALIAS
[3146]239 _os.ioctl = dlsym(REAL_LIBC, "ioctl");
[3166]240#endif
[3246]241 _os.lseek = dlsym(REAL_LIBC, "lseek");
[3264]242 _os.fopen = dlsym(REAL_LIBC, "fopen");
[3657]243 _os.dup   = dlsym(REAL_LIBC, "dup");
244 _os.dup2  = dlsym(REAL_LIBC, "dup2");
[3771]245 _os.select= dlsym(REAL_LIBC, "select");
[3138]246}
247
248static void _init_ptr (void) {
249 int i;
250
251 for (i = 0; i < _MAX_POINTER; i++) {
252  _ptr[i].fh = -1;
253 }
254}
255
256static void _init (void) {
257 static int inited = 0;
258
259 if ( !inited ) {
260  _init_os();
261  _init_ptr();
[3771]262  roar_vio_select(NULL, 0, NULL, NULL);
[3138]263  inited++;
264 }
265}
266
[3157]267static void _find_volume_sid (struct session * session) {
268 int i;
269 int num;
270 int id[ROAR_STREAMS_MAX];
271 struct roar_stream s;
272 char name[1024];
273
274 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
275
276 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
277  return;
278 }
279
280 for (i = 0; i < num; i++) {
281  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
282   continue;
283
284  if ( s.dir != ROAR_DIR_MIXING )
285   continue;
286
287  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
288   continue;
289
290  if ( !strcasecmp(name, "Waveform Mixer") ) {
291   _mix_settings.sid.volume = id[i];
292   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
293   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
294   return;
295  }
296 }
297}
298
[3138]299static int _open_dummy (void) {
300 int p[2];
301
302 if ( pipe(p) == -1 )
303  return -1;
304
305 close(p[1]);
306
307 return p[0];
308}
309
310static struct session * _open_session (char * server, char * name) {
[3652]311 struct session * ses = &_session;
312 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
313
[3183]314 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
315 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
316
[3652]317 if ( new_session ) {
318  ses = malloc(sizeof(struct session));
319  if ( ses == NULL )
320   return NULL;
321
322  memset(ses, 0, sizeof(struct session));
323 }
324
325 if ( ses->refc == 0 ) {
[3138]326
327  if ( name == NULL )
[3500]328   name = getenv("ROAR_OSS_CLIENT_NAME");
329
330  if ( name == NULL )
[3138]331   name = "libroaross client";
332
[3652]333  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
334   if ( new_session )
335    free(ses);
336
[3138]337   return NULL;
[3652]338  }
[3157]339
[3652]340  _find_volume_sid(ses);
[3184]341
[3652]342  if ( !new_session ) {
343   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
344    ses->refc++;
345  }
[3143]346 }
[3138]347
[3652]348 ses->refc++;
[3183]349
[3652]350 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
351 return ses;
[3138]352}
353
354static void _close_session(struct session * session) {
355 if ( session == NULL )
356  return;
357
358 session->refc--;
359
[3144]360 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
361
[3138]362 if ( session->refc == 0 ) {
363  roar_disconnect(&(session->con));
364 }
[3652]365
366 if ( session != &_session )
367  free(session);
[3138]368}
369
[3140]370static struct handle * _open_handle(struct session * session) {
371 struct handle * handle;
372
[3183]373 ROAR_DBG("_open_handle(session=%p) = ?", session);
374
[3140]375 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
376  return NULL;
377
378 memset(handle, 0, sizeof(struct handle));
379
380 handle->refc = 1;
381 handle->session = session;
[3666]382
383 if ( session != NULL )
384  session->refc++; // TODO: better warp this
385
[3140]386 handle->type = HT_NONE;
[3144]387 handle->stream_dir = ROAR_DIR_PLAY;
388 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
[3140]389
[3183]390 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
[3140]391 return handle;
392}
393
394static void _close_handle(struct handle * handle) {
[3664]395 int need_close = 0;
396
[3140]397 if (handle == NULL)
398  return;
399
400 handle->refc--;
401
[3144]402 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
403
[3140]404 if ( handle->refc == 0 ) {
[3664]405  switch (handle->type) {
406   case HT_VIO:
407     need_close = 1;
408    break;
409   case HT_STREAM:
410     if ( handle->stream_opened )
411      need_close = 1;
412    break;
413  }
414
415  if ( need_close )
[3140]416   roar_vio_close(&(handle->stream_vio));
417
[3664]418  if ( handle->session != NULL ) {
419   handle->session->refc--;
[3144]420
[3664]421   _close_session(handle->session);
422  }
[3144]423
[3140]424  roar_mm_free(handle);
425 }
426}
427
428static struct pointer * _get_pointer_by_fh (int fh) {
429 int i;
430
431 for (i = 0; i < _MAX_POINTER; i++) {
432  if ( _ptr[i].fh == fh )
433   return &(_ptr[i]);
434 }
435
436 return NULL;
437}
438
439static struct pointer * _open_pointer(struct handle * handle) {
440 struct pointer * ret = _get_pointer_by_fh(-1);
441
442 if ( ret == NULL )
443  return NULL;
444
445 if ( (ret->fh = _open_dummy()) == -1 )
446  return NULL;
447
448 ret->handle = handle;
449
450 return ret;
451}
452
[3657]453static struct pointer * _attach_pointer(struct handle * handle, int fh) {
454 struct pointer * ret = _get_pointer_by_fh(-1);
455
456 if ( ret == NULL )
457  return NULL;
458
459 if ( (ret->fh = fh) == -1 )
460  return NULL;
461
462 ret->handle = handle;
463
464 handle->refc++;
465
466 return ret;
467}
468
[3140]469static void _close_pointer(struct pointer * pointer) {
470 if ( pointer == NULL )
471  return;
472
473 _os.close(pointer->fh);
474
475 pointer->fh = -1;
476
477 _close_handle(pointer->handle);
478}
[3138]479
480// -------------------------------------
[3142]481// central open function:
482// -------------------------------------
483
484static int _open_file (const char *pathname, int flags) {
[3143]485 struct session * session;
486 struct handle  * handle;
487 struct pointer * pointer;
[3662]488 struct devices * ptr = NULL;
[3143]489 int i;
490
[3665]491 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
492
[3662]493 for (i = 0; _device_list[i].prefix != NULL; i++) {
494  if ( !strcmp(pathname, _device_list[i].prefix) ) {
495   ptr = &(_device_list[i]);
[3143]496  }
497 }
498
499 if ( ptr == NULL )
500  return -2;
501
[3666]502 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
503  session = NULL;
504 } else {
505  if ( (session = _open_session(NULL, NULL)) == NULL ) {
506   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
507   return -1;
508  }
[3143]509 }
510
511 if ( (handle = _open_handle(session)) == NULL ) {
512  _close_session(session);
[3665]513  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3143]514  return -1;
515 }
516
[3244]517 handle->type       = ptr->type;
518 handle->stream_dir = -1;
[3143]519
[3145]520 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
521  case O_RDONLY:
[3244]522    switch (ptr->type) {
523     case HT_WAVEFORM:
524       handle->stream_dir = ROAR_DIR_MONITOR;
525      break;
526     case HT_MIDI:
527       handle->stream_dir = ROAR_DIR_MIDI_OUT;
528      break;
[3246]529     case HT_DMX:
530       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
531      break;
[3665]532     case HT_MIXER:
[3666]533     case HT_STATIC:
[3665]534      break;
[3248]535     default:
[3665]536       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3248]537       return -1;
[3244]538    }
[3145]539   break;
540  case O_WRONLY:
[3244]541    switch (ptr->type) {
542     case HT_WAVEFORM:
543       handle->stream_dir = ROAR_DIR_PLAY;
544      break;
545     case HT_MIDI:
546       handle->stream_dir = ROAR_DIR_MIDI_IN;
547      break;
[3246]548     case HT_DMX:
549       handle->stream_dir = ROAR_DIR_LIGHT_IN;
550      break;
[3666]551     case HT_MIXER:
552     case HT_STATIC:
553      break;
[3248]554     default:
[3665]555       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3248]556       return -1;
[3244]557    }
[3145]558   break;
559  case O_RDWR:
[3244]560    switch (ptr->type) {
561     case HT_WAVEFORM:
562       handle->stream_dir = ROAR_DIR_BIDIR;
563      break;
[3666]564     case HT_MIXER:
565     case HT_STATIC:
566      break;
[3248]567     default:
[3665]568       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3248]569       return -1;
[3244]570    }
571   break;
572 }
573
574 switch (handle->type) {
575  case HT_WAVEFORM:
576    handle->type = HT_STREAM;
577   break;
578  case HT_MIDI:
579    handle->type = HT_STREAM;
580    handle->stream.info.rate     = 0;
581    handle->stream.info.bits     = ROAR_MIDI_BITS;
582    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
583    handle->stream.info.codec    = ROAR_CODEC_MIDI;
[3145]584   break;
[3261]585  case HT_DMX:
586    handle->stream.info.rate     = 0;
587    handle->stream.info.bits     = ROAR_LIGHT_BITS;
588    handle->stream.info.channels = 512;
589    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
590   break;
[3666]591  case HT_STATIC:
592    handle->userdata.sf.len      = ptr->len;
593    handle->userdata.sf.data     = ptr->userdata;
594   break;
[3145]595 }
596
[3143]597 if ( (pointer = _open_pointer(handle)) == NULL ) {
598  _close_handle(handle);
[3665]599  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
[3143]600  return -1;
601 }
602
[3665]603 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
604
[3143]605 return pointer->fh;
[3142]606}
607
608// -------------------------------------
[3144]609// open function for streams:
610// -------------------------------------
611
612static int _open_stream (struct handle * handle) {
613  // FIXME: this should be re-written much more cleanly:
614
615 if ( handle == NULL )
616  return -1;
617
618 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
619                                     &(handle->session->con), &(handle->stream),
620                                     handle->stream.info.rate,
621                                     handle->stream.info.channels,
622                                     handle->stream.info.bits,
623                                     handle->stream.info.codec,
624                                     handle->stream_dir
625                                    ) == -1 )
626  return -1;
627
628 handle->stream_opened++;
629
[3150]630 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
631
[3144]632 return 0;
633}
634
635// -------------------------------------
[3147]636// function to parse format:
637// -------------------------------------
638
639static int _ioctl_stream_format (struct handle * handle, int format) {
640 struct roar_audio_info * info = &(handle->stream.info);
641
642 switch (format) {
643  case AFMT_S8:
644    info->bits  = 8;
645    info->codec = ROAR_CODEC_PCM_S_LE;
646   break;
647  case AFMT_U8:
648    info->bits  = 8;
649    info->codec = ROAR_CODEC_PCM_U_LE;
650   break;
651  case AFMT_S16_BE:
652    info->bits  = 16;
653    info->codec = ROAR_CODEC_PCM_S_BE;
654   break;
655  case AFMT_S16_LE:
656    info->bits  = 16;
657    info->codec = ROAR_CODEC_PCM_S_LE;
658   break;
659  case AFMT_U16_BE:
660    info->bits  = 16;
661    info->codec = ROAR_CODEC_PCM_U_BE;
662   break;
663  case AFMT_U16_LE:
664    info->bits  = 16;
665    info->codec = ROAR_CODEC_PCM_U_LE;
666   break;
667#ifdef AFMT_S32_BE
668  case AFMT_S32_BE:
669    info->bits  = 32;
670    info->codec = ROAR_CODEC_PCM_S_BE;
671   break;
672#endif
673#ifdef AFMT_S32_LE
674  case AFMT_S32_LE:
675    info->bits  = 32;
676    info->codec = ROAR_CODEC_PCM_S_LE;
677   break;
678#endif
679  case AFMT_A_LAW:
680    info->bits  = 8;
681    info->codec = ROAR_CODEC_ALAW;
682   break;
683  case AFMT_MU_LAW:
684    info->bits  = 8;
685    info->codec = ROAR_CODEC_MULAW;
686   break;
687#ifdef AFMT_VORBIS
688  case AFMT_VORBIS:
689    info->codec = ROAR_CODEC_OGG_VORBIS;
690   break;
691#endif
[3148]692  default:
[3229]693    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
[3148]694    errno = ENOSYS;
695    return -1;
696   break;
[3147]697 }
698
[3148]699 return 0;
[3147]700}
701
[3149]702static inline int _ioctl_stream_format_list (void) {
703 int format = 0;
704
705 format |= AFMT_S8;
706 format |= AFMT_U8;
707
708 format |= AFMT_S16_BE;
709 format |= AFMT_S16_LE;
710
711 format |= AFMT_U16_BE;
712 format |= AFMT_U16_LE;
713
714#ifdef AFMT_S32_BE
715 format |= AFMT_S32_BE;
716#endif
717#ifdef AFMT_S32_LE
718 format |= AFMT_S32_LE;
719#endif
720
721 format |= AFMT_A_LAW;
722 format |= AFMT_MU_LAW;
723
724#ifdef AFMT_VORBIS
725 format |= AFMT_VORBIS;
726#endif
727
728 return format;
729}
730
[3147]731// -------------------------------------
[3150]732// mixer ioctls:
733// -------------------------------------
734
[3158]735static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
[3159]736 mixer_info * info;
[3150]737 int channels;
738 struct roar_mixer_settings mixer;
[3155]739 int o_w    =  0;
[3150]740 int o_sid  = -1;
[3158]741 int * ip   = vp;
[3165]742#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
743 char * name = NULL;
744#endif
[3150]745
[3165]746#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
[3150]747 switch (req) {
748#if 0
749  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
750  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
751  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
752  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
753  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
754  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
755  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
756#endif
[3159]757//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
[3152]758  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
759  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
760  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
761  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
[3156]762  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
763  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
[3152]764  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
765  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
766  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
767  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
768  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
769  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
[3156]770//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
771  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
[3152]772/*
773  case :     name = "";     break;
[3156]774  case :     name = "";     break;
[3152]775*/
[3150]776 }
777 if ( name != NULL ) {
[3656]778  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
779  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
[3150]780  errno = ENOSYS;
781  return -1;
782 }
[3165]783#endif
[3150]784
785 switch (req) {
786  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
787  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
788  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
789  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
790  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
791#if 0
792  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
793  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
794  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
795#endif
796  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
797  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
798  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
799  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
800  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
801#if 0
802  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
803  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
804  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
805#endif
[3177]806  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
807  case SOUND_MIXER_READ_PCM:
808    o_w = 0;
809    if ( handle->type == HT_STREAM ) {
810     o_sid = roar_stream_get_id(&(handle->stream));
811    } else {
812     o_sid = _mix_settings.sid.pcm;
813    }
814   break;
815  case SOUND_MIXER_WRITE_PCM:
816    o_w = 1;
817    if ( handle->type == HT_STREAM ) {
818     o_sid = roar_stream_get_id(&(handle->stream));
819    } else {
820     o_sid = _mix_settings.sid.pcm;
821    }
822   break;
[3150]823 }
824 if ( o_sid != -1 ) {
825  // set/get volume
826  if ( o_w ) {
[3536]827   mixer.scale    = OSS_VOLUME_SCALE;
828   mixer.mixer[0] = ( *ip       & 0xFF);
829   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
[3150]830   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
[3156]831    errno = EIO;
[3150]832    return -1;
833   }
834   return 0;
835  } else {
836   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
[3156]837    errno = EIO;
[3150]838    return -1;
839   }
[3153]840   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
[3150]841   return 0;
842  }
843 }
844
845 switch (req) {
[3155]846  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
[3150]847  case SOUND_MIXER_READ_DEVMASK:
848    *ip = 0;
849
850    if ( _mix_settings.sid.volume != -1 )
851     *ip |= SOUND_MASK_VOLUME;
852    if ( _mix_settings.sid.pcm != -1 )
853     *ip |= SOUND_MASK_PCM;
854    if ( _mix_settings.sid.line != -1 )
855     *ip |= SOUND_MASK_LINE;
856    if ( _mix_settings.sid.line1 != -1 )
857     *ip |= SOUND_MASK_LINE1;
858    if ( _mix_settings.sid.line2 != -1 )
859     *ip |= SOUND_MASK_LINE2;
860    if ( _mix_settings.sid.line3 != -1 )
861     *ip |= SOUND_MASK_LINE3;
862    if ( _mix_settings.sid.digital1 != -1 )
[3156]863#if 0
[3150]864     *ip |= SOUND_MASK_DIGITAL1;
865    if ( _mix_settings.sid.digital2 != -1 )
866     *ip |= SOUND_MASK_DIGITAL2;
867    if ( _mix_settings.sid.digital3 != -1 )
868     *ip |= SOUND_MASK_DIGITAL3;
[3156]869#endif
[3150]870
871    return 0;
872   break;
[3153]873  case SOUND_MIXER_READ_RECMASK:
[3154]874  case SOUND_MIXER_READ_RECSRC:
[3153]875    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
876    return 0;
877   break;
[3154]878  case SOUND_MIXER_WRITE_RECSRC:
879    if ( *ip == SOUND_MASK_VOLUME ) {
880     return  0;
881    } else {
882     errno = ENOTSUP;
883     return -1;
884    }
885   break;
[3156]886  case SOUND_MIXER_READ_CAPS:
887    *ip = 0;
888    return 0;
889   break;
[3159]890  case SOUND_MIXER_INFO:
891    info = vp;
892    memset(info, 0, sizeof(*info));
893    strcpy(info->id, "RoarAudio");
894    strcpy(info->name, "RoarAudio");
895    return 0;
896   break;
[3150]897 }
898
[3656]899 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
[3156]900// _os.ioctl(-1, req, ip);
[3656]901 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
[3150]902 errno = ENOSYS;
903 return -1;
904}
905
906// -------------------------------------
[3178]907// buffer size calculation:
908// -------------------------------------
909
910static size_t _get_stream_buffersize (struct handle * handle) {
911 if ( handle->stream_buffersize )
912  return handle->stream_buffersize;
913
914 return handle->stream_buffersize = handle->stream.info.rate     *
915                                    handle->stream.info.channels *
916                                    handle->stream.info.bits     / 800;
917}
918
919// -------------------------------------
[3138]920// emulated functions follow:
921// -------------------------------------
922
923int     open(const char *pathname, int flags, ...) {
[3142]924 int     ret;
925 mode_t  mode = 0;
[3138]926 va_list args;
927
928 _init();
929
[3261]930 if ( pathname == NULL ) {
931  errno = EFAULT;
932  return -1;
933 }
934
935 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
[3142]936 ret = _open_file(pathname, flags);
937
938 switch (ret) {
939  case -2:       // continue as normal, use _op.open()
940   break;
941  case -1:       // pass error to caller
942    return -1;
943   break;
944  default:       // return successfully opened pointer to caller
945    return ret;
946   break;
947 }
948
[3138]949 if (flags & O_CREAT) {
950  va_start(args, flags);
951  mode = va_arg(args, mode_t);
952  va_end(args);
953 }
954
955 return _os.open(pathname, flags, mode);
956}
957
958int     close(int fd) {
[3140]959 struct pointer * pointer;
[3138]960 _init();
961
[3140]962 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
963  _close_pointer(pointer);
964  return 0;
965 }
966
[3138]967 return _os.close(fd);
968}
969
970ssize_t write(int fd, const void *buf, size_t count) {
[3261]971 struct roar_roardmx_message roardmxmsg;
[3140]972 struct pointer * pointer;
[3178]973 ssize_t ret;
[3639]974 size_t i;
[3140]975
[3138]976 _init();
977
[3140]978 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
[3655]979  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
[3261]980  switch (pointer->handle->type) {
[3664]981   case HT_STREAM: // handle stream specific stuff
[3261]982     if ( pointer->handle->stream_opened == 0 ) {
983      if ( _open_stream(pointer->handle) == -1 ) {
984       errno = EIO;
985       return -1;
986      }
987     }
[3664]988   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
[3261]989     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
990     if ( ret > 0 )
991      pointer->handle->writec += ret;
992     return ret;
993    break;
[3664]994   case HT_DMX: // DMX need specal handling as we need to convert the protocol
[3261]995     if ( pointer->handle->stream_opened == 0 ) {
996      if ( _open_stream(pointer->handle) == -1 ) {
997       errno = EIO;
998       return -1;
999      }
1000     }
1001     if ( count > 0 ) {
1002      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
1003       errno = EIO;
1004       return -1;
1005      }
1006      for (i = 0; i < count; i++) {
1007       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1008#ifdef EMSGSIZE
1009        errno = EMSGSIZE;
1010#else
1011        errno = EIO;
1012#endif
1013        return -1;
1014       }
1015      }
1016      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1017       errno = EIO;
1018       return -1;
1019      }
1020     }
1021     pointer->handle->pos += count;
1022     return count;
1023    break;
[3664]1024   default: // we don't know what to do with other types
[3261]1025     errno = EINVAL;
[3140]1026     return -1;
[3261]1027    break;
[3140]1028  }
1029 }
1030
[3138]1031 return _os.write(fd, buf, count);
1032}
1033
1034ssize_t read(int fd, void *buf, size_t count) {
[3140]1035 struct pointer * pointer;
[3178]1036 ssize_t ret;
[3140]1037
[3138]1038 _init();
1039
[3140]1040 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
[3666]1041  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1042
[3664]1043  switch (pointer->handle->type) {
1044   case HT_STREAM:
1045     if ( pointer->handle->stream_opened == 0 ) {
1046      if ( _open_stream(pointer->handle) == -1 ) {
1047       errno = EIO;
1048       return -1;
1049      }
1050     }
1051   case HT_VIO:
1052     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1053     if ( ret > 0 )
1054      pointer->handle->readc += ret;
1055     return ret;
1056    break;
[3666]1057   case HT_STATIC:
1058     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1059     ret = pointer->handle->pos + count; // calc the end of the read
1060
1061     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1062      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1063     }
1064
1065     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1066     pointer->handle->pos += count;
1067     return count;
1068    break;
[3664]1069   default:
1070     errno = EINVAL;
[3140]1071     return -1;
[3664]1072    break;
[3140]1073  }
1074 }
1075
[3138]1076 return _os.read(fd, buf, count);
1077}
1078
[3246]1079off_t lseek(int fildes, off_t offset, int whence) {
1080 struct pointer * pointer;
[3666]1081 ssize_t tmp;
[3246]1082
1083 _init();
1084
1085 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
[3664]1086  switch (pointer->handle->type) {
1087   case HT_DMX:
1088     switch (whence) {
1089      case SEEK_SET:
1090        pointer->handle->pos  = offset;
1091       break;
1092      case SEEK_CUR:
1093        pointer->handle->pos += offset;
1094       break;
1095      case SEEK_END:
1096      default:
1097        errno = EINVAL;
1098        return -1;
1099       break;
1100     }
1101     return pointer->handle->pos;
1102    break;
1103   case HT_VIO:
1104     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1105    break;
[3666]1106   case HT_STATIC:
1107     switch (whence) {
1108      case SEEK_SET:
1109        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1110         errno = EINVAL;
1111         return -1;
1112        }
1113        pointer->handle->pos  = offset;
1114       break;
1115      case SEEK_CUR:
1116        tmp = pointer->handle->pos + offset;
1117        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1118         errno = EINVAL;
1119         return -1;
1120        }
1121        pointer->handle->pos = tmp;
1122       break;
1123      case SEEK_END:
1124        tmp = pointer->handle->userdata.sf.len + offset;
1125        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1126         errno = EINVAL;
1127         return -1;
1128        }
1129        pointer->handle->pos = tmp;
1130       break;
1131      default:
1132        errno = EINVAL;
1133        return -1;
1134       break;
1135     }
1136    break;
[3664]1137   default:
1138     errno = EINVAL;
1139     return -1;
1140    break;
[3246]1141  }
1142 }
1143
1144 return _os.lseek(fildes, offset, whence);
1145}
1146
[3169]1147IOCTL() {
1148 map_args;
[3147]1149 struct pointer * pointer;
1150 struct handle  * handle;
[3169]1151 int * ip = NULL;
[3655]1152 size_t tmp;
[3176]1153 audio_buf_info * bi;
[3178]1154 count_info     * ci;
[3229]1155#ifdef __FIXME__
1156 char * nosys_reqname = NULL;
1157#endif
[3169]1158#ifdef va_argp
[3146]1159 va_list args;
[3169]1160#endif
[3146]1161
1162 _init();
1163
[3656]1164// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
[3148]1165
[3169]1166#ifdef va_argp
[3180]1167 va_start (args, ioctl_lastarg);
[3146]1168 argp = va_arg (args, void *);
1169 va_end (args);
[3169]1170#endif
[3146]1171
[3656]1172// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
[3148]1173
[3147]1174 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
[3148]1175  ip = argp;
[3656]1176//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
[3229]1177#ifdef __FIXME__
1178  switch ((handle = pointer->handle)->type) {
1179   case SOUND_PCM_READ_RATE: nosys_reqname = "SOUND_PCM_READ_RATE"; break;
1180   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1181   case SOUND_PCM_READ_BITS: nosys_reqname = "SOUND_PCM_READ_BITS"; break;
1182   case SOUND_PCM_READ_FILTER: nosys_reqname = "SOUND_PCM_READ_FILTER"; break;
1183   case SNDCTL_COPR_RESET: nosys_reqname = "SNDCTL_COPR_RESET"; break;
1184   case SNDCTL_COPR_LOAD: nosys_reqname = "SNDCTL_COPR_LOAD"; break;
1185   case SNDCTL_COPR_HALT: nosys_reqname = "SNDCTL_COPR_HALT"; break;
1186   case SNDCTL_COPR_RDATA: nosys_reqname = "SNDCTL_COPR_RDATA"; break;
1187   case SNDCTL_COPR_RCODE: nosys_reqname = "SNDCTL_COPR_RCODE"; break;
1188   case SNDCTL_COPR_WDATA: nosys_reqname = "SNDCTL_COPR_WDATA"; break;
1189   case SNDCTL_COPR_WCODE: nosys_reqname = "SNDCTL_COPR_WCODE"; break;
1190   case SNDCTL_COPR_RUN: nosys_reqname = "SNDCTL_COPR_RUN"; break;
1191   case SNDCTL_COPR_SENDMSG: nosys_reqname = "SNDCTL_COPR_SENDMSG"; break;
1192   case SNDCTL_COPR_RCVMSG: nosys_reqname = "SNDCTL_COPR_RCVMSG"; break;
[3654]1193   case SNDCTL_DSP_GETCAPS: nosys_reqname = "SNDCTL_DSP_GETCAPS"; break;
1194   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
[3229]1195/*
1196   case : nosys_reqname = ""; break;
1197   case : nosys_reqname = ""; break;
1198   case : nosys_reqname = ""; break;
1199*/
1200  }
1201#endif
[3147]1202  switch ((handle = pointer->handle)->type) {
1203   case HT_STREAM:
1204     switch (__request) {
1205      case SNDCTL_DSP_RESET:
1206      case SNDCTL_DSP_POST:
[3654]1207      case SNDCTL_DSP_SYNC: // ignore for the moment.
[3162]1208      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
[3654]1209      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
[3175]1210        return 0;
[3147]1211       break;
1212      case SNDCTL_DSP_SPEED:
1213        handle->stream.info.rate = *ip;
[3656]1214        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
[3147]1215        return 0;
1216       break;
1217      case SNDCTL_DSP_CHANNELS:
1218        handle->stream.info.channels = *ip;
[3656]1219        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
[3147]1220        return 0;
1221       break;
[3160]1222      case SNDCTL_DSP_STEREO:
1223        handle->stream.info.channels = *ip ? 2 : 1;
1224        return 0;
1225       break;
[3161]1226      case SNDCTL_DSP_GETBLKSIZE:
[3178]1227        *ip = _get_stream_buffersize(handle);
[3161]1228        return 0;
1229       break;
[3147]1230      case SNDCTL_DSP_SETFMT:
[3656]1231        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
[3147]1232        return _ioctl_stream_format(handle, *ip);
1233       break;
[3148]1234      case SNDCTL_DSP_GETFMTS:
[3656]1235//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
[3149]1236        *ip = _ioctl_stream_format_list();
[3148]1237        return 0;
1238       break;
[3176]1239      case SNDCTL_DSP_GETOSPACE:
1240      case SNDCTL_DSP_GETISPACE:
1241        bi = argp;
1242        memset(bi, 0, sizeof(*bi));
[3178]1243        bi->bytes      = _get_stream_buffersize(handle);
[3176]1244        bi->fragments  = 1;
1245        bi->fragsize   = bi->bytes;
1246        bi->fragstotal = 1;
1247        return 0;
1248       break;
[3178]1249      case SNDCTL_DSP_GETOPTR:
[3655]1250        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
[3178]1251        ci = argp;
1252        memset(ci, 0, sizeof(*ci));
1253        ci->bytes  = handle->writec;
[3655]1254        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1255        ci->ptr    = ci->bytes % tmp;
[3178]1256        return 0;
1257       break;
1258      case SNDCTL_DSP_GETIPTR:
1259        ci = argp;
1260        memset(ci, 0, sizeof(*ci));
1261        ci->bytes  = handle->readc;
[3655]1262        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1263        ci->ptr    = ci->bytes % tmp;
[3178]1264        return 0;
1265       break;
[3177]1266#ifdef SNDCTL_DSP_GETPLAYVOL
1267      case SNDCTL_DSP_GETPLAYVOL:
1268        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1269       break;
1270#endif
1271#ifdef SNDCTL_DSP_SETPLAYVOL
1272      case SNDCTL_DSP_SETPLAYVOL:
1273        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1274       break;
1275#endif
[3147]1276      default:
[3229]1277#ifdef __FIXME__
[3656]1278        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
[3229]1279#else
[3656]1280        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
[3229]1281#endif
[3147]1282        errno = ENOSYS;
1283        return -1;
1284     }
1285    break;
1286   case HT_MIXER:
[3158]1287     return _ioctl_mixer(handle, __request, argp);
[3147]1288    break;
1289   default:
[3656]1290     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1291     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
[3147]1292     errno = EINVAL;
1293     return -1;
1294    break;
1295  }
1296 }
1297
[3166]1298#ifdef IOCTL_IS_ALIAS
1299 errno = ENOSYS;
1300 return -1;
1301#else
[3146]1302 return _os.ioctl(__fd, __request, argp);
[3166]1303#endif
[3146]1304}
1305
[3657]1306int dup(int oldfd) {
1307 struct pointer * pointer;
1308 int ret;
1309
1310 _init();
1311
1312 ret = _os.dup(oldfd);
1313
1314 if (ret == -1)
1315  return -1;
1316
1317 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1318  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1319   _os.close(ret);
1320   return -1;
1321  }
1322 }
1323
1324 return ret;
1325}
1326
1327int dup2(int oldfd, int newfd) {
1328 struct pointer * pointer;
1329 int ret;
1330
1331 _init();
1332
1333 ret = _os.dup2(oldfd, newfd);
1334
1335 if (ret == -1)
1336  return -1;
1337
1338 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1339  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1340   _os.close(ret);
1341   return -1;
1342  }
1343 }
1344
1345 return ret;
1346}
[3264]1347
[3771]1348int select(int nfds, fd_set *readfds, fd_set *writefds,
1349           fd_set *exceptfds, struct timeval *timeout) {
1350 struct roar_vio_selecttv rtv;
1351 struct roar_vio_select * sv  = NULL;
1352 ssize_t ret;
1353 size_t num = 0;
1354 int idx;
1355 int i;
1356 int i_r, i_w, i_e;
1357 int max_index = -1;
1358 volatile static int is_critical = 0;
1359
1360 _init();
1361
1362 if ( is_critical )
1363  return _os.select(nfds, readfds, writefds, exceptfds, timeout);
1364
1365 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = ?", nfds, readfds, writefds, exceptfds, timeout);
1366
1367 if ( nfds == 0 ) {
1368  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1369  return 0;
1370 }
1371
1372 if ( readfds == NULL && writefds == NULL && exceptfds == NULL ) {
1373  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1374  return 0;
1375 }
1376
1377 if ( timeout != NULL ) {
1378  rtv.sec = timeout->tv_sec;
1379  rtv.nsec = timeout->tv_usec*1000;
1380 }
1381
1382 // count number of handles:
1383 for (i = 0; i < nfds; i++) {
1384  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1385  if ( (readfds   != NULL && FD_ISSET(i, readfds  )) ||
1386       (writefds  != NULL && FD_ISSET(i, writefds )) ||
1387       (exceptfds != NULL && FD_ISSET(i, exceptfds))
1388     ) {
1389   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1390   num++;
1391   max_index = i;
1392  }
1393 }
1394
1395 if ( num == 0 ) {
1396  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1397  return 0;
1398 }
1399
1400 nfds = max_index + 1;
1401
1402 // create sv;
1403 sv = roar_mm_malloc(sizeof(struct roar_vio_select)*num);
1404 if ( sv == NULL ) {
1405  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1", nfds, readfds, writefds, exceptfds, timeout);
1406  return -1;
1407 }
1408
1409 memset(sv, 0, sizeof(struct roar_vio_select)*num);
1410
1411 for (i = 0, idx = 0; i < nfds; i++) {
1412  if ( idx >= num ) {
1413   roar_mm_free(sv);
1414   errno = EFAULT;
1415   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);
1416   return -1;
1417  }
1418  i_r = readfds   != NULL && FD_ISSET(i, readfds);
1419  i_w = writefds  != NULL && FD_ISSET(i, writefds);
1420  i_e = exceptfds != NULL && FD_ISSET(i, exceptfds);
1421
1422  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);
1423
1424  if ( i_r || i_w || i_e ) {
1425   // TODO: use VIO for pointers...
1426   sv[idx].vio     = NULL;
1427   sv[idx].fh      = i;
1428
1429   sv[idx].ud.si   = i;
1430   sv[idx].eventsq = (i_r ? ROAR_VIO_SELECT_READ   : 0) |
1431                     (i_w ? ROAR_VIO_SELECT_WRITE  : 0) |
1432                     (i_e ? ROAR_VIO_SELECT_EXCEPT : 0);
1433   idx++;
1434  }
1435 }
1436
1437 is_critical++;
1438 ret = roar_vio_select(sv, num, timeout == NULL ? NULL : &rtv, NULL);
1439 is_critical--;
1440
1441 if ( ret < 1 ) {
1442  roar_mm_free(sv);
1443  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1444  return ret;
1445 }
1446
1447 // update readfds, writefds, exceptfds:
1448 if ( readfds != NULL )
1449  FD_ZERO(readfds);
1450
1451 if ( writefds != NULL )
1452  FD_ZERO(writefds);
1453
1454 if ( exceptfds != NULL )
1455  FD_ZERO(exceptfds);
1456
1457 for (idx = 0; idx < num; idx++) {
1458  if ( sv[idx].eventsa == 0 )
1459   continue;
1460
1461  if ( sv[idx].eventsa & ROAR_VIO_SELECT_READ )
1462   if ( readfds != NULL )
1463    FD_SET(sv[idx].ud.si, readfds);
1464
1465  if ( sv[idx].eventsa & ROAR_VIO_SELECT_WRITE )
1466   if ( writefds != NULL )
1467    FD_SET(sv[idx].ud.si, writefds);
1468
1469  if ( sv[idx].eventsa & ROAR_VIO_SELECT_EXCEPT )
1470   if ( exceptfds != NULL )
1471    FD_SET(sv[idx].ud.si, exceptfds);
1472 }
1473
1474 roar_mm_free(sv);
1475
1476 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1477 return ret;
1478}
1479
[3264]1480// -------------------------------------
1481// emulated stdio functions follow:
1482// -------------------------------------
1483
1484//roar_vio_to_stdio
1485
[3667]1486static int _vio_close    (struct roar_vio_calls * vio) {
1487 int ret = 0;
1488
1489 if ( roar_vio_get_fh(vio) != -1 )
1490  ret = close(roar_vio_get_fh(vio));
1491
1492 roar_mm_free(vio);
1493
1494 return ret;
1495}
1496
[3264]1497FILE *fopen(const char *path, const char *mode) {
[3667]1498 struct roar_vio_calls * vio;
[3264]1499 FILE  * fr;
1500 int     ret;
1501 int     r = 0, w = 0;
1502 int     flags = 0;
1503 int     i;
1504 register char c;
1505
1506 _init();
1507
1508 if ( path == NULL || mode == NULL ) {
1509  errno = EFAULT;
1510  return NULL;
1511 }
1512
[3265]1513 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
[3264]1514
1515 for (i = 0; (c = mode[i]) != 0; i++) {
1516  switch (c) {
1517   case 'r': r = 1; break;
1518   case 'w': w = 1; break;
1519   case 'a': w = 1; break;
1520   case '+':
1521     r = 1;
1522     w = 1;
1523    break;
1524  }
1525 }
1526
1527 if ( r && w ) {
1528  flags = O_RDWR;
1529 } else if ( r ) {
1530  flags = O_RDONLY;
1531 } else if ( w ) {
1532  flags = O_WRONLY;
1533 } else {
1534  errno = EINVAL;
1535  return NULL;
1536 }
1537
1538 ret = _open_file(path, flags);
1539
1540 switch (ret) {
1541  case -2:       // continue as normal, use _op.open()
1542   break;
1543  case -1:       // pass error to caller
1544    return NULL;
1545   break;
1546  default:       // return successfully opened pointer to caller
[3667]1547    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
1548     return NULL; // errno should be set correctly by roar_mm_malloc().
1549    }
1550
1551    roar_vio_init_calls(vio);  // TODO: add error handling.
1552    roar_vio_set_fh(vio, ret); // TODO: add error handling.
1553    vio->close = _vio_close;
1554    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
1555     _vio_close(vio);
1556     errno = EIO;
1557     return NULL;
1558    } else {
1559     return fr;
1560    }
[3264]1561   break;
1562 }
1563
1564 return _os.fopen(path, mode);
1565}
1566
[3138]1567#endif
1568
1569//ll
Note: See TracBrowser for help on using the repository browser.