mbgtools-lx  4.2.8
pcpsdrvr.c
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: pcpsdrvr.c 1.58 2019/03/18 16:13:38 martin REL_M $
5  *
6  * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
7  *
8  * Description:
9  * Driver functions that detect Meinberg PC plug-in devices and set up
10  * the software environment (port base address, clock features, etc.).
11  *
12  * These functions should be used with programs which have direct
13  * access to the hardware (e.g. device drivers).
14  *
15  * Programs which access the devices via device drivers should
16  * use the functions provided by the mbgdevio module.
17  *
18  * There are several preprocessor symbols defined at the top of
19  * pcpsdrvr.h which control the default support of some features
20  * under the different operating systems. If required, each of
21  * those symbols can be overridden by compiler arguments.
22  *
23  * Basically the following devices are supported:
24  * USB v2: DCF600USB, TCR600USB, MSF600USB, WVB600USB,
25  * TCR180USB.
26  * USB v1: USB5131, TCR51USB, MSF51USB, WWVB51USB
27  * PCI express: PEX511, TCR511PEX, GPS170PEX, PTP270PEX,
28  * FRC511PEX, TCR170PEX, GPS180PEX, TCR180PEX
29  * PZF180PEX, GLN180PEX, GPS180AMC, GNS181PEX
30  * PCI bus 5V/3.3V: PCI510, PCI511, GPS169PCI, GPS170PCI,
31  * TCR510PCI, TCR167PCI, TCR511PCI
32  * PCI bus 5V: PCI32, GPS167PCI, PCI509, GPS168PCI
33  * MCA bus: PS31
34  * ISA bus: PC31, PC32, GPS167PC
35  *
36  * USB is not supported for all target environments, eventually
37  * because an operating systems doesn't provide full USB support,
38  * or USB support hasn't yet been implemented.
39  *
40  * PCI support is possible in two different ways. The preferred
41  * functions are compiled in if one of the symbols _PCPS_USE_PCI_PNP
42  * or _PCPS_USE_PCI_BIOS is defined != 0.
43  *
44  * If _PCPS_USE_PCI_PNP is != 0 it is assumed that the operating
45  * system's PCI layer detects a new PCI device and calls a driver's
46  * add_device()/start_device() function to initialize the device.
47  * This technique is supported with PNP operating systems
48  * (e.g. Windows versions after NT, Linux, *BSD).
49  *
50  * If _PCPS_USE_PCI_BIOS is != 0 the program scans the PCI bus
51  * during startup to detect and initialize supported PCI devices.
52  * This techique is used with old non-PNP operating systems.
53  *
54  * The symbol _PCPS_USE_RSRCMGR must be defined != 0 to include
55  * support of resource managers, if necessary.
56  *
57  * If the symbol _PCPS_USE_MCA is defined != 0 then Micro Channel
58  * detection (and therefore auto-detection of a MCA clock) is
59  * supported.
60  *
61  * MCA devices are accessed using the same low level functions as
62  * ISA devices, so if autodetection of MCA clocks is not supported
63  * then a MCA device's known port number can be passed to
64  * pcps_detect_devices() to let it be treated like an ISA device.
65  *
66  * -----------------------------------------------------------------------
67  * $Log: pcpsdrvr.c $
68  * Revision 1.58 2019/03/18 16:13:38 martin
69  * Fixed a bug in the probe routine that had made it into
70  * the previous file version.
71  * Revision 1.57 2019/03/11 16:08:27 martin
72  * Conditionally use local I/O buffers. This may avoid a potential
73  * data corruption problem, but won't work with USB devices on
74  * Linux kernels 4.9 and later.
75  * Revision 1.56 2019/01/15 16:59:59 martin
76  * Use generic format specifiers for a debug message.
77  * Revision 1.55 2018/11/23 08:05:46Z martin
78  * Improved resource handling.
79  * Refactored debug logging stuff.
80  * Return MBG_ERR_TIMEOUT in pcps_read_asic_mm() on SPARC for now.
81  * Variables force_io_access and force_mm16_access are only
82  * supported on targets where _PCPS_USE_MM_IO is not 0.
83  * New preprocessor symbol PCPS_LOG_STD_MSGS to suppress some
84  * messages on direct access targets in non-DEBUG mode.
85  * Revision 1.54 2018/09/21 15:13:41 martin
86  * Added definitions for TCR180USB.
87  * Use only DMA capable variables for device I/O.
88  * Also read ASIC features via MM I/O, if supported.
89  * Fixed do_div() in 32 bit Linux kernel build.
90  * Changed MAX_BOOT_TIME_PTP270PEX from 40 back to 27 s.
91  * Modified wait for PTP270PEX in case uptime is not supported.
92  * Set force_io_access if associated preprocessor macro is defined.
93  * Introduced access mode stuff.
94  * Unified kernel driver messages.
95  * New functions pcps_read_usb_generic() and pcps_write_usb_generic().
96  * Updated function prototypes.
97  * Let the probe routine print a success message.
98  * Cleaned up messages.
99  * Use more appropriate I/O macros.
100  * More unified resource handling.
101  * Renamed a number of symbols.
102  * Use _MBG_IOMEM.
103  * Refactored reading sernum.
104  * Support REPORT_CFG, even without DEBUG.
105  * Unified debugging in low level functions.
106  * Also log USB endpoint attributes in DEBUG.
107  * Mutexes and spinlocks with individual names.
108  * Revision 1.53 2017/08/10 14:03:03 martin
109  * String 'pcps_driver_name' is now defined in pcpsdrvr.h.
110  * Unified extended resource properties handling.
111  * Cleaned up target some dependent code.
112  * Revision 1.52 2017/07/04 16:45:36 martin
113  * Support GPS180AMC and GNS181PEX.
114  * Renamed some functions: Use _device instead of _clock,
115  * pcps_start_device() is now called pcps_probe_device(), etc.
116  * Runtime support for forcing I/O rather than MM access.
117  * Increase MAX_BOOT_TIME_PTP270PEX from 27 to 40 seconds
118  * to be safe in case a firmware update is applied at startup.
119  * Fixed type of a register address.
120  * Cleaned up I/O port usage.
121  * Older defines N_SUPP_DEV, PCPS_MAX_DDEVS, and MBG_MAX_DEVICES
122  * have been obsoleted by new defines N_SUPP_DEV_BUS, N_SUPP_DEV_EXT,
123  * and N_SUPP_DEV_TOTAL.
124  * Fixed DEBUG build under *BSD.
125  * Added DEBUG code dumping RECEIVER_INFO.
126  * Moved mbg_delta_sys_time_ms() to new module mbgsystm.c.
127  * Check for MBG_TGT_POSIX instead of MBG_TGT_UNIX.
128  * Provided a driver name string for debug build on direct-access targets.
129  * Avoid 'redundant redeclaration' warning under FreeBSD 8.2.
130  * Fixed macro definition syntax to avoid clang compiler warnings.
131  * Fixed some other warnings from clang.
132  * Attribute always_inline is now in __mbg_inline.
133  * Conditional USB debug code.
134  * Account for renamed symbols.
135  * Fixed typos, wording, and doxygen comments.
136  * Removed trailing white space.
137  * Revision 1.51 2013/10/01 14:19:03 martin
138  * Support GLN180PEX.
139  * Revision 1.50 2013/03/15 10:01:58 martin
140  * Modified/added some debug messages.
141  * Revision 1.49 2013/03/15 08:35:08 martin
142  * Account for PTP270PEX HW v2 cards which can indicate
143  * when they are ready to be accessed.
144  * Account for unified, renamed PLX symbols.
145  * Revision 1.48 2012/11/05 16:32:02Z martin
146  * Fixed and enhanced some timing DEBUG code.
147  * Rewrote report_uptime().
148  * Revision 1.47 2012/10/15 14:12:08 martin
149  * Support GPS180PEX, TCR180PEX, and PZF180PEX.
150  * Support DCF600USB, TCR600USB, MSF600USB, and WVB600USB.
151  * Support FreeBSD and NetBSD.
152  * Support on-board event log.
153  * If required, wait until PTP270PEX has finished booting.
154  * Use USB micro frame timing conditionally only, yet disabled by default.
155  * Conditional debug code to test PCI access time and/or execution time
156  * of the low level functions.
157  * Always read the serial number directly from the device.
158  * Unified low level functions and use 16 bit types for buffer sizes.
159  * Added warnings in case a device is not handled by chip setup
160  * or device feature check.
161  * Modified low level AMCC read functions for SPARC to fix unaligned access.
162  * Added debug messages for generic I/O.
163  * Initialize device semaphores only early at device initializition
164  * if required, otherwise later, since early initialization can lead
165  * to a trap e.g. under Windows.
166  * Conditional code to test MM I/O for new PCI cards.
167  * Use common mutex primitives from mbgmutex.h.
168  * Optionally support timespec for sys time (USE_TIMESPEC).
169  * Set up basic default receiver info for devices which don't
170  * support this structure.
171  * Moved MBG_TGT_SUPP_MEM_ACC definition to pcpsdev.h.
172  * Introduced and use new function check_ri_feature().
173  * Also detect support for raw IRIG data from RECEIVER_INFO.
174  * Revision 1.46 2009/12/15 14:45:33 daniel
175  * Account for feature to read the raw IRIG bits.
176  * Revision 1.45 2009/09/29 07:24:50Z martin
177  * Use standard feature flag to check if fast HR time is supported.
178  * Revision 1.44 2009/06/23 07:10:47 martin
179  * Fixed/modified some debug messages.
180  * Revision 1.43 2009/06/19 12:13:59 martin
181  * Check if TCR cards support raw IRIG time.
182  * Revision 1.42 2009/06/09 10:15:33 daniel
183  * Check if card has LAN interface and supports PTP.
184  * Revision 1.41 2009/04/08 08:33:20 daniel
185  * Check whether the TCR511PCI or devices with
186  * RECEIVER_INFO support IRIG control function bits.
187  * Revision 1.40 2009/03/27 09:55:13Z martin
188  * Added some debug messages.
189  * Account for renamed library symbols.
190  * Revision 1.39 2009/03/19 12:04:31Z martin
191  * Adjust endianess of ASIC version and ASIC features after having read.
192  * Revision 1.38 2009/03/17 15:33:53 martin
193  * Support reading IRIG control function bits.
194  * Revision 1.37 2009/03/13 09:17:00Z martin
195  * Bug fix: Hadn't checked whether TCR170PEX card provides the
196  * programmable synthesizer.
197  * As a fix moved the code from the body of check_opt_features()
198  * into pcps_start_device() so that the check is done for every
199  * type of card.
200  * Swap receiver_info to make this work on non-x86 architectures.
201  * Support configurable time scales, and reading/writing GPS UTC
202  * parameters via the PC bus.
203  * Use mbg_get_pc_cycles() instead of _pcps_get_cycles().
204  * Revision 1.36 2009/01/13 12:03:57Z martin
205  * Generate a separate warning message if the firmware could not
206  * be read from an ISA card.
207  * Care about "long long" in debug msg.
208  * Revision 1.35 2008/12/16 14:38:49Z martin
209  * Account for new devices PTP270PEX, FRC270PEX, TCR170PEX, and WWVB51USB.
210  * Check the firmware / ASIC version of PEX cards and flag the device
211  * unsafe for IRQs if the versions are older than required.
212  * Check whether PEX511 and PCI511 support HR time.
213  * Moved initialization of common spinlocks and mutexes to pcps_start_device().
214  * Take access cycles count in the low level routines, with interrupts disabled.
215  * Cleanup for pcps_read_usb() which is now possible since access cycles count
216  * is now taken inside the low evel routines.
217  * Support mapped I/O resources, unaligned access and endianess conversion.
218  * Account for ASIC_FEATURES being coded as flags, and account for
219  * new symbol PCI_ASIC_HAS_MM_IO.
220  * Account for new MBG_PC_CYCLES type.
221  * Account for signed irq_num.
222  * Renamed MBG_VIRT_ADDR to MBG_MEM_ADDR.
223  * Use MBG_MEM_ADDR type for memory rather than split high/low types.
224  * Distinguish device port variables for IRQ handling.
225  * Preliminarily support USB latency compensation under Win32 PNP targets
226  * and account for USB EHCI microframe timing which requires a different
227  * latency compensation approach. This is useful if a USB 2.0 hub is connected
228  * between device and host.
229  * Also read the ASIC version at device initialization.
230  * pcps_alloc_ddev() does not take a parameter anymore.
231  * Cleaned up comments.
232  * Revision 1.34 2008/02/27 10:03:02 martin
233  * Support TCR51USB and MSF51USB.
234  * Preliminary support for mapped memory access under Windows and Linux.
235  * Enabled PCPS_IRQ_1_SEC for USB within WIN32 targets
236  * in pcps_start_device().
237  * Fixed a bug in pcps_write() where the error code
238  * that was returned from a USB device was misinterpreted
239  * due to a signed/unsigned mismatch (added typecast).
240  * Removed obsolete function pcps_cleanup_all_devices().
241  * Code cleanup.
242  * Revision 1.33 2008/01/31 08:51:30Z martin
243  * Picked up changes from 1.31.2.1:
244  * Changed default definition of PCI_DWORD to uint32_t.
245  * Removed erraneous brace from debug code.
246  * Revision 1.32 2007/09/26 11:05:57Z martin
247  * Added support for USB in general and new USB device USB5131.
248  * Renamed ..._USE_PCIMGR symbols to ..._USE_PCI_PNP.
249  * Renamed ..._USE_PCIBIOS symbols to ..._USE_PCI_BIOS.
250  * Added new symbol _USE_ISA_PNP to exclude non-PNP stuff.
251  * from build if ISA devices are also handled by the PNP manager.
252  * Use new MBG_... codes defined in mbgerror.h.
253  * Unified timeout handling in low level functions by using an inline function.
254  * Renamed pcps_pnp_start_device() to pcps_start_device().
255  * Renamed pcps_setup_pci_dev() to pcps_setup_and_startpci_dev().
256  * Merged code from init_ddev_cfg() and finish_ddev_cfg() into pcps_start_device().
257  * Improved and unified handling of ISA devices.
258  * Removed calling register_pnp_devices() from pcps_detect_clocks(),
259  * this is now called directly.
260  * Added missing IRIG support to pcps_rsrc_register_device().
261  * Revision 1.31 2007/07/17 08:22:47Z martin
262  * Added support for TCR511PEX and GPS170PEX.
263  * Revision 1.30 2007/07/16 12:56:01Z martin
264  * Added support for PEX511.
265  * Rewrote common resource handling code in order to simplify
266  * OS specific code.
267  * Revision 1.29 2007/03/02 09:40:33Z martin
268  * Use generic port I/O macros.
269  * Pass PCPS_DDEV structure to the low level read functions.
270  * Use new _pcps_..._timeout_clk() macros.
271  * Added init code qualifier.
272  * Preliminary support for *BSD.
273  * Preliminary support for USB.
274  * Revision 1.28 2006/07/11 10:24:20 martin
275  * Use _fmemcpy() in pcps_generic_io() to support environments which
276  * require far data pointers.
277  * Revision 1.27 2006/07/07 09:41:15 martin
278  * Renamed pci_..() function calls to _mbg_pci_..() calls which are defined according to the
279  * OS requirements, in order to avoid naming conflicts.
280  * Revision 1.26 2006/06/19 15:28:52 martin
281  * Added support for TCR511PCI.
282  * Modified parameters required to detect ISA cards.
283  * The array of port addresses does no more require a 0 address
284  * as last value.
285  * Revision 1.25 2006/03/10 11:01:27 martin
286  * Added support for PCI511.
287  * Revision 1.24 2005/11/03 15:50:45Z martin
288  * Added support for GPS170PCI.
289  * Revision 1.23 2005/09/16 08:21:08Z martin
290  * Also flag PCI cards which have base_addr set to 0 as uninitialized.
291  * Revision 1.22 2005/06/02 10:32:07Z martin
292  * Changed more types to C99 fixed size types.
293  * New function pcps_generic_io().
294  * Revision 1.21 2004/12/13 14:19:38Z martin
295  * Support configuration of on-board frequency synthesizer.
296  * Revision 1.20 2004/11/09 13:02:48Z martin
297  * Redefined fixed width data types using standard C99 types.
298  * Fixed warnings about lvalue casts.
299  * Revision 1.19 2004/10/14 15:01:24 martin
300  * Added support for TCR167PCI.
301  * Revision 1.18 2004/09/06 15:16:57Z martin
302  * Support a GPS_DATA interface where sizes are specified
303  * by 16 instead of the original 8 bit quantities, thus allowing
304  * to transfer data blocks which exceed 255 bytes.
305  * Conditionally skip assertions under Linux.
306  * Revision 1.17 2004/04/22 14:47:54 martin
307  * Fixed conversion of firmware rev. number.
308  * Revision 1.16 2004/04/07 09:45:04Z martin
309  * Support new feature PCPS_HAS_IRIG_TX for GPS169PCI.
310  * Revision 1.15 2003/12/22 16:15:21Z martin
311  * Support PCPS_HR_TIME for TCR510PCI.
312  * Revision 1.14 2003/07/30 07:28:23Z martin
313  * Moved prototype for register_pci_devices() outside to top of file.
314  * Revision 1.13 2003/07/08 15:11:55 martin
315  * Support PCI PNP interface under Linux.
316  * New function pcps_rsrc_release().
317  * Made some functions public.
318  * Renamed some public functions to start with pcps_...
319  * Revision 1.12 2003/06/19 10:08:43 MARTIN
320  * Renamed some functions to follow common naming conventions.
321  * Made a function's parameter pointer const.
322  * Changes due to renamed symbols in pcpsdev.h.
323  * Check devices for _pcps_has_ucap() support.
324  * Revision 1.11 2003/05/16 09:28:06 MARTIN
325  * Moved inclusion of some headers to pcpsdrvr.h.
326  * Revision 1.10 2003/04/09 16:35:57 martin
327  * Supports PCI510, GPS169PCI, and TCR510PCI,
328  * and new PCI_ASIC used by those devices.
329  * Revision 1.9 2003/03/20 11:42:37 martin
330  * Fixed syntax for QNX.
331  * Revision 1.8 2002/08/09 08:25:50 MARTIN
332  * Support feature PCPS_CAN_CLR_CAP_BUFF.
333  * Fixed a bug resulting in an unterminated string
334  * if SERNUM was being read.
335  * Revision 1.7 2002/02/26 09:31:57 MARTIN
336  * New function pcps_read_sernum().
337  * Revision 1.6 2002/02/19 09:46:26 MARTIN
338  * Use new header mbg_tgt.h to check the target environment.
339  * Removed function pcps_sn_str_from_ident(), use new
340  * function mbg_gps_ident_decode() from identdec.c now.
341  * If a PCI clock's interface is not properly configured don't
342  * enable the device and set the read function to the new
343  * dummy function pcps_read_null() to prevent driver from
344  * accessing random ports.
345  * Revision 1.5 2002/02/01 12:06:12 MARTIN
346  * Added support for GPS168PCI.
347  * Removed obsolete code.
348  * Revision 1.4 2001/11/30 09:52:48 martin
349  * Added support for event_time which, however, requires
350  * a custom GPS firmware.
351  * Revision 1.3 2001/09/18 06:59:18 MARTIN
352  * Account for new preprocessor symbols in the header file.
353  * Added some type casts to avoid compiler warnings under Win32.
354  * Added some debug messages to clock detection functions.
355  * Revision 1.2 2001/03/16 14:45:33 MARTIN
356  * New functions and definitions to support PNP drivers.
357  * Revision 1.1 2001/03/01 16:26:41 MARTIN
358  * Initial revision for the new library.
359  *
360  **************************************************************************/
361 
362 #define _PCPSDRVR
363  #include <pcpsdrvr.h>
364 #undef _PCPSDRVR
365 
366 #include <identdec.h>
367 #include <mbgddmsg.h>
368 #include <plxdefs.h>
369 #include <pci_asic.h>
370 #include <amccdefs.h>
371 #include <pcidefs.h>
372 
373 #if defined( MBG_TGT_WIN32_PNP )
374  #include <usbdrv.h>
375  #include <pcpsdefs.h>
376  #include <ntddk.h>
377  #include <stdio.h>
378 #elif defined( MBG_TGT_WIN32 )
379  #include <pcps_ioc.h>
380  #include <stdio.h>
381 #elif defined( MBG_TGT_DOS )
382  #include <mbgplx.h>
383 #endif
384 
385 #if defined( MBG_TGT_DOS )
386  #include <assert.h>
387 #endif
388 
389 #if defined( MBG_TGT_FREEBSD )
390  #include <sys/rman.h>
391 #endif
392 
393 #if _PCPS_USE_MCA
394  #include <mca.h>
395 #endif
396 
397 #if _PCPS_USE_PCI
398  #include <pci.h>
399 #endif
400 
401 #if _PCPS_USE_USB
402  #define MBGUSB_MIN_ENDPOINTS_REQUIRED 3
403 #endif
404 
405 
406 
407 #if !defined( REPORT_CFG )
408  #if defined( DEBUG )
409  #define REPORT_CFG 10
410  #else
411  #define REPORT_CFG 0
412  #endif
413 #endif
414 
415 #if !defined( REPORT_CFG_DETAILS )
416  #if ( REPORT_CFG > 1 )
417  #define REPORT_CFG_DETAILS 1
418  #else
419  #define REPORT_CFG_DETAILS 0
420  #endif
421 #endif
422 
423 #define REPORT_CFG_LOG_LVL MBG_LOG_INFO
424 
425 #if !defined( TEST_CFG_DETAILS )
426  #define TEST_CFG_DETAILS 0
427 #endif
428 
429 #if !defined( USE_CMD_PTR )
430  #define USE_CMD_PTR 1
431 #endif
432 
433 #if !defined( DEBUG_ACCESS_TIMING )
434  // Test how much cycles it takes to read/write a register on the board
435  #if ( defined( DEBUG ) && ( DEBUG >= 10 ) && !defined( MBG_TGT_DOS) )
436  #define DEBUG_ACCESS_TIMING 0
437  #else
438  #define DEBUG_ACCESS_TIMING 0
439  #endif
440 #endif
441 
442 #if !defined( DEBUG_IO_TIMING )
443  // test how much cycles it takes for a low level function to execute
444  #if ( defined( DEBUG ) && ( DEBUG >= 10 ) && !defined( MBG_TGT_DOS) )
445  #define DEBUG_IO_TIMING 0 // TODO
446  #else
447  #define DEBUG_IO_TIMING 0
448  #endif
449 #endif
450 
451 #if !defined( DEBUG_IO )
452  // debug which bytes are written to or read from the board
453  #if ( defined( DEBUG ) && !defined( MBG_TGT_DOS ) )
454  #define DEBUG_IO 1
455  #else
456  #define DEBUG_IO 0
457  #endif
458 #endif
459 
460 #if !defined( DEBUG_PORTS )
461  #if defined( DEBUG )
462  #define DEBUG_PORTS 1
463  #else
464  #define DEBUG_PORTS 0
465  #endif
466 #endif
467 
468 #if !defined( DEBUG_SERNUM )
469  #if defined( DEBUG )
470  #define DEBUG_SERNUM 1
471  #else
472  #define DEBUG_SERNUM 0
473  #endif
474 #endif
475 
476 #if !defined( USE_USB_MICRO_FRAMES )
477  #define USE_USB_MICRO_FRAMES 0
478 #endif
479 
480 
481 #if DEBUG_ACCESS_TIMING > 1
482  #define TEST_PORT_ACCESS 1
483 #else
484  #define TEST_PORT_ACCESS 0
485 #endif
486 
487 
488 #if REPORT_CFG || defined( DEBUG )
489  #define MUST_REPORT_PROBE_DEVICE_DETAILS 1
490 #else
491  #define MUST_REPORT_PROBE_DEVICE_DETAILS 0
492 #endif
493 
494 #if REPORT_CFG || DEBUG_RSRC || DEBUG_IO
495  #define MUST_REPORT_ACCESS_MODE 1
496 #else
497  #define MUST_REPORT_ACCESS_MODE 0
498 #endif
499 
500 
501 #if defined( MBG_TGT_KERNEL ) || DEBUG_DEV_INIT
502  #define PCPS_LOG_STD_MSGS 1
503 #else
504  #define PCPS_LOG_STD_MSGS 0
505 #endif
506 
507 
508 
509 // The do_div() macro or inline function has to be used
510 // for 64 bit divisions in Linux kernel mode, so we use a
511 // generic macro _do_div() which uses the Linux function
512 // if required, and just does a simple division otherwise.
513 #if defined ( MBG_TGT_LINUX ) && defined( MBG_TGT_KERNEL )
514  #define _do_div( _x, _y ) do_div( _x, _y )
515 #else
516  #define _do_div( _x, _y ) do { _x /= _y; } while ( 0 )
517 #endif
518 
519 
543 #define MAX_BOOT_TIME_PTP270PEX 27 // [s]
544 
545 
546 #if defined( MBG_TGT_BSD )
547  // Avoid compiler warnings "redundant redeclaration of ..."
548  // e.g. under FreeBSD 8.2 with gcc 4.2.1.
549  #define AVOID_REDUNDANT_REDECLARATION 1
550 #endif
551 
552 
553 
554 // In some environments special far functions are neither
555 // required nor supported, so redefine calls to those functions
556 // to appropriate standard function calls.
557 #if !defined( MBG_TGT_DOS ) && !defined( MBG_TGT_OS2 )
558  #define _fmemcpy( _d, _s, _n ) memcpy( _d, _s, _n )
559  #define _fstrlen( _s ) strlen( _s )
560  #define _fstrncmp( _s1, _s2, _n ) strncmp( (_s1), (_s2), (_n) )
561 #endif
562 
563 #if defined( MBG_TGT_OS2 )
564  #define _fstrncmp( _s1, _s2, _n ) _fmemcmp( (_s1), (_s2), (_n) )
565 
566  // Watcom C Compiler options for the OS/2 device driver result in
567  // warnings if automatic stack addresses are passed to functions.
568  #define static_wc static
569  #define FMT_03X "%X"
570  #define FMT_08X "%X"
571 #else
572  #define static_wc
573  #define FMT_03X "%03X"
574  #define FMT_08X "%08lX"
575 #endif
576 
577 #if defined( MBG_TGT_LINUX )
578  typedef unsigned int PCI_DWORD;
579 #else
580  typedef uint32_t PCI_DWORD;
581 #endif
582 
583 
584 #if defined( MBG_TGT_LINUX )
585 
586  #define _pcps_irq_flags \
587  unsigned long irq_flags;
588 
589  #define _pcps_disb_local_irq_save() \
590  local_irq_save( irq_flags )
591 
592  #define _pcps_local_irq_restore() \
593  local_irq_restore( irq_flags )
594 
595 #elif defined( MBG_TGT_WIN32 )
596 
597  #define _pcps_irq_flags \
598  KIRQL old_irq_lvl;
599 
600  #define _pcps_disb_local_irq_save() \
601  KeRaiseIrql( HIGH_LEVEL, &old_irq_lvl )
602 
603  #define _pcps_local_irq_restore() \
604  KeLowerIrql( old_irq_lvl )
605 
606 #else
607 
608  // Nothing to define here.
609 
610 #endif
611 
612 #if !defined( _pcps_irq_flags ) && \
613  !defined( _pcps_disb_local_irq_save ) && \
614  !defined( _pcps_local_irq_restore)
615  #define _pcps_irq_flags
616  #define _pcps_disb_local_irq_save();
617  #define _pcps_local_irq_restore();
618 #endif
619 
620 
621 #if defined( MBG_TGT_LINUX ) && defined( time_after )
622  #define _pcps_time_after( _curr, _tmo ) \
623  time_after( (unsigned long) _curr, (unsigned long) _tmo )
624 #else
625  #define _pcps_time_after( _curr, _tmo ) ( _curr >= _tmo )
626 #endif
627 
628 
629 #if defined( MBG_TGT_DOS ) || \
630  defined( MBG_TGT_QNX )
631  #define MBG_TGT_HAS_UPTIME 0
632 #elif defined( MBG_TGT_FREEBSD )
633  // Under FreeBSD (at least 8.2) the kernel calls to read uptime always
634  // return 1 when this driver is loaded automatically, so the system
635  // locks up if we wait util uptime has reached a certain value.
636  #define MBG_TGT_HAS_UPTIME 0
637 #else
638  #define MBG_TGT_HAS_UPTIME 1
639 #endif
640 
641 
642 static const char str_empty[] = "";
643 static const char str_unkn_braced[] = "(unknown)";
644 
645 #if DEBUG_IO
646  static const char str_spc_gps[] = " GPS";
647 #endif
648 
649 
650 
662 
663 
664 
688 static uint32_t ri_feat_tbl[N_GPS_FEATURE] =
689 {
690  0,
691  0,
693  0,
695  0,
697  0,
698 
699  0,
700  0,
701  0,
702  0,
703  0,
706  PCPS_HAS_PTP,
707 
708  0,
710  0,
711  0,
712  0,
713  0,
714  0,
716 
717  0,
718  0,
719  0,
720  0,
721  0,
722  0,
723  0
724 };
725 
726 
727 
728 #if REPORT_CFG || REPORT_CFG_DETAILS
729 
734 
735 #endif // REPORT_CFG || REPORT_CFG_DETAILS
736 
737 
738 
739 #if REPORT_CFG
740 
745 
746 #endif // REPORT_CFG
747 
748 
749 
750 #if ( _PCPS_USE_USB || DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING )
751 
752 static const char str_spc_cyc[] = " cyc";
753 static const char str_spc_ns[] = " ns";
754 
755 static __mbg_inline /*HDR*/
764 int64_t pc_cycles_to_ns( MBG_PC_CYCLES cyc, MBG_PC_CYCLES_FREQUENCY freq )
765 {
766  uint64_t tmp = (uint64_t) cyc * 1000000000UL;
767 
768  _do_div( tmp, freq );
769 
770  return tmp;
771 
772 } // pc_cycles_to_ns
773 
774 #endif // ( _PCPS_USE_USB || DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING )
775 
776 
777 
778 static __mbg_inline /*HDR*/
783 {
784  return _pcps_ddev_is_pci( pddev ) &&
785  ( _pcps_ddev_dev_id( pddev ) == PCI_DEV_PTP270PEX );
786 
787 } // pcps_ddev_is_ptp270pex
788 
789 
790 
791 
792 #if defined( MBG_TGT_LINUX )
793 
794 static /*HDR*/
804 int mbg_plx_read_pecs_reg( struct pci_dev *pNode,
805  uint16_t reg, uint32_t *pval )
806 {
807  int pci_rc;
808 
809  if ( reg & 0x03 )
810  return PCI_BAD_REGISTER_NUMB;
811 
812  if ( reg < 0x1000 )
813  {
814  pci_rc = pci_read_config_dword( pNode, reg, pval );
815  }
816  else
817  {
818  uint32_t mcr_idx_sav = (uint32_t) -1;
819 
820  reg -= 0x1000;
821 
822  pci_rc = pci_read_config_dword( pNode, PLX_PECS_MAININDEX, &mcr_idx_sav );
823 
824  if ( pci_rc != PCI_SUCCESS )
825  goto out;
826 
827  pci_rc = pci_write_config_dword( pNode, PLX_PECS_MAININDEX, reg );
828 
829  if ( pci_rc != PCI_SUCCESS )
830  goto out;
831 
832  pci_rc = pci_read_config_dword( pNode, PLX_PECS_MAINDATA, pval );
833 
834  if ( pci_rc != PCI_SUCCESS )
835  goto out;
836 
837  pci_rc = pci_write_config_dword( pNode, PLX_PECS_MAININDEX, mcr_idx_sav );
838  }
839 
840 out:
841  return pci_rc;
842 
843 } // mbg_plx_read_pecs_reg
844 
845 #endif
846 
847 
848 
849 static /*HDR*/
870 {
871  // The GPIO3 input level can only be read via a register
872  // which is located inside the PCI configuration space
873  // of the built-in PLX8111 PCIe-to-PCI bridge.
874  //
875  // So we must first locate the PCI bridge associated with our device,
876  // read the PECS_GPIOCTL register and return 1 if the GPIO3 bit
877  // has been pulled down to 0.
878 
879  uint32_t reg_val = (uint32_t) -1;
880  int pci_rc = -1;
881 
882  #if defined( MBG_TGT_LINUX )
883 
884  struct pci_dev *bridge = NULL;
885 
886  // search for any PLX PCI bridge device
887  while ( ( bridge = pci_get_device( PCI_VENDOR_ID_PLX,
888  PCI_DEVICE_ID_PLX_8111, bridge ) ) != NULL )
889  {
890  uint8_t uc;
891 
892  #if defined( DEBUG )
893  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "Found bridge: %s",
894  pci_name( bridge ) );
895  #endif
896 
897  // Read the secondary bus number.
898  pci_rc = pci_read_config_byte( bridge, 0x19, &uc );
899 
900  if ( ( pci_rc == PCI_SUCCESS ) && ( uc == pddev->dev.cfg.bus_num ) )
901  {
902  #if defined( DEBUG )
903  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "Found bridge associated with device %s",
904  _pcps_ddev_type_name( pddev ) );
905  #endif
906  break;
907  }
908  }
909 
910  if ( bridge ) // associated PCI bridge has been found
911  {
912  pci_rc = mbg_plx_read_pecs_reg( bridge, PLX_PECS_GPIOCTL, &reg_val );
913 
914  #if defined( DEBUG )
915  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "Read cfg dword %04lX: %08lX, rc: %i",
916  (ulong) PLX_PECS_GPIOCTL, (ulong) reg_val, pci_rc );
917  #endif
918 
919  // The pci_get_device() calls above has increased the use count
920  // for the last device which has been found, so we need to decrease
921  // the use count if we don't need to access the device anymore.
922  // This is done by calling the complementary function.
923  pci_dev_put( bridge );
924  }
925 
926  #elif defined( MBG_TGT_WIN32 )
927 
928  // We don't scan the PCI bus to find the associated bridge device
929  // but just assume the card can flag when it's ready. If the card
930  // actually can't then the driver just waits until the maximum
931  // required uptime has been reached or exceeded, so there's no danger
932  // that the system might lock up.
933  pci_rc = PCI_SUCCESS;
934  reg_val = 0;
935 
936  #elif defined( MBG_TGT_DOS )
937 
938  PLX_DEVICE_NODE dn_bridge = { 0 };
939 
940  pci_rc = mbg_find_plx8311_bridge( pddev->dev.cfg.bus_num, &dn_bridge );
941 
942  if ( pci_rc == PCI_SUCCESS )
943  pci_rc = mbg_plx_read_pecs_reg( &dn_bridge, PLX_PECS_GPIOCTL, &reg_val );
944 
945  #else
946 
947  #endif
948 
949  // The device can indicate when it's ready if reg_val
950  // has been read successfully, and the GPIO3 bit is 0.
951  return ( pci_rc == PCI_SUCCESS ) && ( ( reg_val & PLX_PECS_GPIOCTL_GPIO3_DATA ) == 0 );
952 
953 } // ptp270pex_can_flag_ready
954 
955 
956 
957 static /*HDR*/
980 {
981  // GPIO pin USERI is pulled down to 0 by the firmware
982  // as soon as the card is ready to be accessed.
983  // With PTP270PEX HW v1 cards this pin is always 1.
984 
985  // Read the LCS_CNTRL register and return 1 if the USERI
986  // bit is set.
987 
988  MBG_IOPORT_ADDR_MAPPED cntrl_reg = _pcps_ddev_io_base_mapped( pddev, 1 )
989  + PLX_LCS_CNTRL;
990  uint32_t reg_val = _mbg_inp32_to_cpu( pddev, 0, cntrl_reg );
991 
992  return ( reg_val & PLX_LCS_CNTRL_USERI ) == 0;
993 
994 } // ptp270pex_has_flagged_ready
995 
996 
997 
998 #if MBG_TGT_HAS_UPTIME
999 
1000 static /*HDR*/
1011 void report_uptime( const MBG_SYS_UPTIME *p_uptime )
1012 {
1013  #if defined( MBG_TGT_WIN32 )
1014  _mbg_kdd_msg_2( MBG_LOG_INFO, "System uptime: %" PRIi64 " s, required %u s",
1015  (int64_t) *p_uptime, MAX_BOOT_TIME_PTP270PEX );
1016  #else
1017 
1018  char ws[120];
1019  int l = sizeof( ws );
1020  int n = 0;
1021 
1022  n += snprintf( &ws[n], l - n, "System uptime " );
1023 
1024  #if defined( MBG_TGT_LINUX )
1025  n += snprintf( &ws[n], l - n, "%llu jiffies -> ",
1026  (unsigned long long) ( get_jiffies_64() - INITIAL_JIFFIES ) );
1027  #endif
1028 
1029  n += snprintf( &ws[n], l - n, "%llu", (unsigned long long) *p_uptime );
1030  n += snprintf( &ws[n], l - n, " s, required %u s", MAX_BOOT_TIME_PTP270PEX );
1031 
1032  if ( *p_uptime < MAX_BOOT_TIME_PTP270PEX )
1033  {
1034  int waiting = (int) ( MAX_BOOT_TIME_PTP270PEX - *p_uptime );
1035  n += snprintf( &ws[n], l - n, ", waiting %i s", waiting );
1036  }
1037  else
1038  n += snprintf( &ws[n], l - n, ", OK." );
1039 
1040  _mbg_kdd_msg_1( MBG_LOG_INFO, "%s", ws );
1041 
1042  #endif
1043 
1044 } // report_uptime
1045 
1046 #endif // MBG_TGT_HAS_UPTIME
1047 
1048 
1049 
1050 static /*HDR*/
1065 void wait_ptp270pex_ready( const PCPS_DDEV *pddev )
1066 {
1067  MBG_SYS_TIME t1;
1068  MBG_SYS_TIME t2;
1069  MBG_SYS_UPTIME uptime;
1070  int delayed = 0;
1071  bool can_flag_ready;
1072  int i = 0;
1073 
1074  // A newer PTP270PEX card (HW v2.0) can indicate if it has
1075  // finished booting and thus is ready to be accessed, but
1076  // older PTP270PEX cards (HW v1.0) don't support this.
1077  can_flag_ready = ptp270pex_can_flag_ready( pddev );
1078 
1079  mbg_get_sys_time( &t1 );
1080 
1081  for (;;)
1082  {
1083  mbg_get_sys_uptime( &uptime );
1084 
1085  #if MBG_TGT_HAS_UPTIME
1086  #if !defined( DEBUG )
1087  if ( delayed )
1088  #endif
1089  report_uptime( &uptime );
1090  #endif
1091 
1092  if ( can_flag_ready )
1093  {
1094  bool b = ptp270pex_has_flagged_ready( pddev );
1095 
1096  if ( b )
1097  break;
1098  }
1099 
1100  // If the card is unable to indicate when it is ready
1101  // and the target system doesn't support uptime
1102  // then it makes no sense to keep looping and waiting,
1103  // so just stop waiting and hope the card is ready.
1104  if ( uptime == 0 || uptime == -1 )
1105  break; // assume uptime not supported
1106 
1107  // If the target system supports uptime then
1108  // keep looping until the system uptime exceeds
1109  // the max. boot time required by the card.
1110 
1111  if ( uptime >= MAX_BOOT_TIME_PTP270PEX )
1112  break;
1113 
1114  mbg_sleep_sec( 1 );
1115  delayed = 1;
1116 
1117  if ( ++i >= MAX_BOOT_TIME_PTP270PEX )
1118  break;
1119  }
1120 
1121  if ( delayed )
1122  {
1123  long dt;
1124 
1125  mbg_get_sys_time( &t2 );
1126 
1127  dt = mbg_delta_sys_time_ms( &t2, &t1 );
1128 
1129  _mbg_kdd_msg_2( MBG_LOG_INFO, "PTP270PEX startup delay: %li.%03li s",
1130  dt / 1000, ( ( dt < 0 ) ? -dt : dt ) % 1000 );
1131  }
1132 
1133 } // wait_ptp270pex_ready
1134 
1135 
1136 
1137 static /*HDR*/
1153  uint8_t req_asic_ver_major, uint8_t req_asic_ver_minor )
1154 {
1155  bool b = !_pcps_pex_irq_is_safe( _pcps_ddev_fw_rev_num( pddev ), req_fw_ver,
1156  _pcps_ddev_asic_version( pddev ),
1157  req_asic_ver_major, req_asic_ver_minor );
1158 
1159  if ( b )
1160  {
1162 
1163  // Prevent the driver from writing IRQ ACK to the card even if IRQs
1164  // should be unintentionally enabled.
1165  pddev->irq_ack_port = 0;
1166  pddev->irq_ack_mask = 0;
1167  }
1168 
1169  return b;
1170 
1171 } // pcps_check_pex_irq_unsafe
1172 
1173 
1174 
1175 static /*HDR*/
1184 {
1185  PCPS_MM_LAYOUT FAR *mm_addr = (PCPS_MM_LAYOUT FAR *) pddev->rsrc_info.mem[0].start_mapped;
1186 
1187  pddev->mm_asic_addr = NULL;
1188  pddev->mm_tstamp_addr = NULL;
1189 
1190  if ( _pcps_ddev_is_pci_mbgpex( pddev ) )
1191  {
1192  pddev->mm_asic_addr = &mm_addr->mbgpex.asic;
1193  pddev->mm_tstamp_addr = &mm_addr->mbgpex.tstamp;
1194  }
1195  else
1196  if ( _pcps_ddev_is_pci_pex8311( pddev ) )
1197  {
1198  pddev->mm_asic_addr = &mm_addr->pex8311.asic;
1199  pddev->mm_tstamp_addr = &mm_addr->pex8311.tstamp;
1200  }
1201 
1202  #if DEBUG_RSRC
1203  _mbg_kdd_msg_1( MBG_LOG_INFO, "MM base addr: %p", mm_addr );
1204  _mbg_kdd_msg_1( MBG_LOG_INFO, "MM ASIC addr: %p", pddev->mm_asic_addr );
1205  _mbg_kdd_msg_1( MBG_LOG_INFO, "MM tstamp addr: %p", pddev->mm_tstamp_addr );
1206  _mbg_kdd_msg_1( MBG_LOG_INFO, "MM tstamp offs: 0x%02lX",
1207  (ulong) ( (uint8_t *) pddev->mm_tstamp_addr - (uint8_t *) mm_addr ) );
1208  #endif
1209 
1210  return MBG_SUCCESS;
1211 
1212 } // setup_mm_addr
1213 
1214 
1215 
1216 #if defined( DEBUG )
1217 
1218 /*HDR*/
1219 void pcps_dump_data( const void *buffer, size_t count, const char *info )
1220 {
1221  const uint8_t *p = (const uint8_t *) buffer;
1222  size_t i = 0;
1223 
1224  while ( i < count )
1225  {
1226  char ws[80];
1227  const char *cp = (const char *) p;
1228  int j;
1229  int n = 0;
1230  ws[0] = 0;
1231 
1232  for ( j = 0; j < 4; )
1233  {
1234  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n, " %02X", *p++ );
1235 
1236  j++;
1237 
1238  if ( ++i >= count )
1239  break;
1240  }
1241 
1242  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n, " \"" );
1243 
1244  while ( j > 0 )
1245  {
1246  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n, "%c",
1247  ( ( *cp >= ' ' ) && ( *cp < 0x7F ) ) ? *cp : '#' );
1248  cp++;
1249  j--;
1250  }
1251 
1252  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n, "\"" );
1253 
1254  _mbg_kdd_msg_2( MBG_LOG_INFO, "%s:%s", info, ws );
1255  }
1256 
1257 } // pcps_dump_data
1258 
1259 #endif // defined( DEBUG )
1260 
1261 
1262 
1263 #if DEBUG_IO
1264 
1265 static /*HDR*/
1266 void report_io_cmd( uint8_t cmd, uint16_t count, const char *info )
1267 {
1268  _mbg_kdd_msg_4( MBG_LOG_DEBUG, "%s: cmd: 0x%02X (0x%08X), cnt: %u",
1269  info, cmd, _cpu_to_mbg32( cmd ), count );
1270 
1271 } // report_io_cmd
1272 
1273 #endif // DEBUG_IO
1274 
1275 
1276 
1277 #if DEBUG_ACCESS_TIMING
1278 
1279 static uint32_t debug_dummy_var;
1280 
1281 
1282 static /*HDR*/
1293 void report_access_timing( const PCPS_DDEV *pddev, const char *info,
1294  MBG_PC_CYCLES t_after_cmd, MBG_PC_CYCLES t_after_reread )
1295 {
1296  #define _FMT "%s %s: %" PRIi64 "/%" PRIi64 "%s"
1297 
1298  int64_t delta_cyc_write = t_after_cmd - pddev->acc_cycles;
1299  int64_t delta_cyc_read = t_after_reread ? ( t_after_reread - t_after_cmd ) : 0;
1300 
1302  info, delta_cyc_write, delta_cyc_read, str_spc_cyc );
1303 
1304  // We can only report time intervals
1305  // if we know the cycles frequency.
1306  if ( pc_cycles_frequency )
1307  {
1308  int64_t delta_t_write = pc_cycles_to_ns( delta_cyc_write, pc_cycles_frequency );
1309  int64_t delta_t_read = pc_cycles_to_ns( delta_cyc_read, pc_cycles_frequency );
1310 
1312  info, delta_t_write, delta_t_read, str_spc_ns );
1313  }
1314 
1315  #undef _FMT
1316 
1317 } // report_access_timing
1318 
1319 
1320 
1321 #if TEST_PORT_ACCESS
1322 
1323 static /*HDR*/
1333 void report_delta_time( const char *info, MBG_PC_CYCLES t1, MBG_PC_CYCLES t2 )
1334 {
1335  #define _FMT "%s: %" PRIi64 "%s"
1336 
1337  int64_t delta_cyc = t2 - t1;
1338 
1339  _mbg_kdd_msg_3( MBG_LOG_DEBUG, _FMT, info, delta_cyc, str_spc_cyc );
1340 
1341  // We can only report time intervals
1342  // if we know the cycles frequency.
1343  if ( pc_cycles_frequency )
1344  {
1345  int64_t delta_t = pc_cycles_to_ns( delta_cyc, pc_cycles_frequency );
1346 
1347  _mbg_kdd_msg_3( MBG_LOG_DEBUG, _FMT, info, delta_t, str_spc_ns );
1348  }
1349 
1350  #undef _FMT
1351 
1352 } // report_delta_time
1353 
1354 
1355 
1356 volatile uint8_t dummy_u8;
1357 volatile uint16_t dummy_u16;
1358 volatile uint32_t dummy_u32;
1359 
1360 static /*HDR*/
1366 void test_port_access( const PCPS_DDEV *pddev )
1367 {
1368  MBG_PC_CYCLES t1;
1369  MBG_PC_CYCLES t2;
1370 
1371  // FIXME TODO This specific test function may need some review.
1372 
1373  if ( _pcps_ddev_is_usb( pddev ) ||
1374  _pcps_ddev_is_pci_s5920( pddev ) )
1375  {
1376  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "Skipping port access tests for %s.",
1377  _pcps_ddev_type_name( pddev ) );
1378  return;
1379  }
1380 
1381  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "Running port access tests for %s.",
1382  _pcps_ddev_type_name( pddev ) );
1383 
1384 
1385 
1386  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "I/O status port: %lX",
1387  (ulong) pddev->status_port );
1388 
1389  mbg_get_pc_cycles( &t1 );
1390  dummy_u8 = _mbg_inp8( pddev, 0, pddev->status_port );
1391  mbg_get_pc_cycles( &t2 );
1392 
1393 
1394  mbg_get_pc_cycles( &t1 );
1395  dummy_u16 = _mbg_inp16( pddev, 0, pddev->status_port );
1396  mbg_get_pc_cycles( &t2 );
1397 
1398  report_delta_time( "16 bit read I/O status port", t1, t2 );
1399 
1400  mbg_get_pc_cycles( &t1 );
1401  dummy_u32 = _mbg_inp32_to_cpu( pddev, 0, pddev->status_port );
1402  mbg_get_pc_cycles( &t2 );
1403 
1404  report_delta_time( "32 bit read I/O status port", t1, t2 );
1405 
1406 
1407  #if MBG_TGT_SUPP_MEM_ACC
1408 
1409  if ( has_mapped_sys_virtual_address( pddev ) )
1410  {
1411  // Explicitly write to a memory mapped address
1412  // pddev->mm_asic_addr->pci_data.ul = cmd;
1413 
1414  // Explicitly read from a memory mapped address
1415  // debug_dummy_var = pddev->mm_asic_addr->pci_data.ul;
1416  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "MM status port: %p",
1417  &pddev->mm_asic_addr->status_port.ul );
1418 
1419  mbg_get_pc_cycles( &t1 );
1420  dummy_u8 = pddev->mm_asic_addr->pci_data.b[0];
1421  mbg_get_pc_cycles( &t2 );
1422 
1423  report_delta_time( "8 bit read MM status port", t1, t2 );
1424 
1425  mbg_get_pc_cycles( &t1 );
1426  dummy_u16 = pddev->mm_asic_addr->pci_data.us[0];
1427  mbg_get_pc_cycles( &t2 );
1428 
1429  report_delta_time( "16 bit read MM status port", t1, t2 );
1430 
1431  mbg_get_pc_cycles( &t1 );
1432  dummy_u32 = pddev->mm_asic_addr->pci_data.ul;
1433  mbg_get_pc_cycles( &t2 );
1434 
1435  report_delta_time( "32 bit read MM status port", t1, t2 );
1436  }
1437  else
1438  _mbg_kdd_msg_0( MBG_LOG_DEBUG, "MM registers not mapped." );
1439 
1440  #else
1441  _mbg_kdd_msg_0( MBG_LOG_DEBUG, "Memory mapping not supported for this target." );
1442  #endif
1443 
1444 } // test_port_access
1445 
1446 #endif // TEST_PORT_ACCESS
1447 
1448 #endif // DEBUG_ACCESS_TIMING
1449 
1450 
1451 
1452 #if DEBUG_IO_TIMING
1453 
1454 static /*HDR*/
1468 void report_io_timing( const PCPS_DDEV *pddev, const char *info,
1469  uint8_t cmd, uint16_t count, MBG_PC_CYCLES t_after_cmd,
1470  MBG_PC_CYCLES t_after_busy, MBG_PC_CYCLES t_done )
1471 {
1472  #define _FMT_1 "%s %s cmd: 0x%02X (%u bytes)"
1473  #define _FMT_2 "write %" PRIi64 "%s, busy: %" PRIi64 "%s, read: %" PRIi64 "/%" PRIi64 "%s"
1474 
1475  int64_t cmd_cycles = t_after_cmd - pddev->acc_cycles;
1476  int64_t busy_cycles = t_after_busy - t_after_cmd;
1477  int64_t read_cycles = t_done - t_after_busy;
1478  uint64_t cycles_per_read = 0;
1479 
1480  if ( count )
1481  {
1482  cycles_per_read = read_cycles;
1483  _do_div( cycles_per_read, count );
1484  }
1485 
1487  info, cmd, count );
1488 
1489  _mbg_kdd_msg_7( MBG_LOG_DEBUG, _FMT_2, cmd_cycles, str_spc_cyc, busy_cycles,
1490  str_spc_cyc, read_cycles, cycles_per_read, str_spc_cyc );
1491 
1492  // We can only report time intervals
1493  // if we know the cycles frequency.
1494  if ( pc_cycles_frequency )
1495  {
1496  int64_t cmd_time = pc_cycles_to_ns( cmd_cycles, pc_cycles_frequency );
1497  int64_t busy_time = pc_cycles_to_ns( busy_cycles, pc_cycles_frequency );
1498  int64_t read_time = pc_cycles_to_ns( read_cycles, pc_cycles_frequency );
1499  uint64_t time_per_read = 0;
1500 
1501  if ( count )
1502  {
1503  time_per_read = read_time;
1504  _do_div( time_per_read, count );
1505  }
1506 
1507  _mbg_kdd_msg_7( MBG_LOG_DEBUG, _FMT_2, cmd_time, str_spc_ns, busy_time,
1508  str_spc_ns, read_time, cycles_per_read, str_spc_ns );
1509  }
1510 
1511  #if 0 && defined( MBG_TGT_LINUX ) // ###
1512  _mbg_kdd_msg_3( MBG_LOG_INFO, "Cycles after cmd: %lli, after busy: %lli, when done: %lli",
1513  (long long) t_after_cmd,
1514  (long long) t_after_busy,
1515  (long long) t_done );
1516  #endif
1517 
1518  #undef _FMT_1
1519  #undef _FMT_2
1520 
1521 } // report_io_timing
1522 
1523 #endif // DEBUG_IO_TIMING
1524 
1525 
1526 
1527 #if defined( DEBUG )
1528 
1529 static /*HDR*/
1536 void report_ret_val( int rc, const char *info )
1537 {
1538  if ( mbg_rc_is_error( rc ) )
1539  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: FAILED, rc %i: %s",
1540  info, rc, mbg_strerror( rc ) );
1541  #if DEBUG_IO
1542  else
1543  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "%s: success, rc %i",
1544  info, rc );
1545  #endif
1546 
1547 } // report_ret_val
1548 
1549 #endif // defined( DEBUG )
1550 
1551 
1552 
1553 #if _PCPS_USE_USB
1554 
1555 static /*HDR*/
1563 int check_usb_timing( PCPS_DDEV *pddev )
1564 {
1565  int rc = MBG_SUCCESS;
1566 
1567  if ( _pcps_ddev_has_hr_time( pddev ) )
1568  {
1569  #if USE_LOCAL_IO_BUFFER
1570  PCPS_HR_TIME hrt;
1571  PCPS_HR_TIME *p_hrt = &hrt;
1572  #else
1573  PCPS_HR_TIME *p_hrt = &pddev->io_buffer.pcps_hr_time;
1574  #endif
1575 
1576  #define _FMT "USB access: %" PRIi64 "%s"
1577 
1578  MBG_PC_CYCLES completion_cycles;
1579  int64_t delta_cycles;
1580 
1581  #if defined( DEBUG )
1582  _mbg_kdd_msg_0( MBG_LOG_DEBUG, "Reading PCPS_HR_TIME as USB timing test:" );
1583  #endif
1584 
1585  // Determine USB access time. The first cycles value is taken
1586  // by the low level routine and saved in pddev->acc_cycles.
1587  rc = _pcps_read_var( pddev, PCPS_GIVE_HR_TIME, *p_hrt );
1588  mbg_get_pc_cycles( &completion_cycles );
1589 
1590  if ( mbg_rc_is_error( rc ) )
1591  goto out;
1592 
1593 
1594  delta_cycles = mbg_delta_pc_cycles( &completion_cycles, &pddev->acc_cycles );
1595 
1596  #if defined( DEBUG )
1597  _mbg_kdd_msg_2( MBG_LOG_DEBUG, _FMT, delta_cycles, str_spc_cyc );
1598  #endif
1599 
1600  // We can only deal with time intervals
1601  // if we know the cycles frequency.
1602  if ( pc_cycles_frequency )
1603  {
1604  int64_t delta_t_ns = pc_cycles_to_ns( delta_cycles, pc_cycles_frequency );
1605  // If access time is below 1 ms then 125 us microframe timing
1606  // introduced with USB 2.0 is supported.
1607  pddev->usb_20_mode = delta_t_ns < 1000000UL;
1608 
1609  #if defined( DEBUG )
1610  _mbg_kdd_msg_2( MBG_LOG_DEBUG, _FMT, delta_t_ns, str_spc_ns );
1611  #endif
1612  }
1613 
1614  #if MUST_REPORT_PROBE_DEVICE_DETAILS
1615  _mbg_kdd_msg_1( MBG_LOG_INFO, "USB microframe timing%s detected.",
1616  pddev->usb_20_mode ? str_empty : " NOT" );
1617  #endif
1618 
1619  #undef _FMT
1620  }
1621 
1622 out:
1623  if ( mbg_rc_is_error( rc ) )
1625 
1626  return rc;
1627 
1628 } // check_usb_timing
1629 
1630 
1631 
1632 static /*HDR*/
1648 int pcps_read_usb_generic( PCPS_DDEV *pddev, uint8_t cmd,
1649  void FAR *buffer, uint16_t count, bool is_gps_data )
1650 {
1651  int rc;
1652  int transfer_size;
1653 
1654  #if defined( MBG_TGT_WIN32_PNP )
1655  int this_frame_num_1;
1656  int this_frame_num_2;
1657  LARGE_INTEGER UsbPreCount;
1658  LARGE_INTEGER UsbPostCount;
1659  #endif
1660 
1661  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
1662  MBG_PC_CYCLES t_after_cmd = 0;
1663  #endif
1664 
1665  #if DEBUG_IO_TIMING
1666  MBG_PC_CYCLES t_after_busy = 0;
1667  MBG_PC_CYCLES t_done = 0;
1668  #endif
1669 
1670  mbg_get_pc_cycles( &pddev->acc_cycles );
1671 
1672  // We write the request data to our device's private data structure,
1673  // so we don't have to explicitly allocate a buffer here.
1674  if ( is_gps_data )
1675  {
1677  pddev->cmd_info.gps_cmd_info.gps_cmd = cmd;
1678  transfer_size = sizeof( pddev->cmd_info.gps_cmd_info );
1679  }
1680  else
1681  {
1682  pddev->cmd_info.cmd = cmd;
1683  transfer_size = sizeof( pddev->cmd_info.cmd );
1684  }
1685 
1686  rc = pcps_direct_usb_write( pddev, &pddev->cmd_info, transfer_size );
1687 
1688  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
1689  mbg_get_pc_cycles( &t_after_cmd );
1690  #endif
1691 
1692  #if DEBUG_IO_TIMING
1693  t_after_busy = t_after_cmd;
1694  #endif
1695 
1696  if ( mbg_rc_is_error( rc ) )
1697  {
1698  #if defined( DEBUG )
1699  if ( is_gps_data )
1700  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: GPS cmd 0x%02X: failed with rc %i",
1701  __func__, pddev->cmd_info.gps_cmd_info.gps_cmd, rc );
1702  else
1703  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: cmd 0x%02X: failed with rc %i",
1704  __func__, pddev->cmd_info.cmd, rc );
1705  #endif
1706 
1707  goto out;
1708  }
1709 
1710 
1711  #if DEBUG_IO
1712  if ( is_gps_data )
1713  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "%s: GPS write 0x%02X succeeded, %i bytes read",
1714  __func__, pddev->cmd_info.gps_cmd_info.gps_cmd, rc );
1715  else
1716  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "%s: write 0x%02X succeeded, %i bytes read",
1717  __func__, pddev->cmd_info.cmd, rc );
1718  #endif // DEBUG_IO
1719 
1720 
1721  if ( buffer == NULL || count == 0 ) // no data need to be read
1722  {
1723  #if DEBUG_IO
1724  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "%s: no data to be read, exiting", __func__ );
1725  #endif // DEBUG_IO
1726 
1727  goto out;
1728  }
1729 
1730 
1731  #if defined( MBG_TGT_WIN32_PNP )
1732  #if USE_USB_MICRO_FRAMES
1733  this_frame_num_1 = micro_frame_num_1 ? micro_frame_num_1 : frame_num_1;
1734  this_frame_num_2 = micro_frame_num_2 ? micro_frame_num_2 : frame_num_2;
1735  #else
1736  this_frame_num_1 = frame_num_1;
1737  this_frame_num_2 = frame_num_2;
1738  #endif
1739 
1740  UsbPreCount = Count1;
1741  UsbPostCount = Count2;
1742  #endif
1743 
1744  rc = pcps_direct_usb_read( pddev, buffer, count );
1745 
1746  if ( mbg_rc_is_error( rc ) )
1747  {
1748  #if defined( DEBUG )
1749  if ( is_gps_data )
1750  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: rd after GPS cmd 0x%02X failed with rc %i",
1751  __func__, pddev->cmd_info.gps_cmd_info.gps_cmd, rc );
1752  else
1753  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: rd after cmd 0x%02X failed with rc %i",
1754  __func__, pddev->cmd_info.cmd, rc );
1755  #endif
1756 
1757  goto out;
1758  }
1759 
1760  #if DEBUG_IO
1761  if ( is_gps_data )
1762  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "%s: rd after GPS cmd 0x%02X succeeded, bytes read: %i",
1763  __func__, pddev->cmd_info.gps_cmd_info.gps_cmd, rc );
1764  else
1765  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "%s: rd after cmd 0x%02X succeeded, bytes read: %i",
1766  __func__, pddev->cmd_info.cmd, rc );
1767 
1768  pcps_dump_data( buffer, rc, __func__ );
1769  #endif
1770 
1771 
1772  // "rc" should now contain the number of bytes that have been read,
1773  // and this should match "count".
1774  if ( rc != count )
1775  {
1776  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: rcvd. %d != exp. %d",
1777  __func__, rc, count );
1778  rc = MBG_ERR_NBYTES;
1779  goto out;
1780  }
1781 
1782 
1783  #if defined( MBG_TGT_WIN32_PNP )
1784 
1785  if ( cmd == PCPS_GIVE_HR_TIME )
1786  {
1787  ULONGLONG usb_latency_cycles;
1788  ULONGLONG cycles_diff;
1789  ULONGLONG time_diff;
1790  ULONGLONG frame_length_cycles;
1791  int FrameNumberDiff;
1792 
1793  #if !USE_USB_MICRO_FRAMES
1794  if ( pddev->usb_20_mode )
1795  {
1796  // Use USB 2.0 microframe timing.
1797  // Just add an offset to compensate constant latency.
1798  // This value has been determined experimentally on different hardware platforms
1799  usb_latency_cycles = ( (ULONGLONG) PerfFreq.QuadPart ) / 20000UL; // represents 50 us
1800  }
1801  else
1802  #endif
1803  {
1804  // USB 1.1 mode with millisecond timing.
1805  // Compensate latency to millisecond frame boundaries.
1806 
1807  if ( ( this_frame_num_2 - this_frame_num_1 ) < 0 )
1808  FrameNumberDiff = 2;
1809  else
1810  FrameNumberDiff = this_frame_num_2 - this_frame_num_1;
1811 
1812  cycles_diff = (ULONGLONG) ( UsbPostCount.QuadPart - UsbPreCount.QuadPart );
1813 
1814  #if USE_USB_MICRO_FRAMES
1815  if ( micro_frame_num_1 > 0 || micro_frame_num_2 > 0 )
1816  frame_length_cycles = (ULONGLONG) ( (ULONGLONG) PerfFreq.QuadPart ) / 8000UL;
1817  else
1818  frame_length_cycles = (ULONGLONG) ( (ULONGLONG) PerfFreq.QuadPart ) / 1000UL;
1819  #else
1820  frame_length_cycles = (ULONGLONG) ( (ULONGLONG) PerfFreq.QuadPart ) / 1000UL;
1821  #endif
1822 
1823  if ( ( this_frame_num_1 == 0 ) && ( this_frame_num_2 == 0 ) )
1824  {
1825  if ( cycles_diff > frame_length_cycles )
1826  usb_latency_cycles = cycles_diff - frame_length_cycles;
1827  else
1828  usb_latency_cycles = frame_length_cycles - cycles_diff;
1829  }
1830  else
1831  usb_latency_cycles = cycles_diff - ( ( FrameNumberDiff - 1 ) * frame_length_cycles );
1832 
1833  #if defined( DEBUG )
1834  _mbg_kdd_msg_4( MBG_LOG_DEBUG, "FD %d CD %" PRIu64 " l %" PRIu64 " fl %" PRIu64, FrameNumberDiff,
1835  cycles_diff, usb_latency_cycles, frame_length_cycles );
1836  #endif
1837  }
1838 
1839  pddev->acc_cycles += usb_latency_cycles;
1840  }
1841  #endif // defined( MBG_TGT_WIN32_PNP )
1842 
1843 out:
1844  #if DEBUG_IO_TIMING
1845  mbg_get_pc_cycles( &t_done );
1846  report_io_timing( pddev, is_gps_data ? "USB GPS" : "USB", cmd, count, t_after_cmd, t_after_busy, t_done );
1847  #endif
1848 
1849  #if DEBUG_ACCESS_TIMING
1850  report_access_timing( pddev, "USB wr/rd", t_after_cmd, 0 );
1851  #endif
1852 
1853  #if defined( DEBUG )
1854  report_ret_val( rc, __func__ );
1855  #endif
1856 
1857  return rc;
1858 
1859 } // pcps_read_usb_generic
1860 
1861 
1862 
1863 static /*HDR*/
1881 int pcps_write_usb_generic( PCPS_DDEV *pddev, uint8_t cmd,
1882  const void FAR *buffer, uint16_t count, bool is_gps_data )
1883 {
1884  int rc;
1885  int buf_size = ( 2 * sizeof( cmd ) ) + count; // Size of the buffer to allocate: Actually for one
1886  // of the PCPS_CMD_CODES, plus eventually one of the
1887  // PC_GPS_CMD_CODES, plus number of data bytes to transfer.
1888  uint8_t *p = _pcps_kmalloc( buf_size );
1889  uint8_t *pb; // Will point into the allocated buffer.
1890  int transfer_bytes;
1891 
1892  if ( p == NULL )
1893  {
1894  rc = MBG_ERR_NO_MEM;
1895  _mbgddmsg_1( DEBUG, MBG_LOG_ERR, "%s: memory allocation failed", __func__ );
1896  goto out;
1897  }
1898 
1899 
1900  pb = p; // point to start of the allocated buffer
1901 
1902  if ( is_gps_data )
1903  {
1904  *pb++ = PCPS_WRITE_GPS_DATA; // first byte is a specific command code
1905  *pb++ = cmd; // next the cmd, which is actually the data type, one of the PC_GPS_CMD_CODES
1906  transfer_bytes = 2;
1907  }
1908  else
1909  {
1910  *pb++ = cmd; // only the actual cmd code, one of the PCPS_CMD_CODES
1911  transfer_bytes = 1;
1912  }
1913 
1914  #if DEBUG_IO
1915  _mbg_kdd_msg_4( MBG_LOG_DEBUG, "%s:%s cmd %02X, %u bytes",
1916  __func__, is_gps_data ? str_spc_gps : str_empty, cmd, count );
1917  pcps_dump_data( buffer, count, __func__ );
1918  #endif
1919 
1920  // Now append the data bytes.
1921  memcpy( pb, buffer, count );
1922  transfer_bytes += count;
1923 
1924  rc = pcps_direct_usb_write( pddev, p, transfer_bytes );
1925 
1926  if ( mbg_rc_is_error( rc ) )
1927  {
1928  _mbgddmsg_3( DEBUG, MBG_LOG_ERR, "%s: write failed: %s (rc: %i)",
1929  __func__, mbg_strerror( rc ), rc );
1930  goto out_free;
1931  }
1932 
1933  // Read the completion code.
1934  rc = pcps_direct_usb_read( pddev, p, 1 );
1935 
1936  if ( mbg_rc_is_error( rc ) )
1937  {
1938  _mbgddmsg_3( DEBUG, MBG_LOG_ERR, "%s: read completion code failed: %s (rc: %i)",
1939  __func__, mbg_strerror( rc ), rc );
1940 
1941  goto out_free;
1942  }
1943 
1944  rc = (int8_t) p[0]; // return the completion code read from the device
1945 
1946 out_free:
1947  _pcps_kfree( p, buf_size );
1948 
1949 out:
1950  #if defined( DEBUG )
1951  report_ret_val( rc, __func__ );
1952  #endif
1953 
1954  return rc;
1955 
1956 } // pcps_write_usb_generic
1957 
1958 #endif // _PCPS_USE_USB
1959 
1960 
1961 
1962 #if defined( __GNUC__ )
1963 // Avoid "no previous prototype" with some gcc versions.
1964 __mbg_inline
1965 int pcps_wait_busy( PCPS_DDEV *pddev );
1966 #endif
1967 
1968 __mbg_inline /*HDR*/
1982 {
1983  if ( _pcps_ddev_status_busy( pddev ) )
1984  {
1985  #if defined( MBG_TGT_BSD )
1986  struct timeval tv_start;
1987 
1988  getmicrouptime( &tv_start );
1989 
1990  while ( _pcps_ddev_status_busy( pddev ) )
1991  {
1992  struct timeval tv_now;
1993  long long delta_ms;
1994 
1995  getmicrouptime( &tv_now );
1996  delta_ms = ( ( tv_now.tv_sec - tv_start.tv_sec ) * 1000 )
1997  + ( ( tv_now.tv_usec - tv_start.tv_usec ) / 1000 );
1998  if ( delta_ms > _pcps_ddev_timeout_clk( pddev ) )
1999  return MBG_ERR_TIMEOUT;
2000  }
2001  #elif _PCPS_USE_CLOCK_TICK
2002  clock_t timeout_val = clock() + _pcps_ddev_timeout_clk( pddev );
2003 
2004  while ( _pcps_ddev_status_busy( pddev ) )
2005  if ( _pcps_time_after( clock(), timeout_val ) )
2006  return MBG_ERR_TIMEOUT;
2007  #else
2008  long cnt = _pcps_ddev_timeout_clk( pddev );
2009 
2010  for ( ; _pcps_ddev_status_busy( pddev ); cnt-- )
2011  if ( cnt == 0 )
2012  return MBG_ERR_TIMEOUT;
2013  #endif
2014  }
2015 
2016  return MBG_SUCCESS;
2017 
2018 } // pcps_wait_busy
2019 
2020 
2021 
2042 static /*HDR*/
2060  void FAR *buffer, uint16_t count )
2061 {
2062  // avoid compiler warnings
2063  (void) pddev;
2064  (void) cmd;
2065  (void) buffer;
2066  (void) count;
2067 
2068  return MBG_ERR_TIMEOUT;
2069 
2070 } // pcps_read_null
2071 
2072 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2074 #endif
2075 
2076 
2077 static /*HDR*/
2092  void FAR *buffer, uint16_t count )
2093 {
2094  uint8_t FAR *p = (uint8_t FAR *) buffer;
2096  int i;
2097  int rc;
2099 
2100  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2101  MBG_PC_CYCLES t_after_cmd = 0;
2102  #endif
2103 
2104  #if DEBUG_ACCESS_TIMING
2105  MBG_PC_CYCLES t_after_reread = 0;
2106  #endif
2107 
2108  #if DEBUG_IO_TIMING
2109  MBG_PC_CYCLES t_after_busy = 0;
2110  MBG_PC_CYCLES t_done = 0;
2111  #endif
2112 
2113  #if DEBUG_IO
2114  report_io_cmd( cmd, count, "pcps_read_amcc_std" );
2115  #endif
2116 
2117 
2119 
2120  // get current cycles and write the command byte
2121  mbg_get_pc_cycles( &pddev->acc_cycles );
2122  _mbg_outp8( pddev, 0, port, cmd );
2123 
2124  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2125  mbg_get_pc_cycles( &t_after_cmd );
2126  #endif
2127 
2128  #if DEBUG_ACCESS_TIMING
2129  debug_dummy_var = _pcps_ddev_read_status_port( pddev );
2130  mbg_get_pc_cycles( &t_after_reread );
2131  #endif
2132 
2134 
2135 
2136  // wait until BUSY flag goes low or timeout
2137  rc = pcps_wait_busy( pddev );
2138 
2139  #if DEBUG_IO_TIMING
2140  mbg_get_pc_cycles( &t_after_busy );
2141  #endif
2142 
2143  if ( mbg_rc_is_error( rc ) )
2144  goto out;
2145 
2146 
2147  // success: read data, if required
2148 
2149  for ( i = 0; i < count; i++ )
2150  {
2151  *p = _mbg_inp8( pddev, 0, port );
2152 
2153  #if DEBUG_IO
2154  pcps_dump_data( p, sizeof( *p ), "pcps_read_std" );
2155  #endif
2156 
2157  p++;
2158  }
2159 
2160 
2161 out:
2162  #if DEBUG_IO_TIMING
2163  mbg_get_pc_cycles( &t_done );
2164  report_io_timing( pddev, "STD", cmd, count, t_after_cmd, t_after_busy, t_done );
2165  #endif
2166 
2167  #if DEBUG_ACCESS_TIMING
2168  report_access_timing( pddev, "STD wr/rd", t_after_cmd, t_after_reread );
2169  #endif
2170 
2171  #if defined( DEBUG )
2172  report_ret_val( rc, "pcps_read_std" );
2173  #endif
2174 
2175  return rc;
2176 
2177 } // pcps_read_std
2178 
2179 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2181 #endif
2182 
2183 
2184 
2185 #if _PCPS_USE_PCI
2186 
2187 static /*HDR*/
2202  void FAR *buffer, uint16_t count )
2203 {
2204  uint8_t FAR *p = (uint8_t FAR *) buffer;
2206  int i;
2207  int rc;
2209 
2210  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2211  MBG_PC_CYCLES t_after_cmd = 0;
2212  #endif
2213 
2214  #if DEBUG_ACCESS_TIMING
2215  MBG_PC_CYCLES t_after_reread = 0;
2216  #endif
2217 
2218  #if DEBUG_IO_TIMING
2219  MBG_PC_CYCLES t_after_busy = 0;
2220  MBG_PC_CYCLES t_done = 0;
2221  #endif
2222 
2223  #if DEBUG_IO
2224  report_io_cmd( cmd, count, "pcps_read_amcc_s5933" );
2225  #endif
2226 
2227 
2228  // reset inbound mailbox and FIFO status
2229  _mbg_outp8( pddev, 0, port + AMCC_OP_REG_MCSR + 3, 0x0C );
2230 
2231  // set FIFO
2232  _mbg_outp8( pddev, 0, port + AMCC_OP_REG_INTCSR + 3, 0x3C );
2233 
2234 
2236 
2237  mbg_get_pc_cycles( &pddev->acc_cycles );
2238  // write the command byte
2239  _mbg_outp8( pddev, 0, port + AMCC_OP_REG_OMB1, cmd );
2240  #if defined( MBG_ARCH_SPARC )
2241  udelay( 3 );
2242  #endif
2243 
2244  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2245  mbg_get_pc_cycles( &t_after_cmd );
2246  #endif
2247 
2248  #if DEBUG_ACCESS_TIMING
2249  debug_dummy_var = _pcps_ddev_read_status_port( pddev );
2250  mbg_get_pc_cycles( &t_after_reread );
2251  #endif
2252 
2254 
2255 
2256  // wait until BUSY flag goes low or timeout
2257  rc = pcps_wait_busy( pddev );
2258 
2259  #if DEBUG_IO_TIMING
2260  mbg_get_pc_cycles( &t_after_busy );
2261  #endif
2262 
2263  if ( mbg_rc_is_error( rc ) )
2264  goto out;
2265 
2266 
2267  // success: read data, if required
2268 
2269  for ( i = 0; i < count; i++ )
2270  {
2271  if ( _mbg_inp16_to_cpu( pddev, 0, port + AMCC_OP_REG_MCSR ) & 0x20 )
2272  return MBG_ERR_NO_DATA;
2273 
2274  p[i] = _mbg_inp8( pddev, 0, port + AMCC_OP_REG_FIFO + ( i % sizeof( uint32_t) ) );
2275 
2276  #if DEBUG_IO
2277  pcps_dump_data( &p[i], sizeof( p[i] ), "pcps_read_amcc_s5933" );
2278  #endif
2279  }
2280 
2281 
2282 out:
2283  #if DEBUG_IO_TIMING
2284  mbg_get_pc_cycles( &t_done );
2285  report_io_timing( pddev, "S5933", cmd, count, t_after_cmd, t_after_busy, t_done );
2286  #endif
2287 
2288  #if DEBUG_ACCESS_TIMING
2289  report_access_timing( pddev, "S5933 wr/rd", t_after_cmd, t_after_reread );
2290  #endif
2291 
2292  #if defined( DEBUG )
2293  report_ret_val( rc, "pcps_read_amcc_s5933" );
2294  #endif
2295 
2296  return rc;
2297 
2298 } // pcps_read_amcc_s5933
2299 
2300 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2302 #endif
2303 
2304 #endif /* _PCPS_USE_PCI */
2305 
2306 
2307 
2308 #if _PCPS_USE_PCI
2309 
2310 static /*HDR*/
2325  void FAR *buffer, uint16_t count )
2326 {
2327  uint8_t FAR *p = (uint8_t FAR *) buffer;
2328  MBG_IOPORT_ADDR_MAPPED data_port = _pcps_ddev_io_base_mapped( pddev, 1 );
2329  int i;
2330  int rc;
2331  int dt_quot;
2332  int dt_rem;
2334 
2335  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2336  MBG_PC_CYCLES t_after_cmd = 0;
2337  #endif
2338 
2339  #if DEBUG_ACCESS_TIMING
2340  MBG_PC_CYCLES t_after_reread = 0;
2341  #endif
2342 
2343  #if DEBUG_IO_TIMING
2344  MBG_PC_CYCLES t_after_busy = 0;
2345  MBG_PC_CYCLES t_done = 0;
2346  #endif
2347 
2348  #if DEBUG_IO
2349  report_io_cmd( cmd, count, "pcps_read_amcc_s5920" );
2350  #endif
2351 
2352 
2354 
2355  mbg_get_pc_cycles( &pddev->acc_cycles );
2356  // write the command byte
2357  _mbg_outp8( pddev, 0, _pcps_ddev_io_base_mapped( pddev, 0 ) + AMCC_OP_REG_OMB, cmd );
2358  #if defined( MBG_ARCH_SPARC )
2359  udelay( 3 );
2360  #endif
2361 
2362  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2363  mbg_get_pc_cycles( &t_after_cmd );
2364  #endif
2365 
2366  #if DEBUG_ACCESS_TIMING
2367  debug_dummy_var = _pcps_ddev_read_status_port( pddev );
2368  mbg_get_pc_cycles( &t_after_reread );
2369  #endif
2370 
2372 
2373 
2374  dt_quot = count / 4;
2375  dt_rem = count % 4;
2376 
2377 
2378  // wait until BUSY flag goes low or timeout
2379  rc = pcps_wait_busy( pddev );
2380 
2381  #if DEBUG_IO_TIMING
2382  mbg_get_pc_cycles( &t_after_busy );
2383  #endif
2384 
2385  if ( mbg_rc_is_error( rc ) )
2386  goto out;
2387 
2388 
2389  // success: read data, if required
2390 
2391  if ( count )
2392  {
2393  // do this only if we must read data
2394 
2395  uint32_t ul;
2396 
2397  // first read full 32 bit words
2398  for ( i = 0; i < dt_quot; i++ )
2399  {
2400  ul = _mbg_inp32_native( pddev, 1, data_port );
2401  #if DEBUG_IO
2402  pcps_dump_data( &ul, sizeof( ul ), "pcps_read_amcc_s5920" );
2403  #endif
2404  _mbg_put_unaligned( ul, (uint32_t FAR *) p );
2405  p += sizeof( ul );
2406  }
2407 
2408  // then read the remaining bytes, if required
2409  if ( dt_rem )
2410  {
2411  ul = _mbg_inp32_native( pddev, 1, data_port );
2412 
2413  for ( i = 0; i < dt_rem; i++ )
2414  {
2415  #if DEBUG_IO
2416  pcps_dump_data( &ul, dt_rem, "pcps_read_amcc_s5920" );
2417  #endif
2418 
2419  *p++ = BYTE_OF( ul, i );
2420  }
2421  }
2422  }
2423  else
2424  (void) _mbg_inp32_native( pddev, 1, data_port ); // do a dummy read
2425 
2426 out:
2427  #if DEBUG_IO_TIMING
2428  mbg_get_pc_cycles( &t_done );
2429  report_io_timing( pddev, "S5920", cmd, count, t_after_cmd, t_after_busy, t_done );
2430  #endif
2431 
2432  #if DEBUG_ACCESS_TIMING
2433  report_access_timing( pddev, "S5920 wr/rd", t_after_cmd, t_after_reread );
2434  #endif
2435 
2436  #if defined( DEBUG )
2437  report_ret_val( rc, "pcps_read_amcc_s5920" );
2438  #endif
2439 
2440  return rc;
2441 
2442 } // pcps_read_amcc_s5920
2443 
2444 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2446 #endif
2447 
2448 #endif /* _PCPS_USE_PCI */
2449 
2450 
2451 
2452 #if _PCPS_USE_PCI
2453 
2454 static /*HDR*/
2471  void FAR *buffer, uint16_t count )
2472 {
2473  uint8_t FAR *p = (uint8_t FAR *) buffer;
2474  MBG_IOPORT_ADDR_MAPPED data_port;
2475  PCI_ASIC_REG ar;
2476  int i;
2477  int rc;
2478  int dt_quot;
2479  int dt_rem;
2481 
2482  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2483  MBG_PC_CYCLES t_after_cmd = 0;
2484  #endif
2485 
2486  #if DEBUG_ACCESS_TIMING
2487  MBG_PC_CYCLES t_after_reread = 0;
2488  #endif
2489 
2490  #if DEBUG_IO_TIMING
2491  MBG_PC_CYCLES t_after_busy = 0;
2492  MBG_PC_CYCLES t_done = 0;
2493  #endif
2494 
2495  #if DEBUG_IO
2496  report_io_cmd( cmd, count, "pcps_read_asic" );
2497  #endif
2498 
2499 
2501 
2502  // get current cycles and write the command byte
2503  mbg_get_pc_cycles( &pddev->acc_cycles );
2504  _mbg_outp32_to_mbg( pddev, 0, _pcps_ddev_io_base_mapped( pddev, 0 )
2505  + offsetof( PCI_ASIC, pci_data ), cmd );
2506 
2507  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2508  mbg_get_pc_cycles( &t_after_cmd );
2509  #endif
2510 
2511  #if DEBUG_ACCESS_TIMING
2512  debug_dummy_var = _mbg_inp32_to_cpu( pddev, 0, _pcps_ddev_io_base_mapped( pddev, 0 )
2513  + offsetof( PCI_ASIC, addon_data ) );
2514  mbg_get_pc_cycles( &t_after_reread );
2515  #endif
2516 
2518 
2519 
2520  data_port = _pcps_ddev_io_base_mapped( pddev, 0 )
2521  + offsetof( PCI_ASIC, addon_data );
2522  dt_quot = count / 4;
2523  dt_rem = count % 4;
2524 
2525 
2526  // wait until BUSY flag goes low or timeout
2527  rc = pcps_wait_busy( pddev );
2528 
2529  #if DEBUG_IO_TIMING
2530  mbg_get_pc_cycles( &t_after_busy );
2531  #endif
2532 
2533  if ( mbg_rc_is_error( rc ) )
2534  goto out;
2535 
2536 
2537  // success: read data, if required
2538 
2539  // first read full 32 bit words
2540  for ( i = 0; i < dt_quot; i++ )
2541  {
2542  ar.ul = _mbg_inp32_native( pddev, 0, data_port );
2543  #if DEBUG_IO
2544  pcps_dump_data( &ar.ul, sizeof( ar.ul ), "pcps_read_asic" );
2545  #endif
2546  _mbg_put_unaligned( ar.ul, (uint32_t FAR *) p );
2547  p += sizeof( ar.ul );
2548  data_port += sizeof( ar.ul );
2549  }
2550 
2551  // then read the remaining bytes, if required
2552  if ( dt_rem )
2553  {
2554  ar.ul = _mbg_inp32_native( pddev, 0, data_port );
2555 
2556  for ( i = 0; i < dt_rem; i++ )
2557  {
2558  #if DEBUG_IO
2559  pcps_dump_data( &ar.b[i], sizeof( ar.b[i] ), "pcps_read_asic" );
2560  #endif
2561 
2562  *p++ = ar.b[i];
2563  }
2564  }
2565 
2566 out:
2567  #if DEBUG_IO_TIMING
2568  mbg_get_pc_cycles( &t_done );
2569  report_io_timing( pddev, "ASIC", cmd, count, t_after_cmd, t_after_busy, t_done );
2570  #endif
2571 
2572  #if DEBUG_ACCESS_TIMING
2573  report_access_timing( pddev, "ASIC wr/rd", t_after_cmd, t_after_reread );
2574  #endif
2575 
2576  #if defined( DEBUG )
2577  report_ret_val( rc, "pcps_read_asic" );
2578  #endif
2579 
2580  return rc;
2581 
2582 } // pcps_read_asic
2583 
2584 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2586 #endif
2587 
2588 
2589 #if _PCPS_USE_MM_IO
2590 
2591 static /*HDR*/
2610 int pcps_read_asic_mm( PCPS_DDEV *pddev, uint8_t cmd,
2611  void FAR *buffer, uint16_t count )
2612 {
2613  uint8_t FAR *p = (uint8_t FAR *) buffer;
2614  uint32_t _MBG_IOMEM *p_data_reg;
2615  PCI_ASIC_REG ar;
2616  int i;
2617  int rc;
2618  int dt_quot;
2619  int dt_rem;
2621 
2622  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2623  MBG_PC_CYCLES t_after_cmd = 0;
2624  #endif
2625 
2626  #if DEBUG_ACCESS_TIMING
2627  MBG_PC_CYCLES t_after_reread = 0;
2628  #endif
2629 
2630  #if DEBUG_IO_TIMING
2631  MBG_PC_CYCLES t_after_busy = 0;
2632  MBG_PC_CYCLES t_done = 0;
2633  #endif
2634 
2635  #if DEBUG_IO
2636  report_io_cmd( cmd, count, "pcps_read_asic_mm" );
2637  #endif
2638 
2639  #if defined( MBG_ARCH_SPARC )
2640  // Actually there are problems on SPARC ...
2641  return MBG_ERR_TIMEOUT; // FIXME TODO
2642  #endif
2643 
2645 
2646  // get current cycles and write the command byte
2647  #if USE_CMD_PTR
2648  {
2649  uint32_t _MBG_IOMEM *p_cmd_reg = &pddev->mm_asic_addr->pci_data.ul;
2650  mbg_get_pc_cycles( &pddev->acc_cycles );
2651  _mbg_mmwr32_to_mbg( p_cmd_reg, cmd );
2652  }
2653  #else
2654  mbg_get_pc_cycles( &pddev->acc_cycles );
2655  _mbg_mmwr32( &pddev->mm_asic_addr->pci_data.ul, cmd );
2656  #endif
2657 
2658  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2659  mbg_get_pc_cycles( &t_after_cmd );
2660  #endif
2661 
2662  #if DEBUG_ACCESS_TIMING
2663  debug_dummy_var = _mbg_mmrd32_native( &pddev->mm_asic_addr->pci_data.ul );
2664  mbg_get_pc_cycles( &t_after_reread );
2665  #endif
2666 
2668 
2669 
2670  p_data_reg = &pddev->mm_asic_addr->addon_data.ul[0];
2671  dt_quot = count / 4;
2672  dt_rem = count % 4;
2673 
2674 
2675  // wait until BUSY flag goes low or timeout
2676  rc = pcps_wait_busy( pddev );
2677 
2678  #if DEBUG_IO_TIMING
2679  mbg_get_pc_cycles( &t_after_busy );
2680  #endif
2681 
2682  if ( mbg_rc_is_error( rc ) )
2683  goto out;
2684 
2685 
2686  // success: read data, if required
2687 
2688  // first read full 32 bit words
2689  for ( i = 0; i < dt_quot; i++ )
2690  {
2691  ar.ul = _mbg_mmrd32_native( p_data_reg );
2692  #if DEBUG_IO
2693  pcps_dump_data( &ar.ul, sizeof( ar.ul ), "pcps_read_asic_mm" );
2694  #endif
2695  _mbg_put_unaligned( ar.ul, (uint32_t FAR *) p );
2696  p += sizeof( ar.ul );
2697  p_data_reg++;
2698  }
2699 
2700  // then read the remaining bytes, if required
2701  if ( dt_rem )
2702  {
2703  ar.ul = _mbg_mmrd32_native( p_data_reg );
2704 
2705  for ( i = 0; i < dt_rem; i++ )
2706  {
2707  #if DEBUG_IO
2708  pcps_dump_data( &ar.b[i], sizeof( ar.b[i] ), "pcps_read_asic_mm" );
2709  #endif
2710 
2711  *p++ = ar.b[i];
2712  }
2713  }
2714 
2715 out:
2716  #if DEBUG_IO_TIMING
2717  mbg_get_pc_cycles( &t_done );
2718  report_io_timing( pddev, "ASIC MM", cmd, count, t_after_cmd, t_after_busy, t_done );
2719  #endif
2720 
2721  #if DEBUG_ACCESS_TIMING
2722  report_access_timing( pddev, "ASIC MM wr/rd", t_after_cmd, t_after_reread );
2723  #endif
2724 
2725  #if defined( DEBUG )
2726  report_ret_val( rc, "pcps_read_asic_mm" );
2727  #endif
2728 
2729  return rc;
2730 
2731 } // pcps_read_asic_mm
2732 
2733 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2734  PCPS_READ_FNC pcps_read_asic_mm;
2735 #endif
2736 
2737 
2738 
2739 static /*HDR*/
2759 int pcps_read_asic_mm16( PCPS_DDEV *pddev, uint8_t cmd,
2760  void FAR *buffer, uint16_t count )
2761 {
2762  uint8_t FAR *p = (uint8_t FAR *) buffer;
2763  uint16_t _MBG_IOMEM *p_data_reg;
2764  PCI_ASIC_REG ar;
2765  int i;
2766  int rc;
2767  int dt_quot;
2768  int dt_rem;
2770 
2771  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2772  MBG_PC_CYCLES t_after_cmd = 0;
2773  #endif
2774 
2775  #if DEBUG_ACCESS_TIMING
2776  MBG_PC_CYCLES t_after_reread = 0;
2777  #endif
2778 
2779  #if DEBUG_IO_TIMING
2780  MBG_PC_CYCLES t_after_busy = 0;
2781  MBG_PC_CYCLES t_done = 0;
2782  #endif
2783 
2784  #if DEBUG_IO
2785  report_io_cmd( cmd, count, "pcps_read_asic_mm16" );
2786  #endif
2787 
2788 
2790 
2791  // get current cycles and write the command byte
2792  #if USE_CMD_PTR
2793  {
2794  uint32_t _MBG_IOMEM *p_cmd_reg = &pddev->mm_asic_addr->pci_data.ul;
2795  mbg_get_pc_cycles( &pddev->acc_cycles );
2796  _mbg_mmwr32_to_mbg( p_cmd_reg, cmd );
2797  }
2798  #else
2799  mbg_get_pc_cycles( &pddev->acc_cycles );
2800  _mbg_mmwr32_mbg( &pddev->mm_asic_addr->pci_data.ul, cmd );
2801  #endif
2802 
2803  #if DEBUG_ACCESS_TIMING || DEBUG_IO_TIMING
2804  mbg_get_pc_cycles( &t_after_cmd );
2805  #endif
2806 
2807  #if DEBUG_ACCESS_TIMING
2808  debug_dummy_var = _mbg_mmrd32_native( &pddev->mm_asic_addr->pci_data.ul );
2809  mbg_get_pc_cycles( &t_after_reread );
2810  #endif
2811 
2813 
2814 
2815  p_data_reg = &pddev->mm_asic_addr->addon_data.us[0];
2816  dt_quot = count / 2;
2817  dt_rem = count % 2;
2818 
2819 
2820  // wait until BUSY flag goes low or timeout
2821  rc = pcps_wait_busy( pddev );
2822 
2823  #if DEBUG_IO_TIMING
2824  mbg_get_pc_cycles( &t_after_busy );
2825  #endif
2826 
2827  if ( mbg_rc_is_error( rc ) )
2828  goto out;
2829 
2830 
2831  // success: read data, if required
2832 
2833  // first read full 32 bit words
2834  for ( i = 0; i < dt_quot; i++ )
2835  {
2836  ar.us[0] = _mbg_mmrd16_native( p_data_reg );
2837  #if DEBUG_IO
2838  pcps_dump_data( &ar.us[0], sizeof( ar.us[0] ), "pcps_read_asic_mm16" );
2839  #endif
2840  _mbg_put_unaligned( ar.us[0], (uint16_t FAR *) p );
2841  p += sizeof( ar.us[0] );
2842  p_data_reg++;
2843  }
2844 
2845  // then read the remaining bytes, if required
2846  if ( dt_rem )
2847  {
2848  ar.us[0] = _mbg_mmrd16_native( p_data_reg );
2849 
2850  for ( i = 0; i < dt_rem; i++ )
2851  {
2852  #if DEBUG_IO
2853  pcps_dump_data( &ar.b[i], sizeof( ar.b[i] ), "pcps_read_asic_mm16" );
2854  #endif
2855 
2856  *p++ = ar.b[i];
2857  }
2858  }
2859 
2860 out:
2861  #if DEBUG_IO_TIMING
2862  mbg_get_pc_cycles( &t_done );
2863  report_io_timing( pddev, "ASIC MM ww", cmd, count, t_after_cmd, t_after_busy, t_done );
2864  #endif
2865 
2866  #if DEBUG_ACCESS_TIMING
2867  report_access_timing( pddev, "ASIC MM ww wr/rd", t_after_cmd, t_after_reread );
2868  #endif
2869 
2870  #if defined( DEBUG )
2871  report_ret_val( rc, "pcps_read_asic_mm16" );
2872  #endif
2873 
2874  return rc;
2875 
2876 } // pcps_read_asic_mm16
2877 
2878 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2879  PCPS_READ_FNC pcps_read_asic_mm16;
2880 #endif
2881 
2882 #endif // _PCPS_USE_MM_IO
2883 
2884 #endif // _PCPS_USE_PCI
2885 
2886 
2887 
2888 #if _PCPS_USE_USB
2889 
2890 static /*HDR*/
2904 int pcps_read_usb( PCPS_DDEV *pddev, uint8_t cmd,
2905  void FAR *buffer, uint16_t count )
2906 {
2907  int rc;
2908 
2909  #if DEBUG_IO
2910  report_io_cmd( cmd, count, __func__ );
2911  #endif
2912 
2913  rc = pcps_read_usb_generic( pddev, cmd, buffer, count, false );
2914 
2915  return rc;
2916 
2917 } // pcps_read_usb
2918 
2919 #if !defined( AVOID_REDUNDANT_REDECLARATION )
2920  PCPS_READ_FNC pcps_read_usb;
2921 #endif
2922 
2923 #endif // _PCPS_USE_USB
2924 
2929 /*HDR*/
2947 int pcps_write( PCPS_DDEV *pddev, uint8_t cmd,
2948  const void FAR *buffer, uint16_t count )
2949 {
2950  int rc;
2951 
2952 #if _PCPS_USE_USB
2953  if ( _pcps_ddev_is_usb( pddev ) )
2954  rc = pcps_write_usb_generic( pddev, cmd, buffer, count, false );
2955  else
2956 #endif // _PCPS_USE_USB
2957  {
2958  const uint8_t FAR *p = (const uint8_t FAR *) buffer;
2959  int i;
2960  uint8_t bytes_expected;
2961  int8_t write_rc;
2962 
2963  // Write the command and read one byte which will contain
2964  // the number of data bytes that must follow.
2965  rc = _pcps_read_var( pddev, cmd, bytes_expected );
2966 
2967  #if DEBUG_IO
2968  _mbg_kdd_msg_4( MBG_LOG_DEBUG, "pcps_write: cmd %02X, %u bytes, expects %u, rc: %i",
2969  cmd, count, bytes_expected, rc );
2970  #endif
2971 
2972  if ( mbg_rc_is_error( rc ) )
2973  goto out;
2974 
2975 
2976  // Check if the number of data bytes to be written is correct.
2977  if ( bytes_expected != count )
2978  {
2979  rc = MBG_ERR_NBYTES;
2980  goto out;
2981  }
2982 
2983 
2984  // Write all bytes but the last one without reading anything.
2985  bytes_expected--;
2986 
2987  for ( i = 0; i < bytes_expected; i++ )
2988  {
2989  #if DEBUG_IO
2990  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "pcps_write: byte %i: 0x%02X", i, *p );
2991  #endif
2992 
2993  rc = _pcps_write_byte( pddev, *p++ );
2994 
2995  if ( mbg_rc_is_error( rc ) )
2996  goto out;
2997  }
2998 
2999  // Write the last byte and read the completion code.
3000  #if DEBUG_IO
3001  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "pcps_write: last byte %i: 0x%02X", i, *p );
3002  #endif
3003 
3004  rc = _pcps_read_var( pddev, *p++, write_rc );
3005 
3006  if ( mbg_rc_is_success( rc ) ) // write operation was successfull
3007  rc = write_rc; // return the completion code from the device
3008  }
3009 
3010 out:
3011  #if defined( DEBUG )
3012  report_ret_val( rc, "pcps_write" );
3013  #endif
3014 
3015  return rc;
3016 
3017 } // pcps_write
3018 
3019 #if !defined( AVOID_REDUNDANT_REDECLARATION )
3021 #endif
3022 
3023 
3024 
3025 /*HDR*/
3045 int pcps_generic_io( PCPS_DDEV *pddev, uint8_t type,
3046  const void FAR *in_buff, uint8_t in_cnt,
3047  void FAR *out_buff, uint8_t out_cnt )
3048 {
3049  const uint8_t FAR *p;
3050  int i;
3051  int rc;
3052  uint8_t tmp_byte;
3053  int8_t data_read[PCPS_FIFO_SIZE];
3054  uint8_t bytes_to_read;
3055 
3056  #if DEBUG_IO
3057  #if defined( MBG_TGT_DOS )
3058  #define FP_FMT "%Fp"
3059  #else
3060  #define FP_FMT "%p"
3061  #endif
3062  _mbg_kdd_msg_5( MBG_LOG_DEBUG, "pcps_generic_io: type 0x%02X, in_buff: " FP_FMT
3063  " (%u), out_buf " FP_FMT " (%u)",
3064  type, in_buff, in_cnt, out_buff, out_cnt );
3065  #endif
3066 
3067  // Write the command and read one byte which will contain
3068  // the number of data bytes that must follow.
3069  rc = _pcps_read_var( pddev, PCPS_GENERIC_IO, tmp_byte );
3070 
3071  if ( mbg_rc_is_error( rc ) )
3072  return rc;
3073 
3074 
3075  // Check if the number of data bytes to be written is correct.
3076  if ( tmp_byte != 3 )
3077  return MBG_ERR_NBYTES;
3078 
3079 
3080  #if DEBUG_IO
3081  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "pcps_generic_io: going to write type 0x%02X, in_sz %i, out_sz %i",
3082  type, in_cnt, out_cnt );
3083  #endif
3084 
3085  // Write the 3 bytes which are expected:
3086  rc = _pcps_write_byte( pddev, type );
3087 
3088  if ( mbg_rc_is_error( rc ) )
3089  goto out;
3090 
3091 
3092  rc = _pcps_write_byte( pddev, in_cnt );
3093 
3094  if ( mbg_rc_is_error( rc ) )
3095  goto out;
3096 
3097 
3098  if ( in_cnt == 0 )
3099  tmp_byte = out_cnt;
3100  else
3101  {
3102  rc = _pcps_write_byte( pddev, out_cnt );
3103 
3104  if ( mbg_rc_is_error( rc ) )
3105  goto out;
3106 
3107 
3108  // Write the input parameters
3109  #if DEBUG_IO
3110  _mbg_kdd_msg_0( MBG_LOG_DEBUG, "pcps_generic_io: going to write input bytes" );
3111  #endif
3112 
3113  p = (const uint8_t FAR *) in_buff;
3114  tmp_byte = in_cnt - 1;
3115 
3116  for ( i = 0; i < tmp_byte; i++ )
3117  {
3118  rc = _pcps_write_byte( pddev, *p++ );
3119 
3120  if ( mbg_rc_is_error( rc ) )
3121  goto out;
3122  }
3123 
3124  tmp_byte = *p;
3125  }
3126 
3127 
3128  bytes_to_read = 2 + out_cnt;
3129 
3130  if ( bytes_to_read > sizeof( data_read ) )
3131  bytes_to_read = sizeof( data_read );
3132 
3133 
3134  // Write the last byte and read the completion code.
3135  rc = _pcps_read( pddev, tmp_byte, data_read, bytes_to_read );
3136 
3137  if ( out_cnt ) //### TODO should do some more plausibility checks
3138  if ( mbg_rc_is_success( rc ) )
3139  {
3140  _fmemcpy( out_buff, &data_read[2], out_cnt );
3141  }
3142 
3143 out:
3144  // If an error code has been returned by the I/O function,
3145  // return that code, otherwise return the completion code
3146  // read from the board.
3147  if ( mbg_rc_is_success( rc ) )
3148  rc = data_read[0];
3149 
3150  #if defined( DEBUG )
3151  report_ret_val( rc, "pcps_generic_io" );
3152  #endif
3153 
3154  return rc;
3155 
3156 } // pcps_generic_io
3157 
3158 
3159 
3160 static /*HDR*/
3171  const char *info )
3172 {
3173  if ( _pcps_ddev_has_gps_data_16( pddev ) )
3174  {
3175  pddev->size_n_bytes = 2; // 16 bit data size is supported.
3176  goto out_success;
3177  }
3178 
3179  // Only 8 bit data size is supported.
3180  pddev->size_n_bytes = 1; // 16 bit data size is not supported.
3181 
3182 
3183  // This can only be used with small buffers.
3184  if ( count > 255 ) // buffer too large
3185  {
3186  #if defined( DEBUG )
3188  "%s: buffer size > 255, but gps_data_16 not supp.", info );
3189  #else
3190  (void) info;
3191  #endif
3192 
3193  return MBG_ERR_NBYTES;
3194  }
3195 
3196 out_success:
3197  return MBG_SUCCESS;
3198 
3199 } // pcps_check_gps_data_size
3200 
3201 
3202 
3203 static /*HDR*/
3215 int pcps_init_gps_transfer( PCPS_DDEV *pddev, uint8_t cmd, uint8_t data_type,
3216  uint16_t count, const char *info )
3217 {
3218  // Write the read or write cmd code, expect to read one byte.
3219  int rc = _pcps_read_var( pddev, cmd, pddev->uc );
3220 
3221  if ( mbg_rc_is_error( rc ) )
3222  {
3223  #if defined( DEBUG )
3225  "%s: failed to read 1 byte after writing cmd code %02X",
3226  info, cmd );
3227  #else
3228  (void) info;
3229  #endif
3230 
3231  goto out;
3232  }
3233 
3234 
3235  if ( pddev->uc != 1 ) // The board doesn't expect exactly one more byte
3236  {
3237  if ( pddev->uc == 0 )
3238  {
3239  // The device is unable to respond now. This may happen
3240  // if it is still initializing after power-up.
3241  rc = MBG_ERR_NOT_READY;
3242 
3243  #if defined( DEBUG )
3244  _mbg_kdd_msg_1( MBG_LOG_WARN, "%s: device not yet initialized", info );
3245  #endif
3246 
3247  goto out;
3248  }
3249 
3250 
3251  rc = MBG_ERR_NBYTES;
3252 
3253  #if defined( DEBUG )
3254  _mbg_kdd_msg_2( MBG_LOG_ERR, "%s: device expects %u bytes rather than 1",
3255  info, pddev->uc );
3256  #endif
3257 
3258  goto out;
3259  }
3260 
3261 
3262  // Write the code corresponding to the type of data we
3263  // want to read, expect to read the data size expected
3264  // by the device.
3265  pddev->n_bytes = 0;
3266  rc = _pcps_read( pddev, data_type, &pddev->n_bytes, pddev->size_n_bytes );
3267 
3268  if ( mbg_rc_is_error( rc ) )
3269  {
3270  #if defined( DEBUG )
3271  _mbg_kdd_msg_1( MBG_LOG_ERR, "%s: device not yet initialized", info );
3272  #endif
3273 
3274  goto out;
3275  }
3276 
3277 
3278  #if defined( MBG_ARCH_BIG_ENDIAN )
3279  // Swap n_bytes regardless of whether we have actually read 1 or 2 bytes.
3280  // If we have read only 1 byte then the other one is 0 anyway.
3281  pddev->n_bytes = _mbg16_to_cpu( pddev->n_bytes );
3282  #endif
3283 
3284  if ( pddev->n_bytes == 0 )
3285  {
3286  rc = MBG_ERR_INV_TYPE;
3287 
3288  #if defined( DEBUG )
3289  _mbg_kdd_msg_2( MBG_LOG_ERR, "%s: exp. data size 0: type %u not supp.",
3290  info, data_type );
3291  #endif
3292 
3293  goto out;
3294  }
3295 
3296 
3297  if ( pddev->n_bytes != count ) // Size of data structure does not match.
3298  {
3299  rc = MBG_ERR_NBYTES;
3300 
3301  #if defined( DEBUG )
3302  _mbg_kdd_msg_3( MBG_LOG_ERR, "%s: exp. data size %u doesn't match buffer size %u",
3303  info, pddev->n_bytes, count );
3304  #endif
3305 
3306  goto out;
3307  }
3308 
3309 
3310  #if DEBUG_IO
3311  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "%s: exp. data size %u matches buffer size %u",
3312  info, pddev->n_bytes, count );
3313  #endif
3314 
3315 out:
3316  return rc;
3317 
3318 } // pcps_init_gps_transfer
3319 
3320 
3321 
3322 static /*HDR*/
3343  uint8_t data_type,
3344  void FAR *buffer,
3345  uint16_t count,
3346  uint8_t block_num,
3347  uint8_t block_size )
3348 {
3349  int rc = pcps_check_gps_data_size( pddev, count, "pcps_read_gps_block" );
3350 
3351  if ( mbg_rc_is_error( rc ) )
3352  goto out;
3353 
3354  #if DEBUG_IO
3356  "pcps_read_gps_block: cmd 0x%02X, block %u (%u), size_n_bytes = %u",
3357  data_type, block_num, block_size, pddev->size_n_bytes );
3358  #endif
3359 
3360  rc = pcps_init_gps_transfer( pddev, PCPS_READ_GPS_DATA, data_type,
3361  count, "pcps_read_gps_block" );
3362 
3363  if ( mbg_rc_is_error( rc ) )
3364  goto out;
3365 
3366 
3367  // Write the block number and read n bytes of data.
3368  rc = _pcps_read( pddev, block_num, buffer, block_size );
3369 
3370 out:
3371  #if defined( DEBUG )
3372  report_ret_val( rc, "pcps_read_gps_block" );
3373  #endif
3374 
3375  return rc;
3376 
3377 } // pcps_read_gps_block
3378 
3379 
3380 
3381 /*HDR*/
3407 int pcps_read_gps( PCPS_DDEV *pddev,
3408  uint8_t data_type,
3409  void FAR *buffer,
3410  uint16_t count )
3411 {
3412  uint8_t FAR *p;
3413  int dt_quot;
3414  int dt_rem;
3415  int block_num;
3416  int rc;
3417 
3418  #if DEBUG_IO
3419  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "----- pcps_read_gps: data type: 0x%02X, addr: %p, size: %u",
3420  data_type, buffer, count );
3421  #endif
3422 
3423  #if _PCPS_USE_USB
3424  if ( _pcps_ddev_is_usb( pddev ) )
3425  {
3426  rc = pcps_read_usb_generic( pddev, data_type, buffer, count, true );
3427  goto out;
3428  }
3429  #endif // _PCPS_USE_USB
3430 
3431  p = (uint8_t FAR *) buffer;
3432  rc = MBG_SUCCESS;
3433 
3434  // Split buffer size to a number of blocks of PCPS_FIFO_SIZE
3435  // and a number of remaining bytes (less than PCPS_FIFO_SIZE).
3436  dt_quot = count / PCPS_FIFO_SIZE;
3437  dt_rem = count % PCPS_FIFO_SIZE;
3438 
3439  // Read dt_quot full blocks of data.
3440  for ( block_num = 0; block_num < dt_quot; block_num++ )
3441  {
3442  rc = pcps_read_gps_block( pddev, data_type, p, count,
3443  (uint8_t) block_num, PCPS_FIFO_SIZE );
3444 
3445  if ( mbg_rc_is_error( rc ) )
3446  goto out;
3447 
3448  // Move the destination pointer to the next free byte.
3449  p += PCPS_FIFO_SIZE;
3450  }
3451 
3452 
3453  // Read dt_rem additional bytes of data.
3454  if ( dt_rem )
3455  rc = pcps_read_gps_block( pddev, data_type, p, count,
3456  (uint8_t) block_num, (uint8_t) dt_rem );
3457 
3458 out:
3459  #if defined( DEBUG )
3460  report_ret_val( rc, "pcps_read_gps" );
3461  #endif
3462 
3463  return rc;
3464 
3465 } // pcps_read_gps
3466 
3467 #if !defined( AVOID_REDUNDANT_REDECLARATION )
3469 #endif
3470 
3471 
3472 
3473 /*HDR*/
3494 int pcps_write_gps( PCPS_DDEV *pddev,
3495  uint8_t data_type,
3496  const void FAR *buffer,
3497  uint16_t count )
3498 {
3499  const uint8_t FAR *p;
3500  int i;
3501  int rc;
3502 
3503  #if DEBUG_IO
3504  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "----- pcps_write_gps: data type: 0x%02X, addr: %p, size: %u",
3505  data_type, buffer, count );
3506  #endif
3507 
3508  #if _PCPS_USE_USB
3509  if ( _pcps_ddev_is_usb( pddev ) )
3510  {
3511  rc = pcps_write_usb_generic( pddev, data_type, buffer, count, true );
3512  goto out;
3513  }
3514  #endif // _PCPS_USE_USB
3515 
3516  p = (const uint8_t FAR *) buffer;
3517 
3518  rc = pcps_check_gps_data_size( pddev, count, "pcps_write_gps" );
3519 
3520  if ( mbg_rc_is_error( rc ) )
3521  goto out;
3522 
3523 
3524  #if DEBUG_IO
3525  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "pcps_write_gps: size_n_bytes = %u", pddev->size_n_bytes );
3526  #endif
3527 
3528  rc = pcps_init_gps_transfer( pddev, PCPS_WRITE_GPS_DATA, data_type,
3529  count, "pcps_write_gps" );
3530 
3531  if ( mbg_rc_is_error( rc ) )
3532  goto out;
3533 
3534  if ( count == 0 ) // done
3535  goto out;
3536 
3537 
3538  // Write all bytes but the last one without reading.
3539  count--;
3540 
3541  for ( i = 0; i < count; i++ )
3542  {
3543  rc = _pcps_write_byte( pddev, *p++ );
3544 
3545  if ( mbg_rc_is_error( rc ) )
3546  goto out;
3547  }
3548 
3549 
3550  // Write the last byte and read the completion code.
3551  rc = _pcps_read_var( pddev, *p, pddev->n_bytes );
3552 
3553  #if DEBUG_IO
3554  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "pcps_write_gps: wrote last byte, rc: %i, completion code: %u",
3555  rc, pddev->n_bytes );
3556  #endif
3557 
3558  // If an error code has been returned by read_fnc, return that
3559  // code, otherwise return the completion code read from the board.
3560  if ( mbg_rc_is_success( rc ) )
3561  rc = pddev->n_bytes;
3562 
3563 out:
3564  #if defined( DEBUG )
3565  report_ret_val( rc, "pcps_write_gps" );
3566  #endif
3567 
3568  return rc;
3569 
3570 } // pcps_write_gps
3571 
3572 #if !defined( AVOID_REDUNDANT_REDECLARATION )
3574 #endif
3575 
3576 
3577 
3578 static /*HDR*/
3592 {
3593  int rc;
3594 
3595  #if USE_LOCAL_IO_BUFFER
3596  PCPS_ID_STR tmp_fw_id = { 0 };
3597  char *cp = tmp_fw_id;
3598  #else
3599  char *cp = pddev->io_buffer.fw_id;
3600  #endif
3601 
3602  _mbgddmsg_1( DEBUG_DEV_INIT, MBG_LOG_INFO, "Going to read %s firmware ID",
3603  _pcps_ddev_type_name( pddev ) );
3604 
3605  #if !USE_LOCAL_IO_BUFFER
3606  memset( pddev->io_buffer.fw_id, 0, sizeof( pddev->io_buffer.fw_id ) ); // sizeof( fw_id ) would yield pointer size only
3607  #endif
3608 
3609  // read the first part of the firmware ID
3610  rc = _pcps_read( pddev, PCPS_GIVE_FW_ID_1, &cp[0], PCPS_FIFO_SIZE );
3611 
3612  if ( mbg_rc_is_error( rc ) )
3613  goto out;
3614 
3615  // read the second part of the firmware ID
3616  rc = _pcps_read( pddev, PCPS_GIVE_FW_ID_2, &cp[PCPS_FIFO_SIZE], PCPS_FIFO_SIZE );
3617 
3618  // force termination with 0
3619  cp[PCPS_ID_SIZE - 1] = 0; // FIXME is this correct ?
3620 
3621  _mbgddmsg_2( DEBUG_DEV_INIT, MBG_LOG_INFO, "%s firmware ID: \"%s\"",
3622  _pcps_ddev_type_name( pddev ), cp );
3623 
3624 out:
3625  // TODO Should we remove trailing spaces from the firmware ID of some old cards?
3626  memcpy( fw_id, cp, sizeof( PCPS_ID_STR ) );
3627 
3628  return rc;
3629 
3630 } // pcps_get_fw_id
3631 
3632 
3633 
3634 static /*HDR*/
3648 int pcps_check_id( PCPS_DDEV *pddev, const char FAR *ref )
3649 {
3650  // check if the first characters of the string match the reference
3651 
3652  if ( ref )
3653  if ( _fstrncmp( _pcps_ddev_fw_id( pddev ), ref, _fstrlen( ref ) ) )
3654  return MBG_ERR_FW_ID;
3655 
3656  return MBG_SUCCESS;
3657 
3658 } // pcps_check_id
3659 
3660 
3661 
3662 static /*HDR*/
3672 {
3673  int len = _fstrlen( idstr );
3674  int i;
3675 
3676  if ( len < 2 )
3677  goto no_rev_num;
3678 
3679  len -= 2;
3680 
3681  for ( i = 0; i < len; i++ )
3682  {
3683  if ( idstr[i + 1] == '.' )
3684  {
3685  uint8_t rev_num_hi = idstr[i] & 0x0F;
3686  uint8_t rev_num_lo = ( idstr[i + 2] & 0x0F ) << 4;
3687 
3688  // If the minor part of the version string has 2 digits
3689  // then evaluate the 2nd digit, too.
3690 
3691  char c = idstr[i + 3];
3692 
3693  if ( c >= '0' && c <= '9' )
3694  rev_num_lo |= c & 0x0F;
3695 
3696  return ( rev_num_hi << 8 ) | rev_num_lo;
3697  }
3698  }
3699 
3700 no_rev_num:
3701  return 0;
3702 
3703 } // pcps_get_rev_num
3704 
3705 
3706 
3707 static /*HDR*/
3716 bool str_remove_unprintables( char *s, size_t max_len )
3717 {
3718  size_t i;
3719  char *cp;
3720  bool removed = false;
3721 
3722  for ( i = 0, cp = s; i < max_len; i++, cp++ )
3723  {
3724  if ( ( *cp < 0x20 ) || ( *cp >= 0x7F ) )
3725  {
3726  if ( *cp ) // not 0
3727  {
3728  #if REPORT_CFG
3729  *cp = '#';
3730  #else
3731  *cp = 0;
3732  #endif
3733 
3734  removed = true;
3735  }
3736 
3737  if ( *cp == 0 )
3738  break;
3739  }
3740  }
3741 
3742  return removed;
3743 
3744 } // str_remove_unprintables
3745 
3746 
3747 
3748 static /*HDR*/
3749 void beautify_sernum( char *s, size_t max_len )
3750 {
3751  size_t i;
3752 
3753  str_remove_unprintables( s, max_len );
3754 
3755  // Remove trailing ' ' or 'F' characters which may
3756  // unfortunately be returned by some devices.
3757 
3758  for ( i = max_len; ; )
3759  {
3760  char *cp;
3761 
3762  if ( i == 0 )
3763  break;
3764 
3765  --i;
3766  cp = &s[i];
3767 
3768  if ( ( *cp > ' ' ) && ( *cp != 'F' ) )
3769  break; // done
3770 
3771  *cp = 0;
3772  }
3773 
3774 #if 0 // FIXME TODO
3775 
3776  // Specific for old IDENT:
3777  // Some old devices may have non-digits appended
3778  // to the S/N string. Truncate such a string.
3779  for ( cp = _pcps_ddev_sernum( pddev ); *cp; cp++ )
3780  if ( ( *cp < '0' ) || ( *cp > '9' ) )
3781  {
3782  *cp = 0;
3783  break;
3784  }
3785 #endif
3786 
3787 } // beautify_sernum
3788 
3789 
3790 
3791 static /*HDR*/
3792 void check_unknown_sernum( char *s, size_t max_len )
3793 {
3794  if ( max_len && ( s[0] == 0 ) ) // string is empty
3795  {
3796  size_t unkn_len = 8; // Number of '?' characters to write if unknown
3797 
3798  if ( max_len > unkn_len )
3799  max_len = unkn_len;
3800 
3801  memset( s, '?', max_len );
3802  s[max_len] = 0;
3803  }
3804 
3805 } // check_unknown_sernum
3806 
3807 
3808 
3809 #if MUST_REPORT_PROBE_DEVICE_DETAILS
3810 
3811 static /*HDR*/
3812 const char *get_bus_type_str( const PCPS_DDEV *pddev )
3813 {
3814  switch ( _pcps_ddev_bus_flags( pddev ) )
3815  {
3816  case PCPS_BUS_USB_V2: return "USB v2";
3817  case PCPS_BUS_USB: return "USB v1";
3818 
3819  case PCPS_BUS_PCI_MBGPEX: return "Meinberg FPGA";
3820  case PCPS_BUS_PCI_PEX8311: return "PLX PEX8311";
3821  case PCPS_BUS_PCI_ASIC: return "PCI ASIC";
3822  case PCPS_BUS_PCI_S5920: return "AMCC S5920";
3823  case PCPS_BUS_PCI_S5933: return "AMCC S5933";
3824 
3825  case PCPS_BUS_MCA: return "Microchannel";
3826  case PCPS_BUS_ISA: return "ISA";
3827  }
3828 
3829  return str_unkn_braced;
3830 
3831 } // get_bus_type_str
3832 
3833 
3834 
3835 static /*HDR*/
3836 void report_probe_device( const PCPS_DDEV *pddev )
3837 {
3838  char ws[40];
3839 
3840  if ( _pcps_ddev_is_pci( pddev ) )
3841  mbg_kdd_snprintf( ws, sizeof( ws ), "%02i:%02i.%02i",
3842  _pcps_ddev_bus_num( pddev ),
3843  _pcps_ddev_pci_slot_num( pddev ),
3844  _pcps_ddev_pci_fnc_num( pddev ) );
3845  else
3846  mbg_kdd_snprintf( ws, sizeof( ws ), "%03i:%03i",
3847  _pcps_ddev_bus_num( pddev ),
3848  _pcps_ddev_slot_num( pddev ) );
3849 
3850  _mbg_kdd_msg_4( MBG_LOG_INFO, "Probing device %s, ID 0x%04X: %s, bus %s",
3851  _pcps_ddev_type_name( pddev ), _pcps_ddev_dev_id( pddev ),
3852  get_bus_type_str( pddev ), ws );
3853 
3854 } // report_probe_device
3855 
3856 #endif // MUST_REPORT_PROBE_DEVICE_DETAILS
3857 
3858 
3859 
3860 #if REPORT_CFG
3861 
3862 static /*HDR*/
3872 const char *get_pcps_feature_name( PCPS_FEATURES flag_mask )
3873 {
3874  int i;
3875 
3876  for ( i = 0; i < N_PCPS_FEATURE_BITS; i++ )
3877  if ( ( 1UL << i ) == flag_mask )
3878  return pcps_feature_names[i];
3879 
3880  return str_unkn_braced;
3881 
3882 } // get_pcps_feature_name
3883 
3884 #endif // REPORT_CFG
3885 
3886 
3887 
3888 #if REPORT_CFG_DETAILS
3889 
3890 static /*HDR*/
3891 void dump_receiver_info( const PCPS_DDEV *pddev )
3892 {
3893  const RECEIVER_INFO *p_ri = _ri_addr( pddev );
3894 
3895  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.model_code: 0x%04X",
3896  p_ri->model_code );
3897 
3898  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.model_name: \"%s\"",
3899  p_ri->model_name );
3900 
3901  _mbg_kdd_msg_2( REPORT_CFG_LOG_LVL, "ri.sw_rev: code 0x%04X, name \"%s\"",
3902  p_ri->sw_rev.code,
3903  p_ri->sw_rev.name );
3904 
3905  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.sernum: \"%s\"",
3906  p_ri->sernum );
3907 
3908  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.epld_name: \"%s\"",
3909  p_ri->epld_name );
3910 
3911  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.n_channels: %u",
3912  p_ri->n_channels );
3913 
3914  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.ticks_per_sec: %lu",
3915  (ulong) p_ri->ticks_per_sec );
3916 
3917  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.features: 0x%08lX",
3918  (ulong) p_ri->features );
3919 
3920  _mbg_kdd_msg_2( REPORT_CFG_LOG_LVL, "ri.fixed_freq: khz_val %u, range %i",
3921  p_ri->fixed_freq.khz_val,
3922  p_ri->fixed_freq.range );
3923 
3924  _mbg_kdd_msg_2( REPORT_CFG_LOG_LVL, "ri.osc type: %u, flags: 0x%02X",
3925  p_ri->osc_type, p_ri->osc_flags );
3926 
3927  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.n_ucaps: %u",
3928  p_ri->n_ucaps );
3929 
3930  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.n_com_ports: %u",
3931  p_ri->n_com_ports );
3932 
3933  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.n_str_type: %u",
3934  p_ri->n_str_type );
3935 
3936  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.n_prg_out: %u",
3937  p_ri->n_prg_out );
3938 
3939  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "ri.flags: 0x%04X",
3940  p_ri->flags );
3941 
3942 } // dump_receiver_info
3943 
3944 
3945 
3946 static /*HDR*/
3947 void dump_xfeature_buffer( const PCPS_DDEV *pddev )
3948 {
3949  static const char *xfeature_names[N_MBG_XFEATURE] = MBG_XFEATURE_NAMES;
3950 
3951  const MBG_XFEATURE_BUFFER *p = _xfeat_addr( pddev );
3952  int i;
3953 
3954  for ( i = 0; i < MAX_XFEATURE_BITS; i++ )
3955  if ( mbg_rc_is_success( check_feat_supp_byte_array( i, p->b, sizeof( *p ) ) ) )
3957  "xf %i: %s", i, ( i < N_MBG_XFEATURE ) ?
3958  xfeature_names[i] : str_unkn_braced );
3959 
3960 } // dump_xfeature_buffer
3961 
3962 
3963 
3964 static /*HDR*/
3965 void dump_tlv_info( const PCPS_DDEV *pddev )
3966 {
3967  static const char *tlv_feat_type_names[N_MBG_TLV_FEAT_TYPES] = MBG_TLV_FEAT_TYPE_NAMES;
3968 
3969  const MBG_TLV_INFO *p = _tlv_info_addr( pddev );
3970  const MBG_TLV_FEAT_BUFFER *pb = &p->supp_tlv_feat;
3971  int i;
3972 
3973  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "tlv rsvd: 0x%08lX", (ulong) p->reserved );
3974  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "tlv flags: 0x%08lX", (ulong) p->flags );
3975 
3976  for ( i = 0; i < MAX_MBG_TLV_FEAT_TYPES; i++ )
3977  if ( mbg_rc_is_success( check_feat_supp_byte_array( i, pb->b, sizeof( *pb ) ) ) )
3979  "tlv %i: %s", i, ( i < N_MBG_TLV_FEAT_TYPES ) ?
3980  tlv_feat_type_names[i] : str_unkn_braced );
3981 
3982 } // dump_tlv_info
3983 
3984 #endif // REPORT_CFG_DETAILS
3985 
3986 
3987 
3988 static /*HDR*/
4001 void check_feature( PCPS_DDEV *pddev, ushort req_rev_num,
4002  PCPS_FEATURES flag_mask )
4003 {
4004  int supported = _pcps_ddev_fw_rev_num( pddev ) >= req_rev_num;
4005 
4006  if ( supported )
4007  pddev->dev.cfg.features |= flag_mask;
4008 
4009  #if REPORT_CFG
4010  _mbg_kdd_msg_5( REPORT_CFG_LOG_LVL, "%s v%03X: feature 0x%08lX (%s) %ssupported",
4011  _pcps_ddev_type_name( pddev ),
4012  _pcps_ddev_fw_rev_num( pddev ),
4013  (ulong) flag_mask, get_pcps_feature_name( flag_mask ),
4014  supported ? str_empty : "not " );
4015  #endif
4016 
4017 } // check_feature
4018 
4019 
4020 
4021 static /*HDR*/
4032 {
4033  const RECEIVER_INFO *p_ri = _ri_addr( pddev );
4034  int gps_feat_bit;
4035 
4036  for ( gps_feat_bit = 0; gps_feat_bit < N_GPS_FEATURE; gps_feat_bit++ )
4037  {
4038  int supported = ( p_ri->features & ( 1UL << gps_feat_bit ) ) != 0;
4039  PCPS_FEATURES pcps_flags = ri_feat_tbl[gps_feat_bit];
4040 
4041  if ( supported )
4042  {
4043  if ( pcps_flags )
4044  {
4045  pddev->dev.cfg.features |= pcps_flags;
4046 
4047  #if REPORT_CFG
4048  {
4049  int i;
4050 
4051  for ( i = 0; i < 8 * sizeof( pcps_flags ); i++ )
4052  if ( pcps_flags & ( 1UL << i ) )
4053  _mbg_kdd_msg_4( REPORT_CFG_LOG_LVL, "%s v%03X: Supported RI feature \"%s\" maps to PCPS feature %s",
4054  _pcps_ddev_type_name( pddev ),
4055  _pcps_ddev_fw_rev_num( pddev ),
4056  gps_ri_feature_names[gps_feat_bit],
4057  pcps_feature_names[i] );
4058  }
4059  #endif
4060  }
4061  else
4062  {
4063  #if REPORT_CFG
4064  _mbg_kdd_msg_3( REPORT_CFG_LOG_LVL, "%s v%03X: RI feature \"%s\" supported, but no corresponding PCPS feature",
4065  _pcps_ddev_type_name( pddev ),
4066  _pcps_ddev_fw_rev_num( pddev ),
4067  gps_ri_feature_names[gps_feat_bit] );
4068  #endif
4069  }
4070  }
4071  else
4072  {
4073  #if REPORT_CFG_DETAILS
4074  _mbg_kdd_msg_3( REPORT_CFG_LOG_LVL, "%s v%03X: RI feature \"%s\" NOT supported by device",
4075  _pcps_ddev_type_name( pddev ),
4076  _pcps_ddev_fw_rev_num( pddev ),
4077  gps_ri_feature_names[gps_feat_bit] );
4078  #endif
4079  }
4080  }
4081 
4082 } // check_ri_features
4083 
4084 
4085 
4086 /*HDR*/
4098 {
4099  RECEIVER_INFO *p_ri = _ri_addr( pddev );
4100  int rc;
4101 
4102  memset( _pcps_ddev_sernum( pddev ), 0, _pcps_ddev_sernum_size( pddev ) );
4103 
4104  // There are different ways to read the device's S/N. Check which
4105  // way is supported, and read the S/N from the device.
4106  //
4107  // Never just return a previous copy of the serial number which
4108  // has been read earlier since the S/N may just have been set
4109  // by a configuration API call.
4110 
4111  // Read the serial number directly, if the device supports this.
4112  if ( _pcps_ddev_has_sernum( pddev ) )
4113  {
4114  rc = _pcps_read( pddev, PCPS_GIVE_SERNUM,
4115  _pcps_ddev_sernum( pddev ), _pcps_ddev_sernum_size( pddev ) - 1 );
4116 
4117  if ( mbg_rc_is_error( rc ) )
4118  {
4119  _mbg_kdd_msg_2( MBG_LOG_ERR, "Failed to read sernum: %s (rc: %i)",
4120  mbg_strerror( rc ), rc );
4121  goto out;
4122  }
4123 
4124  #if REPORT_CFG
4125  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "sernum directly: \"%s\"",
4126  _pcps_ddev_sernum( pddev ) );
4127  #endif
4128  }
4129 
4130 
4131  // Setup the RECEIVER_INFO substructure.
4132  memset( p_ri, 0, sizeof( *p_ri ) );
4133 
4134  // Read the RECEIVER_INFO directly, if the device supports this.
4135  if ( _pcps_ddev_has_receiver_info( pddev ) )
4136  {
4137  rc = _pcps_read_gps_var( pddev, PC_GPS_RECEIVER_INFO, *p_ri );
4138 
4139  if ( mbg_rc_is_error( rc ) )
4140  {
4141  _mbg_kdd_msg_2( MBG_LOG_ERR, "Failed to read receiver info: %s (rc: %i)",
4142  mbg_strerror( rc ), rc );
4143  goto out;
4144  }
4145 
4146  _mbg_swab_receiver_info( p_ri );
4147 
4148  _mbgddmsg_1( DEBUG_DEV_INIT, MBG_LOG_INFO, "Successfully read receiver info from dev %X",
4149  _pcps_ddev_dev_id( pddev ) );
4150 
4151  #if REPORT_CFG
4152  _mbg_kdd_msg_1( REPORT_CFG_LOG_LVL, "sernum from RI: \"%s\"",
4153  p_ri->sernum );
4154  #endif
4155  }
4156 
4157 
4158  #if REPORT_CFG
4159  // If the serial number is available both via a direct call
4160  // and via the RECEIVER_INFO then maxe sure both are the same.
4161  if ( _pcps_ddev_sernum( pddev )[0] && p_ri->sernum[0] )
4162  if ( strcmp( _pcps_ddev_sernum( pddev ), p_ri->sernum ) )
4163  _mbg_kdd_msg_0( MBG_LOG_WARN, "** RI sernum differs from direct sernum" );
4164  #endif
4165 
4166 
4167  // Very old devices may neither provide a RECEIVER_INFO,
4168  // nor support the sernum API.
4169  if ( p_ri->model_code == GPS_MODEL_UNKNOWN )
4170  {
4171  _mbgddmsg_1( DEBUG_DEV_INIT, MBG_LOG_INFO, "Setting up default receiver info for %s",
4172  _pcps_ddev_type_name( pddev ) );
4173 
4174  // Setup a default RECEIVER_INFO depending on the type of device.
4175  if ( _pcps_ddev_is_gps( pddev ) )
4177  else
4178  _setup_default_receiver_info_dcf( p_ri, &pddev->dev );
4179 
4180  // Older GPS clocks store the S/N in an IDENT structure
4181  // which needs to be decoded to get the S/N.
4182  if ( _pcps_ddev_has_ident( pddev ) )
4183  {
4184  IDENT ident;
4185  char *cp;
4186 
4187  memset( &ident, 0, sizeof( ident ) );
4188 
4189  #if defined( MBG_TGT_DOS )
4190  assert( sizeof( ident ) < sizeof( pddev->dev.cfg.sernum ) );
4191  #endif
4192 
4193  #if DEBUG_SERNUM
4194  _mbg_kdd_msg_0( MBG_LOG_DEBUG, "Getting S/N from ident" );
4195  #endif
4196 
4197  rc = _pcps_read_gps_var( pddev, PC_GPS_IDENT, ident );
4198 
4199  if ( mbg_rc_is_error( rc ) )
4200  {
4201  _mbg_kdd_msg_2( MBG_LOG_WARN, "Failed to read GPS ident: %s (rc: %i)",
4202  mbg_strerror( rc ), rc );
4203  goto out;
4204  }
4205 
4206  // The ident union must never be swapped due to endianess since we are
4207  // using it only as an array of characters.
4208 
4209  #if REPORT_CFG
4210  {
4211  size_t i;
4212 
4213  for ( i = 0; i < sizeof( ident ); i += 4 )
4214  _mbg_kdd_msg_5( MBG_LOG_DEBUG, "Ident[%02u]: %02X %02X %02X %02X",
4215  (unsigned) i, ident.c[i], ident.c[i+1], ident.c[i+2], ident.c[i+3] );
4216  }
4217  #endif
4218 
4219  mbg_gps_ident_decode( _pcps_ddev_sernum( pddev ), &ident );
4220 
4221  #if REPORT_CFG
4222  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "S/N decoded from ident: %s (raw)",
4223  _pcps_ddev_sernum( pddev ) );
4224  #endif
4225 
4226  // Some old devices may have non-digits appended
4227  // to the S/N string. Truncate such a string.
4228  for ( cp = _pcps_ddev_sernum( pddev ); *cp; cp++ )
4229  if ( ( *cp < '0' ) || ( *cp > '9' ) )
4230  {
4231  *cp = 0;
4232  break;
4233  }
4234 
4235  #if DEBUG_SERNUM
4236  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "S/N decoded from ident: %s",
4237  _pcps_ddev_sernum( pddev ) );
4238  #endif
4239  }
4240  }
4241 
4242  // If the RECEIVER_INFO's sernum isn't empty
4243  // "beautify" it in any case.
4244  beautify_sernum( p_ri->sernum, sizeof( p_ri->sernum ) );
4245 
4246  // If it's now empty mark it as unknown.
4247  check_unknown_sernum( p_ri->sernum, sizeof( p_ri->sernum ) );
4248 
4249  // Now beautify the normal sernum.
4250  beautify_sernum( _pcps_ddev_sernum( pddev ), sizeof( p_ri->sernum ) );
4251 
4252  // If the "beautified" sernum is empty then we
4253  // copy from the RECEIVER_INFO, which may be valid
4254  // or unknown.
4255  if ( _pcps_ddev_sernum( pddev )[0] == 0 )
4256  strncpy( _pcps_ddev_sernum( pddev ), p_ri->sernum,
4257  _pcps_ddev_sernum_size( pddev ) );
4258 
4259  rc = MBG_SUCCESS;
4260 
4261 out:
4262  return rc;
4263 
4264 } // setup_sernum_and_receiver_info
4265 
4266 
4267 
4268 /*HDR*/
4275 {
4276  const RECEIVER_INFO *p_ri = _ri_addr( pddev );
4277  int rc;
4278 
4279  #if REPORT_CFG
4280  _mbg_kdd_msg_3( REPORT_CFG_LOG_LVL, "%s v%03X RECEIVER_INFO features: 0x%08lX",
4281  _pcps_ddev_type_name( pddev ), _pcps_ddev_fw_rev_num( pddev ),
4282  (ulong) *_ri_addr( pddev ).features );
4283  #endif
4284 
4285  #if REPORT_CFG_DETAILS
4286  dump_receiver_info( pddev );
4287  #endif
4288 
4289  // Make sure this program supports at least as many ports as
4290  // the current device.
4291  if ( p_ri->n_com_ports > MAX_PARM_PORT )
4292  _mbg_kdd_msg_4( MBG_LOG_WARN, MBG_DEV_NAME_FMT " provides %i COM ports, but this driver only supports %i",
4293  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ),
4294  p_ri->n_com_ports, MAX_PARM_PORT );
4295 
4296  // Make sure this program supports at least as many string types
4297  // as the current device.
4298  if ( p_ri->n_str_type > MAX_PARM_STR_TYPE )
4299  _mbg_kdd_msg_4( MBG_LOG_WARN, MBG_DEV_NAME_FMT " supports %i serial string formats, but this driver only supports %i",
4300  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ),
4301  p_ri->n_str_type, MAX_PARM_STR_TYPE );
4302 
4303  // Make sure this program supports at least as many programmable outputs
4304  // as the current device.
4305  if ( p_ri->n_prg_out > MAX_PARM_POUT )
4306  _mbg_kdd_msg_4( MBG_LOG_WARN, MBG_DEV_NAME_FMT " supports %i programmable outputs, but this driver only supports %i",
4307  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ),
4308  p_ri->n_prg_out, MAX_PARM_POUT );
4309 
4310 
4311  // Detect the presence of some optional features at runtime.
4312  check_ri_features( pddev );
4313 
4314  #if REPORT_CFG
4315  _mbg_kdd_msg_3( REPORT_CFG_LOG_LVL, "%s v%03X initial PCPS features: 0x%08lX",
4316  _pcps_ddev_type_name( pddev ), _pcps_ddev_fw_rev_num( pddev ),
4317  (ulong) _pcps_ddev_features( pddev ) );
4318  #endif
4319 
4320 
4321  #if !defined( MBG_TGT_OS2 ) && !defined( MBG_TGT_BSD ) // TODO
4322  // Function strstr may not be supported at kernel level,
4323  // but this is not required, in most cases, anyway.
4324  if ( strstr( _pcps_ddev_fw_id( pddev ), "CERN" ) != NULL )
4325  pddev->dev.cfg.features |= PCPS_HAS_EVENT_TIME;
4326  #endif
4327 
4328 
4329  // Check if the device supports extended features
4330 
4332 
4333  if ( mbg_rc_is_success( rc ) )
4334  {
4335  _mbgddmsg_2( DEBUG_DEV_INIT, MBG_LOG_INFO, "Going to read XFEATURE_BUFFER from " MBG_DEV_NAME_FMT,
4336  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) );
4337 
4338  rc = _pcps_read_gps_var( pddev, PC_GPS_XFEATURE_BUFFER, *_xfeat_addr( pddev ) );
4339 
4340  if ( mbg_rc_is_error( rc ) )
4341  {
4342  _mbg_kdd_msg_4( MBG_LOG_WARN, "Failed to read XFEATURE_BUFFER from " MBG_DEV_NAME_FMT ": %s (rc: %i)",
4343  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ),
4344  mbg_strerror( rc ), rc );
4345  memset( _xfeat_addr( pddev ), 0, sizeof( *_xfeat_addr( pddev ) ) );
4346  }
4347  else
4348  {
4349  #if REPORT_CFG_DETAILS
4350  dump_xfeature_buffer( pddev );
4351  #endif
4352  }
4353  }
4354 
4355  #if TEST_CFG_DETAILS
4356  {
4359  _set_xfeature_bit( N_MBG_XFEATURE - 1, _xfeat_addr( pddev ) );
4361  dump_xfeature_buffer( pddev );
4362  }
4363  #endif
4364 
4365 
4366  // Check if the device supports the TLV API
4367 
4369 
4370  if ( mbg_rc_is_success( rc ) )
4371  {
4372  _mbgddmsg_2( DEBUG_DEV_INIT, MBG_LOG_INFO, "Going to read TLV_INFO from " MBG_DEV_NAME_FMT,
4373  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) );
4374 
4375  rc = _pcps_read_gps_var( pddev, PC_GPS_TLV_INFO, *_tlv_info_addr( pddev ) );
4376 
4377  if ( mbg_rc_is_error( rc ) )
4378  {
4379  _mbg_kdd_msg_4( MBG_LOG_WARN, "Failed to read TLV_INFO from " MBG_DEV_NAME_FMT ": %s (rc: %i)",
4380  _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ),
4381  mbg_strerror( rc ), rc );
4382  memset( _tlv_info_addr( pddev ), 0, sizeof( *_tlv_info_addr( pddev ) ) );
4383  }
4384  else
4385  {
4386  #if REPORT_CFG_DETAILS
4387  dump_tlv_info( pddev );
4388  #endif
4389  }
4390  }
4391 
4392  #if TEST_CFG_DETAILS
4393  {
4397  dump_tlv_info( pddev );
4398  }
4399  #endif
4400 
4401 } // check_receiver_info_and_features
4402 
4403 
4404 
4405 /*HDR*/
4412 {
4413  int i;
4414 
4415  for ( i = 0; i < pddev->rsrc_info.num_rsrc_io; i++ )
4416  {
4417  MBG_IOPORT_RSRC *p = &_pcps_ddev_io_rsrc( pddev, i );
4418 
4419  if ( p->base_mapped )
4420  {
4421  #if DEBUG_RSRC
4422  _mbg_kdd_msg_3( MBG_LOG_INFO, "IO port rsrc %i (%" PRIX64 "): unmapping %" PRIX64,
4423  i, (uint64_t) p->base_raw, (uint64_t) p->base_mapped );
4424  #endif
4425 
4426  mbg_unmap_ioport_rsrc( p );
4427  }
4428  else
4429  {
4430  #if DEBUG_RSRC
4431  _mbg_kdd_msg_2( MBG_LOG_INFO, "IO port rsrc %i (%" PRIX64 "): nothing to unmap",
4432  i, (uint64_t) p->base_raw );
4433  #endif
4434  }
4435 
4436  #if _PCPS_USE_RSRCMGR
4437  if ( p->base_raw && p->num )
4438  rsrc_dealloc_ports( p->base_raw, p->num );
4439  #endif
4440  }
4441 
4442 
4443  for ( i = 0; i < pddev->rsrc_info.num_rsrc_mem; i++ )
4444  {
4445  MBG_IOMEM_RSRC *p = &_pcps_ddev_mem_rsrc( pddev, i );
4446 
4447  if ( p->start_mapped )
4448  {
4449  #if DEBUG_RSRC
4450  _mbg_kdd_msg_3( MBG_LOG_INFO, "IO mem rsrc %i (%" PRIX64 "): unmapping %p",
4451  i, (uint64_t) p->start_raw, p->start_mapped );
4452  #endif
4453 
4454  mbg_unmap_iomem_rsrc( p );
4455  }
4456  else
4457  {
4458  #if DEBUG_RSRC
4459  _mbg_kdd_msg_2( MBG_LOG_INFO, "IO mem rsrc %i (%" PRIX64 "): nothing to unmap",
4460  i, (uint64_t) p->start_raw );
4461  #endif
4462  }
4463 
4464  #if _PCPS_USE_RSRCMGR
4465  if ( p->start_raw && p->len )
4466  rsrc_dealloc_mem( p->start_raw, p->len );
4467  #endif // _PCPS_USE_RSRCMGR
4468  }
4469 
4470  pddev->mm_asic_addr = NULL;
4471  pddev->mm_tstamp_addr = NULL;
4472 
4473 } // pcps_release_rsrcs
4474 
4475 
4476 
4477 #if _PCPS_USE_RSRCMGR
4478 
4479 #if defined( MBG_TGT_OS2 )
4480 
4481 static /*HDR*/
4487 void pcps_rsrc_register_device( PCPS_DDEV *pddev )
4488 {
4489  #define RSRC_BASE_NAME "RADIOCLK_# Meinberg Radio Clock "
4490  static const char rsrc_type_dcf77[] = RSRC_BASE_NAME "(DCF77)";
4491  static const char rsrc_type_gps[] = RSRC_BASE_NAME "(GPS)";
4492  static const char rsrc_type_irig[] = RSRC_BASE_NAME "(IRIG)";
4493 
4494  uchar bus_type;
4495  ushort rc;
4496  const char *cp;
4497 
4498  #if _PCPS_USE_USB
4499  #error USB not supported for this target environment!
4500  #endif
4501 
4502  if ( _pcps_ddev_is_pci( pddev ) )
4503  bus_type = RSRC_BUS_PCI;
4504  else
4505  if ( _pcps_ddev_is_mca( pddev ) )
4506  bus_type = RSRC_BUS_MCA;
4507  else
4508  bus_type = RSRC_BUS_ISA;
4509 
4510  if ( _pcps_ddev_is_irig_rx( pddev ) )
4511  cp = rsrc_type_irig;
4512  else
4513  if ( _pcps_ddev_is_gps( pddev ) )
4514  cp = rsrc_type_gps;
4515  else
4516  cp = rsrc_type_dcf77;
4517 
4518  rc = rsrc_register_device( &pddev->hDev, &pddev->rsrc, n_ddevs - 1, cp, bus_type );
4519 
4520 } // pcps_rsrc_register_device
4521 
4522 #endif // defined( MBG_TGT_OS2 )
4523 
4524 #endif // _PCPS_USE_RSRCMGR
4525 
4526 
4527 
4528 #if _PCPS_USE_MCA
4529 
4530 /*--------------------------------------------------------------
4531  * PS31 only:
4532  *
4533  * The scheme below shows the way the bits of the POS 103
4534  * configuration byte are mapped to the PS31's programmable
4535  * address decoder:
4536  *
4537  * MSB LSB
4538  * | || |
4539  * 0bbbbbb1000bxxxx <-- 16 bit port base address (binary)
4540  * |||||| |
4541  * \\\\\\ | b: configurable bit
4542  * \\\\\\ | x: don't care bit
4543  * |||||||
4544  * 1bbbbbbb <-- 8 bit configuration byte (POS 103)
4545  * |
4546  * |
4547  * decoder enable bit, always 1 if adapter enabled
4548  *
4549  *-------------------------------------------------------------*/
4550 
4551 static /*HDR*/
4559 uint16_t pcps_port_from_pos( uint16_t pos )
4560 {
4561  uint16_t us = ( ( pos & 0x007E ) << 8 ) | 0x0100;
4562 
4563  if ( pos & 0x0001 )
4564  us |= 0x0010;
4565 
4566  return us;
4567 
4568 } // pcps_port_from_pos
4569 
4570 
4571 
4572 static /*HDR*/
4580 uint8_t pcps_pos_from_port( uint16_t port )
4581 {
4582  uint8_t uc;
4583 
4584 
4585  uc = *( ( (uchar *) (&port) ) + 1 ) & 0x7E;
4586 
4587  if ( port & 0x0010 )
4588  uc |= 1;
4589 
4590  return uc;
4591 
4592 } // pcps_pos_from_port
4593 
4594 
4595 
4596 static /*HDR*/
4602 void pcps_detect_mca_devices( PCPS_DDEV_INIT_FNC *ddev_init_fnc )
4603 {
4604  short rc;
4605  ushort type_idx;
4606 
4607  rc = mca_fnc_init();
4608 
4609  if ( rc != MCA_SUCCESS )
4610  return;
4611 
4612 
4613  // MCA is installed, now try to find a MCA clock with
4614  // known ID.
4615  for ( type_idx = 0; type_idx < N_PCPS_DEV_TYPE; type_idx++ )
4616  {
4617  static_wc MCA_POS_DATA pos_data;
4618  PCPS_DDEV *pddev;
4619  PCPS_DEV_TYPE *p = &pcps_dev_type[type_idx];
4620 
4621  static_wc uchar slot_num; // the slot in which the board is installed
4622 
4623 
4624  if ( !( p->bus_flags & PCPS_BUS_MCA ) )
4625  continue;
4626 
4627 
4628  rc = mca_find_adapter( p->dev_id, &slot_num, &pos_data );
4629 
4630  if ( rc != MCA_SUCCESS )
4631  continue;
4632 
4633 
4634  // New device found, try to add to list.
4635  pddev = ddev_init_fnc();
4636 
4637  if ( pddev ) // Setup only if successful.
4638  {
4639  pddev->dev.type = *p;
4640  pcps_add_rsrc_io( pddev, pcps_port_from_pos( pos_data.pos_103 ),
4642 
4643  //##++ Should try to read the interrupt line assigned to the clock.
4644  // The standard functions, however, don't use any interrupt.
4645 
4646  pcps_probe_device( pddev, 0, slot_num );
4647  }
4648  }
4649 
4650  mca_fnc_deinit();
4651 
4652 } // pcps_detect_mca_devices
4653 
4654 #endif /* _PCPS_USE_MCA */
4655 
4656 
4657 
4658 /*HDR*/
4673 {
4674  int i;
4675 
4676  for ( i = 0; i < N_PCPS_DEV_TYPE; i++ )
4677  {
4678  PCPS_DEV_TYPE *p = &pcps_dev_type[i];
4679 
4680  if ( !( p->bus_flags & bus_mask ) )
4681  continue;
4682 
4683  if ( p->dev_id == dev_id )
4684  return p;
4685  }
4686 
4687  return NULL;
4688 
4689 } // pcps_get_dev_type_table_entry
4690 
4691 
4692 
4693 static /*HDR*/
4705 {
4706  PCPS_DDEV *pddev;
4707 
4709 
4710  pddev = *ppddev;
4711 
4712  if ( pddev )
4713  {
4714  #if !_PCPS_STATIC_DEV_LIST
4715  _pcps_kfree( pddev, sizeof( *pddev ) );
4716  #else
4717  memset( pddev, 0, sizeof( *pddev ) );
4718 
4719  if ( n_ddevs )
4720  n_ddevs--;
4721  #endif
4722 
4723  *ppddev = NULL;
4724  }
4725 
4727 
4728 } // pcps_free_ddev_struc
4729 
4730 
4731 
4732 static
4745 {
4746  PCPS_DDEV *pddev;
4747  int rc;
4748 
4750 
4751  #if !_PCPS_STATIC_DEV_LIST
4752  pddev = _pcps_kmalloc( sizeof( *pddev ) );
4753  #else
4754  if ( n_ddevs < N_SUPP_DEV_BUS )
4755  {
4756  pddev = &pcps_ddev[n_ddevs];
4757  n_ddevs++;
4758  }
4759  else
4760  {
4762  "Unable to add new device: max count reached" );
4763 
4764  pddev = NULL;
4765  }
4766  #endif
4767 
4768  if ( pddev )
4769  {
4770  memset( pddev, 0, sizeof( *pddev ) );
4771  rc = MBG_SUCCESS;
4772  }
4773  else
4774  rc = MBG_ERR_NO_MEM;
4775 
4776  *ppddev = pddev;
4777 
4779 
4780  return rc;
4781 
4782 } // pcps_alloc_ddev_struc
4783 
4784 
4785 
4786 /*HDR*/
4799 int pcps_init_ddev( PCPS_DDEV **ppddev )
4800 {
4801  int rc;
4802 
4804 
4805  rc = pcps_alloc_ddev_struc( ppddev );
4806 
4807  #if defined( _mbg_mutex_destroy ) || defined( _mbg_spin_lock_destroy )
4808  if ( mbg_rc_is_success( rc ) )
4809  {
4810  PCPS_DDEV *pddev = *ppddev;
4811 
4812  // If mutexes or spinlocks need to be destroyed on the target OS
4813  // when the driver shuts down then they are initialized now and
4814  // destroyed in the complementary function ::pcps_free_ddev_struc.
4815  // However, there are target OSs where those semaphores don't need
4816  // to be destroyed, and sometimes even *must not* be initialized
4817  // at this early point of driver initialization, e.g. under Windows,
4818  // in which case the semaphores will be initialized later.
4819  #if defined( _mbg_mutex_destroy )
4820  _mbg_mutex_init( &pddev->dev_mutex, MBG_DRVR_NAME "_dev_mutex" );
4821  #endif
4822  #if defined( _mbg_spin_lock_destroy )
4823  _mbg_spin_lock_init( &pddev->tstamp_lock, MBG_DRVR_NAME "_tstamp_lock" );
4824  _mbg_spin_lock_init( &pddev->irq_lock, MBG_DRVR_NAME "_irq_lock" );
4825  #endif
4826  }
4827  #endif
4828 
4830 
4831  return rc;
4832 
4833 } // pcps_init_ddev
4834 
4835 
4836 
4837 /*HDR*/
4846 {
4848 
4849  if ( pddev )
4850  {
4851  #if defined( _mbg_mutex_destroy )
4852  _mbg_mutex_destroy( &pddev->dev_mutex );
4853  #endif
4854 
4855  #if defined( _mbg_spin_lock_destroy )
4856  _mbg_spin_lock_destroy( &pddev->tstamp_lock );
4857  _mbg_spin_lock_destroy( &pddev->irq_lock );
4858  #endif
4859 
4860  pcps_free_ddev_struc( &pddev );
4861  }
4862 
4864 
4865 } // pcps_cleanup_ddev
4866 
4867 
4868 
4869 static /*HDR*/
4878 void rsrc_port_to_cfg_port( PCPS_SHORT_PORT_RSRC *p_short_port_rsrc, const MBG_IOPORT_RSRC *p_io_rsrc )
4879 {
4880  p_short_port_rsrc->base = (PCPS_SHORT_PORT_ADDR) p_io_rsrc->base_raw;
4881  p_short_port_rsrc->num = (uint16_t) p_io_rsrc->num;
4882 
4883 } // rsrc_port_to_cfg_port
4884 
4885 
4886 
4887 /*HDR*/
4898 {
4899  PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info;
4900 
4901  if ( prsrci->num_rsrc_io < N_PCPS_PORT_RSRC )
4902  {
4903  MBG_IOPORT_RSRC *p = &prsrci->port[prsrci->num_rsrc_io];
4904  int rc;
4905 
4906  #if _PCPS_USE_RSRCMGR
4907  {
4908  rc = rsrc_alloc_ports( base, num );
4909 
4910  // If the resource manager was unable to alloc the resources
4911  // then the selected range of ports is probably in use
4912  // by another hardware device and/or driver
4913  if ( mbg_rc_is_error( rc ) )
4914  {
4916  return rc;
4917  }
4918  }
4919  #endif // _PCPS_USE_RSRCMGR
4920 
4921  p->base_raw = base;
4922  p->num = num;
4923 
4924  rc = mbg_map_ioport_rsrc( p );
4925 
4926  if ( mbg_rc_is_error( rc ) )
4927  {
4928  _mbg_kdd_msg_2( MBG_LOG_ERR, "Failed to map I/O port rsrc %i: %s",
4929  prsrci->num_rsrc_io, mbg_strerror( rc ) );
4930  return rc;
4931  }
4932 
4933  #if DEBUG_RSRC
4934  _mbg_kdd_msg_4( MBG_LOG_INFO, "Added I/O port rsrc %i: %03lX (%lu), mapped: %03lX",
4935  prsrci->num_rsrc_io, (ulong) base, (ulong) num, (ulong) p->base_mapped );
4936  #endif
4937 
4938  prsrci->num_rsrc_io++;
4939 
4940  return MBG_SUCCESS;
4941  }
4942 
4943  return MBG_ERR_RSRC_ITEM;
4944 
4945 } // pcps_add_rsrc_io
4946 
4947 
4948 
4949 /*HDR*/
4960 {
4961  PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info;
4962 
4963  if ( prsrci->num_rsrc_mem < N_PCPS_MEM_RSRC )
4964  {
4965  int rc;
4966  MBG_IOMEM_RSRC *p = &prsrci->mem[prsrci->num_rsrc_mem];
4967 
4968  #if _PCPS_USE_RSRCMGR
4969  {
4970  rc = rsrc_alloc_mem( start, len );
4971 
4972  // If the resource manager was unable to alloc the resources
4973  // then the selected range of ports is probably in use
4974  // by another hardware device and/or driver
4975  if ( mbg_rc_is_error( rc ) )
4976  {
4978  return rc;
4979  }
4980  }
4981  #endif // _PCPS_USE_RSRCMGR
4982 
4983  p->start_raw = start;
4984  p->len = len;
4985 
4986  // Map this memory resource to get a virtual address
4987  rc = mbg_map_iomem_rsrc( p );
4988 
4989  if ( mbg_rc_is_error( rc ) )
4990  {
4991  _mbg_kdd_msg_2( MBG_LOG_ERR, "Failed to map I/O mem rsrc %i: %s",
4992  prsrci->num_rsrc_mem, mbg_strerror( rc ) );
4993  return rc;
4994  }
4995 
4996  #if DEBUG_RSRC
4997  _mbg_kdd_msg_4( MBG_LOG_INFO, "Added I/O mem rsrc %i: %" PRIX64 " (%lu), mapped: %p",
4998  prsrci->num_rsrc_mem, (uint64_t) start, (ulong) len, p->start_mapped );
4999  #endif
5000 
5001  prsrci->num_rsrc_mem++;
5002 
5003  return MBG_SUCCESS;
5004  }
5005 
5006  return MBG_ERR_RSRC_ITEM;
5007 
5008 } // pcps_add_rsrc_mem
5009 
5010 
5011 
5012 /*HDR*/
5021 int pcps_add_rsrc_irq( PCPS_DDEV *pddev, int16_t irq_num )
5022 {
5023  PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info;
5024 
5025  if ( prsrci->num_rsrc_irq == 0 )
5026  {
5027  prsrci->irq.num = irq_num;
5028  prsrci->num_rsrc_irq++;
5029 
5030  #if DEBUG_RSRC
5031  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "Added IRQ rsrc #%i: %i",
5032  prsrci->num_rsrc_irq, irq_num );
5033  #endif
5034 
5035  return MBG_SUCCESS;
5036  }
5037 
5038  return MBG_ERR_GENERIC;
5039 
5040 } // pcps_add_rsrc_irq
5041 
5042 
5043 
5044 #if _PCPS_USE_PNP
5045 
5046 /*HDR*/
5057 int pcps_setup_ddev( PCPS_DDEV *pddev, PCPS_BUS_FLAGS bus_mask, PCPS_DEV_ID dev_id )
5058 {
5059  PCPS_DEV_TYPE *pdt;
5060 
5062 
5063  // First check if we really support the device to be added.
5064  pdt = pcps_get_dev_type_table_entry( bus_mask, dev_id );
5065 
5066  if ( pdt == NULL )
5067  {
5068  _mbgddmsg_2( DEBUG_DEV_INIT, MBG_LOG_ERR, "pcps_setup_ddev: unknown %s ID 0x%04X",
5069  ( bus_mask & PCPS_BUS_USB ) ? "USB" : "PCI", dev_id );
5070 
5072 
5073  return MBG_ERR_DEV_NOT_SUPP;
5074  }
5075 
5076 
5077  pddev->dev.type = *pdt;
5078 
5079  _mbgddmsg_2( DEBUG_DEV_INIT, MBG_LOG_INFO, "pcps_setup_ddev 0x%04X: found %s",
5080  dev_id, pdt->name );
5081 
5083 
5084  return MBG_SUCCESS;
5085 
5086 } // pcps_setup_ddev
5087 
5088 #endif // _PCPS_USE_PNP
5089 
5090 
5091 
5092 /*HDR*/
5112 int pcps_chk_dev_feat( PCPS_DDEV *p_ddev, uint feat_type, uint feat_num )
5113 {
5114  int rc;
5115 
5116  #if defined( DEBUG )
5117  const char *cp = NULL;
5118  int max_bit;
5119  #endif
5120 
5121  // NOTE In the code below we currently check if the bit to be tested
5122  // is really defined in an enumeration, and return an error if a bit
5123  // is tested which is not defined.
5124  // Alternatively we could instead just check if the bit number is valid
5125  // according to the buffer size.
5126 
5127  switch ( feat_type )
5128  {
5129  case DEV_FEAT_TYPE_BUILTIN:
5130  #if defined( DEBUG )
5131  cp = "builtin_feat";
5132  max_bit = N_GPS_BUILTIN_FEATURE_BITS;
5133  #endif
5134  if ( feat_num < N_GPS_BUILTIN_FEATURE_BITS )
5135  {
5136  rc = _check_feat_supp_bit( p_ddev->builtin_features, feat_num );
5137  goto out;
5138  }
5139  break; // invalid
5140 
5141 
5143  #if defined( DEBUG )
5144  cp = "builtin_feat";
5145  max_bit = N_PCPS_REF;
5146  #endif
5147  if ( feat_num < N_PCPS_REF )
5148  {
5149  rc = ( feat_num == _pcps_ddev_ref_type( p_ddev ) ) ? MBG_SUCCESS : MBG_ERR_NOT_SUPP_BY_DEV;
5150  goto out;
5151  }
5152  break; // invalid
5153 
5154 
5155  case DEV_FEAT_TYPE_PCPS:
5156  #if defined( DEBUG )
5157  cp = "pcps_feat";
5158  max_bit = N_PCPS_FEATURE_BITS;
5159  #endif
5160  if ( feat_num < N_PCPS_FEATURE_BITS )
5161  {
5162  rc = _check_feat_supp_bit( p_ddev->dev.cfg.features, feat_num );
5163  goto out;
5164  }
5165  break; // invalid
5166 
5167 
5168  case DEV_FEAT_TYPE_RI:
5169  #if defined( DEBUG )
5170  cp = "ri_feat";
5171  max_bit = N_GPS_FEATURE;
5172  #endif
5173  if ( feat_num < N_GPS_FEATURE )
5174  {
5175  rc = _check_feat_supp_bit( p_ddev->xdev_features.receiver_info.features, feat_num );
5176  goto out;
5177  }
5178  break; // invalid
5179 
5180 
5181  case DEV_FEAT_TYPE_XFEAT:
5182  #if defined( DEBUG )
5183  cp = "x_feat";
5184  max_bit = N_MBG_XFEATURE;
5185  #endif
5186  if ( feat_num < N_MBG_XFEATURE )
5187  {
5189  sizeof( p_ddev->xdev_features.xfeature_buffer ) );
5190  goto out;
5191  }
5192  break; // invalid
5193 
5194 
5196  #if defined( DEBUG )
5197  cp = "tlv_feat";
5198  max_bit = N_MBG_TLV_FEAT_TYPES;
5199  #endif
5200  if ( feat_num < N_MBG_TLV_FEAT_TYPES )
5201  {
5203  sizeof( p_ddev->xdev_features.tlv_info.supp_tlv_feat ) );
5204  goto out;
5205  }
5206  break; // invalid
5207 
5208 
5209  default:
5210  #if defined( DEBUG )
5211  cp = "*invalid* request";
5212  max_bit = 0;
5213  #endif
5214  rc = MBG_ERR_INV_PARM;
5215  goto out;
5216  }
5217 
5218  // Feature bit out of range
5219  rc = MBG_ERR_INV_PARM;
5220 
5221 out:
5222  _mbgddmsg_5( DEBUG, MBG_LOG_INFO, "chk_dev_feat: %s %lu/%lu -> rc %i: %s",
5223  cp, (ulong) feat_num, (ulong) max_bit, rc,
5224  mbg_rc_is_success( rc ) ? "success" : mbg_strerror( rc ) );
5225 
5226  return rc;
5227 
5228 } // pcps_chk_dev_feat
5229 
5230 
5231 
5232 #if _PCPS_USE_USB && !defined( MBG_TGT_WIN32 )
5233 
5234 // The Windows-specific version is implemeted elsewhere.
5235 
5236 static /*HDR*/
5250 int pcps_usb_init( PCPS_DDEV *pddev )
5251 {
5252  int rc = MBG_ERR_NOT_SUPP_ON_OS;
5253 
5254  #if defined( MBG_TGT_LINUX )
5255 
5256  int usb_rc = usb_set_interface( pddev->udev, 0, 0 );
5257 
5258  if ( usb_rc < 0 ) // error returned by USB stack
5259  {
5260  rc = mbg_posix_errno_to_mbg( -usb_rc, NULL );
5261 
5262  _mbg_kdd_msg_3( MBG_LOG_ERR, "usb_set_interface failed with USB rc %d -> %d: %s",
5263  usb_rc, rc, mbg_strerror( rc ) );
5264  }
5265  else
5266  {
5267  struct usb_host_interface *iface_desc = pddev->intf->cur_altsetting;
5268  int i;
5269 
5270  pddev->n_usb_ep = 0;
5271 
5272  for ( i = 0; i < iface_desc->desc.bNumEndpoints; i++ )
5273  {
5274  struct usb_endpoint_descriptor *endpoint = &iface_desc->endpoint[i].desc;
5275  PCPS_USB_EP *p_ep = &pddev->ep[i];
5276  p_ep->addr = endpoint->bEndpointAddress;
5277  p_ep->attrib = endpoint->bmAttributes;
5278  p_ep->max_packet_size = le16_to_cpu( endpoint->wMaxPacketSize );
5279  _mbgddmsg_4( DEBUG_DEV_INIT, MBG_LOG_INFO, "Endpoint %d: addr %02X, size: %d, attrib: %02X",
5280  i, p_ep->addr, p_ep->max_packet_size, p_ep->attrib );
5281  pddev->n_usb_ep++;
5282  }
5283 
5284  rc = MBG_SUCCESS;
5285  }
5286 
5287  #else
5288 
5289  #error USB endpoint configuration can not be determined for this target.
5290 
5291  #endif
5292 
5293  return rc;
5294 
5295 } // pcps_usb_init
5296 
5297 #endif // _PCPS_USE_USB && !defined( MBG_TGT_WIN32 )
5298 
5299 
5300 
5301 static /*HDR*/
5302 void set_access_mode( PCPS_DDEV *pddev, uint mode, bool forced, PCPS_READ_FNC *read_fnc )
5303 {
5304  pddev->access_mode = mode;
5305  pddev->access_mode_forced = forced;
5306  pddev->read = read_fnc;
5307 
5308 } // set_access_mode
5309 
5310 
5311 
5312 static /*HDR*/
5313 void report_access_mode( const PCPS_DDEV *pddev )
5314 {
5315  static const char * const strs[N_PCPS_ACCESS_MODES] = PCPS_ACCESS_MODE_STRS;
5316 
5317  const char *str_access_mode;
5318  int log_lvl;
5319  bool must_report;
5320 
5321  #if MUST_REPORT_ACCESS_MODE
5322  // Always report.
5323  must_report = true;
5324  #else
5325  // Report only if mode forced.
5326  must_report = pddev->access_mode_forced;
5327  #endif
5328 
5329  if ( must_report )
5330  {
5331  if ( pddev->access_mode < N_PCPS_ACCESS_MODES )
5332  {
5333  str_access_mode = strs[pddev->access_mode];
5334  log_lvl = MBG_LOG_INFO;
5335  }
5336  else
5337  {
5338  str_access_mode = str_unkn_braced;
5339  log_lvl = MBG_LOG_WARN;
5340  }
5341 
5342  _mbg_kdd_msg_2( log_lvl, "Access mode: %s%s", str_access_mode,
5344  }
5345 
5346 } // report_access_mode
5347 
5348 
5349 
5350 #if PCPS_LOG_STD_MSGS
5351 
5352 static /*HDR*/
5353 void report_device_info( const PCPS_DDEV *pddev )
5354 {
5355  char ws[160];
5356 
5357  int n = mbg_kdd_snprintf( ws, sizeof( ws ), "Found %s, S/N %s",
5358  _pcps_ddev_fw_id( pddev ), _pcps_ddev_sernum( pddev ) );
5359 
5360  if ( _pcps_ddev_io_base_raw( pddev, 0 ) )
5361  {
5362  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n,
5363  ", port %03lX", (ulong) _pcps_ddev_io_base_raw( pddev, 0 ) );
5364 
5365  if ( _pcps_ddev_io_base_raw( pddev, 1 ) )
5366  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n,
5367  ",%03lX", (ulong) _pcps_ddev_io_base_raw( pddev, 1 ) );
5368  }
5369 
5370  if ( pddev->rsrc_info.num_rsrc_irq )
5371  n += mbg_kdd_snprintf( &ws[n], sizeof( ws ) - n,
5372  ", irq %i", _pcps_ddev_irq_num( pddev ) );
5373 
5374  _mbg_kdd_msg_1( MBG_LOG_INFO, "%s", ws );
5375 
5376  if ( _pcps_ddev_fw_has_20ms_bug( pddev ) )
5377  _mbg_kdd_msg_3( MBG_LOG_WARN, "** Warning: %s v" PCPS_FW_STR_FMT
5378  " has a 20 ms timing bug. Please upgrade the firmware!",
5379  _pcps_ddev_type_name( pddev ),
5382 
5383 } // report_device_info
5384 
5385 #endif // PCPS_LOG_STD_MSGS
5386 
5387 
5388 
5389 /*HDR*/
5410  PCPS_BUS_NUM bus_num,
5411  PCPS_SLOT_NUM dev_fnc_num )
5412 {
5413  // The PC cycles frequency only needs to be determined once,
5414  // so this flag is used to remember if this has been done before.
5415  static bool pc_cycles_frequency_read;
5416 
5417  ushort port_rsrc_len[N_PCPS_PORT_RSRC] = { 0 };
5418  int port_ranges_expected = 0;
5419  int mem_ranges_expected = 0;
5420  const char *cp = str_empty;
5421  int i;
5422  int rc = MBG_ERR_GENERIC;
5423 
5425 
5426  #if !defined( MBG_TGT_DOS )
5427  // Try to read the PC's cycles frequency, but only once.
5428  if ( !pc_cycles_frequency_read )
5429  {
5431  _mbgddmsg_1( DEBUG, MBG_LOG_DEBUG, "PC cycles frequency: %" PRIi64 " Hz",
5433 
5434  pc_cycles_frequency_read = true;
5435  }
5436  #endif
5437 
5438  #if _PCPS_USE_MM_IO
5439  #if defined( FORCE_IO_ACCESS )
5440  force_io_access = FORCE_IO_ACCESS;
5441  #endif
5442 
5443  #if defined( FORCE_MM16_ACCESS )
5444  force_mm16_access = FORCE_MM16_ACCESS;
5445  #endif
5446  #endif
5447 
5448  pddev->dev.cfg.bus_num = bus_num;
5449  pddev->dev.cfg.slot_num = dev_fnc_num;
5450 
5451  #if MUST_REPORT_PROBE_DEVICE_DETAILS
5452  report_probe_device( pddev );
5453  #endif
5454 
5456 
5458  {
5459  _mbgddmsg_3( DEBUG_DEV_INIT, MBG_LOG_ERR, "Probe %s (ID 0x%X) fails, err flags 0x%X",
5460  _pcps_ddev_type_name( pddev ), _pcps_ddev_dev_id( pddev ),
5461  _pcps_ddev_err_flags( pddev ) );
5462 
5463  goto out_fail_generic;
5464  }
5465 
5466 
5467  // If mutexes or spinlocks need to be destroyed on the target OS
5468  // when the driver shuts down then they have already been initialized
5469  // in the device allocation routine and will be destroyed in the
5470  // complementary device deallocation routine.
5471  //
5472  // However, there are target OSs where those semaphores don't need
5473  // to be destroyed, and sometimes even *must not* be initialized
5474  // when the device structure is allocated (e.g under Windows),
5475  // in which case the semaphores need to be initialized here.
5476  #if !defined( _mbg_mutex_destroy )
5477  #if defined( _mbg_mutex_init )
5478  _mbg_mutex_init( &pddev->dev_mutex, MBG_DRVR_NAME "_dev_mutex" );
5479  #endif
5480  #endif
5481  #if !defined( _mbg_spin_lock_destroy )
5482  #if defined( _mbg_spin_lock_init )
5483  _mbg_spin_lock_init( &pddev->tstamp_lock, MBG_DRVR_NAME "_tstamp_lock" );
5484  _mbg_spin_lock_init( &pddev->irq_lock, MBG_DRVR_NAME "_irq_lock" );
5485  #endif
5486  #endif
5487 
5488 
5489  // Next we do some setup depending on the interface type
5490  // and chip.
5491 
5492  switch ( _pcps_ddev_bus_flags( pddev ) )
5493  {
5494  #if _PCPS_USE_USB
5495  case PCPS_BUS_USB:
5496  case PCPS_BUS_USB_V2:
5497  #if defined( MBG_TGT_LINUX ) && USE_LOCAL_IO_BUFFER
5498  _mbg_kdd_msg_0( MBG_LOG_WARN, "Driver built using local I/O buffers, which can cause problems with newer kernels." );
5499  #endif
5500 
5501  // No direct port I/O possible.
5502  set_access_mode( pddev, PCPS_ACC_MODE_USB, 0, pcps_read_usb );
5503 
5504  // Do some USB-specific initializiation.
5505  rc = pcps_usb_init( pddev );
5506 
5507  if ( mbg_rc_is_error( rc ) )
5508  {
5510  goto out;
5511  }
5512 
5513  if ( pddev->n_usb_ep < MBGUSB_MIN_ENDPOINTS_REQUIRED )
5514  {
5515  _mbg_kdd_msg_3( MBG_LOG_ERR, "Device %s supports only %d endpoints while %d are required",
5516  _pcps_ddev_type_name( pddev ), pddev->n_usb_ep,
5517  MBGUSB_MIN_ENDPOINTS_REQUIRED );
5519  goto out_fail_generic;
5520  }
5521  break;
5522 
5523  #endif // _PCPS_USE_USB
5524 
5525 
5526  case PCPS_BUS_PCI_MBGPEX:
5527  port_rsrc_len[0] = sizeof( PCI_ASIC );
5528  port_ranges_expected = 1;
5529  mem_ranges_expected = 1;
5530  pddev->status_port_offs = offsetof( PCI_ASIC, status_port );
5531  #if _PCPS_USE_MM_IO
5532  // If memory mapped access is supported then we use that
5533  // by default, unless I/O access is explicitly requested.
5534  if ( force_io_access )
5536  else
5537  set_access_mode( pddev, PCPS_ACC_MODE_MM, 0, pcps_read_asic_mm );
5538  #else
5539  // If memory mapped access is not supported
5540  // then we do I/O access anyway.
5542  #endif
5543  break;
5544 
5545 
5546  case PCPS_BUS_PCI_PEX8311:
5547  port_rsrc_len[0] = 0;
5548  port_rsrc_len[1] = sizeof( PCI_ASIC ); // same as ASIC
5549  port_ranges_expected = 2; // ranges will be swapped later
5550  // mem_ranges_expected = 2; // TODO Do we need this?
5551  pddev->status_port_offs = offsetof( PCI_ASIC, status_port ); // same as ASIC
5552  // We always use port I/O by default.
5554  #if _PCPS_USE_MM_IO
5555  // If memory mapped access is supported then we use that
5556  // only if explicitly requested since memory mapped access
5557  // with this chip is only 16 bit wide.
5558  if ( force_mm16_access )
5559  set_access_mode( pddev, PCPS_ACC_MODE_MM16, 1, pcps_read_asic_mm16 );
5560  #endif
5561  break;
5562 
5563 
5564  case PCPS_BUS_PCI_ASIC:
5565  port_rsrc_len[0] = sizeof( PCI_ASIC );
5566  port_ranges_expected = 1;
5567  // Only I/O access is supported anyway.
5568  pddev->status_port_offs = offsetof( PCI_ASIC, status_port );
5570  break;
5571 
5572 
5573  case PCPS_BUS_PCI_S5920:
5574  port_rsrc_len[0] = AMCC_OP_REG_RANGE_S5920;
5575  port_rsrc_len[1] = 16; //##++
5576  port_ranges_expected = 2;
5577  pddev->status_port_offs = AMCC_OP_REG_IMB4 + 3;
5578  // Only I/O access is supported anyway.
5580  break;
5581 
5582 
5583  case PCPS_BUS_PCI_S5933:
5584  port_rsrc_len[0] = AMCC_OP_REG_RANGE_S5933;
5585  port_ranges_expected = 1;
5586  pddev->status_port_offs = AMCC_OP_REG_IMB4 + 3;
5587  // Only I/O access is supported anyway.
5589  break;
5590 
5591 
5592  case PCPS_BUS_MCA:
5593  case PCPS_BUS_ISA:
5594  // resource lengths have already been set
5595  port_ranges_expected = 1;
5596  pddev->status_port_offs = 1;
5597  // Only I/O access is supported anyway.
5599  break;
5600 
5601 
5602  default:
5603  _mbg_kdd_msg_2( MBG_LOG_ERR, "Bus flags %04X not handled for device %s",
5604  _pcps_ddev_bus_flags( pddev ), _pcps_ddev_type_name( pddev ) );
5605  goto out_fail_generic;
5606 
5607  } // switch ( _pcps_ddev_bus_flags( pddev ) )
5608 
5609 
5610  if ( _pcps_ddev_access_mode_io( pddev ) )
5611  {
5612  // check if all required I/O resources have been assigned
5613  if ( pddev->rsrc_info.num_rsrc_io < port_ranges_expected )
5614  {
5615  _mbgddmsg_3( DEBUG_DEV_INIT, MBG_LOG_ERR, "Probe %s fails: I/O port ranges (%u) less than expected (%u)",
5616  _pcps_ddev_type_name( pddev ), pddev->rsrc_info.num_rsrc_io, port_ranges_expected );
5618  goto out_fail_generic;
5619  }
5620  }
5621 
5622  if ( _pcps_ddev_access_mode_mm( pddev ) )
5623  {
5624  // check if all required mem resources have been assigned
5625  if ( pddev->rsrc_info.num_rsrc_mem < mem_ranges_expected )
5626  {
5627  _mbgddmsg_3( DEBUG_DEV_INIT, MBG_LOG_ERR, "Probe %s fails: I/O mem ranges (%u) less than expected (%u)",
5628  _pcps_ddev_type_name( pddev ), pddev->rsrc_info.num_rsrc_mem, mem_ranges_expected );
5630  goto out_fail_generic;
5631  }
5632  }
5633 
5634  // Setup additional properties depending on the
5635  // type of bus interface chip.
5636 
5637  if ( _pcps_ddev_is_pci_mbgpex( pddev ) )
5638  {
5639  pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 0 )
5640  + offsetof( PCI_ASIC, control_status );
5641  pddev->irq_flag_port = pddev->irq_enb_disb_port;
5643 
5644  pddev->irq_ack_port = pddev->irq_enb_disb_port;
5646  goto chip_setup_done;
5647  }
5648 
5649 
5650  if ( _pcps_ddev_is_pci_pex8311( pddev ) )
5651  {
5652  // I/O and memory ranges have to be swapped for the
5653  // low level functions because otherwise the first
5654  // range addressed the chip configuration registers
5655  // while the second range addressed data registers.
5656 
5657  MBG_IOMEM_RSRC tmp_mem_rsrc;
5658  MBG_IOPORT_RSRC tmp_io_rsrc;
5659 
5660  tmp_mem_rsrc = pddev->rsrc_info.mem[0];
5661  pddev->rsrc_info.mem[0] = pddev->rsrc_info.mem[1];
5662  pddev->rsrc_info.mem[1] = tmp_mem_rsrc;
5663 
5664  // There should be only a single memory range for the PLX config registers
5665  // with index 0. We have now moved this to index 1, so we have to increase
5666  // the number of resources.
5667  if ( pddev->rsrc_info.num_rsrc_mem & 0x01 ) // odd
5668  pddev->rsrc_info.num_rsrc_mem++; // make it even
5669 
5670  #if DEBUG_RSRC
5671  _mbg_kdd_msg_4( MBG_LOG_INFO, "Port rsrcs before swapping: %04lX (%08lX), %04lX (%08lX)",
5672  (ulong) pddev->rsrc_info.port[0].base_raw, (ulong) pddev->rsrc_info.port[0].base_mapped,
5673  (ulong) pddev->rsrc_info.port[1].base_raw, (ulong) pddev->rsrc_info.port[1].base_mapped );
5674  #endif
5675 
5676  tmp_io_rsrc = pddev->rsrc_info.port[0];
5677  pddev->rsrc_info.port[0] = pddev->rsrc_info.port[1];
5678  pddev->rsrc_info.port[1] = tmp_io_rsrc;
5679 
5680  #if DEBUG_RSRC
5681  _mbg_kdd_msg_4( MBG_LOG_INFO, "Port rsrcs after swapping: %04lX (%08lX), %04lX (%08lX)",
5682  (ulong) pddev->rsrc_info.port[0].base_raw, (ulong) pddev->rsrc_info.port[0].base_mapped,
5683  (ulong) pddev->rsrc_info.port[1].base_raw, (ulong) pddev->rsrc_info.port[1].base_mapped );
5684  #endif
5685 
5686  // Attention: the interrupt control/status register is located in
5687  // the PLX configuration space which is addressed by a different
5688  // port address range than the normal data ports !!
5692 
5695 
5696  pddev->irq_ack_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + offsetof( PCI_ASIC, control_status );
5698  goto chip_setup_done;
5699  }
5700 
5701  if ( _pcps_ddev_is_pci_asic( pddev ) )
5702  {
5703  pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 0 )
5704  + offsetof( PCI_ASIC, control_status );
5705  pddev->irq_flag_port = pddev->irq_enb_disb_port;
5707 
5708  pddev->irq_ack_port = pddev->irq_enb_disb_port;
5710  goto chip_setup_done;
5711  }
5712 
5713  if ( _pcps_ddev_is_pci_amcc( pddev ) )
5714  {
5715  pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 0 )
5717  pddev->irq_enb_mask = AMCC_INT_ENB;
5718  pddev->irq_disb_mask = AMCC_INT_MASK;
5719 
5720  pddev->irq_flag_port = pddev->irq_enb_disb_port;
5721  pddev->irq_flag_mask = AMCC_INT_FLAG;
5722 
5723  pddev->irq_ack_port = pddev->irq_enb_disb_port;
5724  pddev->irq_ack_mask = AMCC_INT_ACK;
5725  goto chip_setup_done;
5726  }
5727 
5728 chip_setup_done:
5729 
5730 
5731  // Chip-specific setup done. Continue with common device setup.
5732 
5733  report_access_mode( pddev );
5734 
5735  setup_mm_addr( pddev );
5736 
5737  pddev->status_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + pddev->status_port_offs;
5738 
5739  // Set up the resource list in pddev->dev.cfg which
5740  // isn't really required anymore, but just informational.
5741 
5742  for ( i = 0; i < N_PCPS_PORT_RSRC; i++ )
5743  {
5744  MBG_IOPORT_RSRC *prsrc;
5745 
5746  if ( i >= port_ranges_expected )
5747  break;
5748 
5749  prsrc = &pddev->rsrc_info.port[i];
5750 
5751  // If the resource len has not yet been set
5752  // then use the default resource len.
5753  if ( prsrc->num == 0 )
5754  prsrc->num = port_rsrc_len[i];
5755 
5756  rsrc_port_to_cfg_port( &pddev->dev.cfg.port[i], &pddev->rsrc_info.port[i] );
5757  }
5758 
5759  pddev->dev.cfg.irq_num = pddev->rsrc_info.num_rsrc_irq ?
5760  pddev->rsrc_info.irq.num : -1;
5762 
5764 
5765  #if DEBUG_PORTS
5766  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "IRQ enb/disb port: %04lX, enb: %08lX, disb: %08lX",
5767  (ulong) pddev->irq_enb_disb_port,
5768  (ulong) pddev->irq_enb_mask,
5769  (ulong) pddev->irq_disb_mask
5770  );
5771  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "IRQ flag port: %04lX, mask: %08lX",
5772  (ulong) pddev->irq_flag_port,
5773  (ulong) pddev->irq_flag_mask
5774  );
5775  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "IRQ ack port: %04lX, mask: %08lX",
5776  (ulong) pddev->irq_ack_port,
5777  (ulong) pddev->irq_ack_mask
5778  );
5779  _mbg_kdd_msg_1( MBG_LOG_DEBUG, "Status port: %04lX", (ulong) pddev->status_port );
5780  #endif
5781 
5782 
5783  // There are some BIOSs out there which don't configure some PEX cards
5784  // with PLX chips properly, and thus the cards can not be accessed.
5785  // See note near the definition of ::_pcps_pci_cfg_err for details.
5786  if ( _pcps_ddev_pci_cfg_err( pddev ) )
5787  {
5788  _mbg_kdd_msg_2( MBG_LOG_WARN, "Duplicate base address 0x%04lX, device %s will not work properly (BIOS faulty)",
5789  (ulong) _pcps_ddev_io_base_raw( pddev, 0 ), _pcps_ddev_type_name( pddev ) );
5790  goto fail_with_cleanup;
5791  }
5792 
5793  #if 0 && DEBUG //### TODO testing only
5794  {
5795  MBG_SYS_UPTIME uptime;
5796  mbg_get_sys_uptime( &uptime );
5797  mbg_sleep_sec( 1 );
5798  mbg_get_sys_uptime( &uptime );
5799  }
5800  #endif
5801 
5802  // A PTP270PEX card must have finished booting
5803  // before it can be accessed.
5804  if ( pcps_ddev_is_ptp270pex( pddev ) )
5805  wait_ptp270pex_ready( pddev );
5806 
5807 
5808  #if TEST_PORT_ACCESS
5809  test_port_access( pddev );
5810  #endif // TEST_PORT_ACCESS
5811 
5812 
5813  // try to read firmware ID
5814  rc = pcps_get_fw_id( pddev, pddev->dev.cfg.fw_id );
5815 
5816  if ( mbg_rc_is_error( rc ) )
5817  {
5818  if ( _pcps_ddev_is_isa( pddev ) )
5819  {
5820  // ISA devices are detected by trying to read a firmware ID via
5821  // a given port, so if the firmware ID could not be read then this
5822  // just means there is no device using the given port address.
5823  _mbgddmsg_1( DEBUG_DEV_INIT, MBG_LOG_WARN, "No ISA card found at port %03lXh.",
5824  (ulong) _pcps_ddev_io_base_raw( pddev, 0 ) );
5825  }
5826  else
5827  {
5828  // Non-ISA devices are detected by some other means, so if the
5829  // firmware ID could not be read this is a serious error.
5830  _mbg_kdd_msg_3( MBG_LOG_ERR, "Probe device %s %i/%i: failed to read firmware ID",
5831  _pcps_ddev_type_name( pddev ), bus_num, dev_fnc_num );
5832  }
5833 
5835  goto fail_with_cleanup;
5836  }
5837 
5838 
5839  if ( _pcps_ddev_bus_flags( pddev ) == PCPS_BUS_ISA )
5840  {
5841  ushort dev_type;
5842 
5843  // Still need to find out which type of ISA clock we have found.
5844  // Check EPROM ID to find out which kind of clock is installed.
5845  if ( pcps_check_id( pddev, fw_id_ref_gps ) == MBG_SUCCESS )
5846  dev_type = PCPS_TYPE_GPS167PC;
5847  else
5848  {
5849  if ( mbg_rc_is_success( pcps_check_id( pddev, fw_id_ref_pcps ) ) )
5850  {
5851  // Device is a PC31, or a PC32 if it has signature code.
5852  // If no support for MCA has been compiled in, it may even
5853  // be a PS31 which is software compatible with a PC31.
5854  dev_type =
5855  ( _mbg_inp16_to_cpu( pddev, 0, _pcps_ddev_io_base_mapped( pddev, 0 ) + 2 )
5858  }
5859  else
5860  {
5862  goto fail_with_cleanup;
5863  }
5864  }
5865 
5866  pddev->dev.type = pcps_dev_type[dev_type];
5867  }
5868 
5869  #if defined( MBG_TGT_OS2 )
5870  pcps_rsrc_register_device( pddev );
5871  #endif
5872 
5873  // Extract the firmware revision number from the ID string.
5874  pddev->dev.cfg.fw_rev_num = pcps_get_rev_num( _pcps_ddev_fw_id( pddev ) );
5875 
5876  // If the device has an ASIC, EPLD or FPGA read the ASIC version number
5877  if ( _pcps_ddev_has_asic_version( pddev ) )
5878  {
5879  #if _PCPS_USE_MM_IO
5880  if ( _pcps_ddev_access_mode_mm( pddev ) )
5881  {
5883  cp = "MM";
5884  }
5885  else
5886  #endif // _PCPS_USE_MM_IO
5887  {
5888  pddev->raw_asic_version = _mbg_inp32_to_cpu( pddev, 0, _pcps_ddev_io_base_mapped( pddev, 0 )
5889  + offsetof( PCI_ASIC, raw_version ) );
5890  cp = "I/O";
5891  }
5892 
5894 
5895  #if DEBUG_IO || DEBUG_RSRC || REPORT_CFG
5896  _mbg_kdd_msg_3( MBG_LOG_INFO, "ASIC version 0x%04lX read via %s (raw: 0x%04lX)",
5897  (ulong) pddev->asic_version, cp,
5898  (ulong) pddev->raw_asic_version );
5899  #endif
5900 
5901  if ( _pcps_ddev_is_pci_asic( pddev ) ) // TODO do we need this? Use macro!
5903  _mbg_kdd_msg_0( MBG_LOG_WARN, "Warning: This old device has a PCI interface CRC bug!" );
5904  }
5905 
5906 
5907  // Setup some feature flags which depend on the device type
5908  // and firmware version.
5909  switch ( _pcps_ddev_type_num( pddev ) )
5910  {
5911  case PCPS_TYPE_PC31:
5912  case PCPS_TYPE_PS31_OLD:
5913  case PCPS_TYPE_PS31:
5920  break;
5921 
5922  case PCPS_TYPE_PC32:
5924  pddev->dev.cfg.features = PCPS_FEAT_PC32;
5925  break;
5926 
5927  case PCPS_TYPE_PCI32:
5929  pddev->dev.cfg.features = PCPS_FEAT_PCI32;
5930  break;
5931 
5932  case PCPS_TYPE_GPS167PC:
5937  break;
5938 
5939  case PCPS_TYPE_GPS167PCI:
5945  break;
5946 
5947  case PCPS_TYPE_PCI509:
5949  pddev->dev.cfg.features = PCPS_FEAT_PCI509;
5950  break;
5951 
5952  case PCPS_TYPE_GPS168PCI:
5957  break;
5958 
5959  case PCPS_TYPE_PCI510:
5961  pddev->dev.cfg.features = PCPS_FEAT_PCI510;
5962  break;
5963 
5964  case PCPS_TYPE_GPS169PCI:
5968  break;
5969 
5970  case PCPS_TYPE_TCR510PCI:
5974  break;
5975 
5976  case PCPS_TYPE_TCR167PCI:
5979  break;
5980 
5981  case PCPS_TYPE_GPS170PCI:
5984  break;
5985 
5986  case PCPS_TYPE_PCI511:
5988  pddev->dev.cfg.features = PCPS_FEAT_PCI511;
5990  break;
5991 
5992  case PCPS_TYPE_TCR511PCI:
5998  break;
5999 
6000  case PCPS_TYPE_PEX511:
6002  pddev->dev.cfg.features = PCPS_FEAT_PEX511;
6003  // HR time support for the PEX511 requires both a certain ASIC
6004  // version plus a certain firmware version.
6008 
6011  break;
6012 
6013  case PCPS_TYPE_TCR511PEX:
6021  break;
6022 
6023  case PCPS_TYPE_GPS170PEX:
6028  break;
6029 
6030  case PCPS_TYPE_USB5131:
6032  pddev->dev.cfg.features = PCPS_FEAT_USB5131;
6033  break;
6034 
6035  case PCPS_TYPE_TCR51USB:
6041  break;
6042 
6043  case PCPS_TYPE_MSF51USB:
6046  break;
6047 
6048  case PCPS_TYPE_PTP270PEX:
6051  break;
6052 
6053  case PCPS_TYPE_FRC511PEX:
6056  break;
6057 
6058  case PCPS_TYPE_TCR170PEX:
6061  break;
6062 
6063  case PCPS_TYPE_WWVB51USB:
6066  break;
6067 
6068  case PCPS_TYPE_GPS180PEX:
6071  break;
6072 
6073  case PCPS_TYPE_TCR180PEX:
6076  break;
6077 
6078  case PCPS_TYPE_DCF600USB:
6081  break;
6082 
6083  case PCPS_TYPE_PZF180PEX:
6086  break;
6087 
6088  case PCPS_TYPE_TCR600USB:
6091  break;
6092 
6093  case PCPS_TYPE_MSF600USB:
6096  break;
6097 
6098  case PCPS_TYPE_WVB600USB:
6101  break;
6102 
6103  case PCPS_TYPE_GLN180PEX:
6106  break;
6107 
6108  case PCPS_TYPE_GPS180AMC:
6111  break;
6112 
6113  case PCPS_TYPE_GNS181PEX:
6116  // pddev->dev.cfg.features |= PCPS_HAS_SERNUM; FIXME This is *not* supported!
6117  break;
6118 
6119  case PCPS_TYPE_TCR180USB:
6122  break;
6123 
6124  default:
6125  _mbg_kdd_msg_1( MBG_LOG_WARN, "No feature detection for device %s",
6126  _pcps_ddev_type_name( pddev ) );
6127  goto fail_with_cleanup;
6128 
6129  } // switch
6130 
6131 
6132  rc = setup_sernum_and_receiver_info( pddev );
6133 
6134  #if PCPS_LOG_STD_MSGS
6135  report_device_info( pddev );
6136  #endif
6137 
6138  if ( mbg_rc_is_error( rc ) )
6139  goto fail_with_cleanup;
6140 
6142 
6143  if ( _pcps_ddev_has_asic_features( pddev ) )
6144  {
6145  #if _PCPS_USE_MM_IO
6146  if ( _pcps_ddev_access_mode_mm( pddev ) )
6147  {
6149  cp = "MM";
6150  }
6151  else
6152  #endif // _PCPS_USE_MM_IO
6153  {
6154  pddev->asic_features = _mbg_inp32_to_cpu( pddev, 0, _pcps_ddev_io_base_mapped( pddev, 0 )
6155  + offsetof( PCI_ASIC, features ) );
6156  cp = "I/O";
6157  }
6158 
6159  #if DEBUG_IO || DEBUG_RSRC || REPORT_CFG
6160  _mbg_kdd_msg_2( MBG_LOG_DEBUG, "ASIC features 0x%08lX read via %s",
6161  (ulong) pddev->asic_features, cp );
6162  #endif
6163 
6164  if ( pddev->asic_features & PCI_ASIC_HAS_MM_IO )
6166  else
6167  if ( pddev->dev.cfg.features & PCPS_HAS_FAST_HR_TSTAMP )
6168  {
6169  // The device supports memory mapped time stamps by default.
6170  // However, this is not reflected by the ASIC features.
6171  #if REPORT_CFG
6172  _mbg_kdd_msg_0( MBG_LOG_WARN, "Warning: ASIC features don't reflect memory mapped time stamp support." );
6173  #endif
6174  }
6175  }
6176 
6177  #if _PCPS_USE_USB
6178  if ( _pcps_ddev_is_usb( pddev ) )
6179  {
6180  rc = check_usb_timing( pddev );
6181 
6182  if ( mbg_rc_is_error( rc ) )
6183  {
6185  goto fail_with_cleanup;
6186  }
6187  }
6188  #endif // _PCPS_USE_USB
6189 
6190 
6191  #if DEBUG_IO && defined( MBG_TGT_LINUX )
6192  {
6193  #if USE_LOCAL_IO_BUFFER
6194  PCPS_TIME t;
6195  PCPS_TIME *p_t = &t;
6196  #else
6197  PCPS_TIME *p_t = &pddev->io_buffer.pcps_time;
6198  #endif
6199 
6200  int sz = sizeof( *p_t );
6201 
6202  memset( p_t, 0, sz );
6203  _mbg_kdd_msg_0( MBG_LOG_INFO, "Reading current PCPS_TIME as test:" );
6204  rc = _pcps_read( pddev, PCPS_GIVE_TIME, p_t, sz );
6205  _mbg_kdd_msg_2( MBG_LOG_INFO, "Read time, sz %lu, returned %i", (ulong) sz, rc );
6206  _mbg_kdd_msg_4( MBG_LOG_INFO, " sec100 %02u, sec %02u, min %02u, hour %02u",
6207  p_t->sec100, p_t->sec, p_t->min, p_t->hour );
6208  _mbg_kdd_msg_4( MBG_LOG_INFO, " mday %02u, wday %02u, month %02u, year %02u",
6209  p_t->mday, p_t->wday, p_t->month, p_t->year );
6210  _mbg_kdd_msg_3( MBG_LOG_INFO, " status 0x%02X, sig 0x%02X, offs_utc 0x%02X",
6211  p_t->status, p_t->signal, p_t->offs_utc );
6212  }
6213  #endif
6214 
6215  #if REPORT_CFG
6216  _mbg_kdd_msg_3( MBG_LOG_DEBUG, "%s v%03X actual PCPS features: 0x%08lX",
6217  _pcps_ddev_type_name( pddev ), _pcps_ddev_fw_rev_num( pddev ),
6218  (ulong) _pcps_ddev_features( pddev ) );
6219  #endif
6220 
6221  rc = MBG_SUCCESS;
6222  goto out;
6223 
6224 
6225 fail_with_cleanup:
6226  pcps_cleanup_device( pddev );
6227  goto out;
6228 
6229 out_fail_generic:
6230  rc = MBG_ERR_GENERIC;
6231 
6232 out:
6233  return rc;
6234 
6235 } // pcps_probe_device
6236 
6237 
6238 
6239 /*HDR*/
6248 {
6250 
6251  #if _PCPS_USE_RSRCMGR
6252  pcps_release_rsrcs( pddev );
6253  #endif
6254 
6255 } // pcps_cleanup_device
6256 
6257 
6258 
6259 #if _PCPS_USE_PCI_BIOS
6260 
6261 static /*HDR*/
6277 PCPS_ERR_FLAGS pcps_read_pci_rsrc( PCPS_BUS_NUM bus_num,
6278  PCPS_SLOT_NUM dev_fnc_num,
6279  PCPS_DDEV *pddev )
6280 {
6281  PCPS_ERR_FLAGS err_flags = 0;
6282  uchar irq;
6283  short pci_rc;
6284  PCI_DWORD dw;
6285  int i;
6286 
6287  // Clear resources
6288  memset( &pddev->rsrc_info, 0, sizeof( pddev->rsrc_info ) );
6289 
6290  for ( i = 0; i < MAX_PCPS_RSRC; i++ )
6291  {
6292  pci_rc = _mbg_pci_read_cfg_dword( bus_num, dev_fnc_num,
6293  PCI_CS_BASE_ADDRESS_0 + i * sizeof( uint32_t ), &dw );
6294 
6295  if ( pci_rc != PCI_SUCCESS )
6296  break;
6297 
6298  if ( dw == 0 ) // base address register not used
6299  continue;
6300 
6301  if ( dw & 0x0001 ) // is an I/O resource
6302  {
6303  if ( dw & 0xFFFF0000UL )
6304  {
6305  // The PCI interface chip is not initialized. This
6306  // should occur ONLY at the first-time installation
6307  // at the factory.
6308  err_flags |= PCPS_EF_IO_INIT;
6309  goto out;
6310  }
6311 
6312  pcps_add_rsrc_io( pddev, (uint16_t) ( dw & ~0x0001 ), 0 );
6313  }
6314  else
6315  pcps_add_rsrc_mem( pddev, dw, 0 ); //##++ range length?
6316  }
6317 
6318  // Read the interrupt line assigned to the clock.
6319  // The standard functions, however, don't use any
6320  // interrupt.
6321  pci_rc = _mbg_pci_read_cfg_byte( bus_num, dev_fnc_num,
6322  PCI_CS_INTERRUPT_LINE, &irq );
6323 
6324  if ( pci_rc == PCI_SUCCESS )
6325  pcps_add_rsrc_irq( pddev, irq );
6326 
6327 out:
6328  return err_flags;
6329 
6330 } // pcps_read_pci_rsrc
6331 
6332 
6333 
6334 static /*HDR*/
6355 PCPS_ERR_FLAGS pcps_enable_pci_dev( PCPS_BUS_NUM bus_num,
6356  PCPS_SLOT_NUM dev_fnc_num,
6357  int num_rsrc_mem )
6358 {
6359  PCPS_ERR_FLAGS err_flags = 0;
6360  uint16_t pci_command; // current value read from the PCI cfg "command" register
6361  uint16_t new_pci_command; // new value to be written to the PCI cfg "command" register
6362  int pci_rc;
6363 
6364 
6365  pci_rc = _mbg_pci_read_cfg_word( bus_num, dev_fnc_num,
6366  PCI_CS_COMMAND, &pci_command );
6367  new_pci_command = pci_command | PCI_CMD_ENB_IO_ACC;
6368 
6369  if ( num_rsrc_mem )
6370  new_pci_command |= PCI_CMD_ENB_MEM_ACC;
6371 
6372  if ( new_pci_command != pci_command )
6373  {
6374  pci_rc = _mbg_pci_write_cfg_word( bus_num, dev_fnc_num,
6375  PCI_CS_COMMAND, pci_command );
6376  if ( pci_rc != PCI_SUCCESS )
6377  {
6378  err_flags |= PCPS_EF_IO_ENB;
6379 
6381  "PCI enable device returned %d", pci_rc );
6382  }
6383  }
6384 
6385  return err_flags;
6386 
6387 } // pcps_enable_pci_dev
6388 
6389 
6390 
6391 /*HDR*/
6400  PCPS_BUS_NUM bus_num, PCPS_SLOT_NUM dev_fnc_num )
6401 {
6402  PCPS_ERR_FLAGS err_flags;
6403  int rc;
6404 
6405  err_flags = pcps_read_pci_rsrc( bus_num, dev_fnc_num, pddev );
6406  _pcps_ddev_set_err_flags( pddev, err_flags );
6407 
6408  if ( !( err_flags & PCPS_EF_IO_INIT ) )
6409  {
6410  err_flags = pcps_enable_pci_dev( bus_num, dev_fnc_num,
6411  pddev->rsrc_info.num_rsrc_mem );
6412  _pcps_ddev_set_err_flags( pddev, err_flags );
6413  }
6414 
6415  rc = pcps_probe_device( pddev, bus_num, dev_fnc_num );
6416 
6417  return rc;
6418 
6419 } // pcps_setup_and_start_pci_dev
6420 
6421 
6422 
6423 /*HDR*/
6433 void pcps_detect_pci_devices( PCPS_DDEV_INIT_FNC *ddev_init_fnc,
6434  PCPS_DDEV_CLEANUP_FNC *ddev_cleanup_fnc,
6435  ushort vendor_id, PCPS_DEV_TYPE dev_type[],
6436  int n_dev_types )
6437 {
6438  #if defined( MBG_TGT_QNX )
6439  #if defined( MBG_TGT_QNX_NTO )
6440  unsigned int pci_handle; // specific to QNX Neutrino
6441  #endif
6442  unsigned int pci_hardware_mechanism;
6443  unsigned int pci_last_bus_number;
6444  unsigned int pci_interface_level_version;
6445  #elif defined( MBG_TGT_LINUX )
6446  // not yet supported/used
6447  #else
6448  uchar pci_hardware_mechanism;
6449  uchar pci_last_bus_number;
6450  ushort pci_interface_level_version;
6451  #endif
6452  ushort type_idx;
6453  int rc;
6454 
6455 
6456  #ifdef _mbg_pci_fnc_init
6457  rc = _mbg_pci_fnc_init();
6458 
6459  if ( rc != PCI_SUCCESS )
6460  return;
6461  #endif
6462 
6463 
6464  // See if PCI BIOS is installed on the machine.
6465  rc = _mbg_pci_find_bios( &pci_hardware_mechanism,
6466  &pci_interface_level_version,
6467  &pci_last_bus_number
6468  );
6469 
6470  if ( rc == PCI_SUCCESS )
6471  {
6472  // PCI BIOS is installed, now try to find a PCI clock with
6473  // known ID (the list is terminated with a ID of 0).
6474  for ( type_idx = 0; type_idx < n_dev_types; type_idx++ )
6475  {
6476  ushort dev_idx;
6477  PCPS_DEV_TYPE *p = &dev_type[type_idx];
6478 
6479  if ( !( p->bus_flags & PCPS_BUS_PCI ) )
6480  continue;
6481 
6482 
6483  for ( dev_idx = 0; ; dev_idx++ )
6484  {
6485  PCPS_DDEV *pddev;
6486  #if defined( MBG_TGT_QNX )
6487  unsigned bus_num;
6488  unsigned dev_fnc_num;
6489  #else
6490  uchar bus_num;
6491  uchar dev_fnc_num;
6492  #endif
6493 
6494  rc = _mbg_pci_find_device( p->dev_id, vendor_id,
6495  dev_idx, &bus_num, &dev_fnc_num );
6496 
6497  if ( rc != PCI_SUCCESS )
6498  break; // go to try next device ID
6499 
6500 
6501  _mbgddmsg_2( DEBUG_DEV_INIT, MBG_LOG_INFO, "Found PCI device %s (0x%04X)",
6502  p->name, p->dev_id );
6503 
6504  // New device found, try to add to list.
6505  rc = ddev_init_fnc( &pddev );
6506 
6507  if ( mbg_rc_is_success( rc ) ) // Setup only if successfull.
6508  {
6509  #if _PCPS_USE_PCI_PNP //##++
6510  // This can be used to test the PNP functions in a
6511  // non-PNP environment.
6512  pcps_setup_ddev( pddev, PCPS_BUS_PCI, p->dev_id );
6513  #else
6514  pddev->dev.type = *p;
6515  #endif
6516 
6517  pcps_setup_and_start_pci_dev( pddev, bus_num, dev_fnc_num );
6518 
6519  #if !_ACCEPT_UNINITD_CLOCKS
6520  if ( pddev->dev.cfg.err_flags )
6521  {
6523  "Remove PCI device: err_flags " FMT_08X "h",
6524  (ulong) pddev->dev.cfg.err_flags );
6525 
6526  if ( ddev_cleanup_fnc )
6527  ddev_cleanup_fnc( pddev );
6528  }
6529  #else
6530  (void) ddev_cleanup_fnc; // avoid compiler warning
6531  #endif
6532  }
6533  }
6534  }
6535  }
6536 
6537  #ifdef _mbg_pci_fnc_deinit
6538  _mbg_pci_fnc_deinit();
6539  #endif
6540 
6541 } // pcps_detect_pci_devices
6542 
6543 #endif // _PCPS_USE_PCI_BIOS
6544 
6545 
6546 
6547 #if !_PCPS_USE_ISA_PNP
6548 
6549 /*HDR*/
6560  PCPS_DDEV_CLEANUP_FNC *ddev_cleanup_fnc,
6561  PCPS_DDEV_REGISTER_FNC *ddev_register_fnc,
6562  int isa_ports[PCPS_MAX_ISA_CARDS],
6563  int isa_irqs[PCPS_MAX_ISA_CARDS] )
6564 {
6565  int *p_port = isa_ports;
6566  int *p_irq = isa_irqs;
6567  PCPS_DDEV *pddev;
6568  int i;
6569  int rc;
6570 
6571  if ( p_port == NULL ) // No list has been passed
6572  return; // so don't try to detect ISA clocks.
6573 
6574 
6575  for( i = 0; i < PCPS_MAX_ISA_CARDS;
6576  i++, p_port++, p_irq ? ( p_irq++ ) : p_irq )
6577  {
6578  int irq_num;
6579 
6580  if ( *p_port == 0 )
6581  continue;
6582 
6583  irq_num = p_irq ? *p_irq : -1;
6584 
6586  "Check ISA device at port " FMT_03X "h, irq %d",
6587  *p_port, irq_num );
6588 
6589  // Assume ISA device is available,
6590  // but clock type is unknown, yet.
6591  rc = ddev_init_fnc( &pddev );
6592 
6593  if ( mbg_rc_is_success( rc ) ) // Setup only if successfull.
6594  {
6595  pddev->dev.type.bus_flags = PCPS_BUS_ISA;
6596 
6597  // Set up basic cfg for ISA devices.
6598  pcps_add_rsrc_io( pddev, (uint16_t) *p_port, PCPS_NUM_PORTS_ISA );
6599 
6600  if ( irq_num != -1 )
6601  pcps_add_rsrc_irq( pddev, (uint16_t) *p_irq );
6602 
6603  // Init the device structure. This includes registration
6604  // of I/O ports with the OS's resource manager (if supported),
6605  // and reading the firmware ID.
6606  pcps_probe_device( pddev, 0, 0 );
6607 
6608  // If an error has occurred, then remove the last
6609  // device from the list and try next.
6610  if ( pddev->dev.cfg.err_flags )
6611  {
6613  "ISA device not found: err_flags " FMT_08X "h",
6614  (ulong) pddev->dev.cfg.err_flags );
6615  if ( ddev_cleanup_fnc )
6616  ddev_cleanup_fnc( pddev );
6617 
6618  continue;
6619  }
6620 
6621  // Register the device with the OS, if required.
6622  if ( ddev_register_fnc )
6623  ddev_register_fnc( pddev ); //##++
6624  }
6625  }
6626 
6627 } // pcps_detect_isa_devices
6628 
6629 #endif
6630 
6631 
6632 
6633 #if !_PCPS_USE_PNP
6634 
6635 static /*HDR*/
6648  PCPS_DDEV_CLEANUP_FNC *ddev_cleanup_fnc,
6649  int isa_ports[PCPS_MAX_ISA_CARDS],
6650  int isa_irqs[PCPS_MAX_ISA_CARDS] )
6651 {
6652  #if defined( MBG_TGT_OS2 )
6653  rsrc_register_driver(); // register driver and init resource manager
6654  #endif
6655 
6656  #if _PCPS_USE_PCI_BIOS
6657  pcps_detect_pci_devices( ddev_init_fnc, ddev_cleanup_fnc, PCI_VENDOR_MEINBERG,
6659  #endif
6660 
6661  #if _PCPS_USE_MCA
6662  pcps_detect_mca_devices( ddev_init_fnc );
6663  #endif
6664 
6665  #if !_PCPS_USE_ISA_PNP
6666  pcps_detect_isa_devices( ddev_init_fnc, ddev_cleanup_fnc, NULL, isa_ports, isa_irqs );
6667  #endif
6668 
6669 } // pcps_detect_devices_init
6670 
6671 
6672 
6673 /*HDR*/
6684  int isa_irqs[PCPS_MAX_ISA_CARDS] )
6685 {
6687 
6688 } // pcps_detect_devices
6689 
6690 #endif // !_PCPS_USE_PNP
6691 
6692 
#define N_PCPS_MEM_RSRC
The max number of bus memory resources used by a device.
Definition: pcpsdrvr.h:666
PCPS_DEV_ID dev_id
see MEINBERG_PCI_DEVICE_IDS and MBG_USB_DEVICE_IDS
Definition: pcpsdev.h:516
#define PCPS_CAN_CLR_UCAP_BUFF
see PCPS_BIT_CAN_CLR_UCAP_BUFF
Definition: pcpsdev.h:720
#define _pcps_ddev_short_port_base(_p, _n)
Definition: pcpsdrvr.h:1173
#define MBG_TLV_FEAT_TYPE_NAMES
Names of TLV API features.
Definition: gpsdefs.h:18190
uint16_t flags
additional information, see RECEIVER_INFO_FLAG_MASKS
Definition: gpsdefs.h:890
uint32_t ul
Definition: pci_asic.h:140
#define _pcps_ddev_sernum(_p)
Definition: pcpsdrvr.h:1186
#define PCPS_FEAT_PEX511
Definition: pcpsdev.h:849
#define BUILTIN_FEAT_GPS180AMC
Definition: gpsdefs.h:1762
#define _fstrlen(_s)
Definition: pcpsdrvr.c:559
PCPS_RSRC_INFO rsrc_info
Summary of resources used by the device.
Definition: pcpsdrvr.h:797
uint8_t n_str_type
max num of string types supported by any port
Definition: gpsdefs.h:888
uint8_t year
year of the century, 0..99
Definition: pcpsdefs.h:1138
static void rsrc_port_to_cfg_port(PCPS_SHORT_PORT_RSRC *p_short_port_rsrc, const MBG_IOPORT_RSRC *p_io_rsrc)
Convert a raw I/O base address to a short format.
Definition: pcpsdrvr.c:4878
General Purpose I/O control.
Definition: plxdefs.h:101
uint8_t uc
Definition: pcpsdrvr.h:852
uint32_t irq_disb_mask
Bit mask to be cleared to disable IRQs.
Definition: pcpsdrvr.h:790
#define _pcps_ddev_io_base_raw(_p, _n)
Definition: pcpsdrvr.h:1176
(r/-) IDENT, serial number, deprecated by PC_GPS_RECEIVER_INFO
Definition: pcpsdefs.h:1648
#define _pcps_fw_rev_num_minor(_v)
Definition: pcpsdev.h:1486
int force_mm16_access
MBG_TLV_FEAT_BUFFER supp_tlv_feat
A byte array of supported TLV feature bits, see MBG_TLV_FEAT_TYPES.
Definition: gpsdefs.h:18267
#define _mbg_pci_find_device
Definition: pci.h:99
#define _pcps_ddev_is_mca(_p)
Definition: pcpsdrvr.h:1152
int pcps_generic_io(PCPS_DDEV *pddev, uint8_t type, const void FAR *in_buff, uint8_t in_cnt, void FAR *out_buff, uint8_t out_cnt)
Generic I/O function.
Definition: pcpsdrvr.c:3045
#define _pcps_fw_rev_num_major(_v)
Definition: pcpsdev.h:1483
#define _pcps_ddev_fw_id(_p)
Definition: pcpsdrvr.h:1185
#define _mbgddmsg_fnc_entry()
Definition: mbgddmsg.h:399
static int pcps_check_gps_data_size(PCPS_DDEV *pddev, uint16_t count, const char *info)
Determine which interface buffer size is supported.
Definition: pcpsdrvr.c:3170
#define PCPS_FEAT_PCI511
Definition: pcpsdev.h:805
#define _mbg_kdd_msg_4(_lvl, _fmt, _p1, _p2, _p3, _p4)
Definition: mbgddmsg.h:245
uint32_t ul[4]
Definition: pci_asic.h:187
static int pcps_get_fw_id(PCPS_DDEV *pddev, PCPS_ID_STR FAR fw_id)
Read the firmware ID from a device.
Definition: pcpsdrvr.c:3591
#define _pcps_ddev_is_usb(_p)
Definition: pcpsdrvr.h:1154
#define MAX_PCPS_RSRC
The max number of bus memory and I/O resources used by a device.
Definition: pcpsdrvr.h:672
int PCPS_WRITE_FNC(PCPS_DDEV *pddev, uint8_t cmd, const void *buffer, uint16_t count)
Definition: pcpsdrvr.h:770
uint8_t cmd
In case of small data we just need one of the PCPS_CMD_CODES.
Definition: pcpsdrvr.h:838
#define PCPS_FEAT_MSF51USB
Definition: pcpsdev.h:868
static int pcps_alloc_ddev_struc(PCPS_DDEV **ppddev)
Allocate a device info structure for a device.
Definition: pcpsdrvr.c:4744
#define _pcps_ddev_has_asic_features(_p)
Definition: pcpsdrvr.h:1290
uint16_t us[8]
Definition: pci_asic.h:188
int mbg_kdd_snprintf(char *buf, size_t size, const char *fmt,...)
uint8_t mday
day of month, 0..31
Definition: pcpsdefs.h:1135
#define PCPS_IRQ_STAT_UNSAFE
Definition: pcpsdev.h:1473
uint8_t sec100
hundredths of seconds, 0..99, 10 ms resolution
Definition: pcpsdefs.h:1130
#define PCPS_HAS_UCAP
see PCPS_BIT_HAS_UCAP
Definition: pcpsdev.h:722
#define PLX_PECS_GPIOCTL_GPIO3_DATA
Definition: plxdefs.h:126
#define _pcps_asic_version_major(_v)
Extract the major part of an ASIC version number.
Definition: pci_asic.h:339
#define _mbg_outp8(_dev, _rsrc_idx, _port_addr, _val)
Definition: mbggenio.h:616
#define _mbgddmsg_3(_f, _lvl, _fmt, _p1, _p2, _p3)
Definition: mbgddmsg.h:330
#define BUILTIN_FEAT_GPS170PCI
Definition: gpsdefs.h:1734
int16_t range
an optional base 10 exponent
Definition: gpsdefs.h:849
#define PCPS_HAS_GPS_DATA_16
see PCPS_BIT_HAS_GPS_DATA_16
Definition: pcpsdev.h:725
static const char str_empty[]
Definition: pcpsdrvr.c:642
#define PCPS_HAS_UTC_PARM
see PCPS_BIT_HAS_UTC_PARM
Definition: pcpsdev.h:729
PCPS_TIME pcps_time
Definition: pcpsiobf.h:83
#define BUILTIN_FEAT_GPS169PCI
Definition: gpsdefs.h:1731
MBG_IOPORT_ADDR_RAW base_raw
A raw port base address.
Definition: mbggenio.h:297
PCPS_ERR_FLAGS err_flags
See PCPS_ERR_FLAG_MASKS.
Definition: pcpsdev.h:599
#define PCPS_HAS_SYNTH
see PCPS_BIT_HAS_SYNTH
Definition: pcpsdev.h:726
#define MAX_PARM_POUT
The max number of programmable pulse outputs supported by configuration programs. ...
Definition: cfg_hlp.h:143
void pcps_release_rsrcs(PCPS_DDEV *pddev)
Release I/O port and memory resource that have been claimed before.
Definition: pcpsdrvr.c:4411
PCPS_IRQ_STAT_INFO irq_stat_info
Definition: pcpsdrvr.h:820
#define REV_HAS_CABLE_LEN_GPS167PCI
Definition: pcpsdev.h:1000
#define REV_HAS_IRQ_FIX_MINOR_GPS170PEX
Definition: pcpsdev.h:956
PCPS_BUS_FLAGS bus_flags
see PCPS_BUS_FLAG_MASKS
Definition: pcpsdev.h:518
feat_num field contains one of the GPS_FEATURE_BITS
Definition: pcpsdev.h:1316
void rsrc_dealloc_mem(ulong start, ulong len)
Release a memory resource range which has been allocated before.
Definition: rsrc_lx.c:131
#define MBG_ERR_NO_DATA
The device&#39;s data output data buffer is empty, though it shouldn&#39;t be.
Definition: mbgerror.h:276
static bool pcps_check_pex_irq_unsafe(PCPS_DDEV *pddev, uint16_t req_fw_ver, uint8_t req_asic_ver_major, uint8_t req_asic_ver_minor)
Check if IRQ usage with a device is unsafe.
Definition: pcpsdrvr.c:1152
(r/-) MBG_TLV_INFO, only if MBG_XFEATURE_TLV_API
Definition: pcpsdefs.h:1682
#define REV_HAS_UCAP_GPS167PCI
Definition: pcpsdev.h:991
short int16_t
Definition: words.h:212
static const char * pcps_feature_names[N_PCPS_FEATURE_BITS]
A table of name strings associated with PCPS_FEATURE_BITS.
Definition: pcpsdrvr.c:744
static void report_ret_val(int rc, const char *info)
Report the return code to be returned by a function.
Definition: pcpsdrvr.c:1536
#define PCPS_FEAT_GPS169PCI
Definition: pcpsdev.h:823
#define PCPS_FEAT_FRC511PEX
Definition: pcpsdev.h:883
char epld_name[(8+1)]
ASCIIZ, file name of EPLD image (optional)
Definition: gpsdefs.h:879
Number of defined extended features.
Definition: gpsdefs.h:2369
uint32_t flags
Future use.
Definition: gpsdefs.h:18266
A timestamp with nanosecond resolution, but 64 bit size.
Definition: words.h:621
#define _pcps_disb_local_irq_save()
Definition: pcpsdrvr.c:589
char name[(16+1)]
Optional string identifying a customized firmware version, should be empty in standard versions...
Definition: gpsdefs.h:735
#define MBG_ERR_INV_PARM
Invalid parameter.
Definition: mbgerror.h:329
#define BUILTIN_FEAT_TCR170PEX
Definition: gpsdefs.h:1746
#define REV_HAS_IRQ_FIX_MINOR_TCR511PEX
Definition: pcpsdev.h:955
ulong MBG_IOPORT_ADDR_MAPPED
Definition: mbggenio.h:187
PCPS_READ_FNC pcps_read_null
Definition: pcpsdrvr.c:2073
PCPS_DEV_TYPE type
Definition: pcpsdev.h:1045
uint16_t PCPS_BUS_NUM
Definition: pcpsdev.h:580
#define _mbg_pci_write_cfg_word
Definition: pci_lx.h:60
uint32_t ticks_per_sec
resolution of fractions of seconds, see GPS_TICKS_PER_SEC
Definition: gpsdefs.h:881
#define _mbgddmsg_fnc_exit_err()
Definition: mbgddmsg.h:419
static MBG_PC_CYCLES_FREQUENCY pc_cycles_frequency
Clock frequency of the PC&#39;s cycles counter, in [Hz].
Definition: pcpsdrvr.c:661
#define PCPS_FEAT_GPS180AMC
Definition: pcpsdev.h:928
#define PCI_VENDOR_MEINBERG
Definition: pcidefs.h:240
#define _pcps_ddev_io_base_mapped(_p, _n)
Definition: pcpsdrvr.h:1177
Supports the GPS_SAVE_CFG command.
Definition: gpsdefs.h:2346
uint32_t reserved
Future use.
Definition: gpsdefs.h:18265
unsigned short uint16_t
Definition: words.h:213
static const char str_unkn_braced[]
Definition: pcpsdrvr.c:643
static __mbg_inline void mbg_get_pc_cycles(MBG_PC_CYCLES *p)
Definition: mbgpccyc.h:178
#define _MBG_IOMEM
Definition: mbggenio.h:165
#define MAX_PARM_PORT
The max number of serial ports supported by configuration programs.
Definition: cfg_hlp.h:137
static void beautify_sernum(char *s, size_t max_len)
Definition: pcpsdrvr.c:3749
int rsrc_alloc_mem(ulong start, ulong len)
Try to allocate a memory resource range.
Definition: rsrc_lx.c:104
static void report_access_mode(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.c:5313
0xEC from local
Definition: plxdefs.h:140
static void report_probe_device(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.c:3836
#define _pcps_ddev_ref_type(_p)
Definition: pcpsdrvr.h:1133
#define MBG_DEV_NAME_FMT
A string format specifier for MBG_DEV_NAME.
Definition: pcpsdev.h:1534
static void dump_receiver_info(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.c:3891
uint8_t n_channels
number of satellites which can be tracked simultaneously
Definition: gpsdefs.h:880
#define _mbg_kdd_msg_3(_lvl, _fmt, _p1, _p2, _p3)
Definition: mbgddmsg.h:242
uint32_t irq_flag_mask
Bit mask used to check if device has generated an IRQ.
Definition: pcpsdrvr.h:791
#define PCPS_FEAT_GPS170PCI
Definition: pcpsdev.h:827
#define _pcps_ddev_is_pci(_p)
Definition: pcpsdrvr.h:1153
PCPS_WRITE_FNC pcps_write
Write data to a device.
Definition: pcpsdrvr.c:3020
#define _pcps_ddev_type_num(_p)
Definition: pcpsdrvr.h:1130
static bool str_remove_unprintables(char *s, size_t max_len)
Remove unprintable characters from a string.
Definition: pcpsdrvr.c:3716
#define PCPS_FEAT_TCR510PCI
Definition: pcpsdev.h:832
Resource info summary for a device.
Definition: pcpsdrvr.h:678
#define _mbgddmsg_fnc_exit_success()
Definition: mbgddmsg.h:415
static void pcps_free_ddev_struc(PCPS_DDEV **ppddev)
Free a previously allocated device info structure.
Definition: pcpsdrvr.c:4704
#define _MBG_INIT_CODE_ATTR
Definition: pcpsdrvr.h:410
#define PCI_CMD_ENB_MEM_ACC
Definition: pcidefs.h:187
#define PCI_CS_INTERRUPT_LINE
Definition: pcidefs.h:177
MBG_IOPORT_ADDR_MAPPED irq_ack_port
Address of the register to acknowledge an IRQ.
Definition: pcpsdrvr.h:788
static __mbg_inline void mbg_get_sys_uptime(MBG_SYS_UPTIME *p)
Definition: mbgsystm.h:248
#define PCPS_GIVE_FW_ID_1
(r-) Read first PCPS_FIFO_SIZE chars of firmware ID
Definition: pcpsdefs.h:752
feat_num field contains one of the PCPS_FEATURE_BITS
Definition: pcpsdev.h:1315
static __mbg_inline void mbg_get_sys_time(MBG_SYS_TIME *p)
Definition: mbgsystm.h:171
#define PCPS_HAS_HR_TIME
see PCPS_BIT_HAS_HR_TIME
Definition: pcpsdev.h:713
#define _pcps_ddev_is_pci_asic(_p)
Definition: pcpsdrvr.h:1161
void pcps_cleanup_ddev(PCPS_DDEV *pddev)
Clean up and free a previously initialized device info structure.
Definition: pcpsdrvr.c:4845
#define PCPS_CAN_SET_TIME
Feature bit masks for bus-level devices.
Definition: pcpsdev.h:707
PCPS_SLOT_NUM slot_num
Definition: pcpsdev.h:601
static __mbg_inline void mbg_unmap_ioport_rsrc(MBG_IOPORT_RSRC *p)
Unmap an I/O port resource to release the virtual address.
Definition: mbggenio.h:464
#define _pcps_ddev_access_mode_io(_p)
Definition: pcpsdrvr.h:1210
#define _xfeat_addr(_p)
Definition: pcpsdev.h:1139
#define MBG_ERR_GENERIC
Generic error.
Definition: mbgerror.h:269
#define _mbgddmsg_0(_f, _lvl, _fmt)
Definition: mbgddmsg.h:312
static void check_ri_features(PCPS_DDEV *pddev)
Check the receiver info features to see if a specific feature is supported.
Definition: pcpsdrvr.c:4031
RI_FEATURES features
optional features, see GPS_FEATURE_MASKS
Definition: gpsdefs.h:882
int pcps_init_ddev(PCPS_DDEV **ppddev)
Allocate and initialize a device info structure.
Definition: pcpsdrvr.c:4799
#define mbg_rc_is_success(_rc)
Definition: mbgerror.h:618
#define PCPS_FEAT_PCI32
Definition: pcpsdev.h:797
#define BUILTIN_FEAT_WWVB511
Definition: gpsdefs.h:1747
#define _pcps_ddev_pci_fnc_num(_p)
Definition: pcpsdrvr.h:1170
static int mbg_plx_read_pecs_reg(struct pci_dev *pNode, uint16_t reg, uint32_t *pval)
Read a dword from a PLX PECS register.
Definition: pcpsdrvr.c:804
#define _do_div(_x, _y)
Definition: pcpsdrvr.c:516
static const char * gps_ri_feature_names[N_GPS_FEATURE]
A table of name strings associated with GPS_FEATURE_BITS.
Definition: pcpsdrvr.c:733
uint8_t b[(1024/8)]
Definition: gpsdefs.h:2440
PCPS_READ_FNC pcps_read_gps
Read a large data structure from a device.
Definition: pcpsdrvr.c:3468
PEX EPLD for TCR511PEX.
Definition: pci_asic.h:373
#define _pcps_ddev_fw_rev_num(_p)
Definition: pcpsdrvr.h:1183
char int8_t
Definition: words.h:209
PEX EPLD for GPS170PEX.
Definition: pci_asic.h:372
feat_num field contains one of the GPS_BUILTIN_FEATURE_BITS
Definition: pcpsdev.h:1313
#define AMCC_OP_REG_OMB1
Definition: amccdefs.h:47
#define _ri_addr(_p)
Definition: pcpsdev.h:1138
#define _pcps_ddev_features(_p)
Definition: pcpsdrvr.h:1184
#define AMCC_INT_MASK
Definition: amccdefs.h:86
#define AMCC_INT_ACK
Definition: amccdefs.h:89
#define PCI_ASIC_FIX_IRQ_MINOR_TCR511PEX
Definition: pci_asic.h:414
#define MBG_ERR_NOT_READY
Bus-level device is temp. unable to respond e.g. during init. after RESET.
Definition: mbgerror.h:277
MBG_IOMEM_ADDR_MAPPED start_mapped
A mapped I/O memory start address.
Definition: mbggenio.h:279
#define PCPS_WRITE_GPS_DATA
(-w) Write large data structure, see PC_GPS_CMD_CODES
Definition: pcpsdefs.h:766
#define PCPS_FEAT_GPS180PEX
IRIG TX only supp. if GPS_HAS_IRIG_TX.
Definition: pcpsdev.h:895
#define PCPS_FEAT_MSF600USB
Definition: pcpsdev.h:922
uint8_t n_com_ports
number of on-board serial ports
Definition: gpsdefs.h:887
PCI_ASIC_ADDON_DATA addon_data
Register set used to return data from add-on to PCI bus.
Definition: pci_asic.h:208
#define static_wc
Definition: pcpsdrvr.c:572
feat_num field contains one of the MBG_TLV_FEAT_TYPES
Definition: pcpsdev.h:1318
A structure used to store extended device features.
Definition: gpsdefs.h:2438
#define PCPS_HAS_CABLE_LEN
see PCPS_BIT_HAS_CABLE_LEN
Definition: pcpsdev.h:717
#define clock()
Definition: mbg_lx.h:89
Memory layout of Meinberg PCI interface register.
Definition: pcpsdrvr.h:746
#define _pcps_ddev_is_irig_rx(_p)
Definition: pcpsdrvr.h:1142
#define _mbg_spin_lock_init(_spl, _n)
Definition: mbgmutex.h:204
#define PCPS_ID_SIZE
The maximum length of an ID string, including terminating 0.
Definition: pcpsdefs.h:915
int16_t irq_num
Definition: pcpsdev.h:604
static int pcps_check_id(PCPS_DDEV *pddev, const char FAR *ref)
Check an ASCIIZ string for a valid signature.
Definition: pcpsdrvr.c:3648
#define PCPS_EF_IO_INIT
I/O interface not initialized.
Definition: pcpsdev.h:626
unsigned int PCI_DWORD
Definition: pcpsdrvr.c:578
PCPS_DEV_TYPE pcps_dev_type[N_PCPS_DEV_TYPE]
#define _mbgddmsg_5(_f, _lvl, _fmt, _p1, _p2, _p3, _p4, _p5)
Definition: mbgddmsg.h:342
uint32_t PCPS_FEATURES
see PCPS_FEATURE_MASKS
Definition: pcpsdev.h:579
static void wait_ptp270pex_ready(const PCPS_DDEV *pddev)
Wait until a PTP270PEX card is ready after power-up.
Definition: pcpsdrvr.c:1065
#define PCPS_EF_TIMEOUT
Possible device initialization error flags.
Definition: pcpsdev.h:624
#define PCI_ASIC_HR_TIME_MINOR_PEX511
Definition: pci_asic.h:403
ulong num
Number of addresses in this range.
Definition: mbggenio.h:299
int pcps_add_rsrc_mem(PCPS_DDEV *pddev, MBG_IOMEM_ADDR_RAW start, ulong len)
Add a memory address range resource to the device structure.
Definition: pcpsdrvr.c:4959
#define _pcps_ddev_fw_has_20ms_bug(_p)
Definition: pcpsdrvr.h:1341
unsigned short ushort
Definition: words.h:282
int num_rsrc_io
Number of actually assigned I/O address ranges.
Definition: pcpsdrvr.h:680
PCI_ASIC_FEATURES features
PCI ASIC feature mask, see PCI_ASIC_FEATURE_MASKS.
Definition: pci_asic.h:202
#define BUILTIN_FEAT_GPS180PEX
Definition: gpsdefs.h:1754
Standard port I/O.
Definition: pcpsdrvr.h:915
#define PCPS_EF_IO_ENB
I/O interface not enabled.
Definition: pcpsdev.h:628
#define PCPS_HAS_LAN_INTF
see PCPS_BIT_HAS_LAN_INTF
Definition: pcpsdev.h:731
#define PCPS_ACCESS_MODE_STRS
Device access mode info strings.
Definition: pcpsdrvr.h:929
#define _mbg_inp32_native(_dev, _rsrc_idx, _port_addr)
Definition: mbggenio.h:612
PCPS_FEATURES features
See PCPS_FEATURE_MASKS.
Definition: pcpsdev.h:607
#define PCPS_NUM_PORTS_MCA
The total number of ports acquired by an MCA device.
Definition: pcpsdrvr.h:967
#define PCPS_FEAT_PC31PS31
Definition: pcpsdev.h:786
#define PLX_LCS_INTCSR_INT_FLAG
Definition: plxdefs.h:159
PCPS_SN_STR sernum
Definition: pcpsdev.h:609
#define _pcps_ddev_set_err_flags(_p, _msk)
Definition: pcpsdrvr.h:1199
number of defined ref time sources
Definition: pcpsdefs.h:302
#define _pcps_ddev_access_mode_mm(_p)
Definition: pcpsdrvr.h:1213
PCPS_FW_REV_NUM fw_rev_num
Definition: pcpsdev.h:606
#define PCPS_HAS_SERIAL
see PCPS_BIT_HAS_SERIAL
Definition: pcpsdev.h:708
PCPS_CLOCK_NAME name
Definition: pcpsdev.h:515
#define PCI_CS_BASE_ADDRESS_0
Definition: pcidefs.h:170
int mbg_posix_errno_to_mbg(int posix_errno, const char *info)
Translate a POSIX errno error code to one of the MBG_ERROR_CODES.
Definition: mbgerror.c:920
int num_rsrc_irq
Number of actually assigned IRQ numbers.
Definition: pcpsdrvr.h:682
#define PCPS_GENERIC_IO
(rw) See pcps_generic_io or _mbgdevio_gen_io
Definition: pcpsdefs.h:755
#define AMCC_OP_REG_RANGE_S5933
Definition: amccdefs.h:64
#define REV_HAS_IRIG_TIME_TCR511PEX
Definition: pcpsdev.h:973
#define _mbg_kdd_msg_1(_lvl, _fmt, _p1)
Definition: mbgddmsg.h:236
#define _mbgddmsg_1(_f, _lvl, _fmt, _p1)
Definition: mbgddmsg.h:318
MBG_XDEV_FEATURES xdev_features
Receiver info plus extended device features.
Definition: pcpsdrvr.h:823
uint16_t model_code
identifier for receiver model, see GPS_MODEL_CODES
Definition: gpsdefs.h:875
A PCI ASIC register as 32, 16, or 8 bit accessible union.
Definition: pci_asic.h:138
static const char * get_pcps_feature_name(PCPS_FEATURES flag_mask)
Get the name assigned to one of the PCPS_FEATURE_MASKS flags.
Definition: pcpsdrvr.c:3872
char sernum[(16+1)]
ASCIIZ, serial number.
Definition: gpsdefs.h:878
#define PCI_DEVICE_ID_PLX_8111
Definition: plxdefs.h:62
PCPS_READ_FNC * read
Pointer to the read function depending on the access mode.
Definition: pcpsdrvr.h:781
MBG_PC_CYCLES acc_cycles
Cycles count taken when device was accessed last time.
Definition: pcpsdrvr.h:799
#define MAX_XFEATURE_BITS
The maximum number of feature bits supported by the MBG_XFEATURE API.
Definition: gpsdefs.h:2333
32 bit memory mapped access
Definition: pcpsdrvr.h:916
static void report_uptime(const MBG_SYS_UPTIME *p_uptime)
Report the system uptime.
Definition: pcpsdrvr.c:1011
#define _check_feat_supp_bit(_supp_msk, _bit_num)
Check if a bits with a specific number is set in an integer bit mask.
Definition: xdevfeat.h:140
#define _mbg_mutex_destroy(_pm)
Definition: mbgmutex.h:183
No real I/O, dummy routine used.
Definition: pcpsdrvr.h:913
#define MBG_ERR_INV_TYPE
Bus-level device didn&#39;t recognize data type.
Definition: mbgerror.h:278
#define REV_HAS_IRQ_FIX_MINOR_PEX511
Definition: pcpsdev.h:954
#define PCPS_FIFO_SIZE
The size of a bus level device&#39;s command/data FIFO.
Definition: pcpsdefs.h:908
static void dump_tlv_info(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.c:3965
Register layout of a PCI ASIC.
Definition: pci_asic.h:198
#define _setup_default_receiver_info_dcf(_p, _pdev)
Initialize a RECEIVER_INFO structure for legacy DCF77 receivers.
Definition: gpsdefs.h:1971
#define AMCC_OP_REG_INTCSR
Definition: amccdefs.h:75
#define PCPS_TIMEOUT_CNT
Definition: pcpsdrvr.h:646
#define MBG_ERR_TIMEOUT
Timeout accessing the device.
Definition: mbgerror.h:270
A structure used to query current TLV capabilities.
Definition: gpsdefs.h:18263
MBG_IOMEM_RSRC mem[2]
Info on actually assigned memory ranges.
Definition: pcpsdrvr.h:684
#define PCPS_HAS_FAST_HR_TSTAMP
see PCPS_BIT_HAS_FAST_HR_TSTAMP
Definition: pcpsdev.h:735
int n_ddevs
int rsrc_alloc_ports(ulong port, ulong n)
Try to allocate an I/O port resource range.
Definition: rsrc_lx.c:60
PCI_ASIC_VERSION asic_version
ASIC version.
Definition: pcpsdrvr.h:795
#define AMCC_INT_ENB
Definition: amccdefs.h:87
uint64_t MBG_IOMEM_ADDR_RAW
Definition: mbggenio.h:175
MBG_XFEATURE_BUFFER xfeature_buffer
Extended features provided by the device.
Definition: xdevfeat.h:92
#define PCPS_GIVE_SERNUM
(r-) Read serial number as PCPS_SN_STR, only if _pcps_has_sernum
Definition: pcpsdefs.h:754
#define PCPS_HAS_TIME_SCALE
see PCPS_BIT_HAS_TIME_SCALE
Definition: pcpsdev.h:728
#define PCPS_FEAT_PCI509
Definition: pcpsdev.h:799
#define PCPS_HAS_SYNC_TIME
see PCPS_BIT_HAS_SYNC_TIME
Definition: pcpsdev.h:709
uint16_t n_bytes
Definition: pcpsdrvr.h:850
#define PCPS_FEAT_PCI510
Definition: pcpsdev.h:803
#define _set_xfeature_bit(_xf_bit, _xf_buffp)
Set an extended feature bit in a MBG_XFEATURE_BUFFER.
Definition: gpsdefs.h:2455
#define PCPS_NUM_PORTS_ISA
The total number of I/O ports used by an ISA bus device.
Definition: pcpsdrvr.h:1000
#define _pcps_read_var(_pddev, _cmd, _s)
Definition: pcpsdrvr.h:1391
#define DEBUG_DEV_INIT
Definition: pcpsdrvr.h:418
PCPS_DEV_CFG cfg
Definition: pcpsdev.h:1046
uint32_t irq_enb_mask
Bit mask to be set to enable IRQs.
Definition: pcpsdrvr.h:789
static __mbg_inline long mbg_delta_sys_time_ms(const MBG_SYS_TIME *t2, const MBG_SYS_TIME *t1)
Compute delta between two MBG_SYS_TIME times, in milliseconds.
Definition: mbgsystm.h:364
static PCPS_FW_REV_NUM pcps_get_rev_num(char FAR *idstr)
Retrieve a version number from a firmware ID string.
Definition: pcpsdrvr.c:3671
#define PCPS_FEAT_GPS170PEX
Definition: pcpsdev.h:853
#define PCI_ASIC_FIX_IRQ_MINOR_PEX511
Definition: pci_asic.h:402
static void dump_xfeature_buffer(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.c:3947
#define _mbg_kdd_msg_5(_lvl, _fmt, _p1, _p2, _p3, _p4, _p5)
Definition: mbgddmsg.h:248
#define REV_HAS_SYNC_TIME_PC31PS31
Definition: pcpsdev.h:1013
#define _mbgddmsg_fnc_exit()
Definition: mbgddmsg.h:407
#define _mbg_pci_find_bios
Definition: pci.h:95
MBG_TLV_INFO tlv_info
TLV info provided by a device.
Definition: xdevfeat.h:93
uint8_t n_ucaps
number of user time capture inputs
Definition: gpsdefs.h:886
#define _pcps_ddev_chk_err_flags(_p, _msk)
Definition: pcpsdrvr.h:1196
int PCPS_READ_FNC(PCPS_DDEV *pddev, uint8_t cmd, void *buffer, uint16_t count)
Definition: pcpsdrvr.h:769
#define PCPS_BUS_ISA
IBM compatible PC/AT ISA bus.
Definition: pcpsdev.h:413
PCPS_ID_STR fw_id
Definition: pcpsdev.h:608
static int irq[PCPS_MAX_ISA_CARDS]
#define _pcps_ddev_has_hr_time(_p)
Definition: pcpsdrvr.h:1225
uint16_t PCPS_DEV_ID
Definition: pcpsdev.h:500
Main Control Register index.
Definition: plxdefs.h:96
PCPS_IO_BUFFER io_buffer
Definition: pcpsdrvr.h:855
#define FP_FMT
#define PCPS_GIVE_TIME
Command codes used to communicate with bus level devices.
Definition: pcpsdefs.h:712
#define _pcps_ddev_is_isa(_p)
Definition: pcpsdrvr.h:1151
#define PCPS_BUS_PCI_S5933
Definition: pcpsdev.h:430
Interrupt control / status.
Definition: plxdefs.h:139
void pcps_cleanup_device(PCPS_DDEV *pddev)
Clean up function called by pcps_probe_device on error.
Definition: pcpsdrvr.c:6247
#define PCPS_FEAT_GPS168PCI
Definition: pcpsdev.h:816
bool access_mode_forced
Flag indicating that the access mode was forced.
Definition: pcpsdrvr.h:783
#define REV_HAS_UTC_OFFS_PC31PS31
Definition: pcpsdev.h:1010
#define REV_HAS_UCAP_GPS168PCI
Definition: pcpsdev.h:992
#define _pcps_asic_version_greater_equal(_v, _v_major, _v_minor)
Check whether a version number is correct and matches a required minimum version. ...
Definition: pci_asic.h:354
#define AMCC_OP_REG_RANGE_S5920
Definition: amccdefs.h:79
static __mbg_inline int pcps_ddev_is_ptp270pex(const PCPS_DDEV *pddev)
Check if a device is a PTP270PEX card.
Definition: pcpsdrvr.c:782
void pcps_dump_data(const void *buffer, size_t count, const char *info)
Definition: pcpsdrvr.c:1219
#define BUILTIN_FEAT_TCR167PCI
Definition: gpsdefs.h:1732
#define PCPS_HAS_RAW_IRIG_DATA
see PCPS_BIT_HAS_RAW_IRIG_DATA
Definition: pcpsdev.h:736
#define _pcps_ddev_pci_slot_num(_p)
Definition: pcpsdrvr.h:1169
unsigned char uchar
Definition: words.h:277
PCI_ASIC_VERSION raw_asic_version
Raw ASIC version.
Definition: pcpsdrvr.h:794
#define PCPS_FEAT_WVB600USB
Definition: pcpsdev.h:924
PCI_ASIC volatile __iomem * mm_asic_addr
Definition: pcpsdrvr.h:807
#define _pcps_ddev_has_ident(_p)
Definition: pcpsdrvr.h:1223
#define PCPS_FEAT_TCR511PEX
Definition: pcpsdev.h:851
#define PCPS_FEAT_TCR170PEX
Definition: pcpsdev.h:891
#define N_PCPS_PORT_RSRC
The max. number of I/O port resources used by a clock.
Definition: pcpsdev.h:555
PCPS_TIME_STAMP volatile __iomem * mm_tstamp_addr
Definition: pcpsdrvr.h:811
#define BUILTIN_FEAT_GPS167PC
Definition: gpsdefs.h:1726
uint8_t b[(128/8)]
Definition: gpsdefs.h:18234
#define PCPS_FEAT_TCR167PCI
Definition: pcpsdev.h:835
uint16_t num
The IRQ number.
Definition: mbggenio.h:316
#define _mbg_inp8(_dev, _rsrc_idx, _port_addr)
Definition: mbggenio.h:610
unsigned char uint8_t
Definition: words.h:210
#define _pcps_ddev_slot_num(_p)
Definition: pcpsdrvr.h:1168
__int64 int64_t
Definition: words.h:249
#define MAX_MBG_TLV_FEAT_TYPES
The maximum number of TLV feature types.
Definition: gpsdefs.h:18108
#define PCPS_FEAT_GLN180PEX
Definition: pcpsdev.h:926
#define _pcps_ddev_is_pci_amcc(_p)
Definition: pcpsdrvr.h:1160
PCPS_DEV_TYPE * pcps_get_dev_type_table_entry(PCPS_BUS_FLAGS bus_mask, PCPS_DEV_ID dev_id)
Lookup a specific device in the device table.
Definition: pcpsdrvr.c:4672
support eXtended features, see Extended feature definitions
Definition: gpsdefs.h:2217
#define BUILTIN_FEAT_PZF180PEX
Definition: gpsdefs.h:1756
int num_rsrc_mem
Number of actually assigned memory address ranges.
Definition: pcpsdrvr.h:681
#define _pcps_ddev_irq_num(_p)
Definition: pcpsdrvr.h:1178
int PCPS_DDEV_REGISTER_FNC(PCPS_DDEV *pddev)
Definition: pcpsdrvr.h:773
MBG_IOPORT_RSRC port[2]
Info on actually assigned port ranges.
Definition: pcpsdrvr.h:683
MBG_IOPORT_ADDR_MAPPED status_port_offs
Definition: pcpsdrvr.h:784
#define MAX_BOOT_TIME_PTP270PEX
Max. time required for PTP270PEX v1 card to be ready after power-up.
Definition: pcpsdrvr.c:543
char PCPS_ID_STR[(2 *16+1)]
A buffer for an ID string, including terminating 0.
Definition: pcpsdefs.h:918
#define fw_id_ref_pcps
Definition: pcpsdrvr.h:1116
#define FAR
Definition: mbggenio.h:132
#define PCPS_HAS_EVENT_TIME
see PCPS_BIT_HAS_EVENT_TIME
Definition: pcpsdev.h:718
#define PCPS_BUS_PCI_MBGPEX
Definition: pcpsdev.h:434
MBG_IOPORT_ADDR_MAPPED base_mapped
A mapped port base address.
Definition: mbggenio.h:298
void pcps_detect_pci_devices(PCPS_DDEV_INIT_FNC *ddev_init_fnc, PCPS_DDEV_CLEANUP_FNC *ddev_cleanup_fnc, ushort vendor_id, PCPS_DEV_TYPE dev_type[], int n_dev_types)
Detect and initialize PCI devices in a non-PnP system.
static void _MBG_INIT_CODE_ATTR pcps_detect_devices_init(PCPS_DDEV_INIT_FNC *ddev_init_fnc, PCPS_DDEV_CLEANUP_FNC *ddev_cleanup_fnc, int isa_ports[PCPS_MAX_ISA_CARDS], int isa_irqs[PCPS_MAX_ISA_CARDS])
_PCPS_USE_ISA_PNP
Definition: pcpsdrvr.c:6647
#define _mbg_mmrd32_native(_iomem_addr)
Definition: mbggenio.h:574
#define AMCC_OP_REG_OMB
Definition: amccdefs.h:72
#define PCPS_HAS_PTP
see PCPS_BIT_HAS_PTP
Definition: pcpsdev.h:732
uint8_t osc_type
type of installed oscillator, see GPS_OSC_TYPES
Definition: gpsdefs.h:884
#define _pcps_ddev_mem_rsrc(_p, _n)
Definition: pcpsdrvr.h:1181
int8_t offs_utc
[hours], 0 if not _pcps_has_utc_offs
Definition: pcpsdefs.h:1142
An I/O port resource used by a device.
Definition: pcpsdev.h:543
#define BUILTIN_FEAT_UNDEFINED
Feature mask used for legacy devices.
Definition: gpsdefs.h:1832
#define REV_HAS_IRIG_CTRL_BITS_TCR51USB
Definition: pcpsdev.h:980
#define _mbgddmsg_fnc_exit_chk_mbg_rc(_rc)
Definition: mbgddmsg.h:437
BUILTIN_FEATURE_MASK builtin_features
Mask of builtin features, depending on device type.
Definition: pcpsdrvr.h:822
PCI_ASIC_REG status_port
The status port register.
Definition: pci_asic.h:203
#define MBG_ERR_NO_MEM
Failed to allocate memory.
Definition: mbgerror.h:282
void mbg_gps_ident_decode(char *s, const IDENT *p_id)
Definition: identdec.c:92
#define PCPS_FEAT_USB5131
Definition: pcpsdev.h:855
PCPS_READ_FNC pcps_read_asic
Definition: pcpsdrvr.c:2585
PCPS_DDEV pcps_ddev[16]
#define MBG_DRVR_NAME
#define PCPS_EF_IO_RSRC_MEM
Memory resource not registered with resource manager.
Definition: pcpsdev.h:630
#define _pcps_kmalloc(_sz)
Definition: pcpsdrvr.h:555
#define PCI_SUCCESS
Definition: pcidefs.h:134
int pcps_chk_dev_feat(PCPS_DDEV *p_ddev, uint feat_type, uint feat_num)
Check if a specific feature of a specific feature type is supported.
Definition: pcpsdrvr.c:5112
#define REV_HAS_RAW_IRIG_DATA_TCR511PCI
Definition: pcpsdev.h:969
#define AMCC_OP_REG_IMB4
Definition: amccdefs.h:54
(r/-) RECEIVER_INFO, rcvr model info, only if PCPS_HAS_RECEIVER_INFO
Definition: pcpsdefs.h:1651
#define PCPS_GIVE_FW_ID_2
(r-) Read last PCPS_FIFO_SIZE chars of firmware ID
Definition: pcpsdefs.h:753
FIXED_FREQ_INFO fixed_freq
optional non-standard fixed frequency, may be 0 if not supported
Definition: gpsdefs.h:883
static int pcps_read_gps_block(PCPS_DDEV *pddev, uint8_t data_type, void FAR *buffer, uint16_t count, uint8_t block_num, uint8_t block_size)
Get a block of data from a GPS device.
Definition: pcpsdrvr.c:3342
#define _pcps_ddev_asic_version(_p)
Definition: pcpsdrvr.h:1190
#define _pcps_ddev_err_flags(_p)
Definition: pcpsdrvr.h:1193
uint8_t osc_flags
oscillator flags, actually not used and always 0
Definition: gpsdefs.h:885
#define PCI_BAD_REGISTER_NUMB
Definition: pcidefs.h:139
#define _fmemcpy(_d, _s, _n)
Definition: pcpsdrvr.c:558
#define MBG_SUCCESS
Error codes used with Meinberg devices and drivers.
Definition: mbgerror.h:259
int force_io_access
#define _mbgddmsg_4(_f, _lvl, _fmt, _p1, _p2, _p3, _p4)
Definition: mbgddmsg.h:336
static bool ptp270pex_can_flag_ready(const PCPS_DDEV *pddev)
Check if a PTP270PEX card can indicate when it&#39;s ready.
Definition: pcpsdrvr.c:869
#define REV_HAS_HR_TIME_TCR510PCI
Definition: pcpsdev.h:1005
uint16_t us[2]
Definition: pci_asic.h:141
static __mbg_inline int mbg_map_ioport_rsrc(MBG_IOPORT_RSRC *p)
Map an I/O port resource to get a virtual address.
Definition: mbggenio.h:438
#define PCI_CMD_ENB_IO_ACC
Definition: pcidefs.h:186
#define PCPS_FEAT_GNS181PEX
Definition: pcpsdev.h:930
static void set_access_mode(PCPS_DDEV *pddev, uint mode, bool forced, PCPS_READ_FNC *read_fnc)
Definition: pcpsdrvr.c:5302
PCI_ASIC_FEATURES asic_features
ASIC feature mask.
Definition: pcpsdrvr.h:796
#define PCPS_HAS_IRIG_TX
see PCPS_BIT_HAS_IRIG_TX
Definition: pcpsdev.h:723
#define _mbg_mmrd32_to_cpu(_iomem_addr)
Definition: mbggenio.h:576
Supports generic TLV API, see Meinberg TLV API definitions.
Definition: gpsdefs.h:2345
#define _set_tlv_feat_bit(_tlv_feat_type, _tlv_feat_buffp)
Set a TLV context type bit in a MBG_TLV_FEAT_BUFFER.
Definition: gpsdefs.h:18249
#define _mbgddmsg_2(_f, _lvl, _fmt, _p1, _p2)
Definition: mbgddmsg.h:324
#define PCPS_BUS_MCA
IBM PS/2 micro channel.
Definition: pcpsdev.h:414
PCI ASIC with CRC bug.
Definition: pci_asic.h:369
uint8_t hour
hours, 0..23
Definition: pcpsdefs.h:1133
#define PCPS_BUS_USB
USB.
Definition: pcpsdev.h:416
#define AMCC_INT_FLAG
Definition: amccdefs.h:88
Definition: myutil.h:117
PCPS_READ_FNC pcps_read_std
Definition: pcpsdrvr.c:2180
#define BUILTIN_FEAT_PTP270PEX
Definition: gpsdefs.h:1743
#define PCPS_FEATURE_NAMES
Definition: pcpsdev.h:744
#define PCPS_FEAT_TCR51USB
Definition: pcpsdev.h:862
#define FMT_03X
Definition: pcpsdrvr.c:573
PCPS_READ_FNC pcps_read_amcc_s5933
Definition: pcpsdrvr.c:2301
#define _mbg_mutex_init(_pm, _n)
Definition: mbgmutex.h:182
#define _pcps_kfree(_p, _sz)
Definition: pcpsdrvr.h:556
16 bit memory mapped access
Definition: pcpsdrvr.h:917
void check_receiver_info_and_features(PCPS_DDEV *pddev)
Check the receiver info and features.
Definition: pcpsdrvr.c:4274
(r/-) MBG_XFEATURE_BUFFER, only if GPS_HAS_XFEATURE
Definition: pcpsdefs.h:1681
#define _mbg_kdd_msg_7(_lvl, _fmt, _p1, _p2, _p3, _p4, _p5, _p6, _p7)
Definition: mbgddmsg.h:254
#define _pcps_read(_pddev, _cmd, _p, _n)
Definition: pcpsdrvr.h:1350
uint64_t MBG_PC_CYCLES_FREQUENCY
Definition: mbgpccyc.h:98
#define PLX_LCS_CNTRL_USERI
Definition: plxdefs.h:148
MBG_IOPORT_ADDR_MAPPED irq_enb_disb_port
Address of the IRQ control register.
Definition: pcpsdrvr.h:786
#define BUILTIN_FEAT_FRC511PEX
Definition: gpsdefs.h:1744
#define REV_HAS_CABLE_LEN_GPS167PC
Definition: pcpsdev.h:1001
#define _mbg_kdd_msg_0(_lvl, _fmt)
Definition: mbgddmsg.h:233
#define PCPS_FEAT_PZF180PEX
Definition: pcpsdev.h:905
#define REV_HAS_HR_TIME_PEX511
Definition: pcpsdev.h:1006
uint access_mode
Access mode used for the device, depending on interface type. See PCPS_ACCESS_MODES.
Definition: pcpsdrvr.h:782
#define _pcps_ddev_type_name(_p)
Definition: pcpsdrvr.h:1131
static __mbg_inline MBG_PC_CYCLES mbg_delta_pc_cycles(const MBG_PC_CYCLES *p1, const MBG_PC_CYCLES *p2)
Definition: mbgpccyc.h:296
#define _mbg_inp32_to_cpu(_dev, _rsrc_idx, _port_addr)
Definition: mbggenio.h:614
#define _mbg_mmwr32_to_mbg(_iomem_addr, _val)
Definition: mbggenio.h:582
#define _pcps_ddev_is_pci_pex8311(_p)
Definition: pcpsdrvr.h:1162
Device type specification.
Definition: pcpsdev.h:512
#define _pcps_ddev_io_rsrc(_p, _n)
Definition: pcpsdrvr.h:1175
uint32_t timeout_clk
Definition: pcpsdev.h:605
I/O port resource information for a device.
Definition: mbggenio.h:292
#define _pcps_ddev_bus_flags(_p)
Definition: pcpsdrvr.h:1134
#define _pcps_pex_irq_is_safe(_curr_fw_ver, _req_fw_ver, _curr_asic_ver, _req_asic_ver_major, _req_asic_ver_minor)
Definition: pcpsdev.h:961
static __mbg_inline uint8_t _pcps_ddev_read_status_port(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.h:1430
#define _mbg_pci_read_cfg_byte
Definition: pci_lx.h:55
PCPS_READ_FNC pcps_read_amcc_s5920
Definition: pcpsdrvr.c:2445
#define PCPS_BUS_PCI
PCI.
Definition: pcpsdev.h:415
ulong MBG_IOPORT_ADDR_RAW
Definition: mbggenio.h:186
#define BUILTIN_FEAT_TCR180USB
Definition: gpsdefs.h:1817
#define _setup_default_receiver_info_gps(_p)
Initialize a RECEIVER_INFO structure for legacy GPS receivers.
Definition: gpsdefs.h:1996
#define PCI_DEV_PTP270PEX
Definition: pcpsdefs.h:408
RECEIVER_INFO receiver_info
Receiver info provided by the device.
Definition: xdevfeat.h:91
#define REV_CAN_CLR_UCAP_BUFF_GPS168PCI
Definition: pcpsdev.h:996
#define REV_HAS_HR_TIME_PCI511
Definition: pcpsdev.h:1007
#define PCPS_BUS_PCI_S5920
Definition: pcpsdev.h:431
#define REV_CAN_CLR_UCAP_BUFF_GPS167PCI
Definition: pcpsdev.h:995
High resolution time including status and local time offset.
Definition: pcpsdefs.h:1085
int pcps_probe_device(PCPS_DDEV *pddev, PCPS_BUS_NUM bus_num, PCPS_SLOT_NUM dev_fnc_num)
Probe if a device is supported, and allocate and setup the device structure.
Definition: pcpsdrvr.c:5409
#define REV_CAN_SET_TIME_PC31PS31
Definition: pcpsdev.h:1028
static __mbg_inline int mbg_map_iomem_rsrc(MBG_IOMEM_RSRC *p)
Map I/O memory resource to get a virtual address.
Definition: mbggenio.h:330
PCPS_BUS_NUM bus_num
Definition: pcpsdev.h:600
#define _pcps_ddev_has_asic_version(_p)
Definition: pcpsdrvr.h:1287
uint16_t code
Version number, e.g. 0x0120 means v1.20.
Definition: gpsdefs.h:734
#define REV_HAS_RAW_IRIG_DATA_TCR511PEX
Definition: pcpsdev.h:968
#define MBG_ERR_RSRC_ITEM
Too many resource items.
Definition: mbgerror.h:382
Main Control Register data.
Definition: plxdefs.h:97
#define REV_HAS_HR_TIME_GPS167PC
Definition: pcpsdev.h:1004
#define _pcps_write_byte(_pddev, _b)
Definition: pcpsdrvr.h:1358
#define REV_HAS_IRIG_CTRL_BITS_TCR511PEX
Definition: pcpsdev.h:978
#define _mbg16_to_cpu(_x)
Definition: mbg_arch.h:119
#define PCI_ASIC_PCI_IRQF
PCI IRQ flag.
Definition: pci_asic.h:242
#define AMCC_OP_REG_MCSR
Definition: amccdefs.h:62
#define BUILTIN_FEAT_TCR180PEX
Definition: gpsdefs.h:1755
#define BUILTIN_FEAT_GNS181PEX
Definition: gpsdefs.h:1803
union PCPS_DDEV_s::@9 cmd_info
uint8_t size_n_bytes
Definition: pcpsdrvr.h:851
#define PCPS_FEAT_PTP270PEX
Definition: pcpsdev.h:874
#define _pcps_ddev_sernum_size(_p)
Definition: pcpsdrvr.h:1187
static const char str_spc_gps[]
Definition: pcpsdrvr.c:646
#define REV_HAS_IRIG_CTRL_BITS_TCR511PCI
Definition: pcpsdev.h:979
int pcps_setup_ddev(PCPS_DDEV *pddev, PCPS_BUS_FLAGS bus_mask, PCPS_DEV_ID dev_id)
Initialize an allocated device structure for a specific device.
static __mbg_inline void mbg_unmap_iomem_rsrc(MBG_IOMEM_RSRC *p)
Unmap an I/O memory resource to release the virtual address.
Definition: mbggenio.h:397
PCPS_SIG_VAL signal
signal strength, see PCPS_SIG_VAL_DEFS
Definition: pcpsdefs.h:1141
uint32_t PCPS_ERR_FLAGS
see PCPS_ERR_FLAG_MASKS
Definition: pcpsdev.h:578
Local calendar date and time, plus sync status.
Definition: pcpsdefs.h:1128
int pcps_add_rsrc_io(PCPS_DDEV *pddev, MBG_IOPORT_ADDR_RAW base, ulong num)
Add an I/O address range resource to the device structure.
Definition: pcpsdrvr.c:4897
#define _mbg_outp32_to_mbg(_dev, _rsrc_idx, _port_addr, _val)
Definition: mbggenio.h:620
#define REV_HAS_GPS_DATA_16_GPS169PCI
Definition: pcpsdev.h:985
uint8_t b[4]
Definition: pci_asic.h:142
#define _pcps_ddev_dev_id(_p)
Definition: pcpsdrvr.h:1132
PCI_ASIC_VERSION raw_version
Raw version code.
Definition: pci_asic.h:201
#define _tlv_info_addr(_p)
Definition: pcpsdev.h:1140
#define _pcps_ddev_bus_num(_p)
Definition: pcpsdrvr.h:1167
static __mbg_inline void mbg_sleep_sec(long sec)
Definition: mbgsystm.h:387
#define PCPS_HAS_EVT_LOG
see PCPS_BIT_HAS_EVT_LOG
Definition: pcpsdev.h:738
feat_num field contains one of the MBG_XFEATURE_BITS
Definition: pcpsdev.h:1317
#define _tlv_feat_buffp(_p)
Definition: pcpsdev.h:1141
void _MBG_INIT_CODE_ATTR pcps_detect_devices(int isa_ports[PCPS_MAX_ISA_CARDS], int isa_irqs[PCPS_MAX_ISA_CARDS])
Detect all bus-level devices in a non-PnP system.
Definition: pcpsdrvr.c:6683
#define PCPS_HAS_IRIG_TIME
see PCPS_BIT_HAS_IRIG_TIME
Definition: pcpsdev.h:734
struct PCPS_DDEV_s::@9::@10 gps_cmd_info
#define PCPS_ACCESS_MODE_STR_FRCD
String to append if access mode has been forced.
Definition: pcpsdrvr.h:943
#define PCPS_BUS_PCI_ASIC
Definition: pcpsdev.h:432
MBG_IOPORT_ADDR_MAPPED status_port
Address of the status port register.
Definition: pcpsdrvr.h:785
static int pcps_init_gps_transfer(PCPS_DDEV *pddev, uint8_t cmd, uint8_t data_type, uint16_t count, const char *info)
Initialize GPS data transfer.
Definition: pcpsdrvr.c:3215
#define _pcps_time_after(_curr, _tmo)
Definition: pcpsdrvr.c:625
#define _pcps_ddev_has_sernum(_p)
Definition: pcpsdrvr.h:1226
uint8_t n_prg_out
number of programmable pulse outputs
Definition: gpsdefs.h:889
ulong len
Number of addresses in this range.
Definition: mbggenio.h:280
#define _fstrncmp(_s1, _s2, _n)
Definition: pcpsdrvr.c:560
#define PCPS_FEAT_WWVB51USB
Definition: pcpsdev.h:893
static void report_io_cmd(uint8_t cmd, uint16_t count, const char *info)
Definition: pcpsdrvr.c:1266
#define _pcps_ddev_is_gps(_p)
Definition: pcpsdrvr.h:1138
uint16_t PCPS_BUS_FLAGS
Definition: pcpsdev.h:502
#define MBG_ERR_NOT_SUPP_BY_DEV
Command or feature not supported by device.
Definition: mbgerror.h:286
#define PCPS_GIVE_HR_TIME
(r-) Read high res. time as PCPS_HR_TIME, only if _pcps_has_hr_time
Definition: pcpsdefs.h:715
static uint32_t ri_feat_tbl[N_GPS_FEATURE]
A table used to map RECEIVER_INFO::features to PCPS_DEV_CFG::features.
Definition: pcpsdrvr.c:688
#define _mbg_mmrd16_native(_iomem_addr)
Definition: mbggenio.h:573
#define _pcps_ddev_timeout_clk(_p)
Definition: pcpsdrvr.h:1179
__mbg_inline int pcps_wait_busy(PCPS_DDEV *pddev)
Wait as long as a device is busy, or until timeout.
Definition: pcpsdrvr.c:1981
#define PCI_ASIC_FIX_IRQ_MINOR_GPS170PEX
Definition: pci_asic.h:409
char model_name[(16+1)]
ASCIIZ, name of receiver model.
Definition: gpsdefs.h:877
#define PCPS_HAS_UTC_OFFS
see PCPS_BIT_HAS_UTC_OFFS
Definition: pcpsdev.h:712
feat_num field contains one of the PCPS_REF_TYPES
Definition: pcpsdev.h:1314
#define PCPS_MAX_ISA_CARDS
Definition: pcpsdrvr.h:1071
#define PLX_LCS_INTCSR_INT_ENB
Definition: plxdefs.h:154
uint32_t irq_ack_mask
Bit mask to be set to acknowledge an IRQ.
Definition: pcpsdrvr.h:792
#define BUILTIN_FEAT_GPS170PEX
Definition: gpsdefs.h:1741
int64_t MBG_SYS_UPTIME
Definition: mbgsystm.h:138
#define PCI_CS_COMMAND
Definition: pcidefs.h:162
MBG_IOMEM_ADDR_RAW start_raw
A raw I/O memory start address.
Definition: mbggenio.h:278
#define mbg_rc_is_error(_rc)
Definition: mbgerror.h:617
uint8_t min
minutes, 0..59
Definition: pcpsdefs.h:1132
#define _mbg_pci_read_cfg_word
Definition: pci_lx.h:56
#define _convert_asic_version_number(_n)
Version number conversion macro.
Definition: pci_asic.h:329
#define BUILTIN_FEAT_GPS167PCI
Definition: gpsdefs.h:1727
MBG_IRQ_RSRC irq
Info on actually assigned IRQ numbers.
Definition: pcpsdrvr.h:685
void pcps_detect_isa_devices(PCPS_DDEV_INIT_FNC *ddev_init_fnc, PCPS_DDEV_CLEANUP_FNC *ddev_cleanup_fnc, PCPS_DDEV_REGISTER_FNC *ddev_register_fnc, int isa_ports[PCPS_MAX_ISA_CARDS], int isa_irqs[PCPS_MAX_ISA_CARDS])
Detect and initialize ISA devices in a non-PnP system.
Definition: pcpsdrvr.c:6559
static const char * get_bus_type_str(const PCPS_DDEV *pddev)
Definition: pcpsdrvr.c:3812
const char * mbg_strerror(int mbg_errno)
Return an error string associated with the MBG_ERROR_CODES.
Definition: mbgerror.c:685
#define _pcps_ddev_status_busy(_d)
Definition: pcpsdrvr.h:1455
MBG_MUTEX dev_mutex
Mutex used for device access serialization.
Definition: pcpsdrvr.h:802
int setup_sernum_and_receiver_info(PCPS_DDEV *pddev)
Read the serial number and receiver info from the device.
Definition: pcpsdrvr.c:4097
PCPS_SHORT_PORT_ADDR base
Definition: pcpsdev.h:545
void rsrc_dealloc_ports(ulong port, ulong n)
Release an I/O port resource range which has been allocated before.
Definition: rsrc_lx.c:85
#define BYTE_OF(_v, _n)
Definition: words.h:440
#define REPORT_CFG_LOG_LVL
Definition: pcpsdrvr.c:423
#define PCPS_BUS_USB_V2
Definition: pcpsdev.h:444
the number of known GPS_FEATURE_BITS, should now be at its limit, i.e. 32.
Definition: gpsdefs.h:2218
unsigned __int64 uint64_t
Definition: words.h:250
#define BUILTIN_FEAT_GLN180PEX
Definition: gpsdefs.h:1772
int PCPS_DDEV_INIT_FNC(PCPS_DDEV **ppddev)
Definition: pcpsdrvr.h:771
SW_REV sw_rev
software revision and ID
Definition: gpsdefs.h:876
unsigned int uint
Definition: words.h:287
#define _mbg_kdd_msg_2(_lvl, _fmt, _p1, _p2)
Definition: mbgddmsg.h:239
#define fw_id_ref_gps
Definition: pcpsdrvr.h:1117
uint16_t PCPS_SHORT_PORT_ADDR
Legacy I/O address type, see PCPS_SHORT_PORT_RSRC.
Definition: pcpsdev.h:527
#define _mbg_inp16_to_cpu(_dev, _rsrc_idx, _port_addr)
Definition: mbggenio.h:613
PCPS_DEV dev
Device info data that can be passed to user space.
Definition: pcpsdrvr.h:779
int pcps_add_rsrc_irq(PCPS_DDEV *pddev, int16_t irq_num)
Add an IRQ number resource to the device structure.
Definition: pcpsdrvr.c:5021
PCPS_HR_TIME pcps_hr_time
Definition: pcpsiobf.h:85
#define PCPS_EF_INV_FW_ID
invalid firmware ID
Definition: pcpsdev.h:625
#define _pcps_ddev_pci_cfg_err(_p)
Definition: pcpsdrvr.h:1332
int64_t MBG_PC_CYCLES
Generic types to hold PC cycle counter values.
Definition: mbgpccyc.h:97
uint16_t PCPS_FW_REV_NUM
firmware revision number, MSB major, LSB minor version
Definition: pcpsdev.h:582
#define REV_HAS_IRIG_TIME_TCR511PCI
Definition: pcpsdev.h:974
#define MBG_ERR_NOT_SUPP_ON_OS
Function is not supported on this operating system.
Definition: mbgerror.h:289
#define MBG_ERR_FW_ID
Invalid firmware ID.
Definition: mbgerror.h:271
char c[16]
Definition: gpsdefs.h:10991
#define _mbg_swab_receiver_info(_p)
Definition: gpsdefs.h:894
static __mbg_inline int check_feat_supp_byte_array(int bit_num, const uint8_t *p, int max_bytes)
Check if a specific bit is set in a byte array.
Definition: xdevfeat.h:161
MBG_IOPORT_ADDR_MAPPED irq_flag_port
Address of the IRQ status register.
Definition: pcpsdrvr.h:787
#define DEFAULT_GPS_FEATURE_NAMES
Names of device features.
Definition: gpsdefs.h:2230
#define PCPS_FEAT_TCR511PCI
Definition: pcpsdev.h:846
PCPS_ID_STR fw_id
Definition: pcpsiobf.h:81
#define PCPS_EF_IO_RSRC_IO
I/O resource not registered with resource manager.
Definition: pcpsdev.h:629
#define _cpu_to_mbg32(_x)
Definition: mbg_arch.h:125
#define MBG_ERR_NBYTES
match the number of bytes expected by the device.
Definition: mbgerror.h:272
unsigned long ulong
Definition: words.h:292
#define _pcps_ddev_is_pci_mbgpex(_p)
Definition: pcpsdrvr.h:1163
Bus memory resource information for a device.
Definition: mbggenio.h:273
#define _pcps_read_gps_var(_pddev, _cmd, _s)
Definition: pcpsdrvr.h:1406
#define _mbg_pci_read_cfg_dword
Definition: pci_lx.h:57
int pcps_setup_and_start_pci_dev(PCPS_DDEV *pddev, PCPS_BUS_NUM bus_num, PCPS_SLOT_NUM dev_fnc_num)
Setup and start a PCI device in a non-PnP system.
uint16_t khz_val
the base frequency in [kHz]
Definition: gpsdefs.h:848
#define PCPS_BUS_PCI_PEX8311
Definition: pcpsdev.h:433
PCPS_SHORT_PORT_ADDR short_status_port
Definition: pcpsdev.h:603
A structure used to identify a device type and supported features.
Definition: gpsdefs.h:873
#define PCPS_FEAT_TCR180USB
IRIG TX only supp. if GPS_HAS_IRIG_TX.
Definition: pcpsdev.h:932
#define MBG_XFEATURE_NAMES
Names of extended device features.
Definition: gpsdefs.h:2385
#define N_SUPP_DEV_BUS
Definition: cfg_hlp.h:114
#define _pcps_ddev_is_pci_s5920(_p)
Definition: pcpsdrvr.h:1159
#define PCI_ASIC_HAS_MM_IO
Bit masks used with PCI_ASIC_FEATURES.
Definition: pci_asic.h:175
#define REV_HAS_RAW_IRIG_DATA_TCR51USB
Definition: pcpsdev.h:970
PCPS_SHORT_PORT_RSRC port[2]
Definition: pcpsdev.h:602
PEX EPLD for PEX511.
Definition: pci_asic.h:371
void PCPS_DDEV_CLEANUP_FNC(PCPS_DDEV *pddev)
Definition: pcpsdrvr.h:772
#define PCPS_READ_GPS_DATA
(r-) Read large data structure, see PC_GPS_CMD_CODES
Definition: pcpsdefs.h:765
#define MBG_ERR_DEV_NOT_SUPP
Device type not supported by driver.
Definition: mbgerror.h:284
PCI_ASIC_REG pci_data
Register used to pass byte from PCI bus to add-on side.
Definition: pci_asic.h:205
#define PCPS_FW_STR_FMT
Definition: pcpsdev.h:1481
A structure used to store a bit mask of supported TLV context types.
Definition: gpsdefs.h:18232
#define REV_HAS_IRIG_TIME_TCR51USB
Definition: pcpsdev.h:975
#define _pcps_ddev_has_receiver_info(_p)
Definition: pcpsdrvr.h:1234
USB I/O, no direct port access.
Definition: pcpsdrvr.h:914
#define PCPS_FEAT_GPS167PC
Definition: pcpsdev.h:807
static __mbg_inline void mbg_get_pc_cycles_frequency(MBG_PC_CYCLES_FREQUENCY *p)
Definition: mbgpccyc.h:250
#define _mbg_put_unaligned(_v, _p)
Definition: mbg_arch.h:77
static int setup_mm_addr(PCPS_DDEV *pddev)
Setup the memory mapped addresses depending on the device type.
Definition: pcpsdrvr.c:1183
#define MAX_PARM_STR_TYPE
The max number of serial string types supported by configuration programs.
Definition: cfg_hlp.h:140
#define _pcps_irq_flags
Definition: pcpsdrvr.c:586
#define PCPS_FEAT_TCR180PEX
IRIG TX only supp. if GPS_HAS_IRIG_TX.
Definition: pcpsdev.h:899
#define BUILTIN_FEAT_GPS168PCI
Definition: gpsdefs.h:1729
uint8_t month
month, 1..12
Definition: pcpsdefs.h:1137
static bool ptp270pex_has_flagged_ready(const PCPS_DDEV *pddev)
Check if a PTP270PEX card indicates it is ready.
Definition: pcpsdrvr.c:979
#define AMCC_OP_REG_FIFO
Definition: amccdefs.h:55
#define _pcps_ddev_has_gps_data_16(_p)
Definition: pcpsdrvr.h:1269
PCPS_TIME_STATUS status
status bits, see PCPS_TIME_STATUS_FLAGS_COMMON
Definition: pcpsdefs.h:1140
#define _pcps_local_irq_restore()
Definition: pcpsdrvr.c:592
#define PCPS_FEAT_PC32
Definition: pcpsdev.h:795
uint8_t sec
seconds, 0..59, or 60 if leap second
Definition: pcpsdefs.h:1131
static void check_unknown_sernum(char *s, size_t max_len)
Definition: pcpsdrvr.c:3792
uint8_t wday
day of week, 1..7, 1 = Monday
Definition: pcpsdefs.h:1136
uint16_t PCPS_SLOT_NUM
Definition: pcpsdev.h:581
#define PCPS_FEAT_DCF600USB
Definition: pcpsdev.h:903
static void check_feature(PCPS_DDEV *pddev, ushort req_rev_num, PCPS_FEATURES flag_mask)
Check the firmware to see if a specific feature is supported.
Definition: pcpsdrvr.c:4001
#define PCPS_FEAT_TCR600USB
Definition: pcpsdev.h:917
#define REV_HAS_SERIAL_PC31PS31
Definition: pcpsdev.h:1016
#define PCPS_HAS_IRIG_CTRL_BITS
see PCPS_BIT_HAS_IRIG_CTRL_BITS
Definition: pcpsdev.h:730
PCPS_WRITE_FNC pcps_write_gps
Write a large data structure to a device.
Definition: pcpsdrvr.c:3573
#define FMT_08X
Definition: pcpsdrvr.c:574
#define PCPS_FEAT_GPS167PCI
Definition: pcpsdev.h:811