From patchwork Fri Nov 27 01:34:25 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jon Smirl X-Patchwork-Id: 63245 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nAR1a3AR015170 for ; Fri, 27 Nov 2009 01:36:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753258AbZK0Be4 (ORCPT ); Thu, 26 Nov 2009 20:34:56 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753010AbZK0Be4 (ORCPT ); Thu, 26 Nov 2009 20:34:56 -0500 Received: from qw-out-2122.google.com ([74.125.92.26]:18051 "EHLO qw-out-2122.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751407AbZK0BeW (ORCPT ); Thu, 26 Nov 2009 20:34:22 -0500 Received: by qw-out-2122.google.com with SMTP id 3so223200qwe.37 for ; Thu, 26 Nov 2009 17:34:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:received:subject:to:from:date :message-id:in-reply-to:references:user-agent:mime-version :content-type:content-transfer-encoding; bh=zYkMwwj5tGM3gGpQ2kvwbwHAXhVb2EZ/uGsfTOU/ZQQ=; b=VNR6KPJSeURsgyGNFW8TYbxlEy8PTOcyCKXtsT5/68en+LI5FGE7lARGrMezCHjx6X 2y+rrc81k2Ze0kFF0WsxgmMr34GZZihxssAadgvkjO3Q8yLPebEsCSrIBDT8hNolSpS7 2gI79xvZIMCBX0fftFkITRaoGT1ubRpFjpads= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=subject:to:from:date:message-id:in-reply-to:references:user-agent :mime-version:content-type:content-transfer-encoding; b=VlJTzv4hD/Yie0m4Vp2lU2QKyL9n2IhAZW+njWpoAQtQkSvJX9BAHU7j7CP3mL8F1Y RmlwxuTH0ZXtTGzmvg8Yzprskc4xpbPmndVdjzBVH6+uM3gKMAFUW0x4BF1DlwMt4RJZ mlJ38qiGRz2USjwkonp1ZpbJJJ4lh4uw/OZMw= Received: by 10.224.78.207 with SMTP id m15mr222337qak.3.1259285667613; Thu, 26 Nov 2009 17:34:27 -0800 (PST) Received: from terra (c-65-96-16-179.hsd1.ma.comcast.net [65.96.16.179]) by mx.google.com with ESMTPS id 2sm3404154qwi.27.2009.11.26.17.34.26 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 26 Nov 2009 17:34:26 -0800 (PST) Received: from localhost ([127.0.0.1] helo=[127.0.1.1]) by terra with esmtp (Exim 4.69) (envelope-from ) id 1NDpj7-00021P-JX; Thu, 26 Nov 2009 20:34:25 -0500 Subject: [IR-RFC PATCH v4 3/6] Configfs support for IR To: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org From: Jon Smirl Date: Thu, 26 Nov 2009 20:34:25 -0500 Message-ID: <20091127013425.7671.82158.stgit@terra> In-Reply-To: <20091127013217.7671.32355.stgit@terra> References: <20091127013217.7671.32355.stgit@terra> User-Agent: StGit/0.15 MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org diff --git a/drivers/input/ir/Makefile b/drivers/input/ir/Makefile index 6acb665..2ccdda3 100644 --- a/drivers/input/ir/Makefile +++ b/drivers/input/ir/Makefile @@ -4,5 +4,5 @@ # Each configuration option enables a list of files. obj-$(CONFIG_INPUT_IR) += ir.o -ir-objs := ir-core.o +ir-objs := ir-core.o ir-configfs.o diff --git a/drivers/input/ir/ir-configfs.c b/drivers/input/ir/ir-configfs.c new file mode 100644 index 0000000..e0819bb --- /dev/null +++ b/drivers/input/ir/ir-configfs.c @@ -0,0 +1,348 @@ +/* + * Configfs routines for IR support + * + * configfs root + * --remotes + * ----specific remote + * ------keymap + * --------protocol + * --------device + * --------command + * --------keycode + * ------repeat keymaps + * --------.... + * ----another remote + * ------more keymaps + * --------.... + * + * Copyright (C) 2008 Jon Smirl + */ + +#include +#include +#include + +#include "ir.h" + +struct keymap { + struct config_item item; + int protocol; + int device; + int command; + int keycode; +}; + +static inline struct keymap *to_keymap(struct config_item *item) +{ + return item ? container_of(item, struct keymap, item) : NULL; +} + +struct remote { + struct config_group group; + struct input_dev *input; +}; + +static inline struct remote *to_remote(struct config_group *group) +{ + return group ? container_of(group, struct remote, group) : NULL; +} + + +static struct configfs_attribute item_protocol = { + .ca_owner = THIS_MODULE, + .ca_name = "protocol", + .ca_mode = S_IRUGO | S_IWUSR, +}; + +static struct configfs_attribute item_device = { + .ca_owner = THIS_MODULE, + .ca_name = "device", + .ca_mode = S_IRUGO | S_IWUSR, +}; + +static struct configfs_attribute item_command = { + .ca_owner = THIS_MODULE, + .ca_name = "command", + .ca_mode = S_IRUGO | S_IWUSR, +}; + +static struct configfs_attribute item_keycode = { + .ca_owner = THIS_MODULE, + .ca_name = "keycode", + .ca_mode = S_IRUGO | S_IWUSR, +}; + +static ssize_t item_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + struct keymap *keymap = to_keymap(item); + + if (attr == &item_protocol) + return sprintf(page, "%d\n", keymap->protocol); + if (attr == &item_device) + return sprintf(page, "%d\n", keymap->device); + if (attr == &item_command) + return sprintf(page, "%d\n", keymap->command); + return sprintf(page, "%d\n", keymap->keycode); +} + +static ssize_t item_store(struct config_item *item, + struct configfs_attribute *attr, + const char *page, size_t count) +{ + struct keymap *keymap = to_keymap(item); + struct remote *remote; + unsigned long tmp; + char *p = (char *) page; + + tmp = simple_strtoul(p, &p, 10); + if (!p || (*p && (*p != '\n'))) + return -EINVAL; + + if (tmp > INT_MAX) + return -ERANGE; + + if (attr == &item_protocol) + keymap->protocol = tmp; + else if (attr == &item_device) + keymap->device = tmp; + else if (attr == &item_command) + keymap->command = tmp; + else { + if (tmp < KEY_MAX) { + remote = to_remote(to_config_group(item->ci_parent)); + set_bit(tmp, remote->input->keybit); + keymap->keycode = tmp; + } + } + return count; +} + +static void keymap_release(struct config_item *item) +{ + struct keymap *keymap = to_keymap(item); + struct remote *remote = to_remote(to_config_group(item->ci_parent)); + + printk("keymap release\n"); + clear_bit(keymap->keycode, remote->input->keybit); + kfree(keymap); +} + +static struct configfs_item_operations keymap_ops = { + .release = keymap_release, + .show_attribute = item_show, + .store_attribute = item_store, +}; + +/* Start the definition of the all of the attributes + * in a single keymap directory + */ +static struct configfs_attribute *keymap_attrs[] = { + &item_protocol, + &item_device, + &item_command, + &item_keycode, + NULL, +}; + +static struct config_item_type keymap_type = { + .ct_item_ops = &keymap_ops, + .ct_attrs = keymap_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_item *make_keymap(struct config_group *group, const char *name) +{ + struct keymap *keymap; + + keymap = kzalloc(sizeof(*keymap), GFP_KERNEL); + if (!keymap) + return ERR_PTR(-ENOMEM); + + config_item_init_type_name(&keymap->item, name, &keymap_type); + return &keymap->item; +} + +/* + * Note that, since no extra work is required on ->drop_item(), + * no ->drop_item() is provided. + */ +static struct configfs_group_operations remote_group_ops = { + .make_item = make_keymap, +}; + +static ssize_t remote_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + struct config_group *group = to_config_group(item); + struct remote *remote = to_remote(group); + const char *path; + + if (strcmp(attr->ca_name, "path") == 0) { + path = kobject_get_path(&remote->input->dev.kobj, GFP_KERNEL); + strcpy(page, path); + kfree(path); + return strlen(page); + } + return sprintf(page, +"Map for a specific remote\n" +"Remote signals matching this map will be translated into keyboard/mouse events\n"); +} + +static void remote_release(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + struct remote *remote = to_remote(group); + + printk("remote_release\n"); + input_free_device(remote->input); + kfree(remote); +} + +static struct configfs_item_operations remote_item_ops = { + .release = remote_release, + .show_attribute = remote_show, +}; + +static struct configfs_attribute remote_attr_description = { + .ca_owner = THIS_MODULE, + .ca_name = "description", + .ca_mode = S_IRUGO, +}; + +static struct configfs_attribute remote_attr_path = { + .ca_owner = THIS_MODULE, + .ca_name = "path", + .ca_mode = S_IRUGO, +}; + +static struct configfs_attribute *remote_attrs[] = { + &remote_attr_description, + &remote_attr_path, + NULL, +}; + +static struct config_item_type remote_type = { + .ct_item_ops = &remote_item_ops, + .ct_group_ops = &remote_group_ops, + .ct_attrs = remote_attrs, + .ct_owner = THIS_MODULE, +}; + +/* Top level remotes directory for all remotes */ + +/* Create a new remote group */ +static struct config_group *make_remote(struct config_group *parent, const char *name) +{ + struct remote *remote; + int ret; + + remote = kzalloc(sizeof(*remote), GFP_KERNEL); + if (!remote) + return ERR_PTR(-ENOMEM); + + remote->input = input_allocate_device(); + if (!remote->input) { + ret = -ENOMEM; + goto free_mem; + } + remote->input->id.bustype = BUS_VIRTUAL; + remote->input->name = name; + remote->input->phys = "remotes"; + + remote->input->evbit[0] = BIT_MASK(EV_KEY); + + ret = input_register_device(remote->input); + if (ret) + goto free_input; + + config_group_init_type_name(&remote->group, name, &remote_type); + return &remote->group; + + free_input: + input_free_device(remote->input); + free_mem: + kfree(remote); + return ERR_PTR(ret); +} + +static ssize_t remotes_show_description(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + return sprintf(page, +"This subsystem allows the creation of IR remote control maps.\n" +"Maps allow IR signals to be mapped into key strokes or mouse events.\n"); +} + +static struct configfs_item_operations remotes_item_ops = { + .show_attribute = remotes_show_description, +}; + +static struct configfs_attribute remotes_attr_description = { + .ca_owner = THIS_MODULE, + .ca_name = "description", + .ca_mode = S_IRUGO, +}; + +static struct configfs_attribute *remotes_attrs[] = { + &remotes_attr_description, + NULL, +}; + +/* + * Note that, since no extra work is required on ->drop_item(), + * no ->drop_item() is provided. + */ +static struct configfs_group_operations remotes_group_ops = { + .make_group = make_remote, +}; + +static struct config_item_type remotes_type = { + .ct_item_ops = &remotes_item_ops, + .ct_group_ops = &remotes_group_ops, + .ct_attrs = remotes_attrs, + .ct_owner = THIS_MODULE, +}; + +struct configfs_subsystem input_ir_remotes = { + .su_group = { + .cg_item = { + .ci_namebuf = "remotes", + .ci_type = &remotes_type, + }, + }, +}; + +void input_ir_translate(struct input_dev *dev, int protocol, int device, int command) +{ + struct config_item *i, *j; + struct config_group *g; + struct remote *remote; + struct keymap *keymap; + + /* generate the IR format event */ + input_report_ir(dev, IR_PROTOCOL, protocol); + input_report_ir(dev, IR_DEVICE, device); + input_report_ir(dev, IR_COMMAND, command); + input_sync(dev); + + mutex_lock(&input_ir_remotes.su_mutex); + + /* search the translation maps to translate into key stroke */ + list_for_each_entry(i, &input_ir_remotes.su_group.cg_children, ci_entry) { + g = to_config_group(i); + list_for_each_entry(j, &g->cg_children, ci_entry) { + keymap = to_keymap(j); + if ((keymap->protocol == protocol) && (keymap->device == device) + && (keymap->command == command)) { + remote = to_remote(g); + input_report_key(remote->input, keymap->keycode, 1); + input_sync(remote->input); + } + } + } + mutex_unlock(&input_ir_remotes.su_mutex); +} diff --git a/drivers/input/ir/ir-core.c b/drivers/input/ir/ir-core.c index 85adfcb..9c81bac 100644 --- a/drivers/input/ir/ir-core.c +++ b/drivers/input/ir/ir-core.c @@ -10,15 +10,6 @@ #include "ir.h" -void input_ir_translate(struct input_dev *dev, int protocol, int device, int command) -{ - /* generate the IR format event */ - input_report_ir(dev, IR_PROTOCOL, protocol); - input_report_ir(dev, IR_DEVICE, device); - input_report_ir(dev, IR_COMMAND, command); - input_sync(dev); -} - static int encode_sony(struct ir_device *ir, struct ir_command *command) { /* Sony SIRC IR code */ @@ -725,11 +716,15 @@ void input_ir_destroy(struct input_dev *dev) static int __init input_ir_init(void) { - return 0; + config_group_init(&input_ir_remotes.su_group); + mutex_init(&input_ir_remotes.su_mutex); + + return configfs_register_subsystem(&input_ir_remotes); } module_init(input_ir_init); static void __exit input_ir_exit(void) { + configfs_unregister_subsystem(&input_ir_remotes); } module_exit(input_ir_exit);