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 <david@xxxxxxxxxxx> --- drivers/media/rc/rc-core-priv.h | 54 +++++++++++- drivers/media/rc/rc-keytable.c | 169 +++++++++++++++++++++++++++++++-------- drivers/media/rc/rc-main.c | 136 ++----------------------------- include/media/rc-core.h | 44 ---------- 4 files changed, 191 insertions(+), 212 deletions(-) diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 4945727..1c6c066 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -168,12 +168,54 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); /* * 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, - u32 scancode, u8 toggle, bool autokeyup); -struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, struct rc_map *rc_map); -void rc_keytable_destroy(struct rc_keytable *kt); +int rc_keytable_add(struct rc_dev *dev, const char *name, struct rc_map *rc_map); +int rc_keytable_del(struct rc_dev *dev, unsigned i); +int rc_keytable_get_name(struct rc_dev *dev, unsigned i, + char *buf, size_t bufsize); + +/** + * 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; + u32 last_scancode; + u8 last_toggle; + struct timer_list timer_keyup; + unsigned long keyup_jiffies; +}; /* 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 23a66c7..1dd75e2 100644 --- a/drivers/media/rc/rc-keytable.c +++ b/drivers/media/rc/rc-keytable.c @@ -591,19 +591,25 @@ static void rc_do_keyup(struct rc_keytable *kt, bool sync) } /** - * rc_keytable_keyup() - signals the release of a keypress - * @kt: the keytable + * rc_keyup() - signals the release of a keypress + * @dev: the struct rc_dev descriptor of the device * - * This routine is used to generate input keyup events. + * Report that a key is no longer pressed. */ -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 @@ -634,23 +640,31 @@ static void rc_timer_keyup(unsigned long cookie) } /** - * rc_keytable_repeat() - signals that a key is still pressed - * @kt: the keytable + * rc_repeat() - signals that a key is still pressed + * @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. */ -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 @@ -663,8 +677,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, - u32 scancode, u8 toggle, bool autoup) +static void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol, + u32 scancode, u8 toggle, bool autoup) { struct rc_scan *scan; unsigned index; @@ -711,6 +725,34 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol, spin_unlock_irqrestore(&kt->key_lock, flags); } +/** + * rc_do_keydown() - report a key press event + * @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: whether to automatically generate a keyup event later + * + * Report that a keypress has been received. + */ +void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, + u32 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(); + + led_trigger_event(led_feedback, LED_FULL); + 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); + static int rc_input_open(struct input_dev *idev) { struct rc_keytable *kt = input_get_drvdata(idev); @@ -762,33 +804,65 @@ static int rc_keytable_init(struct rc_keytable *kt, } /** - * rc_keytable_create() - create 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() - create a new keytable * @dev: the struct rc_dev device this keytable should belong to * @name: the userfriendly name of this keymap - * @rc_map: the keymap to use for the new keytable - * @return: zero on success or a negative error code + * @rc_map: the keymap to use for the new keytable (if any) + * @return: the index of the new rc_keytable or a negative error code * * 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, - struct rc_map *rc_map) +int rc_keytable_add(struct rc_dev *dev, const char *name, struct rc_map *rc_map) { struct rc_keytable *kt; + unsigned i; struct input_dev *idev = NULL; int err; + 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) { - err = -ENOMEM; - goto out; - } + if (!kt) + return -ENOMEM; idev = input_allocate_device(); if (!idev) { err = -ENOMEM; - goto out; + goto out_kt; } kt->idev = idev; @@ -807,7 +881,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, err = rc_keytable_init(kt, rc_map); if (err) - goto out; + goto out_idev; idev->dev.parent = &dev->dev; memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id)); @@ -816,7 +890,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, err = input_register_device(idev); if (err) - goto out; + goto out_scan; /* * Default delay of 250ms is too short for some protocols, especially @@ -833,29 +907,52 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name, */ idev->rep[REP_PERIOD] = 125; - 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); -out: - input_free_device(idev); + return i; + +out_scan: kfree(kt->scan); +out_idev: + input_free_device(idev); +out_kt: kfree(kt); - return ERR_PTR(err); + return err; } /** * rc_keytable_del() - unregisters and frees a keytable - * @kt: the struct rc_keytable to destroy + * @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 unregisters and deletes an existing keytable. */ -void rc_keytable_destroy(struct rc_keytable *kt) +int rc_keytable_del(struct rc_dev *dev, unsigned i) { + struct rc_keytable *kt; + + if (i >= ARRAY_SIZE(dev->keytables)) + return -EINVAL; + + kt = dev->keytables[i]; + rcu_assign_pointer(dev->keytables[i], NULL); + if (kt) + list_del_rcu(&kt->node); + synchronize_rcu(); + if (!kt) - return; + 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 b3db1dd..12f61ae 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -136,116 +136,6 @@ void rc_close(struct rc_dev *dev) } EXPORT_SYMBOL_GPL(rc_close); -/** - * rc_do_keydown() - report a key press event - * @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: whether to automatically generate a keyup event later - * - * Report that a keypress has been received. - */ -void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, - u32 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(); - - led_trigger_event(led_feedback, LED_FULL); - 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_keyup() - signals the release of a keypress - * @dev: the struct rc_dev descriptor of the device - * - * Report that a key is no longer pressed. - */ -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() - report that a key is still pressed - * @dev: the struct rc_dev descriptor of the device - * - * Report that 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); - -static int rc_add_keytable(struct rc_dev *dev, const char *name, - struct rc_map *rc_map) -{ - 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, rc_map); - if (IS_ERR(kt)) - return PTR_ERR(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 0; -} - -static int rc_remove_keytable(struct rc_dev *dev, unsigned i) -{ - struct rc_keytable *kt; - - if (i >= ARRAY_SIZE(dev->keytables)) - return -EINVAL; - - 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; -} - /* class for /sys/class/rc */ static char *rc_devnode(struct device *dev, umode_t *mode) { @@ -943,7 +833,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) { @@ -1020,7 +909,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; @@ -1040,16 +929,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; @@ -1066,7 +949,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_del(dev, ktio.id); } return -EINVAL; } @@ -1295,6 +1178,7 @@ int rc_register_device(struct rc_dev *dev) if (dev->map_name) rc_map = rc_map_get(dev->map_name); + /* FIXME: kind of a hack...the driver should probably do this */ if (dev->change_protocol && rc_map && rc_map->len > 0) { u64 rc_type = (1 << rc_map->scan[0].protocol); rc = dev->change_protocol(dev, &rc_type); @@ -1311,8 +1195,8 @@ int rc_register_device(struct rc_dev *dev) if (rc) goto out_cdev; - rc = rc_add_keytable(dev, dev->map_name, rc_map); - if (rc) + rc = rc_keytable_add(dev, dev->map_name, rc_map); + if (rc < 0) goto out_dev; IR_dprintk(1, "Registered %s (driver: %s, remote: %s, mode %s)\n", @@ -1355,7 +1239,7 @@ void rc_unregister_device(struct rc_dev *dev) cdev_del(&dev->cdev); for (i = 0; i < ARRAY_SIZE(dev->keytables); i++) - rc_remove_keytable(dev, i); + rc_keytable_del(dev, i); /* dev is marked as dead so no one changes dev->users */ if (dev->users && dev->close) diff --git a/include/media/rc-core.h b/include/media/rc-core.h index a7354b7..aff3bdd 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -383,50 +383,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; - u32 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html