Em Fri, 05 Dec 2014 19:49:33 +0900
tsk...@gmail.com escreveu:

> From: Akihiro Tsukada <tsk...@gmail.com>
> 
> Define a standard interface for demod/tuner i2c driver modules.
> A module client calls dvb_i2c_attach_{fe,tuner}(),
> and a module driver defines struct dvb_i2c_module_param and
> calls DEFINE_DVB_I2C_MODULE() macro.
> 
> This template provides implicit module requests and ref-counting,
> alloc/free's private data structures,
> fixes the usage of clientdata of i2c devices,
> and defines the platformdata structures for passing around
> device specific config/output parameters between drivers and clients.
> These kinds of code are common to (almost) all dvb i2c drivers/client,
> but they were scattered over adapter modules and demod/tuner modules.

The idea behind this patch is good. I didn't have time yet to test it on a
device that I have currently access.

I have a few comments below, mostly regards with naming convention.

By seeing the patches you converted a few drivers to use this, I'm a little
bit concern about the conversion. We need something that won't be hard to
convert to the new model without requiring to re-test everything.

Anyway, my plan is to take a deeper look on it next week and convert one
or two drivers to use the new I2C binding approach you're proposing.
> 
> Signed-off-by: Akihiro Tsukada <tsk...@gmail.com>
> ---
>  drivers/media/dvb-core/Makefile       |   4 +
>  drivers/media/dvb-core/dvb_frontend.h |   1 +
>  drivers/media/dvb-core/dvb_i2c.c      | 219 
> ++++++++++++++++++++++++++++++++++
>  drivers/media/dvb-core/dvb_i2c.h      | 110 +++++++++++++++++
>  4 files changed, 334 insertions(+)
>  create mode 100644 drivers/media/dvb-core/dvb_i2c.c
>  create mode 100644 drivers/media/dvb-core/dvb_i2c.h
> 
> diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
> index 8f22bcd..271648d 100644
> --- a/drivers/media/dvb-core/Makefile
> +++ b/drivers/media/dvb-core/Makefile
> @@ -8,4 +8,8 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o   
> \
>                dvb_ca_en50221.o dvb_frontend.o                \
>                $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
>  
> +ifneq ($(CONFIG_I2C)$(CONFIG_I2C_MODULE),)
> +dvb-core-objs += dvb_i2c.o
> +endif
> +
>  obj-$(CONFIG_DVB_CORE) += dvb-core.o
> diff --git a/drivers/media/dvb-core/dvb_frontend.h 
> b/drivers/media/dvb-core/dvb_frontend.h
> index 816269e..41aae1b 100644
> --- a/drivers/media/dvb-core/dvb_frontend.h
> +++ b/drivers/media/dvb-core/dvb_frontend.h
> @@ -415,6 +415,7 @@ struct dtv_frontend_properties {
>  struct dvb_frontend {
>       struct dvb_frontend_ops ops;
>       struct dvb_adapter *dvb;
> +     struct i2c_client *fe_cl;

fe_cl doesn't seem to be a good name for something that should be
accessed by all drivers that use it. fe_i2c_client is likely a
better name for it.

>       void *demodulator_priv;
>       void *tuner_priv;
>       void *frontend_priv;
> diff --git a/drivers/media/dvb-core/dvb_i2c.c 
> b/drivers/media/dvb-core/dvb_i2c.c
> new file mode 100644
> index 0000000..4ea4e5e
> --- /dev/null
> +++ b/drivers/media/dvb-core/dvb_i2c.c
> @@ -0,0 +1,219 @@
> +/*
> + * dvb_i2c.c
> + *
> + * Copyright 2014 Akihiro Tsukada <tskd08 AT gmail DOT com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "dvb_i2c.h"
> +
> +static struct i2c_client *
> +dvb_i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info *info,
> +                const unsigned short *probe_addrs)
> +{
> +     struct i2c_client *cl;
> +
> +     request_module(I2C_MODULE_PREFIX "%s", info->type);
> +     /* Create the i2c client */
> +     if (info->addr == 0 && probe_addrs)
> +             cl = i2c_new_probed_device(adap, info, probe_addrs, NULL);
> +     else
> +             cl = i2c_new_device(adap, info);
> +     if (!cl || !cl->dev.driver)
> +             return NULL;
> +     return cl;

The best would be to also register the device with the media controller,
if CONFIG_MEDIA_CONTROLLER is defined, just like v4l2_i2c_subdev_init()
does.

I would also try to use similar names for the function calls to the ones
that the v4l subsystem uses for subdevices.

> +}
> +
> +struct dvb_frontend *
> +dvb_i2c_attach_fe(struct i2c_adapter *adap, const struct i2c_board_info 
> *info,
> +               const void *cfg, void **out)
> +{
> +     struct i2c_client *cl;
> +     struct i2c_board_info bi;

Better to call this as "tmp_info", as this seems to be just a temp var.

> +     struct dvb_i2c_dev_config dcfg;

I would, instead, call this as "cfg", and rename the parameter as
cfg_template.

> +
> +     dcfg.priv_cfg = cfg;
> +     dcfg.out = out;
> +     bi = *info;
> +     bi.platform_data = &dcfg;
> +
> +     cl = dvb_i2c_new_device(adap, &bi, NULL);
> +     if (!cl)
> +             return NULL;
> +     return i2c_get_clientdata(cl);
> +}
> +EXPORT_SYMBOL(dvb_i2c_attach_fe);
> +
> +struct i2c_client *
> +dvb_i2c_attach_tuner(struct i2c_adapter *adap,
> +                  const struct i2c_board_info *info,
> +                  struct dvb_frontend *fe,
> +                  const void *cfg, void **out)
> +{
> +     struct i2c_board_info bi;
> +     struct dvb_i2c_tuner_config tcfg;

Same as above with regards to name: please rename:
        - bi -> tmp_info
        - tcfg -> cfg

> +
> +     tcfg.fe = fe;
> +     tcfg.devcfg.priv_cfg = cfg;
> +     tcfg.devcfg.out = out;
> +     bi = *info;
> +     bi.platform_data = &tcfg;
> +
> +     return dvb_i2c_new_device(adap, &bi, NULL);
> +}
> +EXPORT_SYMBOL(dvb_i2c_attach_tuner);
> +
> +
> +static int
> +probe_tuner(struct i2c_client *client, const struct i2c_device_id *id,
> +         const struct dvb_i2c_module_param *param,
> +         struct module *this_module)
> +{
> +     struct dvb_frontend *fe;
> +     struct dvb_i2c_tuner_config *tcfg;

Same here with regards to naming convention.

> +     int ret;
> +
> +     if (!try_module_get(this_module))
> +             return -ENODEV;
> +
> +     tcfg = client->dev.platform_data;
> +     fe = tcfg->fe;
> +     i2c_set_clientdata(client, fe);
> +
> +     if (param->priv_size > 0) {
> +             fe->tuner_priv = kzalloc(param->priv_size, GFP_KERNEL);
> +             if (!fe->tuner_priv) {
> +                     ret = -ENOMEM;
> +                     goto err_mem;
> +             }
> +     }
> +
> +     if (param->ops.tuner_ops)
> +             memcpy(&fe->ops.tuner_ops, param->ops.tuner_ops,
> +                     sizeof(fe->ops.tuner_ops));
> +
> +     ret = 0;
> +     if (param->priv_probe)
> +             ret = param->priv_probe(client, id);
> +     if (ret != 0) {
> +             dev_info(&client->dev, "driver private probe failed.\n");
> +             goto err_priv;
> +     }
> +     return 0;
> +
> +err_priv:
> +     kfree(fe->tuner_priv);
> +err_mem:
> +     fe->tuner_priv = NULL;
> +     module_put(this_module);
> +     return ret;
> +}
> +
> +static int remove_tuner(struct i2c_client *client,
> +                     const struct dvb_i2c_module_param *param,
> +                     struct module *this_module)
> +{
> +     struct dvb_frontend *fe;
> +
> +     if (param->priv_remove)
> +             param->priv_remove(client);
> +     fe = i2c_get_clientdata(client);
> +     kfree(fe->tuner_priv);
> +     fe->tuner_priv = NULL;
> +     module_put(this_module);
> +     return 0;
> +}
> +
> +
> +static int probe_fe(struct i2c_client *client, const struct i2c_device_id 
> *id,
> +                 const struct dvb_i2c_module_param *param,
> +                 struct module *this_module)
> +{
> +     struct dvb_frontend *fe;
> +     int ret;
> +
> +     if (!try_module_get(this_module))
> +             return -ENODEV;
> +
> +     fe = kzalloc(sizeof(*fe), GFP_KERNEL);
> +     if (!fe) {
> +             ret = -ENOMEM;
> +             goto err_fe_kfree;
> +     }
> +     i2c_set_clientdata(client, fe);
> +     fe->fe_cl = client;
> +
> +     if (param->priv_size > 0) {
> +             fe->demodulator_priv = kzalloc(param->priv_size, GFP_KERNEL);
> +             if (!fe->demodulator_priv) {
> +                     ret = -ENOMEM;
> +                     goto err_fe_kfree;
> +             }
> +     }
> +
> +     if (param->ops.fe_ops)
> +             memcpy(&fe->ops, param->ops.fe_ops, sizeof(fe->ops));
> +
> +     ret = 0;
> +     if (param->priv_probe)
> +             ret = param->priv_probe(client, id);
> +     if (ret != 0) {
> +             dev_info(&client->dev, "driver private probe failed.\n");
> +             goto err_priv_kfree;
> +     }
> +     return 0;
> +
> +err_priv_kfree:
> +     kfree(fe->demodulator_priv);
> +err_fe_kfree:
> +     kfree(fe);
> +     module_put(this_module);
> +     return ret;
> +}
> +
> +static int remove_fe(struct i2c_client *client,
> +                  const struct dvb_i2c_module_param *param,
> +                  struct module *this_module)
> +{
> +     struct dvb_frontend *fe;
> +
> +     if (param->priv_remove)
> +             param->priv_remove(client);
> +     fe = i2c_get_clientdata(client);
> +     kfree(fe->demodulator_priv);
> +     kfree(fe);
> +     module_put(this_module);
> +     return 0;
> +}
> +
> +
> +int dvb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id,
> +               const struct dvb_i2c_module_param *param,
> +               struct module *this_module)
> +{
> +     return param->is_tuner ? probe_tuner(client, id, param, this_module) :
> +                              probe_fe(client, id, param, this_module);
> +}
> +EXPORT_SYMBOL(dvb_i2c_probe);
> +
> +int dvb_i2c_remove(struct i2c_client *client,
> +                const struct dvb_i2c_module_param *param,
> +                struct module *this_module)
> +{
> +     return param->is_tuner ? remove_tuner(client, param, this_module) :
> +                              remove_fe(client, param, this_module);
> +}
> +EXPORT_SYMBOL(dvb_i2c_remove);
> diff --git a/drivers/media/dvb-core/dvb_i2c.h 
> b/drivers/media/dvb-core/dvb_i2c.h
> new file mode 100644
> index 0000000..2bf409d
> --- /dev/null
> +++ b/drivers/media/dvb-core/dvb_i2c.h
> @@ -0,0 +1,110 @@
> +/*
> + * dvb_i2c.h
> + *
> + * Copyright 2014 Akihiro Tsukada <tskd08 AT gmail DOT com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +/* template code for i2c driver modules */
> +
> +#ifndef _DVB_I2C_H_
> +#define _DVB_I2C_H_
> +
> +#include <linux/i2c.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include "dvb_frontend.h"
> +
> +/* interface for module clients */
> +
> +struct dvb_frontend *dvb_i2c_attach_fe(struct i2c_adapter *adap,
> +                                    const struct i2c_board_info *info,
> +                                    const void *cfg, void **out);
> +
> +struct i2c_client *dvb_i2c_attach_tuner(struct i2c_adapter *adap,
> +                                     const struct i2c_board_info *info,
> +                                     struct dvb_frontend *fe,
> +                                     const void *cfg, void **out);
> +
> +/* interface for module drivers */
> +
> +/* data structures that are set to i2c_client.dev.platform_data */
> +
> +struct dvb_i2c_dev_config {
> +     const void *priv_cfg;
> +     /* @out [OUT] pointer to per-device data returned from driver */
> +     void **out;
> +};
> +
> +struct dvb_i2c_tuner_config {
> +     struct dvb_frontend *fe;
> +     struct dvb_i2c_dev_config devcfg;
> +};
> +
> +typedef int (*dvb_i2c_probe_func)(struct i2c_client *client,
> +                               const struct i2c_device_id *id);
> +typedef int (*dvb_i2c_remove_func)(struct i2c_client *client);
> +
> +struct dvb_i2c_module_param {
> +     union {
> +             const struct dvb_frontend_ops *fe_ops;
> +             const struct dvb_tuner_ops *tuner_ops;
> +     } ops;
> +     /* driver private probe/remove functions */
> +     dvb_i2c_probe_func  priv_probe;
> +     dvb_i2c_remove_func priv_remove;
> +
> +     u32 priv_size; /* sizeof(device private data) */
> +     bool is_tuner;
> +};
> +
> +
> +int dvb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id,
> +               const struct dvb_i2c_module_param *param,
> +               struct module *this_module);
> +
> +int dvb_i2c_remove(struct i2c_client *client,
> +                const struct dvb_i2c_module_param *param,
> +                struct module *this_module);
> +
> +
> +#define DEFINE_DVB_I2C_MODULE(dname, idtab, param) \
> +static int _##dname##_probe(struct i2c_client *client,\
> +                             const struct i2c_device_id *id)\
> +{\
> +     return dvb_i2c_probe(client, id, &(param), THIS_MODULE);\
> +} \
> +\
> +static int _##dname##_remove(struct i2c_client *client)\
> +{\
> +     return dvb_i2c_remove(client, &(param), THIS_MODULE);\
> +} \
> +\
> +MODULE_DEVICE_TABLE(i2c, idtab);\
> +\
> +static struct i2c_driver dname##_driver = {\
> +     .driver = {\
> +             .name = #dname,\
> +     },\
> +     .probe    = _##dname##_probe,\
> +     .remove   = _##dname##_remove,\
> +     .id_table = idtab,\
> +};\
> +\
> +module_i2c_driver(dname##_driver)
> +
> +#endif /* _DVB_I2C_H */


-- 

Cheers,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to