summaryrefslogtreecommitdiff
path: root/mbglib/common/macioctl.h
diff options
context:
space:
mode:
Diffstat (limited to 'mbglib/common/macioctl.h')
-rwxr-xr-xmbglib/common/macioctl.h1817
1 files changed, 1817 insertions, 0 deletions
diff --git a/mbglib/common/macioctl.h b/mbglib/common/macioctl.h
new file mode 100755
index 0000000..d46dcf5
--- /dev/null
+++ b/mbglib/common/macioctl.h
@@ -0,0 +1,1817 @@
+
+/**************************************************************************
+ *
+ * $Id: macioctl.h 1.33.1.7 2011/01/26 16:37:55 martin TEST $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Macros used inside the IOCTL handlers of device drivers
+ * for Meinberg radio clocks.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: macioctl.h $
+ * Revision 1.33.1.7 2011/01/26 16:37:55 martin
+ * Modified inline declarations for gcc.
+ * Revision 1.33.1.6 2011/01/24 17:08:40 martin
+ * Fixed build under FreeBSD.
+ * Revision 1.33.1.5 2010/11/09 10:57:33 martin
+ * Added _sem_inc_safe_no_irp() macro (Windows only).
+ * Revision 1.33.1.4 2010/07/16 08:31:32Z martin
+ * Revision 1.33.1.3 2010/07/15 15:47:07 martin
+ * Revision 1.33.1.2 2010/07/14 14:48:52 martin
+ * Simplified code and renamed some inline functions.
+ * Revision 1.33.1.1 2010/03/03 15:11:51 martin
+ * Fixed macro.
+ * Revision 1.33 2009/12/21 16:22:55 martin
+ * Moved code reading memory mapped timestamps to inline functions.
+ * Revision 1.32 2009/12/15 15:34:57 daniel
+ * Support reading the raw IRIG data bits for firmware versions
+ * which support this feature.
+ * Revision 1.31 2009/11/04 14:58:52Z martin
+ * Conditionally exclude port status query from build.
+ * Revision 1.30 2009/09/29 15:08:39 martin
+ * Support retrieving time discipline info.
+ * Revision 1.29 2009/08/18 08:45:16 martin
+ * Removed IOCTL switch macro, inline code used for all targets.
+ * Revision 1.28 2009/06/26 13:16:11Z martin
+ * Fixed duplicate case in inline code (copy and paste error).
+ * Revision 1.27 2009/06/22 13:52:56 martin
+ * Fixed a bug where the size of GPS data had been truncated to 8 bits,
+ * which resulted in an IOCTL error if a buffer larger than 256 bytes had been
+ * used. This had been observed with the PC_GPS_ALL_STR_TYPE_INFO
+ * command if more than 6 string types are supported by a card.
+ * Revision 1.26 2009/06/19 12:21:12 martin
+ * Support reading raw IRIG time.
+ * Revision 1.25 2009/06/09 10:01:01 daniel
+ * Support configuration of LAN intf. and PTP.
+ * Started to support ARM / firmware.
+ * Conditionally compile ioctl_switch as inline function.
+ * Revision 1.24 2009/03/19 15:25:19 martin
+ * Support UTC parms and configurable time scales.
+ * Support IOCTL_DEV_HAS_IRIG_CTRL_BITS and IOCTL_GET_IRIG_CTRL_BITS.
+ * Support reading MM timestamps without cycles.
+ * IOCTL_GET_PCI_ASIC_VERSION now returns the ASIC
+ * version code from the device info structure which already
+ * has the correct endianess.
+ * For consistent naming renamed IOCTL_GET_FAST_HR_TIMESTAMP
+ * to IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES.
+ * Use mbg_get_cycles...() instead of _pcps_get_cycles...().
+ * Revision 1.23 2008/12/11 10:30:38Z martin
+ * _pcps_get_cycles() is now called inside the low level routines
+ * immediately when the command byte is written.
+ * Mutex for hardware access is now acquired/released in _pcps_sem_inc()
+ * and _pcps_sem_dec(), so other IOCTLs which don't access the card
+ * can be run in parallel.
+ * Moved definitions of _pcps_sem_inc(), _pcps_sem_dec(), and
+ * _pcps_get_cycles() to pcpsdrvr.h.
+ * Defined a macro which checks if access is safe (may be unsafe
+ * with certain PEX cards which have IRQs enabled).
+ * Use _pcps_sem_inc_safe() macro to check if access is safe and
+ * inhibit access if this is not the case.
+ * Consistenly use pcps_drvr_name instead of mbgclock_name
+ * for debug messages.
+ * Don't return error for unmap_mm...() under Linux.
+ * Account for ASIC_FEATURES being coded as flags, and account
+ * for new symbol PCI_ASIC_HAS_MM_IO.
+ * Handle new IOCTLs IOCTL_HAS_PCI_ASIC_FEATURES, IOCTL_HAS_PCI_ASIC_VERSION,
+ * IOCTL_DEV_IS_MSF, IOCTL_DEV_IS_LWR, IOCTL_DEV_IS_WWVB,
+ * IOCTL_GET_IRQ_STAT_INFO, IOCTL_GET_CYCLES_FREQUENCY,
+ * IOCTL_HAS_FAST_HR_TIMESTAMP, and IOCTL_GET_FAST_HR_TIMESTAMP.
+ * Support mapped I/O resources.
+ * Revision 1.22 2008/01/17 09:28:49 daniel
+ * Support for memory mapped I/O under Linux and Windows.
+ * Added macros _io_get_mapped_mem_address(),
+ * _io_unmap_mapped_mem_address().
+ * Account for IOCTL_GET_PCI_ASIC_FEATURES
+ * Cleanup for PCI ASIC version.
+ * Revision 1.21 2007/09/26 07:31:47Z martin
+ * Support reading status port of USB devices.
+ * Use kernel malloc/free macros from pcpsdrvr.h.
+ * Modified _pcps_sem..() to take PCPS_DDEV argument.
+ * Revision 1.20 2007/05/21 15:00:00Z martin
+ * Unified naming convention for symbols related to ref_offs.
+ * Revision 1.19 2007/03/30 13:31:42 martin
+ * Changes due to renamed library symbol.
+ * Revision 1.18 2007/03/02 10:31:21Z martin
+ * Use generic port I/O macros.
+ * Preliminary support for *BSD.
+ * Preliminary _cmd_from_ioctl().
+ * Revision 1.17 2006/03/10 10:35:43 martin
+ * Added support for programmable pulse outputs.
+ * Revision 1.16 2005/06/02 10:16:37Z martin
+ * Implemented IOCTL_PCPS_GENERIC_.. calls.
+ * Added support for SYNTH_STATE.
+ * Moved Debug IOCTL handling here.
+ * Revision 1.15 2005/01/14 10:26:41Z martin
+ * Support IOCTLs which query device features.
+ * Revision 1.14 2004/12/09 11:03:36Z martin
+ * Support configuration of on-board frequency synthesizer.
+ * Revision 1.13 2004/11/09 12:47:19Z martin
+ * Use new macro _pcps_ddev_has_gps_data() to check whether GPS large
+ * data I/O is supported.
+ * Changes due to renamed symbols, IRIG RX/TX.
+ * Modifications were required in order to be able to configure IRIG
+ * settings of cards which provide both IRIG input and output.
+ * GPS169PCI cards with IRIG output and early firmware versions
+ * used the same codes to configure the IRIG output as the TCR
+ * cards use to configure the IRIG input. Those codes are now
+ * exclusively used to configure the IRIG input. A workaround
+ * has been included for those GPS169PCI cards, because otherwise
+ * the IRIG configuration would not work properly after a driver
+ * update, without also doing a firmware update.
+ * Show debug msg if GPS169PCI workaround for IRIG cfg in effect.
+ * Use more specific data types than generic types.
+ * Modified contents of debug messages.
+ * Added (uchar FAR *) cast.
+ * Revision 1.12 2004/06/07 09:20:52 martin
+ * Account for renamed symbols.
+ * Revision 1.11 2004/04/07 09:05:17 martin
+ * Support OS dependent IOCTLs used to trigger debug events.
+ * Revision 1.10 2004/03/16 16:25:42Z martin
+ * Support new macro _pcps_has_irig().
+ * Revision 1.9 2004/01/08 10:57:23Z martin
+ * Support codes to read ASIC version, and read times
+ * with associated cycle counter values.
+ * Support higher baud rates for TCR510PCI and PCI510.
+ * Support PCPS_HR_TIME for TCR510PCI.
+ * Revision 1.8 2003/09/17 12:49:57Z martin
+ * Use PCPS_GIVE_TIME_NOCLEAR in API mbg_get_time().
+ * Revision 1.7 2003/09/09 13:33:55Z martin
+ * Support IOCTL_GET_PCPS_TIME_SEC_CHANGE.
+ * Revision 1.6 2003/06/19 09:18:02Z martin
+ * Supports new APIs IOCTL_PCPS_GET_UCAP_ENTRIES
+ * and IOCTL_PCPS_GET_UCAP_EVENT.
+ * Changes due to renamed symbols.
+ * Preliminary _pout_size for Linux.
+ * Revision 1.5 2003/04/15 08:50:38Z martin
+ * Support ALL_STR_TYPE_INFO, ALL_PORT_INFO for Win32.
+ * Revision 1.4 2003/04/09 16:51:29Z martin
+ * Use new common IOCTL codes from mbgioctl.h.
+ * Support almost all IOCTL codes.
+ * Support for Win32.
+ * Revision 1.3 2001/11/30 09:52:47Z martin
+ * Added support for event_time which, however, requires
+ * a custom GPS firmware.
+ * Revision 1.2 2001/09/14 12:01:17 martin
+ * Decode PCPS_IOCTL_SET_GPS_CMD.
+ * Added some comments.
+ * Revision 1.1 2001/04/09 07:47:01 MARTIN
+ *
+ **************************************************************************/
+
+#ifndef _MACIOCTL_H
+#define _MACIOCTL_H
+
+#include <pcpsdrvr.h>
+#include <mbgioctl.h>
+#include <pci_asic.h>
+#include <mbgddmsg.h>
+
+
+// The types below are used since the macros used in this file
+// have been written to use structs and compilers return errors
+// if those macros are used with array variables.
+
+typedef struct
+{
+ LLA lla;
+} LLAs;
+
+typedef struct
+{
+ XYZ xyz;
+} XYZs;
+
+
+#define USE_DEBUG_PORT !defined( MBG_ARCH_ARM )
+
+
+// OS dependent definitions
+#if defined( MBG_TGT_LINUX )
+
+ #define _pcps_iob( _type, _s ) _type _s
+ #define _pcps_iob_arr( _type, _s, n ) _type _s[_n]
+
+ #define _pcps_iob_to_pout_size( _type, _iob, _pout, _size ) \
+ if ( copy_to_user( (_type *)(_pout), &(_iob), _size ) ) \
+ goto err_to_user;
+
+ #define _pcps_iob_from_pin_size( _type, _iob, _pin, _size ) \
+ if ( copy_from_user( &(_iob), (_type *) (_pin), _size ) ) \
+ goto err_from_user;
+
+ #define _io_wait_pcps_sec_change( _pddev, _cmd, _type, _pout ) \
+ goto err_inval
+
+ #define _io_get_mapped_mem_address( _pddev, _pout ) \
+ { \
+ _pcps_iob( PCPS_MAPPED_MEM, _s ); \
+ _s.pfn_offset = ( pddev->rsrc_info.mem[0].start & ~PAGE_MASK ) + sizeof( PCI_ASIC ); \
+ _s.len = pddev->rsrc_info.mem[0].len - sizeof( PCI_ASIC ); \
+ _pcps_iob_to_pout_size( PCPS_MAPPED_MEM, _s, _pout, sizeof( PCPS_MAPPED_MEM ) ); \
+ }
+
+ #define _io_unmap_mapped_mem_address( _pddev, _pin ) \
+ _nop_macro_fnc()
+
+#elif defined( MBG_TGT_BSD )
+
+ #include <sys/malloc.h>
+
+ #define _pcps_iob( _type, _s ) _type _s
+ #define _pcps_iob_arr( _type, _s, n ) _type _s[_n]
+
+ #define _pcps_iob_to_pout_size( _type, _iob, _pout, _size ) \
+ memcpy( (_type *)(_pout), &(_iob), _size )
+
+ #define _pcps_iob_from_pin_size( _type, _iob, _pin, _size ) \
+ memcpy( &(_iob), (_type *) (_pin), _size )
+
+ #define _io_wait_pcps_sec_change( _pddev, _cmd, _type, _pout ) \
+ goto err_inval
+
+ #define _io_get_mapped_mem_address( _pddev, _pout ) \
+ goto err_inval
+
+ #define _io_unmap_mapped_mem_address( _pddev, _pin ) \
+ goto err_inval
+
+#elif defined( MBG_TGT_WIN32 )
+
+ #define _pcps_iob( _type, _s ) _type _s
+ #define _pcps_iob_arr( _type, _s, n ) _type _s[_n]
+
+ #define _pcps_iob_to_pout_size( _type, _iob, _pout, _size ) \
+ { \
+ RtlCopyMemory( _pout, &_iob, _size ); \
+ *ret_size = _size; \
+ }
+
+ #define _pcps_iob_from_pin_size( _type, _iob, _pin, _size ) \
+ RtlCopyMemory( &_iob, _pin, _size );
+
+ // The following macros are defined in the OS dependent code:
+ //
+ // _io_wait_pcps_sec_change()
+ // _io_get_mapped_mem_address()
+ // _io_unmap_mapped_mem_address()
+ // _io_set_interrupt()
+ //
+
+#endif
+
+
+
+#define _pcps_iob_to_pout( _type, _iob, _pout ) \
+ _pcps_iob_to_pout_size( _type, _iob, _pout, sizeof( _iob ) )
+
+#define _pcps_iob_from_pin( _type, _iob, _pin ) \
+ _pcps_iob_from_pin_size( _type, _iob, _pin, sizeof( _iob ) )
+
+
+// For some cards it may be unsafe to access the card while
+// interrups are enabled for the card since IRQs may during
+// access may mess up the interface. The macro below checks
+// whether this is the case.
+#define _pcps_access_is_unsafe( _pddev ) \
+ ( ( (_pddev)->irq_stat_info & PCPS_IRQ_STATE_DANGER ) == PCPS_IRQ_STATE_DANGER )
+
+
+
+// Check whether a card can be accessed safely and set a flag
+// preventing the card from being accessed from IRQ handler.
+#if defined( MBG_TGT_WIN32 )
+
+ // Under Windows.we need to save a pointer to the current
+ // IRP by default.
+ #define _pcps_sem_inc_safe( _pddev ) \
+ if ( _pcps_access_is_unsafe( _pddev ) ) \
+ goto err_busy_unsafe; \
+ _pcps_sem_inc( _pddev ); \
+ (_pddev)->irp = pIrp
+
+ // If a function which is exported by our kernel driver
+ // is called from a different kernel driver then there is
+ // no IRP, so we provide a different, Windows-only macro
+ // which is used by those export functions and sets the
+ // IRP pointer of the device structure to NULL.
+ #define _pcps_sem_inc_safe_no_irp( _pddev ) \
+ if ( _pcps_access_is_unsafe( _pddev ) ) \
+ goto err_busy_unsafe; \
+ _pcps_sem_inc( _pddev ); \
+ (_pddev)->irp = NULL
+
+#else
+
+ // Other OSs don't use an IRP, so no IRP pointer
+ // needs to be set up.
+ #define _pcps_sem_inc_safe( _pddev ) \
+ if ( _pcps_access_is_unsafe( _pddev ) ) \
+ goto err_busy_unsafe; \
+ _pcps_sem_inc( _pddev ); \
+
+#endif
+
+
+
+
+
+// Read a data structure from a clock device.
+// Check the return code and if no error occurred,
+// copy the data to the caller's memory space.
+#define _io_read_var( _pddev, _cmd, _type, _pout ) \
+{ \
+ _pcps_iob( _type, _s ); \
+ \
+ _pcps_sem_inc_safe( _pddev ); \
+ rc = _pcps_read_var( _pddev, _cmd, _s ); \
+ _pcps_sem_dec( _pddev ); \
+ \
+ if ( rc != MBG_SUCCESS ) \
+ goto err_access; \
+ \
+ _pcps_iob_to_pout( _type, _s, _pout ); \
+}
+
+
+// Retrieve a data structure from the caller's
+// memory space, write it to a clock device and
+// check the return code.
+#define _io_write_var( _pddev, _cmd, _type, _pin ) \
+{ \
+ _pcps_iob( _type, _s ); \
+ \
+ _pcps_iob_from_pin( _type, _s, _pin ); \
+ \
+ _pcps_sem_inc_safe( _pddev ); \
+ rc = _pcps_write_var( _pddev, _cmd, _s ); \
+ _pcps_sem_dec( _pddev ); \
+ \
+ if ( rc != MBG_SUCCESS ) \
+ goto err_access; \
+}
+
+
+// Retrieve a data structure from the caller's
+// memory space, write it to a clock device and
+// check the return code.
+#define _io_write_cmd( _pddev, _cmd ) \
+{ \
+ _pcps_sem_inc_safe( _pddev ); \
+ rc = _pcps_write_byte( _pddev, _cmd ); \
+ _pcps_sem_dec( _pddev ); \
+ \
+ if ( rc != MBG_SUCCESS ) \
+ goto err_access; \
+}
+
+
+// Check if a clock is a GPS device. If it is,
+// read GPS data with variable size from the device.
+// Check the return code and if no error occurred,
+// copy the data to the caller's memory space.
+#define _io_read_gps( _pddev, _cmd, _type, _pout, _size ) \
+{ \
+ _pcps_iob( _type, _s ); \
+ \
+ if ( !_pcps_ddev_has_gps_data( _pddev ) ) \
+ goto err_support; \
+ \
+ _pcps_sem_inc_safe( _pddev ); \
+ rc = pcps_read_gps( _pddev, _cmd, (uchar FAR *) &_s, _size ); \
+ _pcps_sem_dec( _pddev ); \
+ \
+ if ( rc != MBG_SUCCESS ) \
+ goto err_access; \
+ \
+ _pcps_iob_to_pout_size( _type, _s, _pout, _size ); \
+}
+
+
+// Check if a clock is a GPS device. If it is,
+// read a GPS data structure from the device.
+// Check the return code and if no error occurred,
+// copy the data to the caller's memory space.
+#define _io_read_gps_var( _pddev, _cmd, _type, _pout ) \
+{ \
+ _pcps_iob( _type, _s ); \
+ \
+ if ( !_pcps_ddev_has_gps_data( _pddev ) ) \
+ goto err_support; \
+ \
+ _pcps_sem_inc_safe( _pddev ); \
+ rc = _pcps_read_gps_var( _pddev, _cmd, _s ); \
+ _pcps_sem_dec( _pddev ); \
+ \
+ if ( rc != MBG_SUCCESS ) \
+ goto err_access; \
+ \
+ _pcps_iob_to_pout( _type, _s, _pout ); \
+}
+
+
+// Check if a clock is a GPS device. If it is,
+// retrieve a data structure from the caller's
+// memory space, write it to the clock device and
+// check the return code.
+#define _io_write_gps_var( _pddev, _cmd, _type, _pin ) \
+{ \
+ _pcps_iob( _type, _s ); \
+ \
+ if ( !_pcps_ddev_has_gps_data( _pddev ) ) \
+ goto err_support; \
+ \
+ _pcps_iob_from_pin( _type, _s, _pin ); \
+ \
+ _pcps_sem_inc_safe( _pddev ); \
+ rc = _pcps_write_gps_var( _pddev, _cmd, _s ); \
+ _pcps_sem_dec( _pddev ); \
+ \
+ if ( rc != MBG_SUCCESS ) \
+ goto err_access; \
+}
+
+
+// Check a condition an go to an error handler
+// if the condition is not true.
+#define _io_chk_cond( _cond ) \
+ if ( !(_cond) ) \
+ goto err_support;
+
+
+
+// The macros below are similar to those defined above except
+// that they check if a condition is true before they really
+// do anything. This is used for IOCTL calls which may not
+// be supported with any type of clock device.
+#define _io_read_var_chk( _pddev, _cmd, _type, _pout, _cond ) \
+{ \
+ _io_chk_cond( _cond ); \
+ _io_read_var( _pddev, _cmd, _type, _pout ); \
+}
+
+#define _io_write_var_chk( _pddev, _cmd, _type, _pin, _cond ) \
+{ \
+ _io_chk_cond( _cond ); \
+ _io_write_var( _pddev, _cmd, _type, _pin ); \
+}
+
+#define _io_write_cmd_chk( _pddev, _cmd, _cond ) \
+{ \
+ _io_chk_cond( _cond ); \
+ _io_write_cmd( _pddev, _cmd ); \
+}
+
+#define _io_read_gps_chk( _pddev, _cmd, _type, _pout, _size, _cond ) \
+{ \
+ _io_chk_cond( _cond ); \
+ _io_read_gps( _pddev, _cmd, _type, _pout, _size ); \
+}
+
+#define _io_read_gps_var_chk( _pddev, _cmd, _type, _pout, _cond ) \
+{ \
+ _io_chk_cond( _cond ); \
+ _io_read_gps_var( _pddev, _cmd, _type, _pout ); \
+}
+
+#define _io_write_gps_var_chk( _pddev, _cmd, _type, _pin, _cond ) \
+{ \
+ _io_chk_cond( _cond ); \
+ _io_write_gps_var( _pddev, _cmd, _type, _pin ); \
+}
+
+
+#define _report_cond( _cond, _pout ) \
+{ \
+ int retval = _cond; \
+ _pcps_iob_to_pout( int, retval, _pout ); \
+}
+
+
+
+#define _mbg_dbg_set_bit( _d, _v ) \
+{ \
+ mbg_dbg_data |= (_v); \
+ _mbg_outp8( (_d), mbg_dbg_port_mapped, mbg_dbg_data ); \
+}
+
+#define _mbg_dbg_clr_bit( _d, _v ) \
+{ \
+ mbg_dbg_data &= ~(_v); \
+ _mbg_outp8( (_d), mbg_dbg_port_mapped, mbg_dbg_data ); \
+}
+
+#define _mbg_dbg_clr_all( _d ) \
+{ \
+ mbg_dbg_data = 0; \
+ _mbg_outp8( (_d), mbg_dbg_port_mapped, mbg_dbg_data ); \
+}
+
+
+
+#define TEST_MM_ACCESS_TIME ( 0 && defined( MBG_TGT_LINUX ) )
+#define TEST_MM_ACCESS_64 0
+#define TEST_FRAC_ONLY 0
+
+#if TEST_MM_ACCESS_TIME
+ #include <pcpsutil.h>
+#endif
+
+
+#if defined( __GNUC__ )
+// Avoid "no previous prototype" with some gcc versions.
+__mbg_inline
+void swap_tstamp( PCPS_TIME_STAMP *p_ts ) __attribute__((always_inline));
+#endif
+
+__mbg_inline
+void swap_tstamp( PCPS_TIME_STAMP *p_ts )
+{
+ uint32_t tmp = p_ts->sec;
+ p_ts->sec = p_ts->frac;
+ p_ts->frac = tmp;
+
+} // swap_tstamp
+
+
+
+#if defined( __GNUC__ )
+// Avoid "no previous prototype" with some gcc versions.
+__mbg_inline
+void do_get_fast_hr_timestamp_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP *p_ts ) __attribute__((always_inline));
+#endif
+
+
+__mbg_inline
+void do_get_fast_hr_timestamp_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP *p_ts )
+{
+#if TEST_MM_ACCESS_64
+ volatile uint64_t *p = (volatile uint64_t *) pddev->mm_tstamp_addr;
+#else
+ volatile uint32_t *p = (volatile uint32_t *) pddev->mm_tstamp_addr;
+#endif
+
+#if TEST_MM_ACCESS_TIME
+ PCPS_TIME_STAMP tmp;
+ MBG_PC_CYCLES cyc_1;
+ MBG_PC_CYCLES cyc_2;
+ MBG_PC_CYCLES cyc_3;
+ long delta_frac;
+ unsigned delta_ns;
+#endif
+
+#if TEST_MM_ACCESS_TIME
+ mbg_get_pc_cycles( &cyc_1 );
+#endif
+
+ _pcps_spin_lock( &pddev->mm_lock );
+
+#if TEST_MM_ACCESS_64
+ *( (volatile uint64_t *) p_ts ) = *p;
+#else
+ p_ts->frac = _mbg32_to_cpu( *p );
+ #if !TEST_FRAC_ONLY
+ p_ts->sec = _mbg32_to_cpu( *( p + 1 ) );
+ #endif
+#endif
+
+#if TEST_MM_ACCESS_TIME
+ #if TEST_MM_ACCESS_64
+ *( (volatile uint64_t *) &tmp ) = *p;
+ #else
+ tmp.frac = _mbg32_to_cpu( *p );
+ #if !TEST_FRAC_ONLY
+ tmp.sec = _mbg32_to_cpu( *( p + 1 ) );
+ #endif
+ #endif
+#endif
+
+ _pcps_spin_unlock( &pddev->mm_lock );
+
+#if TEST_FRAC_ONLY
+ p_ts->sec = 0;
+ #if TEST_MM_ACCESS_TIME
+ tmp.sec = 0;
+ #endif
+#endif
+
+#if TEST_MM_ACCESS_64
+ swap_tstamp( p_ts );
+ #if TEST_MM_ACCESS_TIME
+ swap_tstamp( &tmp );
+ #endif
+#endif
+
+
+#if TEST_MM_ACCESS_TIME
+ mbg_get_pc_cycles( &cyc_2 );
+ mbg_get_pc_cycles( &cyc_3 );
+#endif
+
+#if TEST_MM_ACCESS_TIME
+ delta_frac = (long) ( tmp.frac - p_ts->frac );
+ delta_ns = (unsigned) frac_sec_from_bin( delta_frac, 1000000000UL );
+
+ printk( KERN_INFO "MM tstamp dev %04X: %li/%li cyc (%lu kHz)"
+ " %08lX.%08lX->%08lX.%08lX: %li (%u.%03u us)"
+ "\n",
+ _pcps_ddev_dev_id( pddev ),
+ (long) ( cyc_2 - cyc_1 ),
+ (long) ( cyc_3 - cyc_2 ),
+ (ulong) cpu_khz,
+ (ulong) p_ts->sec, (ulong) p_ts->frac,
+ (ulong) tmp.sec, (ulong) tmp.frac,
+ (long) ( tmp.frac - p_ts->frac ),
+ delta_ns / 1000,
+ delta_ns % 1000
+ );
+#endif
+
+} // do_get_fast_hr_timestamp_safe
+
+
+
+#if defined( __GNUC__ )
+// Avoid "no previous prototype" with some gcc versions.
+__mbg_inline
+void do_get_fast_hr_timestamp_cycles_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP_CYCLES *p_ts_cyc ) __attribute__((always_inline));
+#endif
+
+__mbg_inline
+void do_get_fast_hr_timestamp_cycles_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP_CYCLES *p_ts_cyc )
+{
+ volatile uint32_t *p = (volatile uint32_t *) pddev->mm_tstamp_addr;
+
+ _pcps_spin_lock( &pddev->mm_lock );
+ mbg_get_pc_cycles( &p_ts_cyc->cycles );
+ p_ts_cyc->tstamp.frac = _mbg32_to_cpu( *p++ );
+ p_ts_cyc->tstamp.sec = _mbg32_to_cpu( *p );
+ _pcps_spin_unlock( &pddev->mm_lock );
+
+} // do_get_fast_hr_timestamp_cycles_safe
+
+
+
+#if defined( __GNUC__ )
+// Avoid "no previous prototype" with some gcc versions.
+__mbg_inline
+int ioctl_switch( PCPS_DDEV *pddev, int ioctl_code,
+ #if defined( MBG_TGT_WIN32 )
+ IRP *pIrp, int *ret_size, uint16_t pout_size,
+ #endif
+ void *pin, void *pout ) __attribute__((always_inline));
+#endif
+
+__mbg_inline
+int ioctl_switch( PCPS_DDEV *pddev, int ioctl_code,
+ #if defined( MBG_TGT_WIN32 )
+ IRP *pIrp, int *ret_size, uint16_t pout_size,
+ #endif
+ void *pin, void *pout )
+{
+ int rc = MBG_SUCCESS;
+
+ switch ( ioctl_code )
+ {
+ case IOCTL_GET_PCPS_DRVR_INFO:
+ _pcps_iob_to_pout( PCPS_DRVR_INFO,
+ drvr_info, pout );
+ break;
+
+
+ case IOCTL_GET_PCPS_DEV:
+ _pcps_iob_to_pout( PCPS_DEV, pddev->dev, pout );
+ break;
+
+
+ #if !defined( OMIT_STATUS_PORT )
+ case IOCTL_GET_PCPS_STATUS_PORT:
+ {
+ if ( _pcps_ddev_is_usb( pddev ) )
+ {
+ _io_read_var( pddev, PCPS_GET_STATUS_PORT,
+ PCPS_STATUS_PORT, pout );
+
+ }
+ else
+ {
+ PCPS_STATUS_PORT status =
+ _pcps_ddev_read_status_port( pddev );
+ _pcps_iob_to_pout( PCPS_STATUS_PORT, status, pout );
+ }
+ break;
+ }
+ #endif
+
+
+ case IOCTL_PCPS_GENERIC_READ:
+ {
+ IOCTL_GENERIC_CTL ctl;
+ IOCTL_GENERIC_BUFFER *p_buff;
+ int buffer_size;
+
+ _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin );
+ buffer_size = sizeof( ctl ) + ctl.data_size_out;
+ p_buff = _pcps_kmalloc( buffer_size );
+
+ if ( p_buff == NULL )
+ goto err_no_mem;
+
+ _pcps_sem_inc_safe( pddev );
+ rc = _pcps_read( pddev, (uint8_t) ctl.info,
+ p_buff->data,
+ (uint8_t) ctl.data_size_out );
+ _pcps_sem_dec( pddev );
+
+ if ( rc == MBG_SUCCESS )
+ {
+ p_buff->ctl = ctl;
+ _pcps_iob_to_pout_size( uint8_t, *p_buff, pout,
+ buffer_size );
+ }
+
+ _pcps_kfree( p_buff );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ break;
+ }
+
+
+ case IOCTL_PCPS_GENERIC_WRITE:
+ {
+ IOCTL_GENERIC_CTL ctl;
+ IOCTL_GENERIC_BUFFER *p_buff;
+ int buffer_size;
+
+ _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin );
+ buffer_size = sizeof( ctl ) + ctl.data_size_in;
+ p_buff = _pcps_kmalloc( buffer_size );
+
+ if ( p_buff == NULL )
+ goto err_no_mem;
+
+ _pcps_iob_from_pin_size( uint8_t, *p_buff, pin,
+ buffer_size );
+
+ _pcps_sem_inc_safe( pddev );
+ rc = pcps_write( pddev, (uint8_t) ctl.info,
+ p_buff->data,
+ (uint8_t) ctl.data_size_in );
+ _pcps_sem_dec( pddev );
+
+ _pcps_kfree( p_buff );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ break;
+ }
+
+
+ case IOCTL_PCPS_GENERIC_READ_GPS:
+ {
+ IOCTL_GENERIC_CTL ctl;
+ IOCTL_GENERIC_BUFFER *p_buff;
+ int buffer_size;
+
+ _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin );
+ buffer_size = sizeof( ctl ) + ctl.data_size_out;
+ p_buff = _pcps_kmalloc( buffer_size );
+
+ if ( p_buff == NULL )
+ goto err_no_mem;
+
+ _pcps_sem_inc_safe( pddev );
+ rc = pcps_read_gps( pddev, (uint8_t) ctl.info,
+ p_buff->data,
+ (uint16_t) ctl.data_size_out );
+ _pcps_sem_dec( pddev );
+
+ if ( rc == MBG_SUCCESS )
+ {
+ p_buff->ctl = ctl;
+ _pcps_iob_to_pout_size( uint8_t, *p_buff, pout,
+ buffer_size );
+ }
+
+ _pcps_kfree( p_buff );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ break;
+ }
+
+
+ case IOCTL_PCPS_GENERIC_WRITE_GPS:
+ {
+ IOCTL_GENERIC_CTL ctl;
+ IOCTL_GENERIC_BUFFER *p_buff;
+ int buffer_size;
+
+ _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin );
+ buffer_size = sizeof( ctl ) + ctl.data_size_in;
+ p_buff = _pcps_kmalloc( buffer_size );
+
+ if ( p_buff == NULL )
+ goto err_no_mem;
+
+ _pcps_iob_from_pin_size( uint8_t, *p_buff, pin,
+ buffer_size );
+
+ _pcps_sem_inc_safe( pddev );
+ rc = pcps_write_gps( pddev, (uint8_t) ctl.info,
+ p_buff->data,
+ (uint8_t) ctl.data_size_in );
+ _pcps_sem_dec( pddev );
+
+ _pcps_kfree( p_buff );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ break;
+ }
+
+
+ case IOCTL_GET_PCPS_TIME:
+ _io_read_var( pddev, PCPS_GIVE_TIME_NOCLEAR,
+ PCPS_TIME, pout );
+ break;
+
+
+ case IOCTL_SET_PCPS_TIME:
+ _io_write_var_chk( pddev, PCPS_SET_TIME,
+ PCPS_STIME, pin,
+ _pcps_ddev_can_set_time( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_SYNC_TIME:
+ _io_read_var_chk( pddev, PCPS_GIVE_SYNC_TIME,
+ PCPS_TIME, pout,
+ _pcps_ddev_has_sync_time( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_TIME_SEC_CHANGE:
+ _io_wait_pcps_sec_change( pddev, PCPS_GIVE_TIME,
+ PCPS_TIME, pout );
+ break;
+
+
+ case IOCTL_GET_PCPS_HR_TIME:
+ _io_read_var_chk( pddev, PCPS_GIVE_HR_TIME,
+ PCPS_HR_TIME, pout,
+ _pcps_ddev_has_hr_time( pddev ) );
+ break;
+
+
+ case IOCTL_SET_PCPS_EVENT_TIME:
+ _io_write_var_chk( pddev, PCPS_SET_EVENT_TIME,
+ PCPS_TIME_STAMP, pin,
+ _pcps_ddev_has_event_time( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_SERIAL:
+ _io_read_var( pddev, PCPS_GET_SERIAL,
+ PCPS_SERIAL, pout );
+ break;
+
+
+ case IOCTL_SET_PCPS_SERIAL:
+ _io_write_var( pddev, PCPS_SET_SERIAL,
+ PCPS_SERIAL, pin );
+ break;
+
+
+ case IOCTL_GET_PCPS_TZCODE:
+ _io_read_var_chk( pddev, PCPS_GET_TZCODE,
+ PCPS_TZCODE, pout,
+ _pcps_ddev_has_tzcode( pddev ) );
+ break;
+
+
+ case IOCTL_SET_PCPS_TZCODE:
+ _io_write_var_chk( pddev, PCPS_SET_TZCODE,
+ PCPS_TZCODE, pin,
+ _pcps_ddev_has_tzcode( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_TZDL:
+ _io_read_var_chk( pddev, PCPS_GET_PCPS_TZDL,
+ PCPS_TZDL, pout,
+ _pcps_ddev_has_pcps_tzdl( pddev ) );
+ break;
+
+
+ case IOCTL_SET_PCPS_TZDL:
+ _io_write_var_chk( pddev, PCPS_SET_PCPS_TZDL,
+ PCPS_TZDL, pin,
+ _pcps_ddev_has_pcps_tzdl( pddev ) );
+ break;
+
+
+ case IOCTL_GET_REF_OFFS:
+ _io_read_var_chk( pddev, PCPS_GET_REF_OFFS,
+ MBG_REF_OFFS, pout,
+ _pcps_ddev_has_ref_offs( pddev ) );
+ break;
+
+
+ case IOCTL_SET_REF_OFFS:
+ _io_write_var_chk( pddev, PCPS_SET_REF_OFFS,
+ MBG_REF_OFFS, pin,
+ _pcps_ddev_has_ref_offs( pddev ) );
+ break;
+
+
+ case IOCTL_GET_MBG_OPT_INFO:
+ _io_read_var_chk( pddev, PCPS_GET_OPT_INFO,
+ MBG_OPT_INFO, pout,
+ _pcps_ddev_has_opt_flags( pddev ) );
+ break;
+
+
+ case IOCTL_SET_MBG_OPT_SETTINGS:
+ _io_write_var_chk( pddev, PCPS_SET_OPT_SETTINGS,
+ MBG_OPT_SETTINGS, pin,
+ _pcps_ddev_has_opt_flags( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_IRIG_RX_INFO:
+ _io_read_var_chk( pddev, PCPS_GET_IRIG_RX_INFO,
+ IRIG_INFO, pout,
+ _pcps_ddev_is_irig_rx( pddev ) );
+ break;
+
+
+ case IOCTL_SET_PCPS_IRIG_RX_SETTINGS:
+ _io_write_var_chk( pddev, PCPS_SET_IRIG_RX_SETTINGS,
+ IRIG_SETTINGS, pin,
+ _pcps_ddev_is_irig_rx( pddev ) );
+ break;
+
+
+ case IOCTL_PCPS_CLR_UCAP_BUFF:
+ _io_write_cmd_chk( pddev, PCPS_CLR_UCAP_BUFF,
+ _pcps_ddev_can_clr_ucap_buff( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_UCAP_ENTRIES:
+ _io_read_var_chk( pddev, PCPS_GIVE_UCAP_ENTRIES,
+ PCPS_UCAP_ENTRIES, pout,
+ _pcps_ddev_has_ucap( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCPS_UCAP_EVENT:
+ _io_read_var_chk( pddev, PCPS_GIVE_UCAP_EVENT,
+ PCPS_HR_TIME, pout,
+ _pcps_ddev_has_ucap( pddev ) );
+ break;
+
+
+ /* slow read/write operations with GPS data */
+
+ case IOCTL_GET_GPS_TZDL:
+ _io_read_gps_var( pddev, PC_GPS_TZDL, TZDL, pout );
+ break;
+
+
+ case IOCTL_SET_GPS_TZDL:
+ _io_write_gps_var( pddev, PC_GPS_TZDL, TZDL, pin );
+ break;
+
+
+ case IOCTL_GET_GPS_SW_REV:
+ _io_read_gps_var( pddev, PC_GPS_SW_REV,
+ SW_REV, pout );
+ break;
+
+
+ case IOCTL_GET_GPS_BVAR_STAT:
+ _io_read_gps_var( pddev, PC_GPS_BVAR_STAT,
+ BVAR_STAT, pout );
+ break;
+
+
+ case IOCTL_GET_GPS_TIME:
+ _io_read_gps_var( pddev, PC_GPS_TIME, TTM, pout );
+ break;
+
+
+ case IOCTL_SET_GPS_TIME:
+ _io_write_gps_var( pddev, PC_GPS_TIME, TTM, pin );
+ break;
+
+
+ case IOCTL_GET_GPS_PORT_PARM:
+ _io_read_gps_var( pddev, PC_GPS_PORT_PARM,
+ PORT_PARM, pout );
+ break;
+
+
+ case IOCTL_SET_GPS_PORT_PARM:
+ _io_write_gps_var( pddev, PC_GPS_PORT_PARM,
+ PORT_PARM, pin );
+ break;
+
+
+ case IOCTL_GET_GPS_ANT_INFO:
+ _io_read_gps_var( pddev, PC_GPS_ANT_INFO,
+ ANT_INFO, pout );
+ break;
+
+
+ case IOCTL_GET_GPS_UCAP:
+ _io_read_gps_var( pddev, PC_GPS_UCAP, TTM, pout );
+ break;
+
+
+ case IOCTL_GET_GPS_ENABLE_FLAGS:
+ _io_read_gps_var( pddev, PC_GPS_ENABLE_FLAGS,
+ ENABLE_FLAGS, pout );
+ break;
+
+
+ case IOCTL_SET_GPS_ENABLE_FLAGS:
+ _io_write_gps_var( pddev, PC_GPS_ENABLE_FLAGS,
+ ENABLE_FLAGS, pin );
+ break;
+
+
+ case IOCTL_GET_GPS_STAT_INFO:
+ _io_read_gps_var( pddev, PC_GPS_STAT_INFO,
+ STAT_INFO, pout );
+ break;
+
+
+ case IOCTL_SET_GPS_CMD:
+ _io_write_gps_var( pddev, PC_GPS_CMD,
+ GPS_CMD, pin );
+ break;
+
+
+ case IOCTL_GET_GPS_IDENT:
+ _io_read_gps_var( pddev, PC_GPS_IDENT,
+ IDENT, pout );
+ break;
+
+
+ case IOCTL_GET_GPS_POS:
+ _io_read_gps_var( pddev, PC_GPS_POS,
+ POS, pout );
+ break;
+
+
+ case IOCTL_SET_GPS_POS_XYZ:
+ _io_write_gps_var( pddev, PC_GPS_POS_XYZ,
+ XYZs, pin );
+ break;
+
+
+ case IOCTL_SET_GPS_POS_LLA:
+ _io_write_gps_var( pddev, PC_GPS_POS_LLA,
+ LLAs, pin );
+ break;
+
+
+ case IOCTL_GET_GPS_ANT_CABLE_LEN:
+ _io_read_gps_var_chk( pddev, PC_GPS_ANT_CABLE_LEN,
+ ANT_CABLE_LEN, pout,
+ _pcps_ddev_has_cab_len( pddev ) );
+ break;
+
+
+ case IOCTL_SET_GPS_ANT_CABLE_LEN:
+ _io_write_gps_var_chk( pddev, PC_GPS_ANT_CABLE_LEN,
+ ANT_CABLE_LEN, pin,
+ _pcps_ddev_has_cab_len( pddev ) );
+ break;
+
+
+ case IOCTL_GET_GPS_RECEIVER_INFO:
+ _io_read_gps_var_chk( pddev, PC_GPS_RECEIVER_INFO,
+ RECEIVER_INFO, pout,
+ _pcps_ddev_has_receiver_info( pddev ) );
+ break;
+
+
+ #if _MBG_SUPP_VAR_ACC_SIZE
+ case IOCTL_GET_GPS_ALL_STR_TYPE_INFO:
+ _io_read_gps_chk( pddev, PC_GPS_ALL_STR_TYPE_INFO,
+ ALL_STR_TYPE_INFO, pout, pout_size,
+ _pcps_ddev_has_receiver_info( pddev ) );
+ break;
+ #endif
+
+
+ #if _MBG_SUPP_VAR_ACC_SIZE
+ case IOCTL_GET_GPS_ALL_PORT_INFO:
+ _io_read_gps_chk( pddev, PC_GPS_ALL_PORT_INFO,
+ ALL_PORT_INFO, pout, pout_size,
+ _pcps_ddev_has_receiver_info( pddev ) );
+ break;
+ #endif
+
+
+ case IOCTL_SET_GPS_PORT_SETTINGS_IDX:
+ _io_write_gps_var_chk( pddev, PC_GPS_PORT_SETTINGS_IDX,
+ PORT_SETTINGS_IDX, pin,
+ _pcps_ddev_has_receiver_info( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PCI_ASIC_VERSION:
+ _io_chk_cond( _pcps_ddev_has_asic_version( pddev ) );
+ {
+ _pcps_iob( PCI_ASIC_VERSION, _s );
+
+ _s = pddev->raw_asic_version;
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( PCI_ASIC_VERSION, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_GET_PCPS_TIME_CYCLES:
+ {
+ _pcps_iob( PCPS_TIME_CYCLES, _s );
+
+ _pcps_sem_inc_safe( pddev );
+ rc = _pcps_read_var( pddev, PCPS_GIVE_TIME_NOCLEAR,
+ _s.t );
+ if ( _pcps_ddev_is_usb( pddev ) )
+ _s.cycles =(pddev)->acc_cycles;
+ else
+ mbg_get_pc_cycles( &(_s).cycles );
+ _pcps_sem_dec( pddev );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ _pcps_iob_to_pout( PCPS_TIME_CYCLES, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_GET_PCPS_HR_TIME_CYCLES:
+ {
+ _pcps_iob( PCPS_HR_TIME_CYCLES, _s );
+
+ _pcps_sem_inc_safe( pddev );
+ rc = _pcps_read_var( pddev, PCPS_GIVE_HR_TIME,
+ _s.t );
+ _s.cycles =(pddev)->acc_cycles;
+ _pcps_sem_dec( pddev );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ _pcps_iob_to_pout( PCPS_HR_TIME_CYCLES, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_GET_PCPS_IRIG_TX_INFO:
+ {
+ /* This is a workaround for GPS169PCIs with early */
+ /* firmware versions. See RCS log for details. */
+ uint8_t pcps_cmd = PCPS_GET_IRIG_TX_INFO;
+
+ if ( _pcps_ddev_requires_irig_workaround( pddev ) )
+ {
+ pcps_cmd = PCPS_GET_IRIG_RX_INFO;
+ _mbgddmsg_1( MBG_DBG_INFO,
+ "%s: workaround for GPS169PCI \"get IRIG TX cfg\"",
+ pcps_driver_name );
+ }
+
+ _io_read_var_chk( pddev, pcps_cmd, IRIG_INFO, pout,
+ _pcps_ddev_has_irig_tx( pddev ) );
+ }
+ break;
+
+
+ case IOCTL_SET_PCPS_IRIG_TX_SETTINGS:
+ {
+ /* This is a workaround for GPS169PCIs with early */
+ /* firmware versions. See RCS log for details. */
+ uint8_t pcps_cmd = PCPS_SET_IRIG_TX_SETTINGS;
+
+ if ( _pcps_ddev_requires_irig_workaround( pddev ) )
+ {
+ pcps_cmd = PCPS_SET_IRIG_RX_SETTINGS;
+ _mbgddmsg_1( MBG_DBG_INFO,
+ "%s: workaround for GPS169PCI \"set IRIG TX cfg\"",
+ pcps_driver_name );
+ }
+
+ _io_write_var_chk( pddev, pcps_cmd,
+ IRIG_SETTINGS, pin,
+ _pcps_ddev_has_irig_tx( pddev ) );
+ }
+ break;
+
+
+ case IOCTL_GET_SYNTH:
+ _io_read_var_chk( pddev, PCPS_GET_SYNTH,
+ SYNTH, pout,
+ _pcps_ddev_has_synth( pddev ) );
+ break;
+
+
+ case IOCTL_SET_SYNTH:
+ _io_write_var_chk( pddev, PCPS_SET_SYNTH,
+ SYNTH, pin,
+ _pcps_ddev_has_synth( pddev ) );
+ break;
+
+
+ case IOCTL_DEV_IS_GPS:
+ _report_cond( _pcps_ddev_is_gps( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_IS_DCF:
+ _report_cond( _pcps_ddev_is_dcf( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_IS_IRIG_RX:
+ _report_cond( _pcps_ddev_is_irig_rx( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_HR_TIME:
+ _report_cond( _pcps_ddev_has_hr_time( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_CAB_LEN:
+ _report_cond( _pcps_ddev_has_cab_len( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_TZDL:
+ _report_cond( _pcps_ddev_has_tzdl( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_PCPS_TZDL:
+ _report_cond( _pcps_ddev_has_pcps_tzdl( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_TZCODE:
+ _report_cond( _pcps_ddev_has_tzcode( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_TZ:
+ _report_cond( _pcps_ddev_has_tz( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_EVENT_TIME:
+ _report_cond( _pcps_ddev_has_event_time( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_RECEIVER_INFO:
+ _report_cond( _pcps_ddev_has_receiver_info( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_CAN_CLR_UCAP_BUFF:
+ _report_cond( _pcps_ddev_can_clr_ucap_buff( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_UCAP:
+ _report_cond( _pcps_ddev_has_ucap( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_IRIG_TX:
+ _report_cond( _pcps_ddev_has_irig_tx( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_SERIAL_HS:
+ _report_cond( _pcps_ddev_has_serial_hs( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_SIGNAL:
+ _report_cond( _pcps_ddev_has_signal( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_MOD:
+ _report_cond( _pcps_ddev_has_mod( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_IRIG:
+ _report_cond( _pcps_ddev_has_irig( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_REF_OFFS:
+ _report_cond( _pcps_ddev_has_ref_offs( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_OPT_FLAGS:
+ _report_cond( _pcps_ddev_has_opt_flags( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_GPS_DATA:
+ _report_cond( _pcps_ddev_has_gps_data( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_SYNTH:
+ _report_cond( _pcps_ddev_has_synth( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_GENERIC_IO:
+ _report_cond( _pcps_ddev_has_generic_io( pddev ), pout );
+ break;
+
+
+ case IOCTL_PCPS_GENERIC_IO:
+ {
+ IOCTL_GENERIC_CTL ctl;
+ IOCTL_GENERIC_BUFFER *p_buff;
+ int buffer_size;
+
+ _io_chk_cond( _pcps_ddev_has_generic_io( pddev ) );
+
+ _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin );
+ buffer_size = sizeof( ctl ) +
+ ( ( ctl.data_size_in > ctl.data_size_out ) ?
+ ctl.data_size_in : ctl.data_size_out );
+ p_buff = _pcps_kmalloc( buffer_size );
+
+ if ( p_buff == NULL )
+ goto err_no_mem;
+
+ _pcps_iob_from_pin_size( uint8_t, *p_buff, pin,
+ sizeof( p_buff->ctl ) + ctl.data_size_in );
+
+ _pcps_sem_inc_safe( pddev );
+ rc = pcps_generic_io( pddev, (uint8_t) ctl.info,
+ p_buff->data,
+ (uint8_t) ctl.data_size_in,
+ p_buff->data,
+ (uint8_t) ctl.data_size_out );
+ _pcps_sem_dec( pddev );
+
+ if ( rc == MBG_SUCCESS )
+ {
+ p_buff->ctl = ctl;
+ _pcps_iob_to_pout_size( uint8_t, *p_buff, pout,
+ sizeof( p_buff->ctl ) + ctl.data_size_out );
+ }
+
+ _pcps_kfree( p_buff );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ break;
+ }
+
+
+ case IOCTL_GET_SYNTH_STATE:
+ _io_read_var_chk( pddev, PCPS_GET_SYNTH_STATE,
+ SYNTH_STATE, pout,
+ _pcps_ddev_has_synth( pddev ) );
+ break;
+
+
+ #if _MBG_SUPP_VAR_ACC_SIZE
+ case IOCTL_GET_GPS_ALL_POUT_INFO:
+ _io_read_gps_chk( pddev, PC_GPS_ALL_POUT_INFO,
+ ALL_POUT_INFO, pout, pout_size,
+ _pcps_ddev_has_receiver_info( pddev ) );
+ break;
+ #endif
+
+
+ case IOCTL_SET_GPS_POUT_SETTINGS_IDX:
+ _io_write_gps_var_chk( pddev, PC_GPS_POUT_SETTINGS_IDX,
+ POUT_SETTINGS_IDX, pin,
+ _pcps_ddev_has_receiver_info( pddev ) );
+ break;
+
+#if USE_DEBUG_PORT
+ case IOCTL_MBG_DBG_GET_PORT_ADDR:
+ {
+ _pcps_iob( MBG_DBG_PORT, _s );
+
+ _s = mbg_dbg_port;
+ _pcps_iob_to_pout( MBG_DBG_PORT, _s, pout );
+
+ rc = MBG_SUCCESS;
+ }
+ break;
+
+
+ case IOCTL_MBG_DBG_SET_PORT_ADDR:
+ {
+ _pcps_iob( MBG_DBG_PORT, _s );
+
+ _pcps_iob_from_pin( MBG_DBG_PORT, _s, pin );
+ mbg_dbg_port = _s;
+ mbg_dbg_port_mapped = _pcps_ioremap( mbg_dbg_port, sizeof( mbg_dbg_port ) );
+
+ rc = MBG_SUCCESS;
+ }
+ break;
+#endif // USE_DEBUG_PORT
+
+
+ case IOCTL_GET_MAPPED_MEM_ADDR:
+ {
+ _io_chk_cond( ( pddev->asic_features & PCI_ASIC_HAS_MM_IO ) );
+ _io_get_mapped_mem_address( pddev, pout );
+ }
+ break;
+
+
+ case IOCTL_UNMAP_MAPPED_MEM:
+ {
+ _io_chk_cond( ( pddev->asic_features & PCI_ASIC_HAS_MM_IO ) );
+ _io_unmap_mapped_mem_address( pddev, pin );
+ }
+ break;
+
+
+ case IOCTL_GET_PCI_ASIC_FEATURES:
+ _io_chk_cond( _pcps_ddev_has_asic_features( pddev ) );
+ {
+ _pcps_iob( PCI_ASIC_FEATURES, _s );
+
+ _s = pddev->asic_features;
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( PCI_ASIC_FEATURES, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_HAS_PCI_ASIC_FEATURES:
+ _report_cond( _pcps_ddev_has_asic_features( pddev ), pout );
+ break;
+
+
+ case IOCTL_HAS_PCI_ASIC_VERSION:
+ _report_cond( _pcps_ddev_has_asic_version( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_IS_MSF:
+ _report_cond( _pcps_ddev_is_msf( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_IS_WWVB:
+ _report_cond( _pcps_ddev_is_wwvb( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_IS_LWR:
+ _report_cond( _pcps_ddev_is_lwr( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_IRQ_STAT_INFO:
+ {
+ _pcps_iob( PCPS_IRQ_STAT_INFO, _s );
+
+ _s = pddev->irq_stat_info;
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( PCPS_IRQ_STAT_INFO, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_GET_CYCLES_FREQUENCY:
+ {
+ _pcps_iob( MBG_PC_CYCLES_FREQUENCY, _s );
+
+ mbg_get_pc_cycles_frequency( &(_s) );
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( MBG_PC_CYCLES_FREQUENCY, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_HAS_FAST_HR_TIMESTAMP:
+ _report_cond( _pcps_ddev_has_fast_hr_timestamp( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES:
+ {
+ _pcps_iob( PCPS_TIME_STAMP_CYCLES, _s );
+
+ if ( !_pcps_ddev_has_fast_hr_timestamp( pddev ) )
+ goto err_support;
+
+ do_get_fast_hr_timestamp_cycles_safe( pddev, &_s );
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( PCPS_TIME_STAMP_CYCLES, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_GET_FAST_HR_TIMESTAMP:
+ {
+ _pcps_iob( PCPS_TIME_STAMP, _s );
+
+ if ( !_pcps_ddev_has_fast_hr_timestamp( pddev ) )
+ goto err_support;
+
+ do_get_fast_hr_timestamp_safe( pddev, &_s );
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( PCPS_TIME_STAMP_CYCLES, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_DEV_HAS_GPS_TIME_SCALE:
+ _report_cond( _pcps_ddev_has_time_scale( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_GPS_TIME_SCALE_INFO:
+ _io_read_gps_var_chk( pddev, PC_GPS_TIME_SCALE,
+ MBG_TIME_SCALE_INFO, pout,
+ _pcps_ddev_has_time_scale( pddev ) );
+ break;
+
+
+ case IOCTL_SET_GPS_TIME_SCALE_SETTINGS:
+ _io_write_gps_var_chk( pddev, PC_GPS_TIME_SCALE,
+ MBG_TIME_SCALE_SETTINGS, pin,
+ _pcps_ddev_has_time_scale( pddev ) );
+ break;
+
+
+ case IOCTL_DEV_HAS_GPS_UTC_PARM:
+ _report_cond( _pcps_ddev_has_utc_parm( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_GPS_UTC_PARM:
+ _io_read_gps_var_chk( pddev, PC_GPS_UTC,
+ UTC, pout,
+ _pcps_ddev_has_utc_parm( pddev ) );
+ break;
+
+
+ case IOCTL_SET_GPS_UTC_PARM:
+ _io_write_gps_var_chk( pddev, PC_GPS_UTC,
+ UTC, pin,
+ _pcps_ddev_has_utc_parm( pddev ) );
+ break;
+
+
+ case IOCTL_DEV_HAS_IRIG_CTRL_BITS:
+ _report_cond( _pcps_ddev_has_irig_ctrl_bits( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_IRIG_CTRL_BITS:
+ _io_read_var_chk( pddev, PCPS_GET_IRIG_CTRL_BITS,
+ MBG_IRIG_CTRL_BITS, pout,
+ _pcps_ddev_has_irig_ctrl_bits( pddev ) );
+ break;
+
+
+ case IOCTL_DEV_HAS_LAN_INTF:
+ _report_cond( _pcps_ddev_has_lan_intf( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_LAN_IF_INFO:
+ _io_read_gps_var_chk( pddev, PC_GPS_LAN_IF_INFO,
+ LAN_IF_INFO, pout,
+ _pcps_ddev_has_lan_intf( pddev ) );
+ break;
+
+
+ case IOCTL_GET_IP4_STATE:
+ _io_read_gps_var_chk( pddev, PC_GPS_IP4_STATE,
+ IP4_SETTINGS, pout,
+ _pcps_ddev_has_lan_intf( pddev ) );
+ break;
+
+
+ case IOCTL_GET_IP4_SETTINGS:
+ _io_read_gps_var_chk( pddev, PC_GPS_IP4_SETTINGS,
+ IP4_SETTINGS, pout,
+ _pcps_ddev_has_lan_intf( pddev ) );
+ break;
+
+
+ case IOCTL_SET_IP4_SETTINGS:
+ _io_write_gps_var_chk( pddev, PC_GPS_IP4_SETTINGS,
+ IP4_SETTINGS, pin,
+ _pcps_ddev_has_lan_intf( pddev ) );
+ break;
+
+
+ case IOCTL_DEV_IS_PTP:
+ _report_cond( _pcps_ddev_is_ptp( pddev ), pout );
+ break;
+
+
+ case IOCTL_DEV_HAS_PTP:
+ _report_cond( _pcps_ddev_has_ptp( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_PTP_STATE:
+ _io_read_gps_var_chk( pddev, PC_GPS_PTP_STATE,
+ PTP_STATE, pout,
+ _pcps_ddev_has_ptp( pddev ) );
+ break;
+
+
+ case IOCTL_GET_PTP_CFG_INFO:
+ _io_read_gps_var_chk( pddev, PC_GPS_PTP_CFG,
+ PTP_CFG_INFO, pout,
+ _pcps_ddev_has_ptp( pddev ) );
+ break;
+
+
+ case IOCTL_SET_PTP_CFG_SETTINGS:
+ _io_write_gps_var_chk( pddev, PC_GPS_PTP_CFG,
+ PTP_CFG_SETTINGS, pin,
+ _pcps_ddev_has_ptp( pddev ) );
+ break;
+
+
+ case IOCTL_DEV_HAS_IRIG_TIME:
+ _report_cond( _pcps_ddev_has_irig_time( pddev ), pout );
+ break;
+
+
+ case IOCTL_GET_IRIG_TIME:
+ _io_read_var_chk( pddev, PCPS_GIVE_IRIG_TIME,
+ PCPS_IRIG_TIME, pout,
+ _pcps_ddev_has_irig_time( pddev ) );
+ break;
+
+
+ case IOCTL_GET_RAW_IRIG_DATA:
+ _io_read_var_chk( pddev, PCPS_GET_RAW_IRIG_DATA,
+ MBG_RAW_IRIG_DATA, pout,
+ _pcps_ddev_has_raw_irig_data( pddev ) );
+ break;
+
+
+ case IOCTL_GET_TIME_INFO_HRT:
+ {
+ _pcps_iob( MBG_TIME_INFO_HRT, _s );
+
+ if ( !_pcps_ddev_has_hr_time( pddev ) )
+ goto err_support;
+
+ mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_before );
+ mbg_get_sys_time( &_s.sys_time_cycles.sys_time );
+ mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_after );
+
+ _pcps_sem_inc_safe( pddev );
+ rc = _pcps_read_var( pddev, PCPS_GIVE_HR_TIME, _s.ref_hr_time_cycles.t );
+ _s.ref_hr_time_cycles.cycles =(pddev)->acc_cycles;
+ _pcps_sem_dec( pddev );
+
+ if ( rc != MBG_SUCCESS )
+ goto err_access;
+
+ _pcps_iob_to_pout( MBG_TIME_INFO_HRT, _s, pout );
+ }
+ break;
+
+
+ case IOCTL_GET_TIME_INFO_TSTAMP:
+ {
+ _pcps_iob( MBG_TIME_INFO_TSTAMP, _s );
+
+ if ( !_pcps_ddev_has_fast_hr_timestamp( pddev ) )
+ goto err_support;
+
+ mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_before );
+ mbg_get_sys_time( &_s.sys_time_cycles.sys_time );
+ mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_after );
+
+ do_get_fast_hr_timestamp_cycles_safe( pddev, &(_s).ref_tstamp_cycles );
+
+ rc = MBG_SUCCESS;
+
+ _pcps_iob_to_pout( MBG_TIME_INFO_TSTAMP, _s, pout );
+ }
+ break;
+
+#if USE_DEBUG_PORT
+ case IOCTL_MBG_DBG_SET_BIT:
+ {
+ _pcps_iob( MBG_DBG_DATA, _s );
+ _pcps_iob( MBG_PC_CYCLES, _c );
+
+ _pcps_iob_from_pin( MBG_DBG_DATA, _s, pin );
+
+ _mbg_dbg_set_bit( pddev, _s );
+ mbg_get_pc_cycles( &(_c) );
+
+ _pcps_iob_to_pout( MBG_PC_CYCLES, _c, pout );
+ }
+ break;
+
+
+ case IOCTL_MBG_DBG_CLR_BIT:
+ {
+ _pcps_iob( MBG_DBG_DATA, _s );
+ _pcps_iob( MBG_PC_CYCLES, _c );
+
+ _pcps_iob_from_pin( MBG_DBG_DATA, _s, pin );
+
+ _mbg_dbg_clr_bit( pddev, _s );
+ mbg_get_pc_cycles( &(_c) );
+
+ _pcps_iob_to_pout( MBG_PC_CYCLES, _c, pout );
+ }
+ break;
+
+
+ case IOCTL_MBG_DBG_CLR_ALL:
+ {
+ _pcps_iob( MBG_PC_CYCLES, _c );
+ _mbg_dbg_clr_all( pddev );
+ mbg_get_pc_cycles( &(_c) );
+
+ _pcps_iob_to_pout( MBG_PC_CYCLES, _c, pout );
+ }
+ break;
+#endif
+
+
+ default:
+ goto err_inval;
+
+ }
+
+ return rc;
+
+
+err_inval:
+ return MBG_ERR_INV_DEV_REQUEST;
+
+err_support:
+ return MBG_ERR_NOT_SUPP_BY_DEV;
+
+err_no_mem:
+ return MBG_ERR_NO_MEM;
+
+err_busy_unsafe:
+ return MBG_ERR_IRQ_UNSAFE;
+
+err_access:
+ return rc; // return the rc from the low level routine
+
+
+#if defined( MBG_TGT_LINUX )
+
+err_to_user:
+ return -EFAULT;
+
+err_from_user:
+ return -EFAULT;
+
+#endif // defined( MBG_TGT_LINUX )
+
+} // ioctl_switch
+
+#endif /* _MACIOCTL_H */
+