Move some more keytable related functionality over to rc-keytable.c which allows more implementational details to be obscured away.
Signed-off-by: David Härdeman <da...@hardeman.nu> --- drivers/media/rc/rc-core-priv.h | 11 +- drivers/media/rc/rc-keytable.c | 213 +++++++++++++++++++++++++++++++++------ drivers/media/rc/rc-main.c | 132 +----------------------- include/media/rc-core.h | 44 -------- 4 files changed, 193 insertions(+), 207 deletions(-) diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 376030e..3f056e3 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -156,13 +156,10 @@ void ir_raw_init(void); /* * Methods from rc-keytable.c to be used internally */ -void rc_keytable_keyup(struct rc_keytable *kt); -void rc_keytable_repeat(struct rc_keytable *kt); -void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol, - u64 scancode, u8 toggle, bool autokeyup); -struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, - const char *map_name); -void rc_keytable_destroy(struct rc_keytable *kt); +int rc_keytable_add(struct rc_dev *dev, const char *name, const char *map_name); +int rc_keytable_remove(struct rc_dev *dev, unsigned i); +int rc_keytable_get_name(struct rc_dev *dev, unsigned i, + char *buf, size_t bufsize); /* Only to be used by rc-core and ir-lirc-codec */ void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx); diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c index d0777cb..027a703 100644 --- a/drivers/media/rc/rc-keytable.c +++ b/drivers/media/rc/rc-keytable.c @@ -29,6 +29,50 @@ /* FIXME: RC_KEYPRESS_TIMEOUT should be protocol specific */ #define RC_KEYPRESS_TIMEOUT 250 +/** + * struct rc_scan - rcu-friendly scancode<->keycode table + * @len: number of elements in the table array + * @table: array of struct rc_map_table elements + */ +struct rc_scan { + unsigned len; + struct rc_map_table table[]; +}; + +/** + * struct rc_keytable - represents one keytable for a rc_dev device + * @node: used to iterate over all keytables for a rc_dev device + * @dev: the rc_dev device this keytable belongs to + * @idev: the input_dev device which belongs to this keytable + * @name: the user-friendly name of this keytable + * @scan_mutex: protects @scan against concurrent writers + * @scan: the current scancode<->keycode table + * @key_lock: protects the key state + * @key_pressed: whether a key is currently pressed or not + * @last_keycode: keycode of the last keypress + * @last_protocol: protocol of the last keypress + * @last_scancode: scancode of the last keypress + * @last_toggle: toggle of the last keypress + * @timer_keyup: responsible for the auto-release of keys + * @keyup_jiffies: when the key should be auto-released + */ +struct rc_keytable { + struct list_head node; + struct rc_dev *dev; + struct input_dev *idev; + char name[RC_KEYTABLE_NAME_SIZE]; + struct mutex scan_mutex; + struct rc_scan __rcu *scan; + spinlock_t key_lock; + bool key_pressed; + u32 last_keycode; + enum rc_type last_protocol; + u64 last_scancode; + u8 last_toggle; + struct timer_list timer_keyup; + unsigned long keyup_jiffies; +}; + /* Used to keep track of known keymaps */ static LIST_HEAD(rc_map_list); static DEFINE_SPINLOCK(rc_map_lock); @@ -557,19 +601,26 @@ static void rc_do_keyup(struct rc_keytable *kt, bool sync) /** * rc_keyup() - signals the release of a keypress - * @kt: the struct rc_keytable descriptor of the keytable + * @dev: the struct rc_dev descriptor of the device * * This routine is used to signal that a key has been released on the * remote control. */ -void rc_keytable_keyup(struct rc_keytable *kt) +void rc_keyup(struct rc_dev *dev) { + struct rc_keytable *kt; unsigned long flags; - spin_lock_irqsave(&kt->key_lock, flags); - rc_do_keyup(kt, true); - spin_unlock_irqrestore(&kt->key_lock, flags); + rcu_read_lock(); + list_for_each_entry_rcu(kt, &dev->keytable_list, node) { + spin_lock_irqsave(&kt->key_lock, flags); + rc_do_keyup(kt, true); + spin_unlock_irqrestore(&kt->key_lock, flags); + } + rcu_read_unlock(); } +EXPORT_SYMBOL_GPL(rc_keyup); + /** * rc_timer_keyup() - generates a keyup event after a timeout @@ -601,22 +652,32 @@ static void rc_timer_keyup(unsigned long cookie) /** * rc_repeat() - signals that a key is still pressed - * @kt: the struct rc_keytable descriptor of the keytable + * @dev: the struct rc_dev descriptor of the device * - * This routine is used when a repeat message which does not include the - * necessary bits to reproduce the scancode has been received. + * This routine is used by when a repeat message which does + * not include the necessary bits to reproduce the scancode has been + * received. */ -void rc_keytable_repeat(struct rc_keytable *kt) +void rc_repeat(struct rc_dev *dev) { + struct rc_keytable *kt; unsigned long flags; - spin_lock_irqsave(&kt->key_lock, flags); - if (kt->key_pressed) { - kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT); - mod_timer(&kt->timer_keyup, kt->keyup_jiffies); + rcu_read_lock(); + list_for_each_entry_rcu(kt, &dev->keytable_list, node) { + spin_lock_irqsave(&kt->key_lock, flags); + if (kt->key_pressed) { + kt->keyup_jiffies = jiffies + + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT); + mod_timer(&kt->timer_keyup, kt->keyup_jiffies); + } + spin_unlock_irqrestore(&kt->key_lock, flags); } - spin_unlock_irqrestore(&kt->key_lock, flags); + rcu_read_unlock(); + + rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1); } +EXPORT_SYMBOL_GPL(rc_repeat); /** * rc_keytable_keydown() - generates input event for a key press @@ -629,8 +690,8 @@ void rc_keytable_repeat(struct rc_keytable *kt) * * This routine is used to signal that a keypress has been detected. */ -void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol, - u64 scancode, u8 toggle, bool autoup) +static void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol, + u64 scancode, u8 toggle, bool autoup) { struct rc_scan *scan; unsigned index; @@ -677,6 +738,35 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol, } /** + * rc_do_keydown() - generates input event for a key press + * @dev: the struct rc_dev descriptor of the device + * @protocol: the protocol for the keypress + * @scancode: the scancode for the keypress + * @toggle: the toggle value (protocol dependent, if the protocol doesn't + * support toggle values, this should be set to zero) + * @autoup: should an automatic keyup event be generated in the future + * + * This routine is used to signal that a key has been pressed on the + * remote control. + */ +void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, + u64 scancode, u8 toggle, bool autoup) +{ + struct rc_keytable *kt; + + rcu_read_lock(); + list_for_each_entry_rcu(kt, &dev->keytable_list, node) + rc_keytable_keydown(kt, protocol, scancode, toggle, autoup); + rcu_read_unlock(); + + rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol); + rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode); + rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle); +} +EXPORT_SYMBOL_GPL(rc_do_keydown); + + +/** * rc_input_open() - called on the initial use of the input device * @idev: the struct input_dev corresponding to the given keytable * @return: zero on success, otherwise a negative error code @@ -755,31 +845,67 @@ static int rc_keytable_init(struct rc_keytable *kt, } /** - * rc_keytable_create() - creates a new keytable + * rc_keytable_get_name() - get the name of a keytable + * @dev: + * @dev: the struct rc_dev device the keytable belongs to + * @i: the index of the keytable + * @buf: the buffer to write the name to + * @bufsize: the size of the buffer + * @return: zero on success or negative error code + * + * This function is used to get the userfriendly name of a keytable. + */ +int rc_keytable_get_name(struct rc_dev *dev, unsigned i, + char *buf, size_t bufsize) +{ + struct rc_keytable *kt; + + rcu_read_lock(); + kt = rcu_dereference(dev->keytables[i]); + if (kt) { + buf[0] = '\0'; + strncat(buf, kt->name, bufsize); + } + rcu_read_unlock(); + + return kt ? 0 : -EINVAL; +} + + +/** + * rc_keytable_add() - creates a new keytable * @dev: the struct rc_dev device this keytable should belong to * @name: the userfriendly name of this keymap * @map_name: the name of the keymap to autoload - * @return: a new struct rc_keytable pointer or NULL on error + * @return: the index of the new rc_keytable or a negative error number * * This function creates a new keytable (essentially the combination of a * keytable and an input device along with some state (whether a key * is currently pressed or not, etc). */ -struct rc_keytable *rc_keytable_create(struct rc_dev *dev, - const char *name, - const char *map_name) +int rc_keytable_add(struct rc_dev *dev, const char *name, const char *map_name) { struct rc_keytable *kt; + unsigned i; struct input_dev *idev = NULL; int error; + for (i = 0; i < ARRAY_SIZE(dev->keytables); i++) + if (!dev->keytables[i]) + break; + + if (i >= ARRAY_SIZE(dev->keytables)) + return -ENFILE; + kt = kzalloc(sizeof(*kt), GFP_KERNEL); if (!kt) - return NULL; + return -ENOMEM; idev = input_allocate_device(); - if (!idev) - goto out; + if (!idev) { + error = -ENOMEM; + goto out_kt; + } kt->idev = idev; kt->dev = dev; @@ -795,7 +921,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, error = rc_keytable_init(kt, rc_map_get(map_name)); if (error) - goto out; + goto out_idev; idev->dev.parent = &dev->dev; memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id)); @@ -822,26 +948,49 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, spin_lock_init(&kt->key_lock); mutex_init(&kt->scan_mutex); - return kt; + + rcu_assign_pointer(dev->keytables[i], kt); + list_add_rcu(&kt->node, &dev->keytable_list); + synchronize_rcu(); + rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i); + + return i; out_table: kfree(kt->scan); -out: +out_idev: input_free_device(idev); +out_kt: kfree(kt); - return NULL; + return error; } /** - * rc_keytable_destroy() - destroys a keytable - * @dev: the struct rc_keytable to destroy + * rc_keytable_remove() - removes a keytable + * @dev: the struct rc_dev device the keytable belongs to + * @i: the index of the keytable + * @return: zero on success or negative error number * - * This function destroys an existing keytable. + * This function removes an existing keytable. */ -void rc_keytable_destroy(struct rc_keytable *kt) +int rc_keytable_remove(struct rc_dev *dev, unsigned i) { + struct rc_keytable *kt; + + kt = dev->keytables[i]; + rcu_assign_pointer(dev->keytables[i], NULL); + if (kt) + list_del_rcu(&kt->node); + synchronize_rcu(); + + if (!kt) + return -EINVAL; + + rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i); del_timer_sync(&kt->timer_keyup); input_unregister_device(kt->idev); kfree(kt->scan); kfree(kt); + + return 0; } diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b16dbf4..e2aa7b1 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -101,73 +101,6 @@ void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val) } EXPORT_SYMBOL_GPL(rc_event); -/** - * rc_keyup() - signals the release of a keypress - * @dev: the struct rc_dev descriptor of the device - * - * This routine is used to signal that a key has been released on the - * remote control. - */ -void rc_keyup(struct rc_dev *dev) -{ - struct rc_keytable *kt; - - rcu_read_lock(); - list_for_each_entry_rcu(kt, &dev->keytable_list, node) - rc_keytable_keyup(kt); - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(rc_keyup); - -/** - * rc_repeat() - signals that a key is still pressed - * @dev: the struct rc_dev descriptor of the device - * - * This routine is used by IR decoders when a repeat message which does - * not include the necessary bits to reproduce the scancode has been - * received. - */ -void rc_repeat(struct rc_dev *dev) -{ - struct rc_keytable *kt; - - rcu_read_lock(); - list_for_each_entry_rcu(kt, &dev->keytable_list, node) - rc_keytable_repeat(kt); - rcu_read_unlock(); - - rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1); -} -EXPORT_SYMBOL_GPL(rc_repeat); - -/** - * rc_do_keydown() - generates input event for a key press - * @dev: the struct rc_dev descriptor of the device - * @protocol: the protocol for the keypress - * @scancode: the scancode for the keypress - * @toggle: the toggle value (protocol dependent, if the protocol doesn't - * support toggle values, this should be set to zero) - * @autoup: should an automatic keyup event be generated in the future - * - * This routine is used to signal that a key has been pressed on the - * remote control. - */ -void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, - u64 scancode, u8 toggle, bool autoup) -{ - struct rc_keytable *kt; - - rcu_read_lock(); - list_for_each_entry_rcu(kt, &dev->keytable_list, node) - rc_keytable_keydown(kt, protocol, scancode, toggle, autoup); - rcu_read_unlock(); - - rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol); - rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode); - rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle); -} -EXPORT_SYMBOL_GPL(rc_do_keydown); - /* class for /sys/class/rc */ static char *rc_devnode(struct device *dev, umode_t *mode) { @@ -493,48 +426,6 @@ void rc_free_device(struct rc_dev *dev) } EXPORT_SYMBOL_GPL(rc_free_device); -static int rc_add_keytable(struct rc_dev *dev, const char *name, - const char *map_name) -{ - struct rc_keytable *kt; - unsigned i; - - for (i = 0; i < ARRAY_SIZE(dev->keytables); i++) - if (!dev->keytables[i]) - break; - - if (i >= ARRAY_SIZE(dev->keytables)) - return -ENFILE; - - kt = rc_keytable_create(dev, name, map_name); - if (!kt) - return -ENOMEM; - - rcu_assign_pointer(dev->keytables[i], kt); - list_add_rcu(&kt->node, &dev->keytable_list); - synchronize_rcu(); - rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i); - return 0; -} - -static int rc_remove_keytable(struct rc_dev *dev, unsigned i) -{ - struct rc_keytable *kt; - - kt = dev->keytables[i]; - rcu_assign_pointer(dev->keytables[i], NULL); - if (kt) - list_del_rcu(&kt->node); - synchronize_rcu(); - - if (!kt) - return -EINVAL; - - rc_keytable_destroy(kt); - rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i); - return 0; -} - static u64 rc_get_allowed_protocols(struct rc_dev *dev) { return dev ? dev->allowed_protos : 0x0; @@ -590,7 +481,7 @@ int rc_register_device(struct rc_dev *dev) if (rc) goto out_chardev; - rc = rc_add_keytable(dev, dev->map_name, dev->map_name); + rc = rc_keytable_add(dev, dev->map_name, dev->map_name); if (rc < 0) goto out_device; @@ -628,7 +519,7 @@ void rc_unregister_device(struct rc_dev *dev) mutex_lock(&dev->mutex); dev->exist = false; for (i = 0; i < ARRAY_SIZE(dev->keytables); i++) - rc_remove_keytable(dev, i); + rc_keytable_remove(dev, i); mutex_unlock(&dev->mutex); mutex_lock(&rc_dev_table_mutex); @@ -923,7 +814,6 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg) struct rc_ir_rx rx; struct rc_ir_tx tx; struct rc_keytable_ioctl ktio; - struct rc_keytable *kt; int error; switch (cmd) { @@ -1000,7 +890,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg) if (strlen(ktio.name) < 1) return -EINVAL; - error = rc_add_keytable(dev, ktio.name, NULL); + error = rc_keytable_add(dev, ktio.name, NULL); if (error < 0) return error; ktio.id = error; @@ -1020,16 +910,10 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg) if (ktio.flags) return -EINVAL; - rcu_read_lock(); - kt = rcu_dereference(dev->keytables[ktio.id]); - if (kt) { - ktio.name[0] = '\0'; - strncat(ktio.name, kt->name, sizeof(ktio.name)); - } - rcu_read_unlock(); - - if (!kt) - return -EINVAL; + error = rc_keytable_get_name(dev, ktio.id, + ktio.name, sizeof(ktio.name)); + if (error) + return error; if (copy_to_user(p, &ktio, sizeof(ktio))) return -EFAULT; @@ -1046,7 +930,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg) if (ktio.flags) return -EINVAL; - return rc_remove_keytable(dev, ktio.id); + return rc_keytable_remove(dev, ktio.id); } return -EINVAL; } diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 056275a..e311242 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -351,50 +351,6 @@ struct rc_dev { int (*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx); }; -/** - * struct rc_scan - rcu-friendly scancode<->keycode table - * @len: number of elements in the table array - * @table: array of struct rc_map_table elements - */ -struct rc_scan { - unsigned len; - struct rc_map_table table[]; -}; - -/** - * struct rc_keytable - represents one keytable for a rc_dev device - * @node: used to iterate over all keytables for a rc_dev device - * @dev: the rc_dev device this keytable belongs to - * @idev: the input_dev device which belongs to this keytable - * @name: the user-friendly name of this keytable - * @scan_mutex: protects @scan against concurrent writers - * @scan: the current scancode<->keycode table - * @key_lock: protects the key state - * @key_pressed: whether a key is currently pressed or not - * @last_keycode: keycode of the last keypress - * @last_protocol: protocol of the last keypress - * @last_scancode: scancode of the last keypress - * @last_toggle: toggle of the last keypress - * @timer_keyup: responsible for the auto-release of keys - * @keyup_jiffies: when the key should be auto-released - */ -struct rc_keytable { - struct list_head node; - struct rc_dev *dev; - struct input_dev *idev; - char name[RC_KEYTABLE_NAME_SIZE]; - struct mutex scan_mutex; - struct rc_scan __rcu *scan; - spinlock_t key_lock; - bool key_pressed; - u32 last_keycode; - enum rc_type last_protocol; - u64 last_scancode; - u8 last_toggle; - struct timer_list timer_keyup; - unsigned long keyup_jiffies; -}; - #define to_rc_dev(d) container_of(d, struct rc_dev, dev) /* -- 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