/* vi:set ts=8 sts=4 sw=4 noet: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * help.c: functions for Vim help */ #include "vim.h" /* * ":help": open a read-only window on a help file */ void ex_help(exarg_T *eap) { char_u *arg; char_u *tag; FILE *helpfd; // file descriptor of help file int n; int i; win_T *wp; int num_matches; char_u **matches; char_u *p; int empty_fnum = 0; int alt_fnum = 0; buf_T *buf; #ifdef FEAT_MULTI_LANG int len; char_u *lang; #endif #ifdef FEAT_FOLDING int old_KeyTyped = KeyTyped; #endif if (ERROR_IF_ANY_POPUP_WINDOW) return; if (eap != NULL) { // A ":help" command ends at the first LF, or at a '|' that is // followed by some text. Set nextcmd to the following command. for (arg = eap->arg; *arg; ++arg) { if (*arg == '\n' || *arg == '\r' || (*arg == '|' && arg[1] != NUL && arg[1] != '|')) { *arg++ = NUL; eap->nextcmd = arg; break; } } arg = eap->arg; if (eap->forceit && *arg == NUL && !curbuf->b_help) { emsg(_(e_dont_panic)); return; } if (eap->skip) // not executing commands return; } else arg = (char_u *)""; // remove trailing blanks p = arg + STRLEN(arg) - 1; while (p > arg && VIM_ISWHITE(*p) && p[-1] != '\\') *p-- = NUL; #ifdef FEAT_MULTI_LANG // Check for a specified language lang = check_help_lang(arg); #endif // When no argument given go to the index. if (*arg == NUL) arg = (char_u *)"help.txt"; // Check if there is a match for the argument. n = find_help_tags(arg, &num_matches, &matches, eap != NULL && eap->forceit); i = 0; #ifdef FEAT_MULTI_LANG if (n != FAIL && lang != NULL) // Find first item with the requested language. for (i = 0; i < num_matches; ++i) { len = (int)STRLEN(matches[i]); if (len > 3 && matches[i][len - 3] == '@' && STRICMP(matches[i] + len - 2, lang) == 0) break; } #endif if (i >= num_matches || n == FAIL) { #ifdef FEAT_MULTI_LANG if (lang != NULL) semsg(_(e_sorry_no_str_help_for_str), lang, arg); else #endif semsg(_(e_sorry_no_help_for_str), arg); if (n != FAIL) FreeWild(num_matches, matches); return; } // The first match (in the requested language) is the best match. tag = vim_strsave(matches[i]); FreeWild(num_matches, matches); #ifdef FEAT_GUI need_mouse_correct = TRUE; #endif // Re-use an existing help window or open a new one. // Always open a new one for ":tab help". if (!bt_help(curwin->w_buffer) || cmdmod.cmod_tab != 0) { if (cmdmod.cmod_tab != 0) wp = NULL; else FOR_ALL_WINDOWS(wp) if (bt_help(wp->w_buffer)) break; if (wp != NULL && wp->w_buffer->b_nwindows > 0) win_enter(wp, TRUE); else { // There is no help window yet. // Try to open the file specified by the "helpfile" option. if ((helpfd = mch_fopen((char *)p_hf, READBIN)) == NULL) { smsg(_("Sorry, help file \"%s\" not found"), p_hf); goto erret; } fclose(helpfd); // Split off help window; put it at far top if no position // specified, the current window is vertically split and // narrow. n = WSP_HELP; if (cmdmod.cmod_split == 0 && curwin->w_width != Columns && curwin->w_width < 80) n |= p_sb ? WSP_BOT : WSP_TOP; if (win_split(0, n) == FAIL) goto erret; if (curwin->w_height < p_hh) win_setheight((int)p_hh); // Open help file (do_ecmd() will set b_help flag, readfile() will // set b_p_ro flag). // Set the alternate file to the previously edited file. alt_fnum = curbuf->b_fnum; (void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL, ECMD_HIDE + ECMD_SET_HELP, NULL); // buffer is still open, don't store info if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) curwin->w_alt_fnum = alt_fnum; empty_fnum = curbuf->b_fnum; } } if (!p_im) restart_edit = 0; // don't want insert mode in help file #ifdef FEAT_FOLDING // Restore KeyTyped, setting 'filetype=help' may reset it. // It is needed for do_tag top open folds under the cursor. KeyTyped = old_KeyTyped; #endif if (tag != NULL) do_tag(tag, DT_HELP, 1, FALSE, TRUE); // Delete the empty buffer if we're not using it. Careful: autocommands // may have jumped to another window, check that the buffer is not in a // window. if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum) { buf = buflist_findnr(empty_fnum); if (buf != NULL && buf->b_nwindows == 0) wipe_buffer(buf, TRUE); } // keep the previous alternate file if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) curwin->w_alt_fnum = alt_fnum; erret: vim_free(tag); } /* * ":helpclose": Close one help window */ void ex_helpclose(exarg_T *eap UNUSED) { win_T *win; FOR_ALL_WINDOWS(win) { if (bt_help(win->w_buffer)) { win_close(win, FALSE); return; } } } #if defined(FEAT_MULTI_LANG) || defined(PROTO) /* * In an argument search for a language specifiers in the form "@xx". * Changes the "@" to NUL if found, and returns a pointer to "xx". * Returns NULL if not found. */ char_u * check_help_lang(char_u *arg) { int len = (int)STRLEN(arg); if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2]) && ASCII_ISALPHA(arg[len - 1])) { arg[len - 3] = NUL; // remove the '@' return arg + len - 2; } return NULL; } #endif /* * Return a heuristic indicating how well the given string matches. The * smaller the number, the better the match. This is the order of priorities, * from best match to worst match: * - Match with least alphanumeric characters is better. * - Match with least total characters is better. * - Match towards the start is better. * - Match starting with "+" is worse (feature instead of command) * Assumption is made that the matched_string passed has already been found to * match some string for which help is requested. webb. */ int help_heuristic( char_u *matched_string, int offset, // offset for match int wrong_case) // no matching case { int num_letters; char_u *p; num_letters = 0; for (p = matched_string; *p; p++) if (ASCII_ISALNUM(*p)) num_letters++; // Multiply the number of letters by 100 to give it a much bigger // weighting than the number of characters. // If there only is a match while ignoring case, add 5000. // If the match starts in the middle of a word, add 10000 to put it // somewhere in the last half. // If the match is more than 2 chars from the start, multiply by 200 to // put it after matches at the start. if (ASCII_ISALNUM(matched_string[offset]) && offset > 0 && ASCII_ISALNUM(matched_string[offset - 1])) offset += 10000; else if (offset > 2) offset *= 200; if (wrong_case) offset += 5000; // Features are less interesting than the subjects themselves, but "+" // alone is not a feature. if (matched_string[0] == '+' && matched_string[1] != NUL) offset += 100; return (int)(100 * num_letters + STRLEN(matched_string) + offset); } /* * Compare functions for qsort() below, that checks the help heuristics number * that has been put after the tagname by find_tags(). */ static int help_compare(const void *s1, const void *s2) { char *p1; char *p2; int cmp; p1 = *(char **)s1 + strlen(*(char **)s1) + 1; p2 = *(char **)s2 + strlen(*(char **)s2) + 1; // Compare by help heuristic number first. cmp = strcmp(p1, p2); if (cmp != 0) return cmp; // Compare by strings as tie-breaker when same heuristic number. return strcmp(*(char **)s1, *(char **)s2); } /* * Find all help tags matching "arg", sort them and return in matches[], with * the number of matches in num_matches. * The matches will be sorted with a "best" match algorithm. * When "keep_lang" is TRUE try keeping the language of the current buffer. */ int find_help_tags( char_u *arg, int *num_matches, char_u ***matches, int keep_lang) { char_u *s, *d; int i; // Specific tags that either have a specific replacement or won't go // through the generic rul
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * PTP hardware clock driver for the IDT 82P33XXX family of clocks.
 *
 * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
 */
