On Thu, Apr 27, 2017 at 10:34:03PM +0200, David Härdeman wrote:
> The device core infrastructure is based on the presumption that
> once a driver calls device_add(), it must be ready to accept
> userspace interaction.
> 
> This requires splitting rc_setup_rx_device() into two functions
> and reorganizing rc_register_device() so that as much work
> as possible is performed before calling device_add().
> 

With this patch applied, I'm no longer getting any scancodes from
my rc devices.

David, please can you test your patches before submitting. I have to go
over them meticulously because I cannot assume you've tested them.

Thanks
Sean

> Signed-off-by: David Härdeman <da...@hardeman.nu>
> ---
>  drivers/media/rc/rc-core-priv.h |    2 +
>  drivers/media/rc/rc-ir-raw.c    |   34 ++++++++++++------
>  drivers/media/rc/rc-main.c      |   75 
> +++++++++++++++++++++++++--------------
>  3 files changed, 73 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index 0455b273c2fc..b3e7cac2c3ee 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -263,7 +263,9 @@ int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int 
> max,
>   * Routines from rc-raw.c to be used internally and by decoders
>   */
>  u64 ir_raw_get_allowed_protocols(void);
> +int ir_raw_event_prepare(struct rc_dev *dev);
>  int ir_raw_event_register(struct rc_dev *dev);
> +void ir_raw_event_free(struct rc_dev *dev);
>  void ir_raw_event_unregister(struct rc_dev *dev);
>  int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
>  void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index 90f66dc7c0d7..ae7785c4fbe7 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -486,14 +486,18 @@ EXPORT_SYMBOL(ir_raw_encode_scancode);
>  /*
>   * Used to (un)register raw event clients
>   */
> -int ir_raw_event_register(struct rc_dev *dev)
> +int ir_raw_event_prepare(struct rc_dev *dev)
>  {
> -     int rc;
> -     struct ir_raw_handler *handler;
> +     static bool raw_init; /* 'false' default value, raw decoders loaded? */
>  
>       if (!dev)
>               return -EINVAL;
>  
> +     if (!raw_init) {
> +             request_module("ir-lirc-codec");
> +             raw_init = true;
> +     }
> +
>       dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
>       if (!dev->raw)
>               return -ENOMEM;
> @@ -502,6 +506,13 @@ int ir_raw_event_register(struct rc_dev *dev)
>       dev->change_protocol = change_protocol;
>       INIT_KFIFO(dev->raw->kfifo);
>  
> +     return 0;
> +}
> +
> +int ir_raw_event_register(struct rc_dev *dev)
> +{
> +     struct ir_raw_handler *handler;
> +
>       /*
>        * raw transmitters do not need any event registration
>        * because the event is coming from userspace
> @@ -510,10 +521,8 @@ int ir_raw_event_register(struct rc_dev *dev)
>               dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
>                                              "rc%u", dev->minor);
>  
> -             if (IS_ERR(dev->raw->thread)) {
> -                     rc = PTR_ERR(dev->raw->thread);
> -                     goto out;
> -             }
> +             if (IS_ERR(dev->raw->thread))
> +                     return PTR_ERR(dev->raw->thread);
>       }
>  
>       mutex_lock(&ir_raw_handler_lock);
> @@ -524,11 +533,15 @@ int ir_raw_event_register(struct rc_dev *dev)
>       mutex_unlock(&ir_raw_handler_lock);
>  
>       return 0;
> +}
> +
> +void ir_raw_event_free(struct rc_dev *dev)
> +{
> +     if (!dev)
> +             return;
>  
> -out:
>       kfree(dev->raw);
>       dev->raw = NULL;
> -     return rc;
>  }
>  
>  void ir_raw_event_unregister(struct rc_dev *dev)
> @@ -547,8 +560,7 @@ void ir_raw_event_unregister(struct rc_dev *dev)
>                       handler->raw_unregister(dev);
>       mutex_unlock(&ir_raw_handler_lock);
>  
> -     kfree(dev->raw);
> -     dev->raw = NULL;
> +     ir_raw_event_free(dev);
>  }
>  
>  /*
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index 802e559cc30e..44189366f232 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -1663,7 +1663,7 @@ struct rc_dev *devm_rc_allocate_device(struct device 
> *dev,
>  }
>  EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
>  
> -static int rc_setup_rx_device(struct rc_dev *dev)
> +static int rc_prepare_rx_device(struct rc_dev *dev)
>  {
>       int rc;
>       struct rc_map *rc_map;
> @@ -1708,10 +1708,22 @@ static int rc_setup_rx_device(struct rc_dev *dev)
>       dev->input_dev->phys = dev->input_phys;
>       dev->input_dev->name = dev->input_name;
>  
> +     return 0;
> +
> +out_table:
> +     ir_free_table(&dev->rc_map);
> +
> +     return rc;
> +}
> +
> +static int rc_setup_rx_device(struct rc_dev *dev)
> +{
> +     int rc;
> +
>       /* rc_open will be called here */
>       rc = input_register_device(dev->input_dev);
>       if (rc)
> -             goto out_table;
> +             return rc;
>  
>       /*
>        * Default delay of 250ms is too short for some protocols, especially
> @@ -1729,27 +1741,23 @@ static int rc_setup_rx_device(struct rc_dev *dev)
>       dev->input_dev->rep[REP_PERIOD] = 125;
>  
>       return 0;
> -
> -out_table:
> -     ir_free_table(&dev->rc_map);
> -
> -     return rc;
>  }
>  
>  static void rc_free_rx_device(struct rc_dev *dev)
>  {
> -     if (!dev || dev->driver_type == RC_DRIVER_IR_RAW_TX)
> +     if (!dev)
>               return;
>  
> -     ir_free_table(&dev->rc_map);
> +     if (dev->input_dev) {
> +             input_unregister_device(dev->input_dev);
> +             dev->input_dev = NULL;
> +     }
>  
> -     input_unregister_device(dev->input_dev);
> -     dev->input_dev = NULL;
> +     ir_free_table(&dev->rc_map);
>  }
>  
>  int rc_register_device(struct rc_dev *dev)
>  {
> -     static bool raw_init; /* 'false' default value, raw decoders loaded? */
>       const char *path;
>       int attr = 0;
>       int minor;
> @@ -1776,30 +1784,39 @@ int rc_register_device(struct rc_dev *dev)
>               dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
>       dev->sysfs_groups[attr++] = NULL;
>  
> +     if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
> +             rc = rc_prepare_rx_device(dev);
> +             if (rc)
> +                     goto out_minor;
> +     }
> +
> +     if (dev->driver_type == RC_DRIVER_IR_RAW ||
> +         dev->driver_type == RC_DRIVER_IR_RAW_TX) {
> +             rc = ir_raw_event_prepare(dev);
> +             if (rc < 0)
> +                     goto out_rx_free;
> +     }
> +
>       rc = device_add(&dev->dev);
>       if (rc)
> -             goto out_unlock;
> +             goto out_raw;
>  
>       path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
>       dev_info(&dev->dev, "%s as %s\n",
>               dev->input_name ?: "Unspecified device", path ?: "N/A");
>       kfree(path);
>  
> +     if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
> +             rc = rc_setup_rx_device(dev);
> +             if (rc)
> +                     goto out_dev;
> +     }
> +
>       if (dev->driver_type == RC_DRIVER_IR_RAW ||
>           dev->driver_type == RC_DRIVER_IR_RAW_TX) {
> -             if (!raw_init) {
> -                     request_module_nowait("ir-lirc-codec");
> -                     raw_init = true;
> -             }
>               rc = ir_raw_event_register(dev);
>               if (rc < 0)
> -                     goto out_dev;
> -     }
> -
> -     if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
> -             rc = rc_setup_rx_device(dev);
> -             if (rc)
> -                     goto out_raw;
> +                     goto out_rx;
>       }
>  
>       /* Allow the RC sysfs nodes to be accessible */
> @@ -1811,11 +1828,15 @@ int rc_register_device(struct rc_dev *dev)
>  
>       return 0;
>  
> -out_raw:
> -     ir_raw_event_unregister(dev);
> +out_rx:
> +     rc_free_rx_device(dev);
>  out_dev:
>       device_del(&dev->dev);
> -out_unlock:
> +out_raw:
> +     ir_raw_event_free(dev);
> +out_rx_free:
> +     ir_free_table(&dev->rc_map);
> +out_minor:
>       ida_simple_remove(&rc_ida, minor);
>       return rc;
>  }

Reply via email to