version 1.267.4.3, 2008/01/23 19:27:33 |
version 1.268, 2007/12/14 03:36:54 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/*- |
/*- |
* Copyright (c) 1998, 1999, 2004, 2008 The NetBSD Foundation, Inc. |
* Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* This code is derived from software contributed to The NetBSD Foundation |
* This code is derived from software contributed to The NetBSD Foundation |
Line 228 static int comconsrate; |
|
Line 228 static int comconsrate; |
|
static tcflag_t comconscflag; |
static tcflag_t comconscflag; |
static struct cnm_state com_cnm_state; |
static struct cnm_state com_cnm_state; |
|
|
|
#ifndef __HAVE_TIMECOUNTER |
|
static int ppscap = |
|
PPS_TSFMT_TSPEC | |
|
PPS_CAPTUREASSERT | |
|
PPS_CAPTURECLEAR | |
|
PPS_OFFSETASSERT | PPS_OFFSETCLEAR; |
|
#endif /* !__HAVE_TIMECOUNTER */ |
|
|
#ifdef KGDB |
#ifdef KGDB |
#include <sys/kgdb.h> |
#include <sys/kgdb.h> |
|
|
Line 642 com_activate(struct device *self, enum d |
|
Line 650 com_activate(struct device *self, enum d |
|
struct com_softc *sc = (struct com_softc *)self; |
struct com_softc *sc = (struct com_softc *)self; |
int rv = 0; |
int rv = 0; |
|
|
|
mutex_spin_enter(&sc->sc_lock); |
switch (act) { |
switch (act) { |
case DVACT_ACTIVATE: |
case DVACT_ACTIVATE: |
rv = EOPNOTSUPP; |
rv = EOPNOTSUPP; |
Line 660 com_activate(struct device *self, enum d |
|
Line 669 com_activate(struct device *self, enum d |
|
break; |
break; |
} |
} |
|
|
|
mutex_spin_exit(&sc->sc_lock); |
return (rv); |
return (rv); |
} |
} |
|
|
Line 677 com_shutdown(struct com_softc *sc) |
|
Line 687 com_shutdown(struct com_softc *sc) |
|
/* Clear any break condition set with TIOCSBRK. */ |
/* Clear any break condition set with TIOCSBRK. */ |
com_break(sc, 0); |
com_break(sc, 0); |
|
|
|
#ifndef __HAVE_TIMECOUNTER |
|
/* Turn off PPS capture on last close. */ |
|
sc->sc_ppsmask = 0; |
|
sc->ppsparam.mode = 0; |
|
#endif /* !__HAVE_TIMECOUNTER */ |
|
|
/* |
/* |
* Hang up if necessary. Wait a bit, so the other side has time to |
* Hang up if necessary. Wait a bit, so the other side has time to |
* notice even if we immediately open the port again. |
* notice even if we immediately open the port again. |
Line 703 com_shutdown(struct com_softc *sc) |
|
Line 719 com_shutdown(struct com_softc *sc) |
|
|
|
CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); |
CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); |
|
|
mutex_spin_exit(&sc->sc_lock); |
|
|
|
if (sc->disable) { |
if (sc->disable) { |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (!sc->enabled) |
if (!sc->enabled) |
Line 713 com_shutdown(struct com_softc *sc) |
|
Line 727 com_shutdown(struct com_softc *sc) |
|
(*sc->disable)(sc); |
(*sc->disable)(sc); |
sc->enabled = 0; |
sc->enabled = 0; |
} |
} |
|
mutex_spin_exit(&sc->sc_lock); |
} |
} |
|
|
int |
int |
Line 754 comopen(dev_t dev, int flag, int mode, s |
|
Line 769 comopen(dev_t dev, int flag, int mode, s |
|
|
|
tp->t_dev = dev; |
tp->t_dev = dev; |
|
|
|
mutex_spin_enter(&sc->sc_lock); |
|
|
if (sc->enable) { |
if (sc->enable) { |
if ((*sc->enable)(sc)) { |
if ((*sc->enable)(sc)) { |
|
mutex_spin_exit(&sc->sc_lock); |
splx(s); |
splx(s); |
printf("%s: device enable failed\n", |
printf("%s: device enable failed\n", |
sc->sc_dev.dv_xname); |
sc->sc_dev.dv_xname); |
return (EIO); |
return (EIO); |
} |
} |
mutex_spin_enter(&sc->sc_lock); |
|
sc->enabled = 1; |
sc->enabled = 1; |
com_config(sc); |
com_config(sc); |
} else { |
|
mutex_spin_enter(&sc->sc_lock); |
|
} |
} |
|
|
/* Turn on interrupts. */ |
/* Turn on interrupts. */ |
Line 779 comopen(dev_t dev, int flag, int mode, s |
|
Line 793 comopen(dev_t dev, int flag, int mode, s |
|
sc->sc_msr = CSR_READ_1(&sc->sc_regs, COM_REG_MSR); |
sc->sc_msr = CSR_READ_1(&sc->sc_regs, COM_REG_MSR); |
|
|
/* Clear PPS capture state on first open. */ |
/* Clear PPS capture state on first open. */ |
|
#ifdef __HAVE_TIMECOUNTER |
memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state)); |
memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state)); |
sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; |
sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; |
pps_init(&sc->sc_pps_state); |
pps_init(&sc->sc_pps_state); |
|
#else /* !__HAVE_TIMECOUNTER */ |
|
sc->sc_ppsmask = 0; |
|
sc->ppsparam.mode = 0; |
|
#endif /* !__HAVE_TIMECOUNTER */ |
|
|
mutex_spin_exit(&sc->sc_lock); |
mutex_spin_exit(&sc->sc_lock); |
|
|
Line 1004 comioctl(dev_t dev, u_long cmd, void *da |
|
Line 1023 comioctl(dev_t dev, u_long cmd, void *da |
|
*(int *)data = com_to_tiocm(sc); |
*(int *)data = com_to_tiocm(sc); |
break; |
break; |
|
|
|
#ifdef __HAVE_TIMECOUNTER |
case PPS_IOC_CREATE: |
case PPS_IOC_CREATE: |
case PPS_IOC_DESTROY: |
case PPS_IOC_DESTROY: |
case PPS_IOC_GETPARAMS: |
case PPS_IOC_GETPARAMS: |
Line 1015 comioctl(dev_t dev, u_long cmd, void *da |
|
Line 1035 comioctl(dev_t dev, u_long cmd, void *da |
|
#endif |
#endif |
error = pps_ioctl(cmd, data, &sc->sc_pps_state); |
error = pps_ioctl(cmd, data, &sc->sc_pps_state); |
break; |
break; |
|
#else /* !__HAVE_TIMECOUNTER */ |
|
case PPS_IOC_CREATE: |
|
break; |
|
|
|
case PPS_IOC_DESTROY: |
|
break; |
|
|
|
case PPS_IOC_GETPARAMS: { |
|
pps_params_t *pp; |
|
pp = (pps_params_t *)data; |
|
*pp = sc->ppsparam; |
|
break; |
|
} |
|
|
|
case PPS_IOC_SETPARAMS: { |
|
pps_params_t *pp; |
|
int mode; |
|
pp = (pps_params_t *)data; |
|
if (pp->mode & ~ppscap) { |
|
error = EINVAL; |
|
break; |
|
} |
|
sc->ppsparam = *pp; |
|
/* |
|
* Compute msr masks from user-specified timestamp state. |
|
*/ |
|
mode = sc->ppsparam.mode; |
|
switch (mode & PPS_CAPTUREBOTH) { |
|
case 0: |
|
sc->sc_ppsmask = 0; |
|
break; |
|
|
|
case PPS_CAPTUREASSERT: |
|
sc->sc_ppsmask = MSR_DCD; |
|
sc->sc_ppsassert = MSR_DCD; |
|
sc->sc_ppsclear = -1; |
|
break; |
|
|
|
case PPS_CAPTURECLEAR: |
|
sc->sc_ppsmask = MSR_DCD; |
|
sc->sc_ppsassert = -1; |
|
sc->sc_ppsclear = 0; |
|
break; |
|
|
|
case PPS_CAPTUREBOTH: |
|
sc->sc_ppsmask = MSR_DCD; |
|
sc->sc_ppsassert = MSR_DCD; |
|
sc->sc_ppsclear = 0; |
|
break; |
|
|
|
default: |
|
error = EINVAL; |
|
break; |
|
} |
|
break; |
|
} |
|
|
|
case PPS_IOC_GETCAP: |
|
*(int*)data = ppscap; |
|
break; |
|
|
|
case PPS_IOC_FETCH: { |
|
pps_info_t *pi; |
|
pi = (pps_info_t *)data; |
|
*pi = sc->ppsinfo; |
|
break; |
|
} |
|
|
|
#ifdef PPS_SYNC |
|
case PPS_IOC_KCBIND: { |
|
int edge = (*(int *)data) & PPS_CAPTUREBOTH; |
|
|
|
if (edge == 0) { |
|
/* |
|
* remove binding for this source; ignore |
|
* the request if this is not the current |
|
* hardpps source |
|
*/ |
|
if (pps_kc_hardpps_source == sc) { |
|
pps_kc_hardpps_source = NULL; |
|
pps_kc_hardpps_mode = 0; |
|
} |
|
} else { |
|
/* |
|
* bind hardpps to this source, replacing any |
|
* previously specified source or edges |
|
*/ |
|
pps_kc_hardpps_source = sc; |
|
pps_kc_hardpps_mode = edge; |
|
} |
|
break; |
|
} |
|
#endif /* PPS_SYNC */ |
|
#endif /* !__HAVE_TIMECOUNTER */ |
|
|
case TIOCDCDTIMESTAMP: /* XXX old, overloaded API used by xntpd v3 */ |
case TIOCDCDTIMESTAMP: /* XXX old, overloaded API used by xntpd v3 */ |
|
#ifdef __HAVE_TIMECOUNTER |
#ifndef PPS_TRAILING_EDGE |
#ifndef PPS_TRAILING_EDGE |
TIMESPEC_TO_TIMEVAL((struct timeval *)data, |
TIMESPEC_TO_TIMEVAL((struct timeval *)data, |
&sc->sc_pps_state.ppsinfo.assert_timestamp); |
&sc->sc_pps_state.ppsinfo.assert_timestamp); |
Line 1024 comioctl(dev_t dev, u_long cmd, void *da |
|
Line 1139 comioctl(dev_t dev, u_long cmd, void *da |
|
TIMESPEC_TO_TIMEVAL((struct timeval *)data, |
TIMESPEC_TO_TIMEVAL((struct timeval *)data, |
&sc->sc_pps_state.ppsinfo.clear_timestamp); |
&sc->sc_pps_state.ppsinfo.clear_timestamp); |
#endif |
#endif |
|
#else /* !__HAVE_TIMECOUNTER */ |
|
/* |
|
* Some GPS clocks models use the falling rather than |
|
* rising edge as the on-the-second signal. |
|
* The old API has no way to specify PPS polarity. |
|
*/ |
|
sc->sc_ppsmask = MSR_DCD; |
|
#ifndef PPS_TRAILING_EDGE |
|
sc->sc_ppsassert = MSR_DCD; |
|
sc->sc_ppsclear = -1; |
|
TIMESPEC_TO_TIMEVAL((struct timeval *)data, |
|
&sc->ppsinfo.assert_timestamp); |
|
#else |
|
sc->sc_ppsassert = -1; |
|
sc->sc_ppsclear = 0; |
|
TIMESPEC_TO_TIMEVAL((struct timeval *)data, |
|
&sc->ppsinfo.clear_timestamp); |
|
#endif |
|
#endif /* !__HAVE_TIMECOUNTER */ |
break; |
break; |
|
|
default: |
default: |
|
|
msr = CSR_READ_1(regsp, COM_REG_MSR); |
msr = CSR_READ_1(regsp, COM_REG_MSR); |
delta = msr ^ sc->sc_msr; |
delta = msr ^ sc->sc_msr; |
sc->sc_msr = msr; |
sc->sc_msr = msr; |
|
#ifdef __HAVE_TIMECOUNTER |
if ((sc->sc_pps_state.ppsparam.mode & PPS_CAPTUREBOTH) && |
if ((sc->sc_pps_state.ppsparam.mode & PPS_CAPTUREBOTH) && |
(delta & MSR_DCD)) { |
(delta & MSR_DCD)) { |
pps_capture(&sc->sc_pps_state); |
pps_capture(&sc->sc_pps_state); |
|
|
PPS_CAPTUREASSERT : |
PPS_CAPTUREASSERT : |
PPS_CAPTURECLEAR); |
PPS_CAPTURECLEAR); |
} |
} |
|
#else /* !__HAVE_TIMECOUNTER */ |
|
/* |
|
* Pulse-per-second (PSS) signals on edge of DCD? |
|
* Process these even if line discipline is ignoring DCD. |
|
*/ |
|
if (delta & sc->sc_ppsmask) { |
|
struct timeval tv; |
|
if ((msr & sc->sc_ppsmask) == sc->sc_ppsassert) { |
|
/* XXX nanotime() */ |
|
microtime(&tv); |
|
TIMEVAL_TO_TIMESPEC(&tv, |
|
&sc->ppsinfo.assert_timestamp); |
|
if (sc->ppsparam.mode & PPS_OFFSETASSERT) { |
|
timespecadd(&sc->ppsinfo.assert_timestamp, |
|
&sc->ppsparam.assert_offset, |
|
&sc->ppsinfo.assert_timestamp); |
|
} |
|
|
|
#ifdef PPS_SYNC |
|
if (pps_kc_hardpps_source == sc && |
|
pps_kc_hardpps_mode & PPS_CAPTUREASSERT) { |
|
hardpps(&tv, tv.tv_usec); |
|
} |
|
#endif |
|
sc->ppsinfo.assert_sequence++; |
|
sc->ppsinfo.current_mode = sc->ppsparam.mode; |
|
|
|
} else if ((msr & sc->sc_ppsmask) == sc->sc_ppsclear) { |
|
/* XXX nanotime() */ |
|
microtime(&tv); |
|
TIMEVAL_TO_TIMESPEC(&tv, |
|
&sc->ppsinfo.clear_timestamp); |
|
if (sc->ppsparam.mode & PPS_OFFSETCLEAR) { |
|
timespecadd(&sc->ppsinfo.clear_timestamp, |
|
&sc->ppsparam.clear_offset, |
|
&sc->ppsinfo.clear_timestamp); |
|
} |
|
|
|
#ifdef PPS_SYNC |
|
if (pps_kc_hardpps_source == sc && |
|
pps_kc_hardpps_mode & PPS_CAPTURECLEAR) { |
|
hardpps(&tv, tv.tv_usec); |
|
} |
|
#endif |
|
sc->ppsinfo.clear_sequence++; |
|
sc->ppsinfo.current_mode = sc->ppsparam.mode; |
|
} |
|
} |
|
#endif /* !__HAVE_TIMECOUNTER */ |
|
|
/* |
/* |
* Process normal status changes |
* Process normal status changes |