#ifndef PTP_IDT82P33_H
#define PTP_IDT82P33_H

#include <linux/ktime.h>
#include <linux/workqueue.h>


/* Register Map - AN888_SMUforIEEE_SynchEther_82P33xxx_RevH.pdf */
#define PAGE_NUM (8)
#define _ADDR(page, offset) (((page) << 0x7) | ((offset) & 0x7f))
#define _PAGE(addr) (((addr) >> 0x7) & 0x7)
#define _OFFSET(addr)  ((addr) & 0x7f)

#define DPLL1_TOD_CNFG 0x134
#define DPLL2_TOD_CNFG 0x1B4

#define DPLL1_TOD_STS 0x10B
#define DPLL2_TOD_STS 0x18B

#define DPLL1_TOD_TRIGGER 0x115
#define DPLL2_TOD_TRIGGER 0x195

#define DPLL1_OPERATING_MODE_CNFG 0x120
#define DPLL2_OPERATING_MODE_CNFG 0x1A0

#define DPLL1_HOLDOVER_FREQ_CNFG 0x12C
#define DPLL2_HOLDOVER_FREQ_CNFG 0x1AC

#define DPLL1_PHASE_OFFSET_CNFG 0x143
#define DPLL2_PHASE_OFFSET_CNFG 0x1C3

