All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Morton <akpm@linux-foundation.org>
To: "Kim, Milo" <Milo.Kim@ti.com>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"Kim, Milo" <Milo.Kim@nsc.com>,
	Richard Purdie <rpurdie@rpsys.net>
Subject: Re: [PATCH] backlight: add new lp855x backlight driver
Date: Fri, 20 Jan 2012 16:23:36 -0800	[thread overview]
Message-ID: <20120120162336.7210b5e3.akpm@linux-foundation.org> (raw)
In-Reply-To: <B567DBAB974C0544994013492B949F8E3812A8DECA@EXMAIL03.scwf.nsc.com>

On Thu, 5 Jan 2012 23:00:24 -0800
"Kim, Milo" <Milo.Kim@ti.com> wrote:

> This patch supports TI LP8550/LP8551/LP8852/LP8553/LP8556 backlight driver.
> 
> The brightness can be controlled by the I2C or PWM input.
> The lp855x driver provides both modes.
> For the PWM control, pwm-specific functions can be defined in the platform data.
> And some information can be read via the debugfs.
> 
> For the details, please refer to 'Documentation/backlight/lp855x-driver.txt'.
> 
>
> ...
>
> +static ssize_t lp855x_help_register(struct file *file, char __user *userbuf,
> +                                   size_t count, loff_t *ppos)
> +{
> +       char buf[320];
> +       unsigned int len;
> +       const char *help = "\n How to read/write LP855x registers\n\n \
> +       (example) To read 0x00 register,\n \
> +       echo 0x00 r > /sys/kernel/debug/lp855x/registers\n \
> +       To write 0xff into 0x1 address,\n \
> +       echo 0x00 0xff w > /sys/kernel/debug/lp855x/registers \n \
> +       To dump values from 0x00 to 0x06 address,\n \
> +       echo 0x00 0x06 d > /sys/kernel/debug/lp855x/registers\n";

lol.  Oh well, it's only debugfs.

> +       len = snprintf(buf, sizeof(buf), "%s\n", help);

`len' should have type size_t.

> +       if (len > sizeof(buf))
> +               len = sizeof(buf);

Here you could use max().  But a better approach is to form the output
using scnprintf().

> +       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> +}
> +
> +static char *lp855x_parse_register_cmd(const char *cmd, u8 *byte)
> +{
> +       char tmp[10];
> +       char *blank;
> +       unsigned long arg;
> +
> +       blank = strchr(cmd, ' ');
> +       memset(tmp, 0x0, sizeof(tmp));
> +       memcpy(tmp, cmd, blank - cmd);
> +
> +       if (strict_strtol(tmp, 16, &arg) < 0)
> +               return NULL;

Gee, what's all this code doing?  Please add a nice comment explaining
what the input format is, and what this function is trying to do with
it.

I worry about what it does when strchr() returns NULL!

> +       *byte = arg;
> +       return blank;
> +}
> +
> +static ssize_t lp855x_ctrl_register(struct file *file,
> +                                   const char __user *userbuf, size_t count,
> +                                   loff_t *ppos)
> +{
> +       char mode, buf[20];
> +       char *pos, *pos2;
> +       u8 i, arg1, arg2, val;
> +       struct lp855x *lp = file->private_data;
> +
> +       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
> +               return -EFAULT;

Looks risky.  If count>sizeof(buf), this will quietly truncate the
user's input.  It would be much better to reject the input in this
case.

> +       mode = buf[count - 2];
> +       switch (mode) {
> +       case 'r':
> +               if (!lp855x_parse_register_cmd(buf, &arg1))
> +                       return -EINVAL;
> +
> +               lp855x_read_byte(lp, arg1, &val);
> +               dev_info(lp->dev, "Read [0x%.2x] = 0x%.2x\n", arg1, val);
> +               break;
> +       case 'w':
> +               pos = lp855x_parse_register_cmd(buf, &arg1);
> +               if (!pos)
> +                       return -EINVAL;
> +               pos2 = lp855x_parse_register_cmd(pos + 1, &arg2);
> +               if (!pos2)
> +                       return -EINVAL;
> +
> +               lp855x_write_byte(lp, arg1, arg2);
> +               dev_info(lp->dev, "Written [0x%.2x] = 0x%.2x\n", arg1, arg2);
> +               break;
> +       case 'd':
> +               pos = lp855x_parse_register_cmd(buf, &arg1);
> +               if (!pos)
> +                       return -EINVAL;
> +               pos2 = lp855x_parse_register_cmd(pos + 1, &arg2);
> +               if (!pos2)
> +                       return -EINVAL;
> +
> +               for (i = arg1; i <= arg2; i++) {
> +                       lp855x_read_byte(lp, i, &val);
> +                       dev_info(lp->dev, "Read [0x%.2x] = 0x%.2x\n", i, val);
> +               }
> +               break;
> +       default:
> +               break;
> +       }
> +
> +       return count;
> +}
> +
> +static ssize_t lp855x_get_chipid(struct file *file, char __user *userbuf,
> +                                size_t count, loff_t *ppos)
> +{
> +       struct lp855x *lp = file->private_data;
> +       char buf[10];
> +       unsigned int len;
> +
> +       len = snprintf(buf, sizeof(buf), "%s\n", lp->chipid);
> +
> +       if (len > sizeof(buf))
> +               len = sizeof(buf);

See above.

> +       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> +}
> +
> +static ssize_t lp855x_get_bl_mode(struct file *file, char __user *userbuf,
> +                                 size_t count, loff_t *ppos)
> +{
> +       char buf[20];
> +       unsigned int len;
> +       char *strmode = NULL;
> +       struct lp855x *lp = file->private_data;
> +       enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
> +
> +       if (mode == PWM_BASED)
> +               strmode = "pwm based";
> +       else if (mode == REGISTER_BASED)
> +               strmode = "register based";
> +
> +       len = snprintf(buf, sizeof(buf), "%s\n", strmode);
> +
> +       if (len > sizeof(buf))
> +               len = sizeof(buf);

More...

> +       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> +}
> +
> +#define LP855X_DBG_ENTRY(name, pread, pwrite) \
> +static const struct file_operations dbg_##name##_fops = { \
> +       .open = lp855x_dbg_open, \
> +       .read = pread, \
> +       .write = pwrite, \
> +       .owner = THIS_MODULE, \
> +       .llseek = default_llseek, \
> +}
> +
> +LP855X_DBG_ENTRY(registers, lp855x_help_register, lp855x_ctrl_register);
> +LP855X_DBG_ENTRY(chip, lp855x_get_chipid, NULL);
> +LP855X_DBG_ENTRY(blmode, lp855x_get_bl_mode, NULL);
> +
> +static void lp855x_create_debugfs(struct lp855x *lp)
> +{
> +       struct debug_dentry *dd = &lp->dd;
> +
> +       dd->dir = debugfs_create_dir("lp855x", NULL);
> +
> +       dd->reg = debugfs_create_file("registers", S_IWUSR | S_IRUGO,
> +                                     dd->dir, lp, &dbg_registers_fops);
> +
> +       dd->chip = debugfs_create_file("chip_id", S_IRUGO,
> +                                      dd->dir, lp, &dbg_chip_fops);
> +
> +       dd->blmode = debugfs_create_file("bl_ctl_mode", S_IRUGO,
> +                                        dd->dir, lp, &dbg_blmode_fops);

Error checking?

> +}
> +
>
> ...
>
> +static void lp855x_init_device(struct lp855x *lp)
> +{
> +       u8 val, addr;
> +       int i, ret;
> +       struct lp855x_platform_data *pd = lp->pdata;
> +
> +       val = pd->initial_brightness;
> +       ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
> +
> +       val = pd->device_control;
> +       ret |= lp855x_write_byte(lp, DEVICE_CTRL, val);
> +
> +       if (pd->load_new_rom_data && pd->size_program) {
> +               for (i = 0; i < pd->size_program; i++) {
> +                       addr = pd->rom_data[i].addr;
> +                       val = pd->rom_data[i].val;
> +                       if (!lp855x_is_valid_rom_area(lp, addr))
> +                               continue;
> +
> +                       ret |= lp855x_write_byte(lp, addr, val);
> +               }
> +       }
> +
> +       if (ret)
> +               dev_err(lp->dev, "i2c write err\n");
> +}

This isn't very good.  lp855x_write_byte() can return various -Efoo
values: -EINVAL, -ENOMEM, etc.  But this function can end up
bitwise-ORing those errnos together, thus producing a completely new
(and wrong) errno.

That's not a big problem in this case, because that errno is simply
dropped on the floor.  However it would be more useful if the errno
were reported to the operator in that dev_err() call.

>
> ...
>
> +static int lp855x_backlight_register(struct lp855x *lp)
> +{
> +       struct backlight_device *bl;
> +       struct backlight_properties props;
> +       const char *name = lp->pdata->name;
> +
> +       if (!name)
> +               return -ENODEV;
> +
> +       props.brightness = lp->pdata->initial_brightness;
> +       props.max_brightness =
> +               (lp->pdata->max_brightness < lp->pdata->initial_brightness) ?
> +               255 : lp->pdata->max_brightness;
> +
> +       bl = backlight_device_register(name, lp->dev, lp,
> +                                      &lp855x_bl_ops, &props);
> +       if (IS_ERR(bl))
> +               return -EIO;

If `lb' contains an errno, we should return that errno to the caller
rather than unconditionally overwriting it with -EIO?

> +       lp->bl = bl;
> +
> +       return 0;
> +}
> +
>
> ...
>


  reply	other threads:[~2012-01-21  0:23 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <B567DBAB974C0544994013492B949F8E3812710288@EXMAIL03.scwf.nsc.com>
     [not found] ` <B567DBAB974C0544994013492B949F8E381271028A@EXMAIL03.scwf.nsc.com>
2011-12-11 16:12   ` [PATCH] backlight: add new lp855x backlight driver Kim, Milo
2012-01-06  7:00   ` Kim, Milo
2012-01-21  0:23     ` Andrew Morton [this message]
2012-01-25  6:21       ` Kim, Milo
2012-01-17  4:04   ` Kim, Milo
2012-01-17  4:06     ` Kim, Milo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120120162336.7210b5e3.akpm@linux-foundation.org \
    --to=akpm@linux-foundation.org \
    --cc=Milo.Kim@nsc.com \
    --cc=Milo.Kim@ti.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rpurdie@rpsys.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.