diff options
| author | Tony Lindgren <tony@atomide.com> | 2012-01-24 19:28:08 -0500 |
|---|---|---|
| committer | Linus Walleij <linus.walleij@linaro.org> | 2012-01-26 08:13:11 -0500 |
| commit | b9130b776ee481acbc27a7e56d98df75680de369 (patch) | |
| tree | b7933b4d3e562e806c3dc61544352e46f35820cb | |
| parent | 9e2551e10b5c7ba550849bd9ed519e498cc30e68 (diff) | |
pinctrl: add checks for empty function names
This is needed as otherwise we can get the following when
dealing with buggy data in a pinmux driver for
pinmux_search_function:
Unable to handle kernel NULL pointer dereference at virtual
address 00000000
...
PC is at strcmp+0xc/0x34
LR is at pinmux_get+0x350/0x8f4
...
As we need pctldev initialized to call ops->list_functions,
let's initialize it before check_ops calls and pass the
pctldev to the check_ops functions. Do this for both pinmux
and pinconf check_ops functions.
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
| -rw-r--r-- | drivers/pinctrl/core.c | 36 | ||||
| -rw-r--r-- | drivers/pinctrl/pinconf.c | 4 | ||||
| -rw-r--r-- | drivers/pinctrl/pinconf.h | 4 | ||||
| -rw-r--r-- | drivers/pinctrl/pinmux.c | 17 | ||||
| -rw-r--r-- | drivers/pinctrl/pinmux.h | 4 |
5 files changed, 41 insertions, 24 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index d9d35fcbfc6b..8fe15cf15ac8 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c | |||
| @@ -583,40 +583,40 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, | |||
| 583 | if (pctldesc->name == NULL) | 583 | if (pctldesc->name == NULL) |
| 584 | return NULL; | 584 | return NULL; |
| 585 | 585 | ||
| 586 | pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL); | ||
| 587 | if (pctldev == NULL) | ||
| 588 | return NULL; | ||
| 589 | |||
| 590 | /* Initialize pin control device struct */ | ||
| 591 | pctldev->owner = pctldesc->owner; | ||
| 592 | pctldev->desc = pctldesc; | ||
| 593 | pctldev->driver_data = driver_data; | ||
| 594 | INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); | ||
| 595 | spin_lock_init(&pctldev->pin_desc_tree_lock); | ||
| 596 | INIT_LIST_HEAD(&pctldev->gpio_ranges); | ||
| 597 | mutex_init(&pctldev->gpio_ranges_lock); | ||
| 598 | pctldev->dev = dev; | ||
| 599 | |||
| 586 | /* If we're implementing pinmuxing, check the ops for sanity */ | 600 | /* If we're implementing pinmuxing, check the ops for sanity */ |
| 587 | if (pctldesc->pmxops) { | 601 | if (pctldesc->pmxops) { |
| 588 | ret = pinmux_check_ops(pctldesc->pmxops); | 602 | ret = pinmux_check_ops(pctldev); |
| 589 | if (ret) { | 603 | if (ret) { |
| 590 | pr_err("%s pinmux ops lacks necessary functions\n", | 604 | pr_err("%s pinmux ops lacks necessary functions\n", |
| 591 | pctldesc->name); | 605 | pctldesc->name); |
| 592 | return NULL; | 606 | goto out_err; |
| 593 | } | 607 | } |
| 594 | } | 608 | } |
| 595 | 609 | ||
| 596 | /* If we're implementing pinconfig, check the ops for sanity */ | 610 | /* If we're implementing pinconfig, check the ops for sanity */ |
| 597 | if (pctldesc->confops) { | 611 | if (pctldesc->confops) { |
| 598 | ret = pinconf_check_ops(pctldesc->confops); | 612 | ret = pinconf_check_ops(pctldev); |
| 599 | if (ret) { | 613 | if (ret) { |
| 600 | pr_err("%s pin config ops lacks necessary functions\n", | 614 | pr_err("%s pin config ops lacks necessary functions\n", |
| 601 | pctldesc->name); | 615 | pctldesc->name); |
| 602 | return NULL; | 616 | goto out_err; |
| 603 | } | 617 | } |
| 604 | } | 618 | } |
| 605 | 619 | ||
| 606 | pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL); | ||
| 607 | if (pctldev == NULL) | ||
| 608 | return NULL; | ||
| 609 | |||
| 610 | /* Initialize pin control device struct */ | ||
| 611 | pctldev->owner = pctldesc->owner; | ||
| 612 | pctldev->desc = pctldesc; | ||
| 613 | pctldev->driver_data = driver_data; | ||
| 614 | INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); | ||
| 615 | spin_lock_init(&pctldev->pin_desc_tree_lock); | ||
| 616 | INIT_LIST_HEAD(&pctldev->gpio_ranges); | ||
| 617 | mutex_init(&pctldev->gpio_ranges_lock); | ||
| 618 | pctldev->dev = dev; | ||
| 619 | |||
| 620 | /* Register all the pins */ | 620 | /* Register all the pins */ |
| 621 | pr_debug("try to register %d pins on %s...\n", | 621 | pr_debug("try to register %d pins on %s...\n", |
| 622 | pctldesc->npins, pctldesc->name); | 622 | pctldesc->npins, pctldesc->name); |
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 1892a3794b99..9fb75456824c 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c | |||
| @@ -205,8 +205,10 @@ int pin_config_group_set(const char *dev_name, const char *pin_group, | |||
| 205 | } | 205 | } |
| 206 | EXPORT_SYMBOL(pin_config_group_set); | 206 | EXPORT_SYMBOL(pin_config_group_set); |
| 207 | 207 | ||
| 208 | int pinconf_check_ops(const struct pinconf_ops *ops) | 208 | int pinconf_check_ops(struct pinctrl_dev *pctldev) |
| 209 | { | 209 | { |
| 210 | const struct pinconf_ops *ops = pctldev->desc->confops; | ||
| 211 | |||
| 210 | /* We must be able to read out pin status */ | 212 | /* We must be able to read out pin status */ |
| 211 | if (!ops->pin_config_get && !ops->pin_config_group_get) | 213 | if (!ops->pin_config_get && !ops->pin_config_group_get) |
| 212 | return -EINVAL; | 214 | return -EINVAL; |
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index e7dc6165032a..006b77fa737e 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #ifdef CONFIG_PINCONF | 14 | #ifdef CONFIG_PINCONF |
| 15 | 15 | ||
| 16 | int pinconf_check_ops(const struct pinconf_ops *ops); | 16 | int pinconf_check_ops(struct pinctrl_dev *pctldev); |
| 17 | void pinconf_init_device_debugfs(struct dentry *devroot, | 17 | void pinconf_init_device_debugfs(struct dentry *devroot, |
| 18 | struct pinctrl_dev *pctldev); | 18 | struct pinctrl_dev *pctldev); |
| 19 | int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, | 19 | int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, |
| @@ -23,7 +23,7 @@ int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin, | |||
| 23 | 23 | ||
| 24 | #else | 24 | #else |
| 25 | 25 | ||
| 26 | static inline int pinconf_check_ops(const struct pinconf_ops *ops) | 26 | static inline int pinconf_check_ops(struct pinctrl_dev *pctldev) |
| 27 | { | 27 | { |
| 28 | return 0; | 28 | return 0; |
| 29 | } | 29 | } |
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 3ffa9324ed82..7c3193f7a044 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c | |||
| @@ -889,8 +889,11 @@ void pinmux_disable(struct pinmux *pmx) | |||
| 889 | } | 889 | } |
| 890 | EXPORT_SYMBOL_GPL(pinmux_disable); | 890 | EXPORT_SYMBOL_GPL(pinmux_disable); |
| 891 | 891 | ||
| 892 | int pinmux_check_ops(const struct pinmux_ops *ops) | 892 | int pinmux_check_ops(struct pinctrl_dev *pctldev) |
| 893 | { | 893 | { |
| 894 | const struct pinmux_ops *ops = pctldev->desc->pmxops; | ||
| 895 | unsigned selector = 0; | ||
| 896 | |||
| 894 | /* Check that we implement required operations */ | 897 | /* Check that we implement required operations */ |
| 895 | if (!ops->list_functions || | 898 | if (!ops->list_functions || |
| 896 | !ops->get_function_name || | 899 | !ops->get_function_name || |
| @@ -899,6 +902,18 @@ int pinmux_check_ops(const struct pinmux_ops *ops) | |||
| 899 | !ops->disable) | 902 | !ops->disable) |
| 900 | return -EINVAL; | 903 | return -EINVAL; |
| 901 | 904 | ||
| 905 | /* Check that all functions registered have names */ | ||
| 906 | while (ops->list_functions(pctldev, selector) >= 0) { | ||
| 907 | const char *fname = ops->get_function_name(pctldev, | ||
| 908 | selector); | ||
| 909 | if (!fname) { | ||
| 910 | pr_err("pinmux ops has no name for function%u\n", | ||
| 911 | selector); | ||
| 912 | return -EINVAL; | ||
| 913 | } | ||
| 914 | selector++; | ||
| 915 | } | ||
| 916 | |||
| 902 | return 0; | 917 | return 0; |
| 903 | } | 918 | } |
| 904 | 919 | ||
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index 844500b3331b..97f52223fbc2 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | #ifdef CONFIG_PINMUX | 13 | #ifdef CONFIG_PINMUX |
| 14 | 14 | ||
| 15 | int pinmux_check_ops(const struct pinmux_ops *ops); | 15 | int pinmux_check_ops(struct pinctrl_dev *pctldev); |
| 16 | void pinmux_init_device_debugfs(struct dentry *devroot, | 16 | void pinmux_init_device_debugfs(struct dentry *devroot, |
| 17 | struct pinctrl_dev *pctldev); | 17 | struct pinctrl_dev *pctldev); |
| 18 | void pinmux_init_debugfs(struct dentry *subsys_root); | 18 | void pinmux_init_debugfs(struct dentry *subsys_root); |
| @@ -21,7 +21,7 @@ void pinmux_unhog_maps(struct pinctrl_dev *pctldev); | |||
| 21 | 21 | ||
| 22 | #else | 22 | #else |
| 23 | 23 | ||
| 24 | static inline int pinmux_check_ops(const struct pinmux_ops *ops) | 24 | static inline int pinmux_check_ops(struct pinctrl_dev *pctldev) |
| 25 | { | 25 | { |
| 26 | return 0; | 26 | return 0; |
| 27 | } | 27 | } |