#define DPLL1_SYNC_EDGE_CNFG 0X140
#define DPLL2_SYNC_EDGE_CNFG 0X1C0

#define DPLL1_INPUT_MODE_CNFG 0X116
#define DPLL2_INPUT_MODE_CNFG 0X196

#define OUT_MUX_CNFG(outn) _ADDR(0x6, (0xC * (outn)))

#define PAGE_ADDR 0x7F
/* Register Map end */

/* Register definitions - AN888_SMUforIEEE_SynchEther_82P33xxx_RevH.pdf*/
#define TOD_TRIGGER(wr_trig, rd_trig) ((wr_trig & 0xf) << 4 | (rd_trig & 0xf))
#define SYNC_TOD BIT(1)
#define PH_OFFSET_EN BIT(7)
#define SQUELCH_ENABLE BIT(5)

/* Bit definitions for the DPLL_MODE register */
#define PLL_MODE_SHIFT                    (0)
#define PLL_MODE_MASK                     (0x1F)

enum pll_mode {
	PLL_MODE_MIN = 0,
	PLL_MODE_AUTOMATIC = PLL_MODE_MIN,
	PLL_MODE_FORCE_FREERUN = 1,
	PLL_MODE_FORCE_HOLDOVER = 2,
	PLL_MODE_FORCE_LOCKED = 4,
	PLL_MODE_FORCE_PRE_LOCKED2 = 5,
	PLL_MODE_FORCE_PRE_LOCKED = 6,
	PLL_MODE_FORCE_LOST_PHASE = 7,
	PLL_MODE_DCO = 10,
	PLL_MODE_WPH = 18,
	PLL_MODE_MAX = PLL_MODE_WPH,
};

enum hw_tod_trig_sel {
	HW_TOD_TRIG_SEL_MIN = 0,
	HW_TOD_TRIG_SEL_NO_WRITE = HW_TOD_TRIG_SEL_MIN,
	HW_TOD_TRIG_SEL_SYNC_SEL = 1,
	HW_TOD_TRIG_SEL_IN12 = 2,
	HW_TOD_TRIG_SEL_IN13 = 3,
	HW_TOD_TRIG_SEL_IN14 = 4,
	HW_TOD_TRIG_SEL_TOD_PPS = 5,
	HW_TOD_TRIG_SEL_TIMER_INTERVAL = 6,
	HW_TOD_TRIG_SEL_MSB_PHASE_OFFSET_CNFG = 7,
	HW_TOD_TRIG_SEL_MSB_HOLDOVER_FREQ_CNFG = 8,
	HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG = 9,
	HW_TOD_RD_TRIG_SEL_LSB_TOD_STS = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
	WR_TRIG_SEL_MAX = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
};

