@@ -162,8 +162,8 @@ 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);
-int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map);
-void rc_keytable_del(struct rc_dev *dev);
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map);
+void rc_keytable_destroy(struct rc_keytable *kt);
/* 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);
@@ -322,7 +322,7 @@ static unsigned int ir_establish_scancode(struct rc_keytable *kt,
*/
static inline enum rc_type guess_protocol(struct rc_dev *rdev)
{
- struct rc_map *rc_map = &rdev->kt->rc_map;
+ struct rc_map *rc_map = &rdev->keytables[0]->rc_map;
if (hweight64(rdev->enabled_protocols) == 1)
return rc_bitmap_to_type(rdev->enabled_protocols);
@@ -604,40 +604,63 @@ out:
return retval;
}
-/**
- * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
- * @dev: the struct rc_dev descriptor of the device
- * @protocol: the protocol to look for
- * @scancode: the scancode to look for
- * @return: the corresponding keycode, or KEY_RESERVED
- *
- * This routine is used by drivers which need to convert a scancode to a
- * keycode. Normally it should not be used since drivers should have no
- * interest in keycodes.
- */
-u32 rc_g_keycode_from_table(struct rc_dev *dev,
- enum rc_type protocol, u64 scancode)
+static u32 rc_get_keycode(struct rc_keytable *kt,
+ enum rc_type protocol, u64 scancode)
{
- struct rc_map *rc_map = &dev->kt->rc_map;
- unsigned int keycode;
+ struct rc_map *rc_map;
+ unsigned int keycode = KEY_RESERVED;
unsigned int index;
unsigned long flags;
+ rc_map = &kt->rc_map;
+ if (!rc_map)
+ return KEY_RESERVED;
+
spin_lock_irqsave(&rc_map->lock, flags);
index = ir_lookup_by_scancode(rc_map, protocol, scancode);
- keycode = index < rc_map->len ?
- rc_map->scan[index].keycode : KEY_RESERVED;
+ if (index < rc_map->len)
+ keycode = rc_map->scan[index].keycode;
spin_unlock_irqrestore(&rc_map->lock, flags);
if (keycode != KEY_RESERVED)
IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
- dev->input_name, protocol,
+ kt->dev->input_name, protocol,
(unsigned long long)scancode, keycode);
return keycode;
}
+
+
+/**
+ * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol to look for
+ * @scancode: the scancode to look for
+ * @return: the corresponding keycode, or KEY_RESERVED
+ *
+ * This routine is used by drivers which need to convert a scancode to a
+ * keycode. It should not be used since drivers should have no
+ * interest in keycodes. (deprecated)
+ */
+u32 rc_g_keycode_from_table(struct rc_dev *dev,
+ enum rc_type protocol, u64 scancode)
+{
+ struct rc_keytable *kt;
+ unsigned int keycode = KEY_RESERVED;
+
+ /* FIXME: This entire function is a hack. Remove it */
+ rcu_read_lock();
+ kt = rcu_dereference(dev->keytables[0]);
+ if (!kt)
+ goto out;
+ keycode = rc_get_keycode(kt, protocol, scancode);
+
+out:
+ rcu_read_unlock();
+ return keycode;
+}
EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
/**
@@ -751,7 +774,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
spin_lock_irqsave(&kt->keylock, flags);
- keycode = rc_g_keycode_from_table(kt->dev, protocol, scancode);
+ keycode = rc_get_keycode(kt, protocol, scancode);
new_event = (!kt->keypressed ||
kt->last_protocol != protocol ||
kt->last_scancode != scancode ||
@@ -800,16 +823,16 @@ static void rc_input_close(struct input_dev *idev)
}
/**
- * rc_keytable_add() - adds a new keytable
+ * rc_keytable_create() - create a new keytable
* @dev: the struct rc_dev device this keytable should belong to
* @rc_map: the keymap to use for the new keytable
* @return: zero on success or a negative error code
*
- * This function add 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).
+ * 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).
*/
-int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map)
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, struct rc_map *rc_map)
{
struct rc_keytable *kt;
struct input_dev *idev = NULL;
@@ -870,31 +893,29 @@ int rc_keytable_add(struct rc_dev *dev, struct rc_map *rc_map)
*/
idev->rep[REP_PERIOD] = 125;
- dev->kt = kt;
- return 0;
+ return kt;
out:
ir_free_table(&kt->rc_map);
input_free_device(idev);
kfree(kt);
- return err;
+ return ERR_PTR(err);
}
/**
- * rc_keytable_del() - unregisters and deletes a keytable
- * @dev: the struct rc_dev device with the keytable
+ * rc_keytable_del() - unregisters and frees a keytable
+ * @kt: the struct rc_keytable to destroy
*
* This function unregisters and deletes an existing keytable.
*/
-void rc_keytable_del(struct rc_dev *dev)
+void rc_keytable_destroy(struct rc_keytable *kt)
{
- if (!dev->kt)
+ if (!kt)
return;
- del_timer_sync(&dev->kt->timer_keyup);
- ir_free_table(&dev->kt->rc_map);
- input_unregister_device(dev->kt->idev);
- kfree(dev->kt);
- dev->kt = NULL;
+ del_timer_sync(&kt->timer_keyup);
+ ir_free_table(&kt->rc_map);
+ input_unregister_device(kt->idev);
+ kfree(kt);
}
@@ -150,8 +150,14 @@ EXPORT_SYMBOL_GPL(rc_close);
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_keytable_keydown(dev->kt, protocol, scancode, toggle, autoup);
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);
@@ -166,7 +172,12 @@ EXPORT_SYMBOL_GPL(rc_do_keydown);
*/
void rc_keyup(struct rc_dev *dev)
{
- rc_keytable_keyup(dev->kt);
+ 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);
@@ -179,11 +190,60 @@ EXPORT_SYMBOL_GPL(rc_keyup);
*/
void rc_repeat(struct rc_dev *dev)
{
- rc_keytable_repeat(dev->kt);
+ 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, struct rc_map *rc_map)
+{
+ struct rc_keytable *kt;
+ unsigned i;
+
+ if (!rc_map)
+ rc_map = rc_map_get(RC_MAP_EMPTY);
+
+ if (!rc_map)
+ return -EFAULT;
+
+ 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, 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();
+ return 0;
+}
+
+static void rc_remove_keytable(struct rc_dev *dev, unsigned i)
+{
+ struct rc_keytable *kt;
+
+ if (i >= ARRAY_SIZE(dev->keytables))
+ return;
+
+ kt = dev->keytables[i];
+ rcu_assign_pointer(dev->keytables[i], NULL);
+ if (kt)
+ list_del_rcu(&kt->node);
+ synchronize_rcu();
+ rc_keytable_destroy(kt);
+}
+
/* class for /sys/class/rc */
static char *rc_devnode(struct device *dev, umode_t *mode)
{
@@ -1108,6 +1168,7 @@ struct rc_dev *rc_allocate_device(void)
INIT_LIST_HEAD(&dev->client_list);
spin_lock_init(&dev->client_lock);
+ INIT_LIST_HEAD(&dev->keytable_list);
mutex_init(&dev->txmutex);
init_waitqueue_head(&dev->txwait);
init_waitqueue_head(&dev->rxwait);
@@ -1215,7 +1276,7 @@ int rc_register_device(struct rc_dev *dev)
if (rc)
goto out_cdev;
- rc = rc_keytable_add(dev, rc_map);
+ rc = rc_add_keytable(dev, rc_map);
if (rc)
goto out_dev;
@@ -1243,6 +1304,7 @@ EXPORT_SYMBOL_GPL(rc_register_device);
void rc_unregister_device(struct rc_dev *dev)
{
struct rc_client *client;
+ unsigned i;
if (!dev)
return;
@@ -1263,7 +1325,8 @@ void rc_unregister_device(struct rc_dev *dev)
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
- rc_keytable_del(dev);
+ for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+ rc_remove_keytable(dev, i);
/* dev is marked as dead so no one changes dev->users */
if (dev->users && dev->close)
@@ -1329,3 +1392,4 @@ module_param_named(debug, rc_core_debug, int, 0644);
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
+
@@ -303,6 +303,7 @@ enum rc_filter_type {
* @get_ir_tx: allow driver to provide tx settings
* @set_ir_tx: allow driver to change tx settings
*/
+#define RC_MAX_KEYTABLES 1
struct rc_dev {
struct device dev;
struct cdev cdev;
@@ -312,7 +313,8 @@ struct rc_dev {
struct input_id input_id;
char *driver_name;
const char *map_name;
- struct rc_keytable *kt;
+ struct rc_keytable *keytables[RC_MAX_KEYTABLES];
+ struct list_head keytable_list;
struct mutex lock;
bool dead;
struct list_head client_list;
@@ -362,6 +364,7 @@ struct rc_dev {
/**
* 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
* @rc_map: holds the scancode <-> keycode mappings
@@ -375,6 +378,7 @@ struct rc_dev {
* @last_toggle: toggle of the last keypress
*/
struct rc_keytable {
+ struct list_head node;
struct rc_dev *dev;
struct input_dev *idev;
struct rc_map rc_map;
This is another step towards allowing multiple keytables per rc_dev. struct rc_dev is changed to hold an array of keytables (used later for indexed access to keytables) as well as a list of the same keytables (used for iteration in fast paths). Signed-off-by: David Härdeman <david@hardeman.nu> --- drivers/media/rc/rc-core-priv.h | 4 +- drivers/media/rc/rc-keytable.c | 95 ++++++++++++++++++++++++--------------- drivers/media/rc/rc-main.c | 74 ++++++++++++++++++++++++++++-- include/media/rc-core.h | 6 ++ 4 files changed, 134 insertions(+), 45 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html