H Mauro, On 09/19/2017 07:42 AM, Mauro Carvalho Chehab wrote: > Currently, there are two handlers for ioctls: > - dvb_frontend_ioctl_properties() > - dvb_frontend_ioctl_legacy() > > Despite their names, both handles non-legacy DVB ioctls. > > Besides that, there's no reason why to not handle all ioctls > on a single handler function. > > So, merge them into a single function (dvb_frontend_handle_ioctl) > and reorganize the ioctl's to indicate what's the current DVB > API and what's deprecated. > > Despite the big diff, the handling logic for each ioctl is the > same as before. > > Signed-off-by: Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxxxxx> > --- > drivers/media/dvb-core/dvb_frontend.c | 402 +++++++++++++++++----------------- > 1 file changed, 195 insertions(+), 207 deletions(-) > > diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c > index 725cb1c8a088..cbe697a094d2 100644 > --- a/drivers/media/dvb-core/dvb_frontend.c > +++ b/drivers/media/dvb-core/dvb_frontend.c > @@ -1315,10 +1315,8 @@ static int dtv_get_frontend(struct dvb_frontend *fe, > return 0; > } > > -static int dvb_frontend_ioctl_legacy(struct file *file, > - unsigned int cmd, void *parg); > -static int dvb_frontend_ioctl_properties(struct file *file, > - unsigned int cmd, void *parg); > +static int dvb_frontend_handle_ioctl(struct file *file, > + unsigned int cmd, void *parg); > > static int dtv_property_process_get(struct dvb_frontend *fe, > const struct dtv_frontend_properties *c, > @@ -1816,12 +1814,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, > break; > case DTV_VOLTAGE: > c->voltage = tvp->u.data; > - r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, > + r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, > (void *)c->voltage); > break; > case DTV_TONE: > c->sectone = tvp->u.data; > - r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, > + r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, > (void *)c->sectone); > break; > case DTV_CODE_RATE_HP: > @@ -1928,14 +1926,13 @@ static int dtv_property_process_set(struct dvb_frontend *fe, > return r; > } > > -static int dvb_frontend_ioctl(struct file *file, > - unsigned int cmd, void *parg) > +static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg) > { > struct dvb_device *dvbdev = file->private_data; > struct dvb_frontend *fe = dvbdev->priv; > struct dtv_frontend_properties *c = &fe->dtv_property_cache; > struct dvb_frontend_private *fepriv = fe->frontend_priv; > - int err = -EOPNOTSUPP; > + int err; > > dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); > if (down_interruptible(&fepriv->sem)) > @@ -1953,121 +1950,13 @@ static int dvb_frontend_ioctl(struct file *file, > return -EPERM; > } > > - if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) > - err = dvb_frontend_ioctl_properties(file, cmd, parg); > - else { > - c->state = DTV_UNDEFINED; > - err = dvb_frontend_ioctl_legacy(file, cmd, parg); > - } > + c->state = DTV_UNDEFINED;> + err = dvb_frontend_handle_ioctl(file, cmd, parg); With this change, c->state value gets changed unconditionally before calling the ioctl. dvb_frontend_ioctl_properties() has logic for c->state == DTV_TUNE. Is it safe to set change c->state here? I think it should be set only when cmd is != FE_SET_PROPERTY or FE_GET_PROPERTY?? > > up(&fepriv->sem); > return err; > } > > -static int dvb_frontend_ioctl_properties(struct file *file, > - unsigned int cmd, void *parg) > -{ > - struct dvb_device *dvbdev = file->private_data; > - struct dvb_frontend *fe = dvbdev->priv; > - struct dvb_frontend_private *fepriv = fe->frontend_priv; > - struct dtv_frontend_properties *c = &fe->dtv_property_cache; > - int err, i; > - > - dev_dbg(fe->dvb->device, "%s:\n", __func__); > - > - switch(cmd) { > - case FE_SET_PROPERTY: { > - struct dtv_properties *tvps = parg; > - struct dtv_property *tvp = NULL; > - > - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", > - __func__, tvps->num); > - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", > - __func__, tvps->props); > - > - /* > - * Put an arbitrary limit on the number of messages that can > - * be sent at once > - */ > - if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) > - return -EINVAL; > - > - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); > - if (IS_ERR(tvp)) > - return PTR_ERR(tvp); > - > - for (i = 0; i < tvps->num; i++) { > - err = dtv_property_process_set(fe, tvp + i, file); > - if (err < 0) { > - kfree(tvp); > - return err; > - } > - (tvp + i)->result = err; > - } > - > - if (c->state == DTV_TUNE) > - dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); > - > - kfree(tvp); > - break; > - } > - case FE_GET_PROPERTY: { > - struct dtv_properties *tvps = parg; > - struct dtv_property *tvp = NULL; > - struct dtv_frontend_properties getp = fe->dtv_property_cache; > - > - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", > - __func__, tvps->num); > - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", > - __func__, tvps->props); > - > - /* > - * Put an arbitrary limit on the number of messages that can > - * be sent at once > - */ > - if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) > - return -EINVAL; > - > - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); > - if (IS_ERR(tvp)) > - return PTR_ERR(tvp); > - > - /* > - * Let's use our own copy of property cache, in order to > - * avoid mangling with DTV zigzag logic, as drivers might > - * return crap, if they don't check if the data is available > - * before updating the properties cache. > - */ > - if (fepriv->state != FESTATE_IDLE) { > - err = dtv_get_frontend(fe, &getp, NULL); > - if (err < 0) { > - kfree(tvp); > - return err; > - } > - } > - for (i = 0; i < tvps->num; i++) { > - err = dtv_property_process_get(fe, &getp, tvp + i, file); > - if (err < 0) { > - kfree(tvp); > - return err; > - } > - (tvp + i)->result = err; > - } > - > - if (copy_to_user((void __user *)tvps->props, tvp, > - tvps->num * sizeof(struct dtv_property))) { > - kfree(tvp); > - return -EFAULT; > - } > - kfree(tvp); > - break; > - } > - default: > - return -ENOTSUPP; > - } /* switch */ > - return 0; > -} > - > static int dtv_set_frontend(struct dvb_frontend *fe) > { > struct dvb_frontend_private *fepriv = fe->frontend_priv; > @@ -2205,59 +2094,102 @@ static int dtv_set_frontend(struct dvb_frontend *fe) > } > > > -static int dvb_frontend_ioctl_legacy(struct file *file, > - unsigned int cmd, void *parg) > +static int dvb_frontend_handle_ioctl(struct file *file, > + unsigned int cmd, void *parg) > { > struct dvb_device *dvbdev = file->private_data; > struct dvb_frontend *fe = dvbdev->priv; > struct dvb_frontend_private *fepriv = fe->frontend_priv; > struct dtv_frontend_properties *c = &fe->dtv_property_cache; > - int err = -EOPNOTSUPP; > + int i, err; > > - switch (cmd) { > - case FE_GET_INFO: { > - struct dvb_frontend_info* info = parg; > + dev_dbg(fe->dvb->device, "%s:\n", __func__); > > - memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); > - dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); > + switch(cmd) { > + case FE_SET_PROPERTY: { > + struct dtv_properties *tvps = parg; > + struct dtv_property *tvp = NULL; > + > + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", > + __func__, tvps->num); > + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", > + __func__, tvps->props); > + > + /* > + * Put an arbitrary limit on the number of messages that can > + * be sent at once > + */ > + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) > + return -EINVAL; > + > + tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); > + if (IS_ERR(tvp)) > + return PTR_ERR(tvp); > + > + for (i = 0; i < tvps->num; i++) { > + err = dtv_property_process_set(fe, tvp + i, file); > + if (err < 0) { > + kfree(tvp); > + return err; > + } > + (tvp + i)->result = err; > + } > + > + if (c->state == DTV_TUNE) > + dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); With the c->state being set unconditionally to DTV_UNDEFINED, this will break. > + > + kfree(tvp); > + break; > + } > + case FE_GET_PROPERTY: { > + struct dtv_properties *tvps = parg; > + struct dtv_property *tvp = NULL; > + struct dtv_frontend_properties getp = fe->dtv_property_cache; > + > + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", > + __func__, tvps->num); > + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", > + __func__, tvps->props); > + > + /* > + * Put an arbitrary limit on the number of messages that can > + * be sent at once > + */ > + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) > + return -EINVAL; > + > + tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); > + if (IS_ERR(tvp)) > + return PTR_ERR(tvp); > > /* > - * Associate the 4 delivery systems supported by DVBv3 > - * API with their DVBv5 counterpart. For the other standards, > - * use the closest type, assuming that it would hopefully > - * work with a DVBv3 application. > - * It should be noticed that, on multi-frontend devices with > - * different types (terrestrial and cable, for example), > - * a pure DVBv3 application won't be able to use all delivery > - * systems. Yet, changing the DVBv5 cache to the other delivery > - * system should be enough for making it work. > + * Let's use our own copy of property cache, in order to > + * avoid mangling with DTV zigzag logic, as drivers might > + * return crap, if they don't check if the data is available > + * before updating the properties cache. > */ > - switch (dvbv3_type(c->delivery_system)) { > - case DVBV3_QPSK: > - info->type = FE_QPSK; > - break; > - case DVBV3_ATSC: > - info->type = FE_ATSC; > - break; > - case DVBV3_QAM: > - info->type = FE_QAM; > - break; > - case DVBV3_OFDM: > - info->type = FE_OFDM; > - break; > - default: > - dev_err(fe->dvb->device, > - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", > - __func__, c->delivery_system); > - fe->ops.info.type = FE_OFDM; > + if (fepriv->state != FESTATE_IDLE) { > + err = dtv_get_frontend(fe, &getp, NULL); > + if (err < 0) { > + kfree(tvp); > + return err; > + } > + } > + for (i = 0; i < tvps->num; i++) { > + err = dtv_property_process_get(fe, &getp, tvp + i, file); > + if (err < 0) { > + kfree(tvp); > + return err; > + } > + (tvp + i)->result = err; > } > - dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", > - __func__, c->delivery_system, fe->ops.info.type); > > - /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ > - if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) > - info->caps |= FE_CAN_INVERSION_AUTO; > - err = 0; > + if (copy_to_user((void __user *)tvps->props, tvp, > + tvps->num * sizeof(struct dtv_property))) { > + kfree(tvp); > + return -EFAULT; > + } > + kfree(tvp); > break; > } > > @@ -2278,42 +2210,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file, > break; > } > > - case FE_READ_BER: > - if (fe->ops.read_ber) { > - if (fepriv->thread) > - err = fe->ops.read_ber(fe, (__u32 *) parg); > - else > - err = -EAGAIN; > - } > - break; > - > - case FE_READ_SIGNAL_STRENGTH: > - if (fe->ops.read_signal_strength) { > - if (fepriv->thread) > - err = fe->ops.read_signal_strength(fe, (__u16 *) parg); > - else > - err = -EAGAIN; > - } > - break; > - > - case FE_READ_SNR: > - if (fe->ops.read_snr) { > - if (fepriv->thread) > - err = fe->ops.read_snr(fe, (__u16 *) parg); > - else > - err = -EAGAIN; > - } > - break; > - > - case FE_READ_UNCORRECTED_BLOCKS: > - if (fe->ops.read_ucblocks) { > - if (fepriv->thread) > - err = fe->ops.read_ucblocks(fe, (__u32 *) parg); > - else > - err = -EAGAIN; > - } > - break; > - > case FE_DISEQC_RESET_OVERLOAD: > if (fe->ops.diseqc_reset_overload) { > err = fe->ops.diseqc_reset_overload(fe); > @@ -2365,6 +2261,23 @@ static int dvb_frontend_ioctl_legacy(struct file *file, > } > break; > > + case FE_DISEQC_RECV_SLAVE_REPLY: > + if (fe->ops.diseqc_recv_slave_reply) > + err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); > + break; > + > + case FE_ENABLE_HIGH_LNB_VOLTAGE: > + if (fe->ops.enable_high_lnb_voltage) > + err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); > + break; > + > + case FE_SET_FRONTEND_TUNE_MODE: > + fepriv->tune_mode_flags = (unsigned long) parg; > + err = 0; > + break; > + > + /* DEPRECATED dish control ioctls */ > + > case FE_DISHNETWORK_SEND_LEGACY_CMD: > if (fe->ops.dishnetwork_send_legacy_command) { > err = fe->ops.dishnetwork_send_legacy_command(fe, > @@ -2430,15 +2343,91 @@ static int dvb_frontend_ioctl_legacy(struct file *file, > } > break; > > - case FE_DISEQC_RECV_SLAVE_REPLY: > - if (fe->ops.diseqc_recv_slave_reply) > - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); > + /* DEPRECATED statistics ioctls */ > + > + case FE_READ_BER: > + if (fe->ops.read_ber) { > + if (fepriv->thread) > + err = fe->ops.read_ber(fe, (__u32 *) parg); > + else > + err = -EAGAIN; > + } > + break; > + > + case FE_READ_SIGNAL_STRENGTH: > + if (fe->ops.read_signal_strength) { > + if (fepriv->thread) > + err = fe->ops.read_signal_strength(fe, (__u16 *) parg); > + else > + err = -EAGAIN; > + } > break; > > - case FE_ENABLE_HIGH_LNB_VOLTAGE: > - if (fe->ops.enable_high_lnb_voltage) > - err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); > + case FE_READ_SNR: > + if (fe->ops.read_snr) { > + if (fepriv->thread) > + err = fe->ops.read_snr(fe, (__u16 *) parg); > + else > + err = -EAGAIN; > + } > + break; > + > + case FE_READ_UNCORRECTED_BLOCKS: > + if (fe->ops.read_ucblocks) { > + if (fepriv->thread) > + err = fe->ops.read_ucblocks(fe, (__u32 *) parg); > + else > + err = -EAGAIN; > + } > + break; > + > + /* DEPRECATED DVBv3 ioctls */ > + > + case FE_GET_INFO: { > + struct dvb_frontend_info* info = parg; > + > + memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); > + dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); > + > + /* > + * Associate the 4 delivery systems supported by DVBv3 > + * API with their DVBv5 counterpart. For the other standards, > + * use the closest type, assuming that it would hopefully > + * work with a DVBv3 application. > + * It should be noticed that, on multi-frontend devices with > + * different types (terrestrial and cable, for example), > + * a pure DVBv3 application won't be able to use all delivery > + * systems. Yet, changing the DVBv5 cache to the other delivery > + * system should be enough for making it work. > + */ > + switch (dvbv3_type(c->delivery_system)) { > + case DVBV3_QPSK: > + info->type = FE_QPSK; > + break; > + case DVBV3_ATSC: > + info->type = FE_ATSC; > + break; > + case DVBV3_QAM: > + info->type = FE_QAM; > + break; > + case DVBV3_OFDM: > + info->type = FE_OFDM; > + break; > + default: > + dev_err(fe->dvb->device, > + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", > + __func__, c->delivery_system); > + fe->ops.info.type = FE_OFDM; > + } > + dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", > + __func__, c->delivery_system, fe->ops.info.type); > + > + /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ > + if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) > + info->caps |= FE_CAN_INVERSION_AUTO; > + err = 0; > break; > + } > > case FE_SET_FRONTEND: > err = dvbv3_set_delivery_system(fe); > @@ -2466,11 +2455,10 @@ static int dvb_frontend_ioctl_legacy(struct file *file, > err = dtv_get_frontend(fe, &getp, parg); > break; > } > - case FE_SET_FRONTEND_TUNE_MODE: > - fepriv->tune_mode_flags = (unsigned long) parg; > - err = 0; > - break; > - } > + > + default: > + return -ENOTSUPP; > + } /* switch */ > > return err; > } > Rest looks okay to me. With c->state issue addressed and/or explained: Reviewed-by: Shuah Khan <shuahkh@xxxxxxxxxxxxxxx> thanks, -- Shuah