/* Register bit definitions end */
#define FW_FILENAME	"idt82p33xxx.bin"
#define MAX_PHC_PLL (2)
#define TOD_BYTE_COUNT (10)
#define MAX_MEASURMENT_COUNT (5)
#define SNAP_THRESHOLD_NS (150000)
#define SYNC_TOD_TIMEOUT_SEC (5)

#define PLLMASK_ADDR_HI	0xFF
#define PLLMASK_ADDR_LO	0xA5

#define PLL0_OUTMASK_ADDR_HI	0xFF
#define PLL0_OUTMASK_ADDR_LO	0xB0

#define PLL1_OUTMASK_ADDR_HI	0xFF
#define PLL1_OUTMASK_ADDR_LO	0xB2

#define PLL2_OUTMASK_ADDR_HI	0xFF
#define PLL2_OUTMASK_ADDR_LO	0xB4

#define PLL3_OUTMASK_ADDR_HI	0xFF
#define PLL3_OUTMASK_ADDR_LO	0xB6

#define DEFAULT_PLL_MASK	(0x01)
#define DEFAULT_OUTPUT_MASK_PLL0	(0xc0)
#define DEFAULT_OUTPUT_MASK_PLL1	DEFAULT_OUTPUT_MASK_PLL0

/* PTP Hardware Clock interface */
struct idt82p33_channel {
	struct ptp_clock_info	caps;
	struct ptp_clock	*ptp_clock;
	struct idt82p33	*idt82p33;
	enum pll_mode	pll_mode;
	/* task to turn off SYNC_TOD bit after pps sync */
	struct delayed_work	sync_tod_work;
	bool			sync_tod_on;
	s32			current_freq_ppb;
	u8			output_mask;
	u16			dpll_tod_cnfg;
	u16			dpll_tod_trigger;
	u16			dpll_tod_sts;
	u16			dpll_mode_cnfg;
	u16			dpll_freq_cnfg;
	u16			dpll_phase_cnfg;
	u16			dpll_sync_cnfg;
	u16			dpll_input_mode_cnfg;
};

struct idt82p33 {
	struct idt82p33_channel channel[MAX_PHC_PLL];
	struct i2c_client	*client;
	u8	page_offset;
	u8	pll_mask;
	ktime_t start_time;
	int calculate_overhead_flag;
	s64 tod_write_overhead_ns;
	/* Protects I2C read/modify/write registers from concurrent access */
	struct mutex	reg_lock;
};

/* firmware interface */
struct idt82p33_fwrc {
	u8 hiaddr;
	u8 loaddr;
	u8 value;
	u8 reserved;
} __packed;

/**
 * @brief Maximum absolute value for write phase offset in femtoseconds
 */
#define WRITE_PHASE_OFFSET_LIMIT (20000052084ll)

/** @brief Phase offset resolution
 *
 *  DPLL phase offset = 10^15 fs / ( System Clock  * 2^13)
 *                    = 10^15 fs / ( 1638400000 * 2^23)
 *                    = 74.5058059692382 fs
 */
#define IDT_T0DPLL_PHASE_RESOL 74506


