diff options
Diffstat (limited to 'mbglib/common/macioctl.h')
-rwxr-xr-x | mbglib/common/macioctl.h | 1817 |
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 */ + |