diff options
Diffstat (limited to 'mbglib/common/pcpsdev.h')
-rwxr-xr-x | mbglib/common/pcpsdev.h | 1657 |
1 files changed, 1657 insertions, 0 deletions
diff --git a/mbglib/common/pcpsdev.h b/mbglib/common/pcpsdev.h new file mode 100755 index 0000000..4250a5a --- /dev/null +++ b/mbglib/common/pcpsdev.h @@ -0,0 +1,1657 @@ + +/************************************************************************** + * + * $Id: pcpsdev.h 1.49.1.25 2011/02/04 14:44:44 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used to share information on radio clock devices + * between device drivers which have direct access to the hardware + * devices and user space programs which evaluate and present that + * information. + * + * At the bottom of the file there are some macros defined which + * should be used to access the structures to extract characteristics + * of an individual clock. + * + * ----------------------------------------------------------------------- + * $Log: pcpsdev.h $ + * Revision 1.49.1.25 2011/02/04 14:44:44 martin + * Revision 1.49.1.24 2011/02/04 10:10:00 martin + * Revision 1.49.1.23 2011/02/02 12:34:10 martin + * Revision 1.49.1.22 2011/02/01 17:12:04 martin + * Revision 1.49.1.21 2011/01/28 13:11:11 martin + * Preliminary implementation of mbg_get_sys_time for FreeBSD traps. + * Revision 1.49.1.20 2011/01/28 10:34:37 martin + * Moved MBG_TGT_SUPP_MEM_ACC definition here. + * Revision 1.49.1.19 2011/01/26 16:39:05 martin + * Preliminarily support FreeBSD build. + * Revision 1.49.1.18 2011/01/24 17:09:51 martin + * Preliminarily fixed build under FreeBSD. + * Revision 1.49.1.17 2010/12/14 13:19:58 martin + * Fixed doxgen comments. + * Revision 1.49.1.16 2010/12/14 12:20:10 martin + * Revision 1.49.1.15 2010/11/25 14:54:22 martin + * Moved status port register definitions to pcpsdefs.h. + * Revision 1.49.1.14 2010/11/11 09:15:38 martin + * Added definitions to support DCF600USB. + * Revision 1.49.1.13 2010/09/27 13:09:06 martin + * Features are now defined using enum and bit masks. + * Added initializer for feature names (used for debug). + * Revision 1.49.1.12 2010/08/25 12:44:42 martin + * Revision 1.49.1.11 2010/08/20 09:34:41Z martin + * Added macro _pcps_features(). + * Revision 1.49.1.10 2010/08/17 15:34:23 martin + * Revision 1.49.1.9 2010/08/16 15:41:32 martin + * Revision 1.49.1.8 2010/08/13 12:14:46 daniel + * Revision 1.49.1.7 2010/08/13 11:57:54Z martin + * Revision 1.49.1.6 2010/08/13 11:39:28Z martin + * Revision 1.49.1.5 2010/08/13 11:19:41 martin + * Implemented portable mbg_get_sys_uptime() and mbg_sleep_sec() + * functions and associated types. + * Revision 1.49.1.4 2010/08/11 14:32:14 martin + * Revision 1.49.1.3 2010/08/11 13:47:42 martin + * Cleanup. + * Revision 1.49.1.2 2010/07/14 14:50:42 martin + * Revision 1.49.1.1 2010/06/30 13:17:18 martin + * Support GPS180PEX and TCR180PEX. + * Revision 1.49 2010/06/30 13:03:48 martin + * Use new preprocessor symbol MBG_ARCH_X86. + * Use ulong port addresses for all platforms but x86. + * Support mbg_get_pc_cycles() for IA64, but mbg_get_pc_cycles_frequency() + * is not yet supported. + * Don't pack interface structures on Sparc and IA64 architecture. + * Revision 1.48 2010/04/26 14:47:42 martin + * Define symbol MBG_PC_CYCLES_SUPPORTED if this is the case. + * Revision 1.47 2010/01/12 14:03:22 daniel + * Added definitions to support reading the raw IRIG data bits. + * Revision 1.46 2009/09/29 15:10:35Z martin + * Support generic system time, and retrieving time discipline info. + * Added _pcps_has_fast_hr_timestamp() macro and associated feature flag. + * Revision 1.45 2009/06/19 12:15:18 martin + * Added has_irig_time feature and associated macros. + * Revision 1.44 2009/06/08 19:30:48 daniel + * Account for new features PCPS_HAS_LAN_INTF and + * PCPS_HAS_PTP. + * Revision 1.43 2009/04/08 08:26:20 daniel + * Define firmware version at which the TCR511PCI starts + * to support IRIG control bits. + * Revision 1.42 2009/03/19 14:58:47Z martin + * Tmp. workaround in mbg_delta_pc_cycles() under SPARC which might + * generate bus errors due to unaligned access. + * Revision 1.41 2009/03/16 16:01:22 martin + * Support reading IRIG control function bits. + * Revision 1.40 2009/03/13 09:13:39 martin + * Support new features .._has_time_scale() and .._has_utc_parm(). + * Moved some inline functions dealing with MBG_PC_CYCLES + * from mbgdevio.h here. + * Merged the code from _pcps_get_cycles() and _pcps_get_cycles_frequency() + * to the mbg_get_pc_cycles...() inline functions which now replace the + * _pcps_get_cycles...() macros. + * Fixed cycles code for non-x86 architectures. + * Revision 1.39 2008/12/05 16:24:24Z martin + * Changed MAX_PARM_STR_TYPE from 10 to 20. + * Added support for WWVB signal source. + * Support new devices PTP270PEX, FRC511PEX, TCR170PEX, and WWVB51USB. + * Added macros _pcps_is_ptp(), _pcps_is_frc(), and _pcps_is_wwvb(). + * Defined firmware version numbers which fix an IRQ problem with PEX511, + * TCR511PEX, and GPS170PEX cards. The fix also requires specific ASIC + * versions specified in pci_asic.h. + * Defined firmware versions at which PCI511 and PEX511 start + * to support HR time. + * Support mapped I/O resources. + * Changed MBG_PC_CYCLES type for Windows to int64_t. + * Renamed MBG_VIRT_ADDR to MBG_MEM_ADDR. + * Added MBG_PC_CYCLES_FREQUENCY type. + * Added definition of PCPS_TIME_STAMP_CYCLES. + * Added PCPS_IRQ_STAT_INFO type and associated flags. + * Added macros to convert the endianess of structures. + * Added macros _pcps_fw_rev_num_major() and _pcps_fw_rev_num_minor(). + * Made irq_num signed to use -1 for unassigned IRQ numbers. + * Revision 1.38 2008/01/17 10:12:34 daniel + * Added support for TCR51USB and MSF51USB. + * New type MBG_VIRT_ADDR to specify virtual address values. + * New struct PCPS_MAPPED_MEM + * Cleanup for PCI ASIC version and features. + * Added macros _pcps_is_msf(), _pcps_is_lwr(), + * _psps_has_asic_version(), _pcps_has_asic_features(). + * Revision 1.37 2008/01/17 09:58:11Z daniel + * Made comments compatible for doxygen parser. + * No sourcecode changes. + * Revision 1.36 2007/09/26 09:34:38Z martin + * Added support for USB in general and new USB device USB5131. + * Added new types PCPS_DEV_ID and PCPS_REF_TYPE. + * Removed old PCPS_ERR_... codes. Use MBG_ERR_... codes + * from mbgerror.h instead. The old values haven't changed. + * Revision 1.35 2007/07/17 08:22:47Z martin + * Added support for TCR511PEX and GPS170PEX. + * Revision 1.34 2007/07/16 12:50:41Z martin + * Added support for PEX511. + * Modified/renamed some macros and symbols. + * Revision 1.33 2007/03/02 09:40:04Z martin + * Changes due to renamed library symbols. + * Removed obsolete inclusion of headers. + * Preliminary support for *BSD. + * Preliminary support for USB. + * Revision 1.32 2006/10/23 08:47:55Z martin + * Don't use abs() in _pcps_ref_offs_out_of_range() since this might + * not work properly for 16 bit integers and value 0x8000. + * Revision 1.31 2006/06/14 12:59:13Z martin + * Added support for TCR511PCI. + * Revision 1.30 2006/04/05 14:58:41 martin + * Support higher baud rates for PCI511. + * Revision 1.29 2006/04/03 07:29:07Z martin + * Added a note about the missing PCPS_ST_IRQF signal + * on PCI510 cards. + * Revision 1.28 2006/03/10 10:32:56Z martin + * Added support for PCI511. + * Added support for programmable pulse outputs. + * Revision 1.27 2005/11/04 08:48:00Z martin + * Added support for GPS170PCI. + * Revision 1.26 2005/06/02 08:34:38Z martin + * New types MBG_DBG_PORT, MBG_DBG_DATA. + * Revision 1.25 2005/05/03 10:04:14 martin + * Added macro _pcps_is_pci_amcc(). + * Revision 1.24 2005/03/29 12:58:19Z martin + * Support GENERIC_IO feature. + * Revision 1.23 2004/12/09 11:03:37Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.22 2004/11/09 12:57:52Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Added support for TCR167PCI. + * New macro _pcps_has_gps_data(). + * New type PCPS_STATUS_PORT. + * Removed obsolete inclusion of asm/timex.h for Linux. + * Revision 1.21 2004/09/06 15:19:49Z martin + * Support a GPS_DATA interface where sizes are specified + * by 16 instead of the original 8 bit quantities, thus allowing + * to transfer data blocks which exceed 255 bytes. + * Modified inclusion of header files under Linux. + * Modified definition of MBG_PC_CYCLES for Linux. + * Revision 1.20 2004/04/14 09:09:11 martin + * Source code cleanup. + * Revision 1.19 2004/04/07 09:49:14Z martin + * Support new feature PCPS_HAS_IRIG_TX. + * New macros _pcps_has_irig(), _pcps_has_irig_tx(). + * Revision 1.18 2004/01/14 11:02:14Z MARTIN + * Added formal type MBG_PC_CYCLES for OS/2, + * though it's not really required or used. + * Revision 1.17 2003/12/22 15:40:16 martin + * Support higher baud rates for TCR510PCI and PCI510. + * Supports PCPS_HR_TIME for TCR510PCI. + * New structures used to read device time together with associated + * PC CPU cycles. + * For Win32, differentiate between kernel mode and non-kernel mode. + * Moved some definitions here from mbgdevio.h. + * New type PCPS_ASIC_VERSION. + * New macro _pcps_ref_offs_out_of_range(). + * Revision 1.16 2003/06/19 09:48:30Z MARTIN + * Renamed symbols ..clr_cap_buffer to ..clr_ucap_buffer. + * New macro _pcps_has_ucap(). + * New definitions to support cmds PCPS_GIVE_UCAP_ENTRIES + * and PCPS_GIVE_UCAP_EVENT. + * Revision 1.15 2003/04/15 09:57:25 martin + * New typedefs ALL_STR_TYPE_INFO, ALL_PORT_INFO, + * RECEIVER_PORT_CFG. + * Revision 1.14 2003/04/09 14:07:01Z martin + * Supports PCI510, GPS169PCI, and TCR510PCI, + * and new PCI_ASIC used by those devices. + * Renamed macro _pcps_is_irig() to _pcps_is_irig_rx(). + * New macros _pcps_has_ref_offs(), _pcps_has_opt_flags(). + * Fixed macro _pcps_has_hr_time(). + * New type PCPS_BUS_FLAGS. + * Preliminary support for PCPS_TZDL. + * Revision 1.13 2002/08/09 07:19:49 MARTIN + * Moved definition of ref time sources to pcpsdefs.h. + * New feature PCPS_CAN_CLR_CAP_BUFF and + * associated macro _pcps_can_clr_cap_buff(). + * New macros _pcps_is_irig(), _pcps_has_signal(), + * _pcps_has_mod(). + * Revision 1.12 2002/02/19 09:22:53 MARTIN + * Added definitions for the maximum number of clocks' serial ports + * and string types that can be handled by the configuration programs. + * Revision 1.11 2002/02/01 11:36:58 MARTIN + * Added new definitions for GPS168PCI. + * Inserted definitions of firmware REV_NUMs for supported features + * which had previously been defined in pcpsdefs.h. + * Include use_pack.h. + * Updated comments. + * Source code cleanup. + * Revision 1.10 2001/11/30 09:52:48 martin + * Added support for event_time which, however, requires + * a custom GPS firmware. + * Revision 1.9 2001/10/16 10:11:14 MARTIN + * New Macro _pcps_has_serial_hs() which determines whether + * DCF77 clock supports baud rate higher than default. + * Re-arranged order of macro definitions. + * Revision 1.8 2001/09/03 07:15:05 MARTIN + * Added macro to access the firmware revision number. + * Cleaned up macro syntax. + * Added some comments. + * Revision 1.7 2001/08/30 13:20:04 MARTIN + * New macro to mark a PCPS_TIME variable as unread. + * New macro to check if a PCPS_TIME variable is unread. + * Revision 1.6 2001/03/15 15:45:01 MARTIN + * Added types PCPS_ERR_FLAGS, PCPS_BUS_NUM, PCPS_SLOT_NUM. + * Revision 1.5 2001/03/01 13:53:10 MARTIN + * Initial version for the new driver library. + * + **************************************************************************/ + +#ifndef _PCPSDEV_H +#define _PCPSDEV_H + +#include <pcpsdefs.h> +#include <gpsdefs.h> +#include <usbdefs.h> +#include <mbg_tgt.h> +#include <mbgtime.h> +#include <use_pack.h> + +#if defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + #include <linux/delay.h> + #else + #include <unistd.h> + #endif + + #if defined( MBG_ARCH_IA64 ) + #include <asm/ia64regs.h> + #include <asm/intel_intrin.h> + #endif + +#endif + +#if defined( MBG_TGT_BSD ) + #include <machine/clock.h> +#endif + +#if defined( MBG_TGT_DOS ) + #include <dos.h> // for delay() +#endif + + + +/* Start of header body */ + +#if defined( MBG_ARCH_SPARC ) || defined( MBG_ARCH_IA64 ) + #undef _USE_PACK // don't pack interface structures +#endif + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + + + +/** + Define generic types to hold PC cycle counter values and system timestamps. + The generic types are defined using native types used by the target operating + systems. + + The cycle counter value is usually derived from the PC CPU's TSC or some other + timer hardware on the mainboard. + */ +#if defined( MBG_TGT_WIN32 ) + + #define MBG_TGT_SUPP_MEM_ACC 1 + + // used with QueryPerformanceCounter() + typedef int64_t MBG_PC_CYCLES; + typedef uint64_t MBG_PC_CYCLES_FREQUENCY; + + typedef int64_t MBG_SYS_UPTIME; // [s] + + typedef LARGE_INTEGER MBG_SYS_TIME; + +#elif defined( MBG_TGT_LINUX ) + + #define MBG_TGT_SUPP_MEM_ACC 1 + + typedef uint64_t MBG_PC_CYCLES; + typedef uint64_t MBG_PC_CYCLES_FREQUENCY; + + typedef int64_t MBG_SYS_UPTIME; // [s] + + #if defined( __KERNEL__ ) + #include <linux/time.h> + #else + #include <sys/time.h> + #endif + + typedef struct timeval MBG_SYS_TIME; + +#elif defined( MBG_TGT_BSD ) + + #define MBG_TGT_SUPP_MEM_ACC 1 + + typedef uint64_t MBG_PC_CYCLES; + typedef uint64_t MBG_PC_CYCLES_FREQUENCY; + + typedef int64_t MBG_SYS_UPTIME; // [s] + + typedef struct timeval MBG_SYS_TIME; + + #if defined( _KERNEL ) + #include <sys/sysproto.h> + #include <sys/pcpu.h> + #else + #include <sys/time.h> + #endif + +#elif defined( MBG_TGT_OS2 ) + + typedef uint32_t MBG_PC_CYCLES; //##++ should differentiate more + typedef uint32_t MBG_PC_CYCLES_FREQUENCY; + + typedef long MBG_SYS_UPTIME; //## dummy + + typedef uint32_t MBG_SYS_TIME; //## dummy + +#elif defined( MBG_TGT_DOS ) + + typedef uint32_t MBG_PC_CYCLES; //##++ should differentiate more + typedef uint32_t MBG_PC_CYCLES_FREQUENCY; + #define MBG_MEM_ADDR uint32_t // 64 bit not supported, nor required. + + typedef long MBG_SYS_UPTIME; //## dummy + + typedef uint32_t MBG_SYS_TIME; //## dummy + +#else // other target OSs which access the hardware directly + + typedef uint32_t MBG_PC_CYCLES; //##++ should differentiate more + typedef uint32_t MBG_PC_CYCLES_FREQUENCY; + + typedef long MBG_SYS_UPTIME; //## dummy + + typedef uint32_t MBG_SYS_TIME; //## dummy + +#endif + + +#if !defined( MBG_TGT_SUPP_MEM_ACC ) + #define MBG_TGT_SUPP_MEM_ACC 0 +#endif + + +// MBG_PC_CYCLES, MBG_PC_CYCLES_FREQUENCY, and MBG_SYS_TIME are always read +// in native machine endianess, so no endianess conversion is required. +#define _mbg_swab_mbg_pc_cycles( _p ) \ + _nop_macro_fnc() + +#define _mbg_swab_mbg_pc_cycles_frequency( _p ) \ + _nop_macro_fnc() + +#define _mbg_swab_mbg_sys_time( _p ) \ + _nop_macro_fnc() + + + +/** + The structure holds a system timestamp in a format depending on the target OS + plus two cycles counter values which can be taken before and after reading + the system time. These cycles values can be used to determine the execution + time required to read the system time. + + Limitations of the operating system need to be taken into account, + e.g. the Windows system time may increase once every ~16 ms only. + */ +typedef struct +{ + MBG_PC_CYCLES cyc_before; /**< cycles count before sys time is read */ + MBG_PC_CYCLES cyc_after; /**< cycles count after sys time has been read */ + MBG_SYS_TIME sys_time; /**< system time stamp */ +} MBG_SYS_TIME_CYCLES; + +#define _mbg_swab_mbg_sys_time_cycles( _p ) \ +{ \ + _mbg_swab_mbg_pc_cycles( &(_p)->cyc_before ); \ + _mbg_swab_mbg_pc_cycles( &(_p)->cyc_after ); \ + _mbg_swab_mbg_sys_time( &(_p)->sys_time ); \ +} + + + + +#if ( defined( MBG_TGT_LINUX ) || defined( MBG_TGT_BSD ) ) && defined( MBG_ARCH_X86 ) + + static __mbg_inline unsigned long long int mbg_rdtscll( void ) + { + // The code below is a hack to get around issues with + // different versions of gcc. + // + // Normally the inline asm code could look similar to: + // + // __asm__ volatile ( "rdtsc" : "=A" (x) ) + // + // which would copy the output regs edx:eax as a 64 bit + // number to a variable x. + // + // The "=A" expression should implicitely tell the compiler + // the edx and eax registers have been clobbered. However, + // this does not seem to work properly at least with gcc 4.1.2 + // shipped with Centos 5. + // + // If optimization level 1 or higher is used then function + // parameters are also passed in registers. If the inline + // code above is used inside a function then the edx register + // is clobbered but the gcc 4.1.2 is not aware of this and + // assumes edx is unchanged, which may yield faulty results + // or even lead to segmentation faults. + // + // A possible workaround could be to mark edx explicitely as + // being clobbered in the asm inline code, but unfortunately + // other gcc versions report an error if a register which is + // implicitely (by "=A") known to be clobbered is also listed + // explicitely to be clobbered. + // + // So the code below is a workaround which tells the compiler + // implicitely that the eax ("=a") and edx ("=d") registers + // are being used and thus clobbered. + + union + { + struct + { + uint32_t lo; + uint32_t hi; + } u32; + + uint64_t u64; + + } tsc_val; + + __asm__ __volatile__( "rdtsc" : "=a" (tsc_val.u32.lo), "=d" (tsc_val.u32.hi) ); + + return tsc_val.u64; + + } // mbg_rdtscll + +#endif + + + +static __mbg_inline +void mbg_get_pc_cycles( MBG_PC_CYCLES *p ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + *p = (MBG_PC_CYCLES) KeQueryPerformanceCounter( NULL ).QuadPart; + #else // user space + QueryPerformanceCounter( (LARGE_INTEGER *) p ); + #endif + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 ) + + #if 0 && ( defined( CONFIG_X86_TSC ) || defined( CONFIG_M586TSC ) ) //##++++ + #define _pcps_get_cycles( _c ) \ + _c = get_cycles() + #else + *p = mbg_rdtscll(); + #endif + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #elif defined( MBG_TGT_BSD ) && defined( MBG_ARCH_X86 ) + + *p = mbg_rdtscll(); + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_IA64 ) + + unsigned long result = ia64_getreg( _IA64_REG_AR_ITC ); + ia64_barrier(); + + #ifdef CONFIG_ITANIUM + while (unlikely((__s32) result == -1)) { + result = ia64_getreg(_IA64_REG_AR_ITC); + ia64_barrier(); + } + #endif + + *p = result; + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #else + + *p = 0; + + #endif + +} // mbg_get_pc_cycles + + + +static __mbg_inline +void mbg_get_pc_cycles_frequency( MBG_PC_CYCLES_FREQUENCY *p ) +{ + #if defined( MBG_TGT_WIN32 ) + LARGE_INTEGER li; + + #if defined( _KDD_ ) // kernel space + KeQueryPerformanceCounter( &li ); + #else // user space + QueryPerformanceFrequency( &li ); + #endif + + *p = li.QuadPart; + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 ) + + #if defined( __KERNEL__ ) + + *p = ( cpu_khz * 1000 ); + + #else + + *p = 0; + + #endif + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_IA64 ) + + #error A way to get cycles frequency needs to be defined for Linux/IA64. + + // we probably can use + // ia64_sal_freq_base(unsigned long which, unsigned long *ticks_per_second, + // unsigned long *drift_info) + // However, this is not tested. + + #elif defined( MBG_TGT_BSD ) + + #if defined( MBG_ARCH_X86 ) && defined( _KERNEL ) + + *p = tsc_freq; + + #else + + *p = 0; + + #endif + + #else + + #if MBG_PC_CYCLES_SUPPORTED + + #error A way to get cycles frequency needs to be defined for this target. + + #else + *p = 0; + #endif + + #endif + +} // mbg_get_pc_cycles_frequency + + + +static __mbg_inline +MBG_PC_CYCLES mbg_delta_pc_cycles( const MBG_PC_CYCLES *p1, const MBG_PC_CYCLES *p2 ) +{ +#if !defined( MBG_PC_CYCLES_SUPPORTED ) + // Cycle counts not supported on this target platform. + // Under SPARC this may even result in bus errors + // due to alignment of the underlying data structures. + return 0; +#else + return *p1 - *p2; +#endif + +} // mbg_delta_pc_cycles + + + +static __mbg_inline +void mbg_get_sys_time( MBG_SYS_TIME *p ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + KeQuerySystemTime( p ); + #else // user space + { + FILETIME ft; + GetSystemTimeAsFileTime( &ft ); + p->LowPart = ft.dwLowDateTime; + p->HighPart = ft.dwHighDateTime; + } + #endif + + #elif defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + do_gettimeofday( p ); + #else + gettimeofday( p, NULL ); + #endif + + #elif defined( MBG_TGT_BSD ) + + #if defined( _KERNEL ) + microtime( p ); + #else + gettimeofday( p, NULL ); + #endif + + #else + + *p = 0; + + #endif + +} // mbg_get_sys_time + + + +static __mbg_inline +void mbg_get_sys_uptime( MBG_SYS_UPTIME *p ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + + ULONGLONG time_increment = KeQueryTimeIncrement(); + LARGE_INTEGER tick_count; + + KeQueryTickCount( &tick_count ); + + // multiplication by time_increment yields HNS units, + // but we need seconds + *p = ( tick_count.QuadPart * time_increment ) / HNS_PER_SEC; + + #else // user space + + DWORD tickCount; + DWORD timeAdjustment; + DWORD timeIncrement; + BOOL timeAdjustmentDisabled; + + if ( !GetSystemTimeAdjustment( &timeAdjustment, &timeIncrement, &timeAdjustmentDisabled ) ) + *p = -1; // failed + + // ATTENTION: This is compatible with older Windows versions, but + // the returned tick count wraps around to zero after 49.7 days. + // A new GetTickCount64() call is available under Windows Vista and newer, + // but the function call had to be imported dynamically since otherwise + // programs refused to start under pre-Vista versions due to undefined DLL symbol. + tickCount = GetTickCount(); + + *p = ( ( (MBG_SYS_UPTIME) tickCount ) * timeIncrement ) / HNS_PER_SEC; + + #endif + + #elif defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + { + // Using a simple 64 bit division may result in a linker error + // in kernel mode due to a missing symbol __udivdi3, so we use + // a specific inline function do_div(). + // Also, the jiffies counter is not set to 0 at startup but to + // a defined initialization value we need to account for. + uint64_t tmp = get_jiffies_64() - INITIAL_JIFFIES; + do_div( tmp, HZ ); + *p = tmp; + } + #else + //##++++ Still need to implement this for Linux user space. + // A possible way would be to parse the contents + // of the pseudo-file /proc/uptime. + *p = -1; + #endif + + #elif defined( MBG_TGT_BSD ) + + #if defined( _KERNEL ) + { + struct timeval tv; + + getmicrouptime( &tv ); + + *p = tv.tv_sec; + } + #else + //##++++ Still need to implement this for user space. + *p = -1; + #endif + + #else + + *p = -1; // not supported + + #endif + +} // mbg_get_sys_uptime + + + +static __mbg_inline +void mbg_sleep_sec( long sec ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + LARGE_INTEGER delay; + + // we need to pass a negative value to KeDelayExecutionThread() + // since the given time is a relative time interval, not absolute + // time. See the API docs for KeDelayExecutionThread(). + delay.QuadPart = (LONGLONG) sec * HNS_PER_SEC; + + KeDelayExecutionThread( KernelMode, FALSE, &delay ); + #else // user space + // Sleep() expects milliseconds + Sleep( sec * 1000 ); + #endif + + #elif defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + // msleep is not defined in older kernels, so we use this + // only if it is surely supported. + #if ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 16 ) ) //##+++++ + msleep( sec * 1000 ); + #else + { + DECLARE_WAIT_QUEUE_HEAD( tmp_wait ); + wait_event_interruptible_timeout( tmp_wait, 0, sec * HZ + 1 ); + } + #endif + #else + sleep( sec ); + #endif + + #elif defined( MBG_TGT_BSD ) + + //##+++++++++++++++++++ needs to be defined + + #elif defined( MBG_TGT_DOS ) + + delay( sec * 1000 ); + + #else + + // This needs to be implemented for the target OS + // and thus will probably yield a linker error. + do_sleep_sec( sec ); + + #endif + +} // mbg_sleep_sec + + + +#if !defined( MBG_MEM_ADDR ) + // By default a memory address is stored + // as a 64 bit quantitiy. + #define MBG_MEM_ADDR uint64_t +#endif + + +typedef uint8_t MBG_DBG_DATA; +typedef uint16_t MBG_DBG_PORT; + + +// The following flags describe the bus types which are +// supported by the plugin clocks. +#define PCPS_BUS_ISA 0x0001 // IBM compatible PC/AT ISA bus +#define PCPS_BUS_MCA 0x0002 // IBM PS/2 micro channel +#define PCPS_BUS_PCI 0x0004 // PCI +#define PCPS_BUS_USB 0x0008 // USB + +// The flags below are or'ed to the PC_BUS_PCI code +// in order to indicate which PCI interface chip is used +// on a PCI card. If no flag is set then the S5933 chip is +// installed which has been used for the first generation +// of Meinberg PCI cards. + +// S5920 PCI interface chip. +#define PCPS_BUS_PCI_CHIP_S5920 0x8000 + +// Meinberg's own PCI interface chip. +#define PCPS_BUS_PCI_CHIP_ASIC 0x4000 + +// PEX8311 PCI Express interface chip +#define PCPS_BUS_PCI_CHIP_PEX8311 0x2000 + +// Meinberg's own PCI Express interface chip +#define PCPS_BUS_PCI_CHIP_MBGPEX 0x1000 + + +// The constant below combines the PCI bus flags. +#define PCPS_BUS_PCI_S5933 ( PCPS_BUS_PCI ) +#define PCPS_BUS_PCI_S5920 ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_S5920 ) +#define PCPS_BUS_PCI_ASIC ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_ASIC ) +#define PCPS_BUS_PCI_PEX8311 ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_PEX8311 ) +#define PCPS_BUS_PCI_MBGPEX ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_MBGPEX ) + + + +/** A list of known radio clocks. */ +enum PCPS_TYPES +{ + PCPS_TYPE_PC31, + PCPS_TYPE_PS31_OLD, + PCPS_TYPE_PS31, + PCPS_TYPE_PC32, + PCPS_TYPE_PCI32, + PCPS_TYPE_GPS167PC, + PCPS_TYPE_GPS167PCI, + PCPS_TYPE_PCI509, + PCPS_TYPE_GPS168PCI, + PCPS_TYPE_PCI510, + PCPS_TYPE_GPS169PCI, + PCPS_TYPE_TCR510PCI, + PCPS_TYPE_TCR167PCI, + PCPS_TYPE_GPS170PCI, + PCPS_TYPE_PCI511, + PCPS_TYPE_TCR511PCI, + PCPS_TYPE_PEX511, + PCPS_TYPE_TCR511PEX, + PCPS_TYPE_GPS170PEX, + PCPS_TYPE_USB5131, + PCPS_TYPE_TCR51USB, + PCPS_TYPE_MSF51USB, + PCPS_TYPE_PTP270PEX, + PCPS_TYPE_FRC511PEX, + PCPS_TYPE_TCR170PEX, + PCPS_TYPE_WWVB51USB, + PCPS_TYPE_GPS180PEX, + PCPS_TYPE_TCR180PEX, + PCPS_TYPE_DCF600USB, + N_PCPS_DEV_TYPE +}; + + +#define PCPS_CLOCK_NAME_SZ 10 // including terminating 0 + +typedef uint16_t PCPS_DEV_ID; +typedef uint16_t PCPS_REF_TYPE; +typedef uint16_t PCPS_BUS_FLAGS; + +/** + The structure contains the characteristics of each + of the clocks listed above. These fields are always the + same for a single type of clock and do not change with + firmware version, port address, etc. + */ +typedef struct +{ + uint16_t num; + char name[PCPS_CLOCK_NAME_SZ]; + PCPS_DEV_ID dev_id; + PCPS_REF_TYPE ref_type; + PCPS_BUS_FLAGS bus_flags; +} PCPS_DEV_TYPE; + + + +#if !defined( MBG_TGT_LINUX ) || defined( MBG_ARCH_X86 ) + typedef uint16_t PCPS_PORT_ADDR; +#else + typedef ulong PCPS_PORT_ADDR; +#endif + + + +/** + The structure below describes an I/O port resource + used by a clock. +*/ +typedef struct +{ + PCPS_PORT_ADDR base; + uint16_t num; +} PCPS_PORT_RSRC; + +/** The max number of I/O port resources used by a clock. */ +#define N_PCPS_PORT_RSRC 2 + + + +typedef struct +{ + MBG_MEM_ADDR user_virtual_address; + ulong len; + #if defined( MBG_TGT_LINUX ) + uint32_t pfn_offset; + #endif +} PCPS_MAPPED_MEM; + + + +typedef uint32_t PCPS_ERR_FLAGS; /**< see \ref group_err_flags "Error flags" */ +typedef uint32_t PCPS_FEATURES; /**< see \ref group_features "Features" */ +typedef uint16_t PCPS_BUS_NUM; +typedef uint16_t PCPS_SLOT_NUM; + +/** + The structure below contains data which depends + on a individual instance of the clock, e.g. + the firmware which is currently installed, the + port address which has been configured, etc. +*/ +typedef struct +{ + PCPS_ERR_FLAGS err_flags; /**< See \ref group_err_flags "Error flags" */ + PCPS_BUS_NUM bus_num; + PCPS_SLOT_NUM slot_num; + PCPS_PORT_RSRC port[N_PCPS_PORT_RSRC]; + uint16_t status_port; + int16_t irq_num; + uint32_t timeout_clk; + uint16_t fw_rev_num; + PCPS_FEATURES features; /**< See \ref group_features "Feature flags" */ + PCPS_ID_STR fw_id; + PCPS_SN_STR sernum; +} PCPS_DEV_CFG; + +/** @defgroup group_err_flags Error flags in PCPS_DEV_CFG + Flags used with PCPS_DEV_CFG::err_flags + @{ +*/ +#define PCPS_EF_TIMEOUT 0x00000001 /**< timeout occured */ +#define PCPS_EF_INV_EPROM_ID 0x00000002 /**< invalid EPROM ID */ +#define PCPS_EF_IO_INIT 0x00000004 /**< I/O intf not init'd */ +#define PCPS_EF_IO_CFG 0x00000008 /**< I/O intf not cfg'd */ +#define PCPS_EF_IO_ENB 0x00000010 /**< I/O intf not enabled */ +#define PCPS_EF_IO_RSRC 0x00000020 /**< I/O not registered w/ rsrcmgr */ +/** @} */ + +/** @defgroup group_features Feature flags used with PCPS_FEATURES + + Some features of the radio clocks have been introduced with + specific firmware versions, so depending on the firmware version + a clock may support a feature or not. The clock detection function + checks the clock model and firmware version and updates the field + PCPS_DEV_CFG::features accordingly. There are some macros which + can easily be used to query whether a clock device actually + supports a function, or not. The definitions define + the possible features. + @{ +*/ +enum +{ + PCPS_BIT_CAN_SET_TIME, + PCPS_BIT_HAS_SERIAL, + PCPS_BIT_HAS_SYNC_TIME, + PCPS_BIT_HAS_TZDL, + PCPS_BIT_HAS_IDENT, + PCPS_BIT_HAS_UTC_OFFS, + PCPS_BIT_HAS_HR_TIME, + PCPS_BIT_HAS_SERNUM, + PCPS_BIT_HAS_TZCODE, + PCPS_BIT_HAS_CABLE_LEN, + PCPS_BIT_HAS_EVENT_TIME, // custom GPS firmware only + PCPS_BIT_HAS_RECEIVER_INFO, + PCPS_BIT_CAN_CLR_UCAP_BUFF, + PCPS_BIT_HAS_PCPS_TZDL, + PCPS_BIT_HAS_UCAP, + PCPS_BIT_HAS_IRIG_TX, + PCPS_BIT_HAS_GPS_DATA_16, // use 16 bit size specifiers + PCPS_BIT_HAS_SYNTH, + PCPS_BIT_HAS_GENERIC_IO, + PCPS_BIT_HAS_TIME_SCALE, + PCPS_BIT_HAS_UTC_PARM, + PCPS_BIT_HAS_IRIG_CTRL_BITS, + PCPS_BIT_HAS_LAN_INTF, + PCPS_BIT_HAS_PTP, + PCPS_BIT_HAS_IRIG_TIME, + PCPS_BIT_HAS_FAST_HR_TSTAMP, + PCPS_BIT_HAS_RAW_IRIG_DATA, + N_PCPS_FEATURE +}; + + +#define PCPS_CAN_SET_TIME ( 1UL << PCPS_BIT_CAN_SET_TIME ) +#define PCPS_HAS_SERIAL ( 1UL << PCPS_BIT_HAS_SERIAL ) +#define PCPS_HAS_SYNC_TIME ( 1UL << PCPS_BIT_HAS_SYNC_TIME ) +#define PCPS_HAS_TZDL ( 1UL << PCPS_BIT_HAS_TZDL ) +#define PCPS_HAS_IDENT ( 1UL << PCPS_BIT_HAS_IDENT ) +#define PCPS_HAS_UTC_OFFS ( 1UL << PCPS_BIT_HAS_UTC_OFFS ) +#define PCPS_HAS_HR_TIME ( 1UL << PCPS_BIT_HAS_HR_TIME ) +#define PCPS_HAS_SERNUM ( 1UL << PCPS_BIT_HAS_SERNUM ) +#define PCPS_HAS_TZCODE ( 1UL << PCPS_BIT_HAS_TZCODE ) +#define PCPS_HAS_CABLE_LEN ( 1UL << PCPS_BIT_HAS_CABLE_LEN ) +#define PCPS_HAS_EVENT_TIME ( 1UL << PCPS_BIT_HAS_EVENT_TIME ) +#define PCPS_HAS_RECEIVER_INFO ( 1UL << PCPS_BIT_HAS_RECEIVER_INFO ) +#define PCPS_CAN_CLR_UCAP_BUFF ( 1UL << PCPS_BIT_CAN_CLR_UCAP_BUFF ) +#define PCPS_HAS_PCPS_TZDL ( 1UL << PCPS_BIT_HAS_PCPS_TZDL ) +#define PCPS_HAS_UCAP ( 1UL << PCPS_BIT_HAS_UCAP ) +#define PCPS_HAS_IRIG_TX ( 1UL << PCPS_BIT_HAS_IRIG_TX ) +#define PCPS_HAS_GPS_DATA_16 ( 1UL << PCPS_BIT_HAS_GPS_DATA_16 ) +#define PCPS_HAS_SYNTH ( 1UL << PCPS_BIT_HAS_SYNTH ) +#define PCPS_HAS_GENERIC_IO ( 1UL << PCPS_BIT_HAS_GENERIC_IO ) +#define PCPS_HAS_TIME_SCALE ( 1UL << PCPS_BIT_HAS_TIME_SCALE ) +#define PCPS_HAS_UTC_PARM ( 1UL << PCPS_BIT_HAS_UTC_PARM ) +#define PCPS_HAS_IRIG_CTRL_BITS ( 1UL << PCPS_BIT_HAS_IRIG_CTRL_BITS ) +#define PCPS_HAS_LAN_INTF ( 1UL << PCPS_BIT_HAS_LAN_INTF ) +#define PCPS_HAS_PTP ( 1UL << PCPS_BIT_HAS_PTP ) +#define PCPS_HAS_IRIG_TIME ( 1UL << PCPS_BIT_HAS_IRIG_TIME ) +#define PCPS_HAS_FAST_HR_TSTAMP ( 1UL << PCPS_BIT_HAS_FAST_HR_TSTAMP ) +#define PCPS_HAS_RAW_IRIG_DATA ( 1UL << PCPS_BIT_HAS_RAW_IRIG_DATA ) + + + +#define PCPS_FEATURE_NAMES \ +{ \ + "PCPS_CAN_SET_TIME", \ + "PCPS_HAS_SERIAL", \ + "PCPS_HAS_SYNC_TIME", \ + "PCPS_HAS_TZDL", \ + "PCPS_HAS_IDENT", \ + "PCPS_HAS_UTC_OFFS", \ + "PCPS_HAS_HR_TIME", \ + "PCPS_HAS_SERNUM", \ + "PCPS_HAS_TZCODE", \ + "PCPS_HAS_CABLE_LEN", \ + "PCPS_HAS_EVENT_TIME", \ + "PCPS_HAS_RECEIVER_INFO", \ + "PCPS_CAN_CLR_UCAP_BUFF", \ + "PCPS_HAS_PCPS_TZDL", \ + "PCPS_HAS_UCAP", \ + "PCPS_HAS_IRIG_TX", \ + "PCPS_HAS_GPS_DATA_16", \ + "PCPS_HAS_SYNTH", \ + "PCPS_HAS_GENERIC_IO", \ + "PCPS_HAS_TIME_SCALE", \ + "PCPS_HAS_UTC_PARM", \ + "PCPS_HAS_IRIG_CTRL_BITS", \ + "PCPS_HAS_LAN_INTF", \ + "PCPS_HAS_PTP", \ + "PCPS_HAS_IRIG_TIME", \ + "PCPS_HAS_FAST_HR_TSTAMP", \ + "PCPS_HAS_RAW_IRIG_DATA" \ +} + +/** @} */ + + + +// The constants below define those features which are available +// in ALL firmware versions which have been shipped with a +// specific clock. + +#define PCPS_FEAT_PC31PS31 0 + +// Some of the features are available in all newer clocks, +// so these have been put together in one definition: +#define PCPS_FEAT_LVL2 ( PCPS_CAN_SET_TIME \ + | PCPS_HAS_SERIAL \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_UTC_OFFS ) + +#define PCPS_FEAT_PC32 ( PCPS_FEAT_LVL2 ) + +#define PCPS_FEAT_PCI32 ( PCPS_FEAT_LVL2 ) + +#define PCPS_FEAT_PCI509 ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_TZCODE ) + +#define PCPS_FEAT_PCI510 ( PCPS_FEAT_PCI509 ) + +#define PCPS_FEAT_PCI511 ( PCPS_FEAT_PCI510 ) + +#define PCPS_FEAT_GPS167PC ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_IDENT ) + +#define PCPS_FEAT_GPS167PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_IDENT \ + | PCPS_HAS_HR_TIME ) + +#define PCPS_FEAT_GPS168PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_IDENT \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_CABLE_LEN \ + | PCPS_HAS_RECEIVER_INFO ) + +#define PCPS_FEAT_GPS169PCI ( PCPS_FEAT_GPS168PCI \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP ) + +#define PCPS_FEAT_GPS170PCI ( PCPS_FEAT_GPS169PCI \ + | PCPS_HAS_IRIG_TX \ + | PCPS_HAS_GPS_DATA_16 \ + | PCPS_HAS_GENERIC_IO ) + +#define PCPS_FEAT_TCR510PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_SERNUM ) + +#define PCPS_FEAT_TCR167PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_RECEIVER_INFO \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP \ + | PCPS_HAS_IRIG_TX \ + | PCPS_HAS_GPS_DATA_16 \ + | PCPS_HAS_GENERIC_IO ) + +#define PCPS_FEAT_TCR511PCI ( PCPS_FEAT_TCR510PCI \ + | PCPS_HAS_HR_TIME ) + +#define PCPS_FEAT_PEX511 ( PCPS_FEAT_PCI511 ) + +#define PCPS_FEAT_TCR511PEX ( PCPS_FEAT_TCR511PCI ) + +#define PCPS_FEAT_GPS170PEX ( PCPS_FEAT_GPS170PCI ) + +#define PCPS_FEAT_USB5131 ( PCPS_HAS_UTC_OFFS \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_CAN_SET_TIME \ + | PCPS_HAS_TZCODE ) + +#define PCPS_FEAT_TCR51USB ( PCPS_HAS_UTC_OFFS \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_CAN_SET_TIME ) + +#define PCPS_FEAT_MSF51USB ( PCPS_HAS_UTC_OFFS \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_CAN_SET_TIME ) + +#define PCPS_FEAT_PTP270PEX ( PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_RECEIVER_INFO \ + | PCPS_CAN_SET_TIME \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP \ + | PCPS_HAS_GPS_DATA_16 ) + +#define PCPS_FEAT_FRC511PEX ( PCPS_HAS_SERNUM \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_RECEIVER_INFO \ + | PCPS_CAN_SET_TIME \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP \ + | PCPS_HAS_GPS_DATA_16 ) + +#define PCPS_FEAT_TCR170PEX ( PCPS_FEAT_TCR167PCI ) + +#define PCPS_FEAT_WWVB51USB ( PCPS_FEAT_MSF51USB ) + +#define PCPS_FEAT_GPS180PEX ( PCPS_FEAT_GPS170PEX | PCPS_HAS_FAST_HR_TSTAMP ) + +#define PCPS_FEAT_TCR180PEX ( PCPS_FEAT_TCR170PEX | PCPS_HAS_FAST_HR_TSTAMP ) + +#define PCPS_FEAT_DCF600USB ( PCPS_FEAT_USB5131 ) + +// Some features of the API used to access Meinberg plug-in radio clocks +// have been implemented starting with the special firmware revision +// numbers defined below. +// +// If no number is specified for a feature/clock model then the feature +// is either always supported by that clock model, or not at all. + + +// There are some versions of PCI Express cards out there which do not +// safely support hardware IRQs. The following firmware versions are required +// for safe IRQ operation: +#define REV_HAS_IRQ_FIX_MINOR_PEX511 0x0106 +#define REV_HAS_IRQ_FIX_MINOR_TCR511PEX 0x0105 +#define REV_HAS_IRQ_FIX_MINOR_GPS170PEX 0x0104 +// Additionally there are certain revisions of the bus interface logic +// required. The associated version codes are defined in pci_asic.h. + +// The macro below can be used to check whether the required versions are there: +#define _pcps_pex_irq_is_safe( _curr_fw_ver, _req_fw_ver, _curr_asic_ver, \ + _req_asic_ver_major, _req_asic_ver_minor ) \ + ( ( (_curr_fw_ver) >= (_req_fw_ver) ) && _pcps_asic_version_greater_equal( \ + (_curr_asic_ver), (_req_asic_ver_major), (_req_asic_ver_minor ) ) \ + ) + +/* command PCPS_GIVE_RAW_IRIG_DATA: */ +#define REV_HAS_RAW_IRIG_DATA_TCR511PEX 0x0111 +#define REV_HAS_RAW_IRIG_DATA_TCR511PCI 0x0111 +#define REV_HAS_RAW_IRIG_DATA_TCR51USB 0x0106 + +/* command PCPS_GIVE_IRIG_TIME: */ +#define REV_HAS_IRIG_TIME_TCR511PEX 0x0109 +#define REV_HAS_IRIG_TIME_TCR511PCI 0x0109 +#define REV_HAS_IRIG_TIME_TCR51USB 0x0106 + +/* command PCPS_GET_IRIG_CTRL_BITS: */ +#define REV_HAS_IRIG_CTRL_BITS_TCR511PEX 0x0107 +#define REV_HAS_IRIG_CTRL_BITS_TCR511PCI 0x0107 +#define REV_HAS_IRIG_CTRL_BITS_TCR51USB 0x0106 + +/* This board uses the GPS_DATA interface with 16 bit buffer sizes + instead of the original 8 bit sizes, thus allowing to transfer + data blocks which exceed 255 bytes (PCPS_HAS_GPS_DATA_16) */ +#define REV_HAS_GPS_DATA_16_GPS169PCI 0x0202 + +/* the clock supports a higher baud rate than N_PCPS_BD_DCF */ +#define REV_HAS_SERIAL_HS_PCI509 0x0104 + +/* commands PCPS_GIVE_UCAP_ENTRIES, PCPS_GIVE_UCAP_EVENT */ +#define REV_HAS_UCAP_GPS167PCI 0x0421 +#define REV_HAS_UCAP_GPS168PCI 0x0104 + +/* command PCPS_CLR_UCAP_BUFF */ +#define REV_CAN_CLR_UCAP_BUFF_GPS167PCI 0x0419 +#define REV_CAN_CLR_UCAP_BUFF_GPS168PCI 0x0101 + +/* commands PCPS_READ_GPS_DATA and PCPS_WRITE_GPS_DATA with */ +/* code PC_GPS_ANT_CABLE_LEN */ +#define REV_HAS_CABLE_LEN_GPS167PCI 0x0411 +#define REV_HAS_CABLE_LEN_GPS167PC 0x0411 + +/* command PCPS_GIVE_HR_TIME, structure PCPS_HR_TIME: */ +#define REV_HAS_HR_TIME_GPS167PC 0x0305 +#define REV_HAS_HR_TIME_TCR510PCI 0x0200 +#define REV_HAS_HR_TIME_PEX511 0x0105 // This also requires a certain ASIC version. +#define REV_HAS_HR_TIME_PCI511 0x0103 + +/* field offs_utc in structure PCPS_TIME: */ +#define REV_HAS_UTC_OFFS_PC31PS31 0x0300 + +/* command PCPS_GIVE_SYNC_TIME: */ +#define REV_HAS_SYNC_TIME_PC31PS31 0x0300 + +/* command PCPS_GET_SERIAL, PCPS_SET_SERIAL: */ +#define REV_HAS_SERIAL_PC31PS31 0x0300 + +/* command PCPS_GIVE_TIME_NOCLEAR: */ +#define REV_GIVE_TIME_NOCLEAR_PC31PS31 0x0300 + +/* status bit PCPS_LS_ANN: */ +#define REV_PCPS_LS_ANN_PC31PS31 0x0300 + +/* status bit PCPS_IFTM: */ +#define REV_PCPS_IFTM_PC31PS31 0x0300 + +/* command PCPS_SET_TIME: */ +#define REV_CAN_SET_TIME_PC31PS31 0x0240 + +/* command PCPS_GIVE_TIME_NOCLEAR: */ +// This is supported by all clocks but PC31/PS31 with +// firmware versions before v3.0. If such a card shall +// be used then the firmware should be updated to the +// last recent version. + + +/** + The structure has been defined to pass all + information on a clock device from a device driver + to a user program. */ +typedef struct +{ + PCPS_DEV_TYPE type; + PCPS_DEV_CFG cfg; +} PCPS_DEV; + + +// The macros below simplify access to the data +// stored in PCPS_DEV structure and should be used +// to extract the desired information. +// If the formal parameter is called _d then a pointer +// to device structure PCPS_DEV is expected. +// If the formal parameter is called _c then a pointer +// to configuration structure PCPS_DEV_CFG is expected. + +// Access device type information: +#define _pcps_type_num( _d ) ( (_d)->type.num ) +#define _pcps_type_name( _d ) ( (_d)->type.name ) +#define _pcps_dev_id( _d ) ( (_d)->type.dev_id ) +#define _pcps_ref_type( _d ) ( (_d)->type.ref_type ) +#define _pcps_bus_flags( _d ) ( (_d)->type.bus_flags ) + +// Query device type features: +#define _pcps_is_gps( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_GPS ) +#define _pcps_is_dcf( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_DCF ) +#define _pcps_is_msf( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_MSF ) +#define _pcps_is_wwvb( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_WWVB ) +#define _pcps_is_irig_rx( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_IRIG ) +#define _pcps_is_ptp( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_PTP ) +#define _pcps_is_frc( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_FRC ) + +#define _pcps_is_lwr( _d ) ( _pcps_is_dcf( _d ) || _pcps_is_msf( _d ) || _pcps_is_wwvb( _d ) ) + +#define _pcps_is_isa( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_ISA ) +#define _pcps_is_mca( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_MCA ) +#define _pcps_is_pci( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_PCI ) +#define _pcps_is_usb( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_USB ) + +#define _pcps_is_pci_s5933( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_S5933 ) +#define _pcps_is_pci_s5920( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_S5920 ) +#define _pcps_is_pci_amcc( _d ) ( _pcps_is_pci_s5920( _d ) || _pcps_is_pci_s5933( _d ) ) +#define _pcps_is_pci_asic( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_ASIC ) +#define _pcps_is_pci_pex8311( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_PEX8311 ) +#define _pcps_is_pci_mbgpex( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_MBGPEX ) + + +// Access device configuration information: +#define _pcps_bus_num( _d ) ( (_d)->cfg.bus_num ) +#define _pcps_slot_num( _d ) ( (_d)->cfg.slot_num ) + +#define _pcps_cfg_port_rsrc( _c, _n ) ( (_c)->port[_n] ) +#define _pcps_port_rsrc( _d, _n ) _pcps_cfg_port_rsrc( &(_d)->cfg, (_n) ) +#define _pcps_port_rsrc_unused( _d ) ( (_d)->base == 0 || (_d)->num == 0 ) + +#define _pcps_cfg_port_base( _c, _n ) ( _pcps_cfg_port_rsrc( (_c), (_n) ).base ) +#define _pcps_port_base( _d, _n ) ( _pcps_port_rsrc( (_d), (_n) ).base ) + +#define _pcps_cfg_irq_num( _c ) ( (_c)->irq_num ) +#define _pcps_irq_num( _d ) _pcps_cfg_irq_num( &(_d)->cfg ) + +#define _pcps_cfg_timeout_clk( _c ) ( (_c)->timeout_clk ) +#define _pcps_timeout_clk( _d ) _pcps_cfg_timeout_clk( &(_d)->cfg ) + +#define _pcps_fw_rev_num( _d ) ( (_d)->cfg.fw_rev_num ) +#define _pcps_features( _d ) ( (_d)->cfg.features ) +#define _pcps_fw_id( _d ) ( (_d)->cfg.fw_id ) +#define _pcps_sernum( _d ) ( (_d)->cfg.sernum ) + + +// The macros below handle the clock device's err_flags. +#define _pcps_err_flags( _d ) ( (_d)->cfg.err_flags ) +#define _pcps_chk_err_flags( _d, _msk ) ( _pcps_err_flags( _d ) & (_msk) ) +#define _pcps_set_err_flags( _d, _msk ) ( _pcps_err_flags( _d ) |= (_msk) ) +#define _pcps_clr_err_flags( _d, _msk ) ( _pcps_err_flags( _d ) &= ~(_msk) ) + + +// Query whether a special feature is supported: +#define _pcps_has_feature( _d, _f ) ( ( (_d)->cfg.features & (_f) ) != 0 ) +#define _pcps_can_set_time( _d ) _pcps_has_feature( (_d), PCPS_CAN_SET_TIME ) +#define _pcps_has_serial( _d ) _pcps_has_feature( (_d), PCPS_HAS_SERIAL ) +#define _pcps_has_sync_time( _d ) _pcps_has_feature( (_d), PCPS_HAS_SYNC_TIME ) +#define _pcps_has_ident( _d ) _pcps_has_feature( (_d), PCPS_HAS_IDENT ) +#define _pcps_has_utc_offs( _d ) _pcps_has_feature( (_d), PCPS_HAS_UTC_OFFS ) +#define _pcps_has_hr_time( _d ) _pcps_has_feature( (_d), PCPS_HAS_HR_TIME ) +#define _pcps_has_sernum( _d ) _pcps_has_feature( (_d), PCPS_HAS_SERNUM ) +#define _pcps_has_cab_len( _d ) _pcps_has_feature( (_d), PCPS_HAS_CABLE_LEN ) +#define _pcps_has_tzdl( _d ) _pcps_has_feature( (_d), PCPS_HAS_TZDL ) +#define _pcps_has_pcps_tzdl( _d ) _pcps_has_feature( (_d), PCPS_HAS_PCPS_TZDL ) +#define _pcps_has_tzcode( _d ) _pcps_has_feature( (_d), PCPS_HAS_TZCODE ) +#define _pcps_has_tz( _d ) _pcps_has_feature( (_d), PCPS_HAS_TZDL \ + | PCPS_HAS_PCPS_TZDL \ + | PCPS_HAS_TZCODE ) +// The next one is supported only with a certain GPS firmware version: +#define _pcps_has_event_time( _d ) _pcps_has_feature( (_d), PCPS_HAS_EVENT_TIME ) +#define _pcps_has_receiver_info( _d ) _pcps_has_feature( (_d), PCPS_HAS_RECEIVER_INFO ) +#define _pcps_can_clr_ucap_buff( _d ) _pcps_has_feature( (_d), PCPS_CAN_CLR_UCAP_BUFF ) +#define _pcps_has_ucap( _d ) _pcps_has_feature( (_d), PCPS_HAS_UCAP ) +#define _pcps_has_irig_tx( _d ) _pcps_has_feature( (_d), PCPS_HAS_IRIG_TX ) + +// The macro below determines whether a DCF77 clock +// supports a higher baud rate than standard +#define _pcps_has_serial_hs( _d ) \ + ( ( _pcps_type_num( _d ) == PCPS_TYPE_TCR511PEX ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PEX511 ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_TCR511PCI ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_TCR510PCI ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PCI511 ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PCI510 ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PCI509 && \ + _pcps_fw_rev_num( _d ) >= REV_HAS_SERIAL_HS_PCI509 ) ) + + +#define _pcps_has_signal( _d ) \ + ( _pcps_is_dcf( _d ) || _pcps_is_msf( _d ) || _pcps_is_wwvb( _d ) || _pcps_is_irig_rx( _d ) ) + +#define _pcps_has_mod( _d ) \ + ( _pcps_is_dcf( _d ) || _pcps_is_msf( _d ) || _pcps_is_wwvb( _d ) ) + + +#define _pcps_has_irig( _d ) \ + ( _pcps_is_irig_rx( _d ) || _pcps_has_irig_tx( _d ) ) + +#define _pcps_has_irig_ctrl_bits( _d ) \ + _pcps_has_feature( (_d), PCPS_HAS_IRIG_CTRL_BITS ) + +#define _pcps_has_irig_time( _d ) \ + _pcps_has_feature( (_d), PCPS_HAS_IRIG_TIME ) + +#define _pcps_has_raw_irig_data( _d ) \ + _pcps_has_feature( (_d), PCPS_HAS_RAW_IRIG_DATA ) + +#define _pcps_has_ref_offs( _d ) \ + _pcps_is_irig_rx( _d ) + +#define _pcps_ref_offs_out_of_range( _n ) \ + ( ( (_n) > MBG_REF_OFFS_MAX ) || ( (_n) < -MBG_REF_OFFS_MAX ) ) + +#define _pcps_has_opt_flags( _d ) \ + _pcps_is_irig_rx( _d ) + +#define _pcps_has_gps_data_16( _d ) _pcps_has_feature( (_d), PCPS_HAS_GPS_DATA_16 ) + +#define _pcps_has_gps_data( _d ) \ + ( _pcps_is_gps( _d ) || _pcps_has_gps_data_16( _d ) ) + +#define _pcps_has_synth( _d ) _pcps_has_feature( (_d), PCPS_HAS_SYNTH ) + +#define _pcps_has_generic_io( _d ) _pcps_has_feature( (_d), PCPS_HAS_GENERIC_IO ) + +#define _pcps_has_time_scale( _d ) _pcps_has_feature( (_d), PCPS_HAS_TIME_SCALE ) + +#define _pcps_has_utc_parm( _d ) _pcps_has_feature( (_d), PCPS_HAS_UTC_PARM ) + +#define _pcps_has_fast_hr_timestamp( _d ) _pcps_has_feature( (_d), PCPS_HAS_FAST_HR_TSTAMP ) + +#define _pcps_has_lan_intf( _d ) _pcps_has_feature( (_d), PCPS_HAS_LAN_INTF ) + +#define _pcps_has_ptp( _d ) _pcps_has_feature( (_d), PCPS_HAS_PTP ) + + +#define _pcps_has_asic_version( _d ) ( _pcps_is_pci_asic( _d ) \ + || _pcps_is_pci_pex8311( _d ) \ + || _pcps_is_pci_mbgpex( _d ) ) + +#define _pcps_has_asic_features( _d ) _pcps_has_asic_version( _d ) + + + +// There are some versions of IRIG receiver cards which ignore the TFOM code +// of an incoming IRIG signal even if an IRIG code has been configured which +// supports this. In this case these cards synchronize to the incoming IRIG +// signal even if the TFOM code reports the IRIG generator is not synchronized. +// The intended behaviour is that the IRIG receiver card changes its status +// to "freewheeling" in this case, unless it has been configured to ignore +// the TFOM code of the incoming IRIG signal (see the IFLAGS_DISABLE_TFOM flag +// defined in gpsdefs.h). + +// The macro below can be used to check based on the device info if a specific +// card with a specific firmware always ignores the TFOM code: +#define _pcps_incoming_tfom_ignored( _d ) \ + ( ( ( _pcps_type_num( _d ) == PCPS_TYPE_TCR167PCI ) && ( _pcps_fw_rev_num( _d ) <= 0x121 ) ) \ + || ( ( _pcps_type_num( _d ) == PCPS_TYPE_TCR170PEX ) && ( _pcps_fw_rev_num( _d ) <= 0x103 ) ) ) + + + +/** + The structure is used to return info + on the device driver.*/ +typedef struct +{ + uint16_t ver_num; /**< the device driver's version number */ + uint16_t n_devs; /**< the number of radio clocks handled by the driver */ + PCPS_ID_STR id_str; /**< the device driver's ID string */ +} PCPS_DRVR_INFO; + + + +/* + * The definitions and types below are used to collect + * all configuration parameters of a clock's serial ports + * that can be handled by this library: + */ + +// The maximum number of clocks' serial ports and string types +// that can be handled by the configuration programs: +#define MAX_PARM_PORT 4 +#define MAX_PARM_STR_TYPE 20 + +typedef PORT_INFO_IDX ALL_PORT_INFO[MAX_PARM_PORT]; +typedef STR_TYPE_INFO_IDX ALL_STR_TYPE_INFO[MAX_PARM_STR_TYPE]; + +typedef struct +{ + ALL_PORT_INFO pii; + ALL_STR_TYPE_INFO stii; + PORT_PARM tmp_pp; + +} RECEIVER_PORT_CFG; + + + +/* + * The definitions and types below are used to collect + * all configuration parameters of a clock's programmable + * pulse outputs that can be handled by this library: + */ + +#define MAX_PARM_POUT 4 + +typedef POUT_INFO_IDX ALL_POUT_INFO[MAX_PARM_POUT]; + + + +// The macros below can be used to mark a PCPS_TIME variable +// as unread, i.e. its contents have not been read from the clock, +// and to check if such a variable is marked as unread. +#define _pcps_time_set_unread( _t ); { (_t)->sec = 0xFF; } +#define _pcps_time_is_read( _t ) ( (uchar) (_t)->sec != 0xFF ) + + + +/** + The structure is used to read the current time from + a device, combined with an associated PC cycle counter value + to compensate program execution time. + */ +typedef struct +{ + MBG_PC_CYCLES cycles; + PCPS_TIME t; +} PCPS_TIME_CYCLES; + + + +/** + The structure is used to read a high resolution UTC time stamp + plus associated PC cycles counter value to compensate the latency. + */ +typedef struct +{ + MBG_PC_CYCLES cycles; + PCPS_TIME_STAMP tstamp; /**< High resolution time stamp (UTC) */ +} PCPS_TIME_STAMP_CYCLES; + +#define _mbg_swab_pcps_time_stamp_cycles( _p ) \ +{ \ + _mbg_swab_mbg_pc_cycles( &(_p)->cycles ); \ + _mbg_swab_pcps_time_stamp( &(_p)->tstamp ); \ +} + + + +/** + The structure is used to read the current high resolution time + from a device, combined with an associated PC cycle counter value + to compensate program execution time. + */ +typedef struct +{ + MBG_PC_CYCLES cycles; + PCPS_HR_TIME t; +} PCPS_HR_TIME_CYCLES; + +#define _mbg_swab_pcps_hr_time_cycles( _p ) \ +{ \ + _mbg_swab_mbg_pc_cycles( &(_p)->cycles ); \ + _mbg_swab_pcps_hr_time( &(_p)->t ); \ +} + + + +/** + The structure below can be used to let the kernel driver read + the current system time plus the associated HR time from a plugin card + as close as possibly, and return the results to a user space application + which can then compute the time difference and latencies. + This structure also contains the card's status information (e.g. sync status). + */ +typedef struct +{ + PCPS_HR_TIME_CYCLES ref_hr_time_cycles; /**< HR time read from the card, plus cycles */ + MBG_SYS_TIME_CYCLES sys_time_cycles; /**< system timestamp plus associated cycles */ +} MBG_TIME_INFO_HRT; + +#define _mbg_swab_mbg_time_info_hrt( _p ) \ +{ \ + _mbg_swab_pcps_hr_time_cycles( &(_p)->ref_hr_time_cycles ); \ + _mbg_swab_mbg_sys_time_cycles( &(_p)->sys_time_cycles ); \ +} + + + +/** + The structure below can be used to let the kernel driver read + the current system time plus an associated HR timestamp from a plugin card + as close as possibly, and return the results to a user space application + which can then compute the time difference and latencies. + Since the card's time stamp is usually taken using the fast memory mapped + access this structure does *not* contain the card's status information + (e.g. sync status). + */ +typedef struct +{ + PCPS_TIME_STAMP_CYCLES ref_tstamp_cycles; /**< HR timestamp from the card, plus cycles */ + MBG_SYS_TIME_CYCLES sys_time_cycles; /**< system timestamp plus associated cycles */ +} MBG_TIME_INFO_TSTAMP; + +#define _mbg_swab_mbg_time_info_tstamp( _p ) \ +{ \ + _mbg_swab_pcps_time_stamp_cycles( &(_p)->ref_tstamp_cycles ); \ + _mbg_swab_mbg_sys_time_cycles( &(_p)->sys_time_cycles ); \ +} + + + +typedef uint32_t PCPS_IRQ_STAT_INFO; + +// Flags used with PCPS_IRQ_STAT_INFO: +#define PCPS_IRQ_STAT_ENABLE_CALLED 0x01 +#define PCPS_IRQ_STAT_ENABLED 0x02 +#define PCPS_IRQ_STAT_UNSAFE 0x04 // IRQs unsafe with this firmeware version / ASIC + +#define PCPS_IRQ_STATE_DANGER ( PCPS_IRQ_STAT_ENABLED | PCPS_IRQ_STAT_UNSAFE ) + +#define _pcps_fw_rev_num_major( _v ) \ + ( ( (_v) >> 8 ) & 0xFF ) + +#define _pcps_fw_rev_num_minor( _v ) \ + ( (_v) & 0xFF ) + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#undef _ext + +#endif /* _PCPSDEV_H */ + |