#endif /* PTP_IDT82P33_H */
har_u **)ga.ga_data)[i], dir, p2 + 1); emsg((char *)NameBuff); *p2 = '\t'; break; } ++p1; ++p2; } } if (utf8 == TRUE) fprintf(fd_tags, "!_TAG_FILE_ENCODING\tutf-8\t//\n"); // Write the tags into the file. for (i = 0; i < ga.ga_len; ++i) { s = ((char_u **)ga.ga_data)[i]; if (STRNCMP(s, "help-tags\t", 10) == 0) // help-tags entry was added in formatted form fputs((char *)s, fd_tags); else { fprintf(fd_tags, "%s\t/*", s); for (p1 = s; *p1 != '\t'; ++p1) { // insert backslash before '\\' and '/' if (*p1 == '\\' || *p1 == '/') putc('\\', fd_tags); putc(*p1, fd_tags); } fprintf(fd_tags, "*\n"); } } } if (mix) got_int = FALSE; // continue with other languages for (i = 0; i < ga.ga_len; ++i) vim_free(((char_u **)ga.ga_data)[i]); ga_clear(&ga); fclose(fd_tags); // there is no check for an error... } /* * Generate tags in one help directory, taking care of translations. */ static void do_helptags(char_u *dirname, int add_help_tags, int ignore_writeerr) { #ifdef FEAT_MULTI_LANG int len; int i, j; garray_T ga; char_u lang[2]; char_u ext[5]; char_u fname[8]; int filecount; char_u **files; // Get a list of all files in the help directory and in subdirectories. STRCPY(NameBuff, dirname); add_pathsep(NameBuff); STRCAT(NameBuff, "**"); if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, EW_FILE|EW_SILENT) == FAIL || filecount == 0) { semsg(_(e_no_match_str_1), NameBuff); return; } // Go over all files in the directory to find out what languages are // present. ga_init2(&ga, 1, 10); for (i = 0; i < filecount; ++i) { len = (int)STRLEN(files[i]); if (len <= 4) continue; if (STRICMP(files[i] + len - 4, ".txt") == 0) { // ".txt" -> language "en" lang[0] = 'e'; lang[1] = 'n'; } else if (files[i][len - 4] == '.' && ASCII_ISALPHA(files[i][len - 3]) && ASCII_ISALPHA(files[i][len - 2]) && TOLOWER_ASC(files[i][len - 1]) == 'x') { // ".abx" -> language "ab" lang[0] = TOLOWER_ASC(files[i][len - 3]); lang[1] = TOLOWER_ASC(files[i][len - 2]); } else continue; // Did we find this language already? for (j = 0; j < ga.ga_len; j += 2) if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0) break; if (j == ga.ga_len) { // New language, add it. if (ga_grow(&ga, 2) == FAIL) break; ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0]; ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1]; } } // Loop over the found languages to generate a tags file for each one. for (j = 0; j < ga.ga_len; j += 2) { STRCPY(fname, "tags-xx"); fname[5] = ((char_u *)ga.ga_data)[j]; fname[6] = ((char_u *)ga.ga_data)[j + 1]; if (fname[5] == 'e' && fname[6] == 'n') { // English is an exception: use ".txt" and "tags". fname[4] = NUL; STRCPY(ext, ".txt"); } else { // Language "ab" uses ".abx" and "tags-ab". STRCPY(ext, ".xxx"); ext[1] = fname[5]; ext[2] = fname[6]; } helptags_one(dirname, ext, fname, add_help_tags, ignore_writeerr); } ga_clear(&ga); FreeWild(filecount, files); #else // No language support, just use "*.txt" and "tags". helptags_one(dirname, (char_u *)".txt", (char_u *)"tags", add_help_tags, ignore_writeerr); #endif } static void helptags_cb(char_u *fname, void *cookie) { do_helptags(fname, *(int *)cookie, TRUE); } /* * ":helptags" */ void ex_helptags(exarg_T *eap) { expand_T xpc; char_u *dirname; int add_help_tags = FALSE; // Check for ":helptags ++t {dir}". if (STRNCMP(eap->arg, "++t", 3) == 0 && VIM_ISWHITE(eap->arg[3])) { add_help_tags = TRUE; eap->arg = skipwhite(eap->arg + 3); } if (STRCMP(eap->arg, "ALL") == 0) { do_in_path(p_rtp, "", (char_u *)"doc", DIP_ALL + DIP_DIR, helptags_cb, &add_help_tags); } else { ExpandInit(&xpc); xpc.xp_context = EXPAND_DIRECTORIES; dirname = ExpandOne(&xpc, eap->arg, NULL, WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); if (dirname == NULL || !mch_isdir(dirname)) semsg(_(e_not_a_directory_str), eap->arg); else do_helptags(dirname, add_help_tags, FALSE); vim_free(dirname); } }