From e06493203cd31d5c30d44c8b324da87f1b786d99 Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Tue, 7 May 2019 16:59:08 +0200 Subject: [PATCH] Add QNX platform specific implementations Change-Id: Ic0b9c377e111cb59ed4859819b810842347e8525 Signed-off-by: Timo Wischer --- common/jack/systemdeps.h | 2 +- qnx/JackAtomic_os.h | 86 +++++++++++ qnx/JackLinuxTime.c | 215 +++++++++++++++++++++++++++ qnx/JackPlatformPlug_os.h | 85 +++++++++++ qnx/driver.h | 300 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 687 insertions(+), 1 deletion(-) mode change 100644 => 100755 common/jack/systemdeps.h create mode 100755 qnx/JackAtomic_os.h create mode 100755 qnx/JackLinuxTime.c create mode 100755 qnx/JackPlatformPlug_os.h create mode 100755 qnx/driver.h diff --git a/common/jack/systemdeps.h b/common/jack/systemdeps.h old mode 100644 new mode 100755 index 1a111927..2a2ffbeb --- a/common/jack/systemdeps.h +++ b/common/jack/systemdeps.h @@ -107,7 +107,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #endif /* _WIN32 && !__CYGWIN__ && !GNU_WIN32 */ -#if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32) +#if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32) || defined(__QNXNTO__) #if defined(__CYGWIN__) || defined(GNU_WIN32) #include diff --git a/qnx/JackAtomic_os.h b/qnx/JackAtomic_os.h new file mode 100755 index 00000000..e201d0d6 --- /dev/null +++ b/qnx/JackAtomic_os.h @@ -0,0 +1,86 @@ +/* +Copyright (C) 2004-2008 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackAtomic_linux__ +#define __JackAtomic_linux__ + +#include "JackTypes.h" + +#ifdef __PPC__ + +static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr) +{ + register int result; + register UInt32 tmp; + asm volatile ( + "# CAS \n" + " lwarx %4, 0, %1 \n" // creates a reservation on addr + " cmpw %4, %2 \n" // test value at addr + " bne- 1f \n" + " sync \n" // synchronize instructions + " stwcx. %3, 0, %1 \n" // if the reservation is not altered + // stores the new value at addr + " bne- 1f \n" + " li %0, 1 \n" + " b 2f \n" + "1: \n" + " li %0, 0 \n" + "2: \n" + : "=r" (result) + : "r" (addr), "r" (value), "r" (newvalue), "r" (tmp) + ); + return result; +} + +#endif + +#if defined(__i386__) || defined(__x86_64__) + +#define LOCK "lock ; " + +static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) +{ + register char ret; + __asm__ __volatile__ ( + "# CAS \n\t" + LOCK "cmpxchg %2, (%1) \n\t" + "sete %0 \n\t" + : "=a" (ret) + : "c" (addr), "d" (newvalue), "a" (value) + ); + return ret; +} + +#endif + + + + +#if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__) + + +static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) +{ + return __sync_bool_compare_and_swap ((UInt32*)addr, value, newvalue); +} +#endif + + +#endif + diff --git a/qnx/JackLinuxTime.c b/qnx/JackLinuxTime.c new file mode 100755 index 00000000..a5ece765 --- /dev/null +++ b/qnx/JackLinuxTime.c @@ -0,0 +1,215 @@ +/* +Copyright (C) 2001-2003 Paul Davis +Copyright (C) 2005 Jussi Laako +Copyright (C) 2004-2008 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackConstants.h" +#include "JackTime.h" +#include "JackTypes.h" +#include "JackError.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +jack_time_t (*_jack_get_microseconds)(void) = 0; + +#if defined(__gnu_linux__) && (defined(__i386__) || defined(__x86_64__)) +#define HPET_SUPPORT +#define HPET_MMAP_SIZE 1024 +#define HPET_CAPS 0x000 +#define HPET_PERIOD 0x004 +#define HPET_COUNTER 0x0f0 +#define HPET_CAPS_COUNTER_64BIT (1 << 13) +#if defined(__x86_64__) +typedef uint64_t hpet_counter_t; +#else +typedef uint32_t hpet_counter_t; +#endif +static int hpet_fd; +static unsigned char *hpet_ptr; +static uint32_t hpet_period; /* period length in femto secs */ +static uint64_t hpet_offset = 0; +static uint64_t hpet_wrap; +static hpet_counter_t hpet_previous = 0; +#endif /* defined(__gnu_linux__) && (__i386__ || __x86_64__) */ + +#ifdef HPET_SUPPORT + +static int jack_hpet_init () +{ + uint32_t hpet_caps; + + hpet_fd = open("/dev/hpet", O_RDONLY); + if (hpet_fd < 0) { + jack_error ("This system has no accessible HPET device (%s)", strerror (errno)); + return -1; + } + + hpet_ptr = (unsigned char *) mmap(NULL, HPET_MMAP_SIZE, + PROT_READ, MAP_SHARED, hpet_fd, 0); + if (hpet_ptr == MAP_FAILED) { + jack_error ("This system has no mappable HPET device (%s)", strerror (errno)); + close (hpet_fd); + return -1; + } + + /* this assumes period to be constant. if needed, + it can be moved to the clock access function + */ + hpet_period = *((uint32_t *) (hpet_ptr + HPET_PERIOD)); + hpet_caps = *((uint32_t *) (hpet_ptr + HPET_CAPS)); + hpet_wrap = ((hpet_caps & HPET_CAPS_COUNTER_64BIT) && + (sizeof(hpet_counter_t) == sizeof(uint64_t))) ? + 0 : ((uint64_t) 1 << 32); + + return 0; +} + +static jack_time_t jack_get_microseconds_from_hpet (void) +{ + hpet_counter_t hpet_counter; + long double hpet_time; + + hpet_counter = *((hpet_counter_t *) (hpet_ptr + HPET_COUNTER)); + if (hpet_counter < hpet_previous) + hpet_offset += hpet_wrap; + hpet_previous = hpet_counter; + hpet_time = (long double) (hpet_offset + hpet_counter) * + (long double) hpet_period * (long double) 1e-9; + return ((jack_time_t) (hpet_time + 0.5)); +} + +#else + +static int jack_hpet_init () +{ + jack_error ("This version of JACK or this computer does not have HPET support.\n" + "Please choose a different clock source."); + return -1; +} + +static jack_time_t jack_get_microseconds_from_hpet (void) +{ + /* never called */ + return 0; +} + +#endif /* HPET_SUPPORT */ + +#define HAVE_CLOCK_GETTIME 1 + +#ifndef HAVE_CLOCK_GETTIME + +static jack_time_t jack_get_microseconds_from_system (void) +{ + jack_time_t jackTime; + struct timeval tv; + + gettimeofday (&tv, NULL); + jackTime = (jack_time_t) tv.tv_sec * 1000000 + (jack_time_t) tv.tv_usec; + return jackTime; +} + +#else + +static jack_time_t jack_get_microseconds_from_system (void) +{ + jack_time_t jackTime; + struct timespec time; + + clock_gettime(CLOCK_MONOTONIC, &time); + jackTime = (jack_time_t) time.tv_sec * 1e6 + + (jack_time_t) time.tv_nsec / 1e3; + return jackTime; +} + +#endif /* HAVE_CLOCK_GETTIME */ + + +SERVER_EXPORT void JackSleep(long usec) +{ + usleep(usec); +} + +SERVER_EXPORT void InitTime() +{ + /* nothing to do on a generic system - we use the system clock */ +} + +SERVER_EXPORT void EndTime() +{} + +void SetClockSource(jack_timer_type_t source) +{ + jack_log("Clock source : %s", ClockSourceName(source)); + + switch (source) + { + case JACK_TIMER_HPET: + if (jack_hpet_init () == 0) { + _jack_get_microseconds = jack_get_microseconds_from_hpet; + } else { + _jack_get_microseconds = jack_get_microseconds_from_system; + } + break; + + case JACK_TIMER_SYSTEM_CLOCK: + default: + _jack_get_microseconds = jack_get_microseconds_from_system; + break; + } +} + +const char* ClockSourceName(jack_timer_type_t source) +{ + switch (source) { + case JACK_TIMER_HPET: + return "hpet"; + case JACK_TIMER_SYSTEM_CLOCK: + #ifdef HAVE_CLOCK_GETTIME + return "system clock via clock_gettime"; + #else + return "system clock via gettimeofday"; + #endif + } + + /* what is wrong with gcc ? */ + return "unknown"; +} + +SERVER_EXPORT jack_time_t GetMicroSeconds() +{ + return _jack_get_microseconds(); +} + +SERVER_EXPORT jack_time_t jack_get_microseconds() +{ + return _jack_get_microseconds(); +} + diff --git a/qnx/JackPlatformPlug_os.h b/qnx/JackPlatformPlug_os.h new file mode 100755 index 00000000..c845dca8 --- /dev/null +++ b/qnx/JackPlatformPlug_os.h @@ -0,0 +1,85 @@ +/* +Copyright (C) 2004-2008 Grame + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackPlatformPlug_linux__ +#define __JackPlatformPlug_linux__ + +#define jack_server_dir "/dev/shm" +#define jack_client_dir "/dev/shm" +#define JACK_DEFAULT_DRIVER "alsa" + +namespace Jack +{ + struct JackRequest; + struct JackResult; + + class JackPosixMutex; + class JackPosixThread; + class JackFifo; + class JackSocketServerChannel; + class JackSocketClientChannel; + class JackSocketServerNotifyChannel; + class JackSocketNotifyChannel; + class JackClientSocket; + class JackNetUnixSocket; +} + +/* __JackPlatformMutex__ */ +#include "JackPosixMutex.h" +namespace Jack {typedef JackPosixMutex JackMutex; } + +/* __JackPlatformThread__ */ +#include "JackPosixThread.h" +namespace Jack { typedef JackPosixThread JackThread; } + +#include "JackFifo.h" +namespace Jack { typedef JackFifo JackSynchro; } + + +/* __JackPlatformChannelTransaction__ */ +/* +#include "JackSocket.h" +namespace Jack { typedef JackClientSocket JackChannelTransaction; } +*/ + +/* __JackPlatformProcessSync__ */ +#include "JackPosixProcessSync.h" +namespace Jack { typedef JackPosixProcessSync JackProcessSync; } + +/* __JackPlatformServerChannel__ */ +#include "JackSocketServerChannel.h" +namespace Jack { typedef JackSocketServerChannel JackServerChannel; } + +/* __JackPlatformClientChannel__ */ +#include "JackSocketClientChannel.h" +namespace Jack { typedef JackSocketClientChannel JackClientChannel; } + +/* __JackPlatformServerNotifyChannel__ */ +#include "JackSocketServerNotifyChannel.h" +namespace Jack { typedef JackSocketServerNotifyChannel JackServerNotifyChannel; } + +/* __JackPlatformNotifyChannel__ */ +#include "JackSocketNotifyChannel.h" +namespace Jack { typedef JackSocketNotifyChannel JackNotifyChannel; } + +/* __JackPlatformNetSocket__ */ +#include "JackNetUnixSocket.h" +namespace Jack { typedef JackNetUnixSocket JackNetSocket; } + +#endif diff --git a/qnx/driver.h b/qnx/driver.h new file mode 100755 index 00000000..6e1466f4 --- /dev/null +++ b/qnx/driver.h @@ -0,0 +1,300 @@ +/* + Copyright (C) 2001 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: driver.h,v 1.2 2005/11/23 11:24:29 letz Exp $ +*/ + +#ifndef __jack_driver_h__ +#define __jack_driver_h__ + +#include +#include "types.h" +#include "jslist.h" +#include "driver_interface.h" + +typedef float gain_t; +typedef long channel_t; + +typedef enum { + Lock = 0x1, + NoLock = 0x2, + Sync = 0x4, + NoSync = 0x8 +} ClockSyncStatus; + +typedef void (*ClockSyncListenerFunction)(channel_t, ClockSyncStatus, void*); + +typedef struct +{ + unsigned long id; + ClockSyncListenerFunction function; + void *arg; +} +ClockSyncListener; + +struct _jack_engine; +struct _jack_driver; + +typedef int (*JackDriverAttachFunction)(struct _jack_driver *, + struct _jack_engine *); +typedef int (*JackDriverDetachFunction)(struct _jack_driver *, + struct _jack_engine *); +typedef int (*JackDriverReadFunction)(struct _jack_driver *, + jack_nframes_t nframes); +typedef int (*JackDriverWriteFunction)(struct _jack_driver *, + jack_nframes_t nframes); +typedef int (*JackDriverNullCycleFunction)(struct _jack_driver *, + jack_nframes_t nframes); +typedef int (*JackDriverStopFunction)(struct _jack_driver *); +typedef int (*JackDriverStartFunction)(struct _jack_driver *); +typedef int (*JackDriverBufSizeFunction)(struct _jack_driver *, + jack_nframes_t nframes); +/* + Call sequence summary: + + 1) engine loads driver via runtime dynamic linking + - calls jack_driver_load + - we call dlsym for "driver_initialize" and execute it + 2) engine attaches to driver + 3) engine starts driver + 4) driver runs its own thread, calling + while () { + driver->wait (); + driver->engine->run_cycle () + } + 5) engine stops driver + 6) engine detaches from driver + 7) engine calls driver `finish' routine + + Note that stop/start may be called multiple times in the event of an + error return from the `wait' function. +*/ + +typedef struct _jack_driver +{ + + /* The _jack_driver structure fields are included at the beginning of + each driver-specific structure using the JACK_DRIVER_DECL macro, + which is defined below. The comments that follow describe each + common field. + + The driver should set this to be the interval it expects to elapse + between returning from the `wait' function. if set to zero, it + implies that the driver does not expect regular periodic wakeups. + + jack_time_t period_usecs; + + + The driver should set this within its "wait" function to indicate + the UST of the most recent determination that the engine cycle + should run. it should not be set if the "extra_fd" argument of + the wait function is set to a non-zero value. + + jack_time_t last_wait_ust; + + + These are not used by the driver. They should not be written to or + modified in any way + + void *handle; + struct _jack_internal_client *internal_client; + + This should perform any cleanup associated with the driver. it will + be called when jack server process decides to get rid of the + driver. in some systems, it may not be called at all, so the driver + should never rely on a call to this. it can set it to NULL if + it has nothing do do. + + void (*finish)(struct _jack_driver *); + + + The JACK engine will call this when it wishes to attach itself to + the driver. the engine will pass a pointer to itself, which the driver + may use in anyway it wishes to. the driver may assume that this + is the same engine object that will make `wait' calls until a + `detach' call is made. + + JackDriverAttachFunction attach; + + + The JACK engine will call this when it is finished using a driver. + + JackDriverDetachFunction detach; + + + The JACK engine will call this when it wants to wait until the + driver decides that its time to process some data. the driver returns + a count of the number of audioframes that can be processed. + + it should set the variable pointed to by `status' as follows: + + zero: the wait completed normally, processing may begin + negative: the wait failed, and recovery is not possible + positive: the wait failed, and the driver stopped itself. + a call to `start' will return the driver to + a correct and known state. + + the driver should also fill out the `delayed_usecs' variable to + indicate any delay in its expected periodic execution. for example, + if it discovers that its return from poll(2) is later than it + expects it to be, it would place an estimate of the delay + in this variable. the engine will use this to decide if it + plans to continue execution. + + JackDriverWaitFunction wait; + + + The JACK engine will call this to ask the driver to move + data from its inputs to its output port buffers. it should + return 0 to indicate successful completion, negative otherwise. + + This function will always be called after the wait function (above). + + JackDriverReadFunction read; + + + The JACK engine will call this to ask the driver to move + data from its input port buffers to its outputs. it should + return 0 to indicate successful completion, negative otherwise. + + this function will always be called after the read function (above). + + JackDriverWriteFunction write; + + + The JACK engine will call this after the wait function (above) has + been called, but for some reason the engine is unable to execute + a full "cycle". the driver should do whatever is necessary to + keep itself running correctly, but cannot reference ports + or other JACK data structures in any way. + + JackDriverNullCycleFunction null_cycle; + + + The engine will call this when it plans to stop calling the `wait' + function for some period of time. the driver should take + appropriate steps to handle this (possibly no steps at all). + NOTE: the driver must silence its capture buffers (if any) + from within this function or the function that actually + implements the change in state. + + JackDriverStopFunction stop; + + + The engine will call this to let the driver know that it plans + to start calling the `wait' function on a regular basis. the driver + should take any appropriate steps to handle this (possibly no steps + at all). NOTE: The driver may wish to silence its playback buffers + (if any) from within this function or the function that actually + implements the change in state. + + JackDriverStartFunction start; + + The engine will call this to let the driver know that some client + has requested a new buffer size. The stop function will be called + prior to this, and the start function after this one has returned. + + JackDriverBufSizeFunction bufsize; + */ + + /* define the fields here... */ +#define JACK_DRIVER_DECL \ + jack_time_t period_usecs; \ + jack_time_t last_wait_ust; \ + void *handle; \ + struct _jack_client_internal * internal_client; \ + void (*finish)(struct _jack_driver *);\ + JackDriverAttachFunction attach; \ + JackDriverDetachFunction detach; \ + JackDriverReadFunction read; \ + JackDriverWriteFunction write; \ + JackDriverNullCycleFunction null_cycle; \ + JackDriverStopFunction stop; \ + JackDriverStartFunction start; \ + JackDriverBufSizeFunction bufsize; + + JACK_DRIVER_DECL /* expand the macro */ +} +jack_driver_t; + +void jack_driver_init (jack_driver_t *); +void jack_driver_release (jack_driver_t *); + +jack_driver_t *jack_driver_load (int argc, char **argv); +void jack_driver_unload (jack_driver_t *); + +/**************************** + *** Non-Threaded Drivers *** + ****************************/ + +/* + Call sequence summary: + + 1) engine loads driver via runtime dynamic linking + - calls jack_driver_load + - we call dlsym for "driver_initialize" and execute it + - driver_initialize calls jack_driver_nt_init + 2) nt layer attaches to driver + 3) nt layer starts driver + 4) nt layer runs a thread, calling + while () { + driver->nt_run_ctcle(); + } + 5) nt layer stops driver + 6) nt layer detaches driver + 7) engine calls driver `finish' routine which calls jack_driver_nt_finish + + Note that stop/start may be called multiple times in the event of an + error return from the `wait' function. +*/ + +struct _jack_driver_nt; + +typedef int (*JackDriverNTAttachFunction)(struct _jack_driver_nt *); +typedef int (*JackDriverNTDetachFunction)(struct _jack_driver_nt *); +typedef int (*JackDriverNTStopFunction)(struct _jack_driver_nt *); +typedef int (*JackDriverNTStartFunction)(struct _jack_driver_nt *); +typedef int (*JackDriverNTBufSizeFunction)(struct _jack_driver_nt *, + jack_nframes_t nframes); +typedef int (*JackDriverNTRunCycleFunction)(struct _jack_driver_nt *); + +typedef struct _jack_driver_nt +{ +#define JACK_DRIVER_NT_DECL \ + JACK_DRIVER_DECL \ + struct _jack_engine * engine; \ + volatile int nt_run; \ + pthread_t nt_thread; \ + pthread_mutex_t nt_run_lock; \ + JackDriverNTAttachFunction nt_attach; \ + JackDriverNTDetachFunction nt_detach; \ + JackDriverNTStopFunction nt_stop; \ + JackDriverNTStartFunction nt_start; \ + JackDriverNTBufSizeFunction nt_bufsize; \ + JackDriverNTRunCycleFunction nt_run_cycle; +#define nt_read read +#define nt_write write +#define nt_null_cycle null_cycle + + JACK_DRIVER_NT_DECL +} +jack_driver_nt_t; + +void jack_driver_nt_init (jack_driver_nt_t * driver); +void jack_driver_nt_finish (jack_driver_nt_t * driver); + +#endif /* __jack_driver_h__ */