staticint can_validate_bittiming(conststruct can_bittiming *bt, struct netlink_ext_ack *extack)
{ /* sample point is in one-tenth of a percent */ if (bt->sample_point >= 1000) {
NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%");
/* Make sure that valid CAN FD configurations always consist of * - nominal/arbitration bittiming * - data bittiming * - control mode with CAN_CTRLMODE_FD set * - TDC parameters are coherent (details below)
*/
/* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */ if (tdc_flags == CAN_CTRLMODE_FD_TDC_MASK) return -EOPNOTSUPP; /* If one of the CAN_CTRLMODE_TDC_* flag is set then * TDC must be set and vice-versa
*/ if (!!tdc_flags != !!data[IFLA_CAN_TDC]) return -EOPNOTSUPP; /* If providing TDC parameters, at least TDCO is * needed. TDCV is needed if and only if * CAN_CTRLMODE_TDC_MANUAL is set
*/ if (data[IFLA_CAN_TDC]) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1];
/* We need synchronization with dev->stop() */
ASSERT_RTNL();
if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm;
u32 ctrlstatic;
u32 maskedflags;
/* Do not allow changing controller mode while running */ if (dev->flags & IFF_UP) return -EBUSY;
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
ctrlstatic = can_get_static_ctrlmode(priv);
maskedflags = cm->flags & cm->mask;
/* check whether provided bits are allowed to be passed */ if (maskedflags & ~(priv->ctrlmode_supported | ctrlstatic)) return -EOPNOTSUPP;
/* do not check for static fd-non-iso if 'fd' is disabled */ if (!(maskedflags & CAN_CTRLMODE_FD))
ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
/* make sure static options are provided by configuration */ if ((maskedflags & ctrlstatic) != ctrlstatic) return -EOPNOTSUPP;
/* clear bits to be modified and copy the flag values */
priv->ctrlmode &= ~cm->mask;
priv->ctrlmode |= maskedflags;
/* CAN_CTRLMODE_FD can only be set when driver supports FD */ if (priv->ctrlmode & CAN_CTRLMODE_FD) {
dev->mtu = CANFD_MTU;
} else {
dev->mtu = CAN_MTU;
memset(&priv->fd.data_bittiming, 0, sizeof(priv->fd.data_bittiming));
priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK;
memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc));
}
fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK; /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually * exclusive: make sure to turn the other one off
*/ if (fd_tdc_flag_provided)
priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_FD_TDC_MASK;
}
if (data[IFLA_CAN_BITTIMING]) { struct can_bittiming bt;
/* Do not allow changing bittiming while running */ if (dev->flags & IFF_UP) return -EBUSY;
/* Calculate bittiming parameters based on * bittiming_const if set, otherwise pass bitrate * directly via do_set_bitrate(). Bail out if neither * is given.
*/ if (!priv->bittiming_const && !priv->do_set_bittiming &&
!priv->bitrate_const) return -EOPNOTSUPP;
if (priv->do_set_bittiming) { /* Finally, set the bit-timing registers */
err = priv->do_set_bittiming(dev); if (err) return err;
}
}
if (data[IFLA_CAN_RESTART_MS]) { unsignedint restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
if (restart_ms != 0 && !priv->do_set_mode) {
NL_SET_ERR_MSG(extack, "Device doesn't support restart from Bus Off"); return -EOPNOTSUPP;
}
/* Do not allow changing restart delay while running */ if (dev->flags & IFF_UP) return -EBUSY;
priv->restart_ms = restart_ms;
}
if (data[IFLA_CAN_RESTART]) { if (!priv->do_set_mode) {
NL_SET_ERR_MSG(extack, "Device doesn't support restart from Bus Off"); return -EOPNOTSUPP;
}
/* Do not allow a restart while not running */ if (!(dev->flags & IFF_UP)) return -EINVAL;
err = can_restart_now(dev); if (err) return err;
}
if (data[IFLA_CAN_DATA_BITTIMING]) { struct can_bittiming dbt;
/* Do not allow changing bittiming while running */ if (dev->flags & IFF_UP) return -EBUSY;
/* Calculate bittiming parameters based on * data_bittiming_const if set, otherwise pass bitrate * directly via do_set_bitrate(). Bail out if neither * is given.
*/ if (!priv->fd.data_bittiming_const && !priv->fd.do_set_data_bittiming &&
!priv->fd.data_bitrate_const) return -EOPNOTSUPP;
if (!priv->do_set_termination) return -EOPNOTSUPP;
/* check whether given value is supported by the interface */ for (i = 0; i < num_term; i++) { if (termval == priv->termination_const[i]) break;
} if (i >= num_term) return -EINVAL;
/* Finally, set the termination value */
err = priv->do_set_termination(dev, termval); if (err) return err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.