Skip to content
Snippets Groups Projects
rc-main.c 29.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* rc-core.c - handle IR scancode->keycode tables
    
     * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
    
     *
     * This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation version 2 of the License.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
    
    #include <media/ir-core.h>
    #include <linux/spinlock.h>
    #include <linux/delay.h>
    
    #include <linux/device.h>
    
    #include "rc-core-priv.h"
    
    /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
    #define IR_TAB_MIN_SIZE	256
    #define IR_TAB_MAX_SIZE	8192
    
    /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
    #define IR_KEYPRESS_TIMEOUT 250
    
    
    /* Used to keep track of known keymaps */
    
    static LIST_HEAD(rc_map_list);
    static DEFINE_SPINLOCK(rc_map_lock);
    
    static struct rc_keymap *seek_rc_map(const char *name)
    {
    	struct rc_keymap *map = NULL;
    
    	spin_lock(&rc_map_lock);
    	list_for_each_entry(map, &rc_map_list, list) {
    		if (!strcmp(name, map->map.name)) {
    			spin_unlock(&rc_map_lock);
    			return map;
    		}
    	}
    	spin_unlock(&rc_map_lock);
    
    	return NULL;
    }
    
    struct ir_scancode_table *get_rc_map(const char *name)
    {
    
    	struct rc_keymap *map;
    
    	map = seek_rc_map(name);
    #ifdef MODULE
    	if (!map) {
    		int rc = request_module(name);
    		if (rc < 0) {
    			printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
    			return NULL;
    		}
    		msleep(20);	/* Give some time for IR to register */
    
    		map = seek_rc_map(name);
    	}
    #endif
    	if (!map) {
    		printk(KERN_ERR "IR keymap %s not found\n", name);
    		return NULL;
    	}
    
    	printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
    
    	return &map->map;
    }
    EXPORT_SYMBOL_GPL(get_rc_map);
    
    int ir_register_map(struct rc_keymap *map)
    {
    	spin_lock(&rc_map_lock);
    	list_add_tail(&map->list, &rc_map_list);
    	spin_unlock(&rc_map_lock);
    	return 0;
    }
    EXPORT_SYMBOL_GPL(ir_register_map);
    
    void ir_unregister_map(struct rc_keymap *map)
    {
    	spin_lock(&rc_map_lock);
    	list_del(&map->list);
    	spin_unlock(&rc_map_lock);
    }
    EXPORT_SYMBOL_GPL(ir_unregister_map);
    
    
    static struct ir_scancode empty[] = {
    	{ 0x2a, KEY_COFFEE },
    };
    
    static struct rc_keymap empty_map = {
    	.map = {
    		.scan    = empty,
    		.size    = ARRAY_SIZE(empty),
    		.ir_type = IR_TYPE_UNKNOWN,	/* Legacy IR type */
    		.name    = RC_MAP_EMPTY,
    	}
    };
    
    
    /**
     * ir_create_table() - initializes a scancode table
     * @rc_tab:	the ir_scancode_table to initialize
     * @name:	name to assign to the table
     * @ir_type:	ir type to assign to the new table
     * @size:	initial size of the table
     * @return:	zero on success or a negative error code
     *
     * This routine will initialize the ir_scancode_table and will allocate
    
     * memory to hold at least the specified number of elements.
    
     */
    static int ir_create_table(struct ir_scancode_table *rc_tab,
    			   const char *name, u64 ir_type, size_t size)
    {
    	rc_tab->name = name;
    	rc_tab->ir_type = ir_type;
    	rc_tab->alloc = roundup_pow_of_two(size * sizeof(struct ir_scancode));
    	rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
    	rc_tab->scan = kmalloc(rc_tab->alloc, GFP_KERNEL);
    	if (!rc_tab->scan)
    		return -ENOMEM;
    
    	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
    		   rc_tab->size, rc_tab->alloc);
    	return 0;
    }
    
    /**
     * ir_free_table() - frees memory allocated by a scancode table
     * @rc_tab:	the table whose mappings need to be freed
     *
     * This routine will free memory alloctaed for key mappings used by given
     * scancode table.
     */
    static void ir_free_table(struct ir_scancode_table *rc_tab)
    {
    	rc_tab->size = 0;
    	kfree(rc_tab->scan);
    	rc_tab->scan = NULL;
    }
    
    
     * ir_resize_table() - resizes a scancode table if necessary
     * @rc_tab:	the ir_scancode_table to resize
    
     * @gfp_flags:	gfp flags to use when allocating memory
    
     * @return:	zero on success or a negative error code
    
     * This routine will shrink the ir_scancode_table if it has lots of
     * unused entries and grow it if it is full.
    
    static int ir_resize_table(struct ir_scancode_table *rc_tab, gfp_t gfp_flags)
    
    	unsigned int oldalloc = rc_tab->alloc;
    	unsigned int newalloc = oldalloc;
    	struct ir_scancode *oldscan = rc_tab->scan;
    	struct ir_scancode *newscan;
    
    	if (rc_tab->size == rc_tab->len) {
    		/* All entries in use -> grow keytable */
    		if (rc_tab->alloc >= IR_TAB_MAX_SIZE)
    			return -ENOMEM;
    
    		newalloc *= 2;
    		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
    	}
    
    	if ((rc_tab->len * 3 < rc_tab->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
    		/* Less than 1/3 of entries in use -> shrink keytable */
    		newalloc /= 2;
    		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
    	}
    
    	if (newalloc == oldalloc)
    		return 0;
    
    	newscan = kmalloc(newalloc, gfp_flags);
    
    	if (!newscan) {
    		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
    		return -ENOMEM;
    	}
    
    	memcpy(newscan, rc_tab->scan, rc_tab->len * sizeof(struct ir_scancode));
    	rc_tab->scan = newscan;
    	rc_tab->alloc = newalloc;
    	rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
    	kfree(oldscan);
    	return 0;
    
     * ir_update_mapping() - set a keycode in the scancode->keycode table
    
     * @dev:	the struct rc_dev device descriptor
    
     * @rc_tab:	scancode table to be adjusted
     * @index:	index of the mapping that needs to be updated
     * @keycode:	the desired keycode
     * @return:	previous keycode assigned to the mapping
     *
    
     * This routine is used to update scancode->keycode mapping at given
    
    static unsigned int ir_update_mapping(struct rc_dev *dev,
    
    				      struct ir_scancode_table *rc_tab,
    				      unsigned int index,
    				      unsigned int new_keycode)
    {
    	int old_keycode = rc_tab->scan[index].keycode;
    	int i;
    
    	/* Did the user wish to remove the mapping? */
    	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
    		IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
    			   index, rc_tab->scan[index].scancode);
    		rc_tab->len--;
    		memmove(&rc_tab->scan[index], &rc_tab->scan[index+ 1],
    			(rc_tab->len - index) * sizeof(struct ir_scancode));
    	} else {
    		IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
    			   index,
    			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
    			   rc_tab->scan[index].scancode, new_keycode);
    		rc_tab->scan[index].keycode = new_keycode;
    
    		__set_bit(new_keycode, dev->input_dev->keybit);
    
    	}
    
    	if (old_keycode != KEY_RESERVED) {
    		/* A previous mapping was updated... */
    
    		__clear_bit(old_keycode, dev->input_dev->keybit);
    
    		/* ... but another scancode might use the same keycode */
    		for (i = 0; i < rc_tab->len; i++) {
    			if (rc_tab->scan[i].keycode == old_keycode) {
    
    				__set_bit(old_keycode, dev->input_dev->keybit);
    
    				break;
    			}
    		}
    
    		/* Possibly shrink the keytable, failure is not a problem */
    		ir_resize_table(rc_tab, GFP_ATOMIC);
    	}
    
    	return old_keycode;
    }
    
    /**
    
     * ir_establish_scancode() - set a keycode in the scancode->keycode table
    
     * @dev:	the struct rc_dev device descriptor
    
     * @rc_tab:	scancode table to be searched
     * @scancode:	the desired scancode
     * @resize:	controls whether we allowed to resize the table to
     *		accomodate not yet present scancodes
     * @return:	index of the mapping containing scancode in question
     *		or -1U in case of failure.
    
     * This routine is used to locate given scancode in ir_scancode_table.
     * If scancode is not yet present the routine will allocate a new slot
     * for it.
    
    static unsigned int ir_establish_scancode(struct rc_dev *dev,
    
    					  struct ir_scancode_table *rc_tab,
    					  unsigned int scancode,
    					  bool resize)
    
    
    	/*
    	 * Unfortunately, some hardware-based IR decoders don't provide
    	 * all bits for the complete IR code. In general, they provide only
    	 * the command part of the IR code. Yet, as it is possible to replace
    	 * the provided IR with another one, it is needed to allow loading
    
    	 * IR tables from other remotes. So, we support specifying a mask to
    	 * indicate the valid bits of the scancodes.
    
    	if (dev->scanmask)
    		scancode &= dev->scanmask;
    
    
    	/* First check if we already have a mapping for this ir command */
    	for (i = 0; i < rc_tab->len; i++) {
    
    		if (rc_tab->scan[i].scancode == scancode)
    			return i;
    
    
    		/* Keytable is sorted from lowest to highest scancode */
    
    		if (rc_tab->scan[i].scancode >= scancode)
    
    	/* No previous mapping found, we might need to grow the table */
    	if (rc_tab->size == rc_tab->len) {
    		if (!resize || ir_resize_table(rc_tab, GFP_ATOMIC))
    			return -1U;
    	}
    
    	/* i is the proper index to insert our new keycode */
    	if (i < rc_tab->len)
    
    		memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
    			(rc_tab->len - i) * sizeof(struct ir_scancode));
    
    	rc_tab->scan[i].scancode = scancode;
    	rc_tab->scan[i].keycode = KEY_RESERVED;
    	rc_tab->len++;
    
     * ir_setkeycode() - set a keycode in the scancode->keycode table
    
     * @idev:	the struct input_dev device descriptor
    
     * @keycode:	result
     * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
    
     * This routine is used to handle evdev EVIOCSKEY ioctl.
    
    static int ir_setkeycode(struct input_dev *idev,
    
    			 const struct input_keymap_entry *ke,
    			 unsigned int *old_keycode)
    
    	struct rc_dev *rdev = input_get_drvdata(idev);
    	struct ir_scancode_table *rc_tab = &rdev->rc_tab;
    
    	unsigned int index;
    	unsigned int scancode;
    	int retval;
    	unsigned long flags;
    
    	spin_lock_irqsave(&rc_tab->lock, flags);
    
    
    	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
    		index = ke->index;
    		if (index >= rc_tab->len) {
    			retval = -EINVAL;
    			goto out;
    		}
    	} else {
    		retval = input_scancode_to_scalar(ke, &scancode);
    		if (retval)
    			goto out;
    
    
    		index = ir_establish_scancode(rdev, rc_tab, scancode, true);
    
    		if (index >= rc_tab->len) {
    			retval = -ENOMEM;
    			goto out;
    		}
    	}
    
    
    	*old_keycode = ir_update_mapping(rdev, rc_tab, index, ke->keycode);
    
    	spin_unlock_irqrestore(&rc_tab->lock, flags);
    
     * ir_setkeytable() - sets several entries in the scancode->keycode table
    
     * @dev:	the struct rc_dev device descriptor
    
     * @to:		the struct ir_scancode_table to copy entries to
     * @from:	the struct ir_scancode_table to copy entries from
    
     * @return:	-ENOMEM if all keycodes could not be inserted, otherwise zero.
    
     * This routine is used to handle table initialization.
    
    static int ir_setkeytable(struct rc_dev *dev,
    
    			  const struct ir_scancode_table *from)
    
    	struct ir_scancode_table *rc_tab = &dev->rc_tab;
    
    	rc = ir_create_table(rc_tab, from->name,
    			     from->ir_type, from->size);
    
    	if (rc)
    		return rc;
    
    	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
    		   rc_tab->size, rc_tab->alloc);
    
    	for (i = 0; i < from->size; i++) {
    
    		index = ir_establish_scancode(dev, rc_tab,
    
    					      from->scan[i].scancode, false);
    		if (index >= rc_tab->len) {
    			rc = -ENOMEM;
    
    		ir_update_mapping(dev, rc_tab, index,
    
    /**
     * ir_lookup_by_scancode() - locate mapping by scancode
    
     * @rc_tab:	the struct ir_scancode_table to search
    
     * @scancode:	scancode to look for in the table
     * @return:	index in the table, -1U if not found
     *
     * This routine performs binary search in RC keykeymap table for
     * given scancode.
     */
    static unsigned int ir_lookup_by_scancode(const struct ir_scancode_table *rc_tab,
    					  unsigned int scancode)
    {
    
    	int start = 0;
    	int end = rc_tab->len - 1;
    	int mid;
    
    
    	while (start <= end) {
    		mid = (start + end) / 2;
    		if (rc_tab->scan[mid].scancode < scancode)
    			start = mid + 1;
    		else if (rc_tab->scan[mid].scancode > scancode)
    			end = mid - 1;
    		else
    			return mid;
    	}
    
    	return -1U;
    }
    
    
     * ir_getkeycode() - get a keycode from the scancode->keycode table
    
     * @idev:	the struct input_dev device descriptor
    
     * @keycode:	used to return the keycode, if found, or KEY_RESERVED
     * @return:	always returns zero.
    
     * This routine is used to handle evdev EVIOCGKEY ioctl.
    
    static int ir_getkeycode(struct input_dev *idev,
    
    			 struct input_keymap_entry *ke)
    
    	struct rc_dev *rdev = input_get_drvdata(idev);
    	struct ir_scancode_table *rc_tab = &rdev->rc_tab;
    
    	struct ir_scancode *entry;
    	unsigned long flags;
    	unsigned int index;
    	unsigned int scancode;
    	int retval;
    
    	spin_lock_irqsave(&rc_tab->lock, flags);
    
    
    	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
    		index = ke->index;
    	} else {
    		retval = input_scancode_to_scalar(ke, &scancode);
    		if (retval)
    			goto out;
    
    		index = ir_lookup_by_scancode(rc_tab, scancode);
    	}
    
    	if (index >= rc_tab->len) {
    		if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
    			IR_dprintk(1, "unknown key for scancode 0x%04x\n",
    				   scancode);
    		retval = -EINVAL;
    		goto out;
    
    	entry = &rc_tab->scan[index];
    
    	ke->index = index;
    	ke->keycode = entry->keycode;
    	ke->len = sizeof(entry->scancode);
    	memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
    
    
    out:
    	spin_unlock_irqrestore(&rc_tab->lock, flags);
    	return retval;
    
    }
    
    /**
     * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
    
     * @dev:	the struct rc_dev descriptor of the device
     * @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 ir_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
    
    	struct ir_scancode_table *rc_tab = &dev->rc_tab;
    
    	unsigned int keycode;
    	unsigned int index;
    	unsigned long flags;
    
    	spin_lock_irqsave(&rc_tab->lock, flags);
    
    	index = ir_lookup_by_scancode(rc_tab, scancode);
    	keycode = index < rc_tab->len ?
    			rc_tab->scan[index].keycode : KEY_RESERVED;
    
    	spin_unlock_irqrestore(&rc_tab->lock, flags);
    
    	if (keycode != KEY_RESERVED)
    		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
    
    			   dev->input_name, scancode, keycode);
    
    EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
    
     * ir_do_keyup() - internal function to signal the release of a keypress
    
     * @dev:	the struct rc_dev descriptor of the device
    
     * This function is used internally to release a keypress, it must be
     * called with keylock held.
    
    static void ir_do_keyup(struct rc_dev *dev)
    
    	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
    	input_report_key(dev->input_dev, dev->last_keycode, 0);
    	input_sync(dev->input_dev);
    	dev->keypressed = false;
    
     * ir_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 ir_keyup(struct rc_dev *dev)
    
    	spin_lock_irqsave(&dev->keylock, flags);
    	ir_do_keyup(dev);
    	spin_unlock_irqrestore(&dev->keylock, flags);
    
    EXPORT_SYMBOL_GPL(ir_keyup);
    
    
    /**
     * ir_timer_keyup() - generates a keyup event after a timeout
    
     * @cookie:	a pointer to the struct rc_dev for the device
    
     *
     * This routine will generate a keyup event some time after a keydown event
     * is generated when no further activity has been detected.
    
    static void ir_timer_keyup(unsigned long cookie)
    
    	struct rc_dev *dev = (struct rc_dev *)cookie;
    
    	unsigned long flags;
    
    	/*
    	 * ir->keyup_jiffies is used to prevent a race condition if a
    	 * hardware interrupt occurs at this point and the keyup timer
    	 * event is moved further into the future as a result.
    	 *
    	 * The timer will then be reactivated and this function called
    	 * again in the future. We need to exit gracefully in that case
    	 * to allow the input subsystem to do its auto-repeat magic or
    	 * a keyup event might follow immediately after the keydown.
    	 */
    
    	spin_lock_irqsave(&dev->keylock, flags);
    	if (time_is_before_eq_jiffies(dev->keyup_jiffies))
    		ir_do_keyup(dev);
    	spin_unlock_irqrestore(&dev->keylock, flags);
    
     * ir_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 ir_repeat(struct rc_dev *dev)
    
    {
    	unsigned long flags;
    
    	spin_lock_irqsave(&dev->keylock, flags);
    
    	input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
    
    	dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
    	mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
    
    	spin_unlock_irqrestore(&dev->keylock, flags);
    
    EXPORT_SYMBOL_GPL(ir_repeat);
    
     * ir_do_keydown() - internal function to process a keypress
    
     * @dev:	the struct rc_dev descriptor of the device
    
     * @scancode:   the scancode of the keypress
     * @keycode:    the keycode of the keypress
     * @toggle:     the toggle value of the keypress
    
     * This function is used internally to register a keypress, it must be
     * called with keylock held.
    
    static void ir_do_keydown(struct rc_dev *dev, int scancode,
    
    	input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
    
    	/* Repeat event? */
    
    	if (dev->keypressed &&
    	    dev->last_scancode == scancode &&
    	    dev->last_toggle == toggle)
    
    	/* Release old keypress */
    
    	dev->last_scancode = scancode;
    	dev->last_toggle = toggle;
    	dev->last_keycode = keycode;
    
    
    	if (keycode == KEY_RESERVED)
    
    	/* Register a keypress */
    
    	IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
    
    		   dev->input_name, keycode, scancode);
    	input_report_key(dev->input_dev, dev->last_keycode, 1);
    	input_sync(dev->input_dev);
    
    /**
     * ir_keydown() - generates input event for a key press
    
     * @dev:	the struct rc_dev descriptor of the device
    
     * @scancode:   the scancode that we're seeking
     * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
     *              support toggle values, this should be set to zero)
     *
    
     * This routine is used to signal that a key has been pressed on the
     * remote control.
    
    void ir_keydown(struct rc_dev *dev, int scancode, u8 toggle)
    
    {
    	unsigned long flags;
    	u32 keycode = ir_g_keycode_from_table(dev, scancode);
    
    
    	spin_lock_irqsave(&dev->keylock, flags);
    
    	ir_do_keydown(dev, scancode, keycode, toggle);
    
    
    	if (dev->keypressed) {
    		dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
    		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
    
    	spin_unlock_irqrestore(&dev->keylock, flags);
    
    /**
     * ir_keydown_notimeout() - generates input event for a key press without
     *                          an automatic keyup event at a later time
    
     * @dev:	the struct rc_dev descriptor of the device
    
     * @scancode:   the scancode that we're seeking
     * @toggle:     the toggle value (protocol dependent, if the protocol doesn't
     *              support toggle values, this should be set to zero)
     *
    
     * This routine is used to signal that a key has been pressed on the
     * remote control. The driver must manually call ir_keyup() at a later stage.
    
    void ir_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
    
    {
    	unsigned long flags;
    	u32 keycode = ir_g_keycode_from_table(dev, scancode);
    
    
    	spin_lock_irqsave(&dev->keylock, flags);
    
    	ir_do_keydown(dev, scancode, keycode, toggle);
    
    	spin_unlock_irqrestore(&dev->keylock, flags);
    
    static int ir_open(struct input_dev *idev)
    
    	struct rc_dev *rdev = input_get_drvdata(idev);
    
    static void ir_close(struct input_dev *idev)
    
    	struct rc_dev *rdev = input_get_drvdata(idev);
    
    /* class for /sys/class/rc */
    static char *ir_devnode(struct device *dev, mode_t *mode)
    {
    	return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
    }
    
    static struct class ir_input_class = {
    	.name		= "rc",
    	.devnode	= ir_devnode,
    };
    
    static struct {
    	u64	type;
    	char	*name;
    } proto_names[] = {
    	{ IR_TYPE_UNKNOWN,	"unknown"	},
    	{ IR_TYPE_RC5,		"rc-5"		},
    	{ IR_TYPE_NEC,		"nec"		},
    	{ IR_TYPE_RC6,		"rc-6"		},
    	{ IR_TYPE_JVC,		"jvc"		},
    	{ IR_TYPE_SONY,		"sony"		},
    	{ IR_TYPE_RC5_SZ,	"rc-5-sz"	},
    	{ IR_TYPE_LIRC,		"lirc"		},
    };
    
    #define PROTO_NONE	"none"
    
    /**
     * show_protocols() - shows the current IR protocol(s)
    
     * @device:	the device descriptor
    
     * @mattr:	the device attribute struct (unused)
     * @buf:	a pointer to the output buffer
     *
     * This routine is a callback routine for input read the IR protocol type(s).
     * it is trigged by reading /sys/class/rc/rc?/protocols.
     * It returns the protocol names of supported protocols.
     * Enabled protocols are printed in brackets.
     */
    
    static ssize_t show_protocols(struct device *device,
    
    			      struct device_attribute *mattr, char *buf)
    {
    
    	struct rc_dev *dev = to_rc_dev(device);
    
    	u64 allowed, enabled;
    	char *tmp = buf;
    	int i;
    
    	/* Device is being removed */
    
    	if (dev->driver_type == RC_DRIVER_SCANCODE) {
    		enabled = dev->rc_tab.ir_type;
    		allowed = dev->allowed_protos;
    	} else {
    		enabled = dev->raw->enabled_protocols;
    
    		allowed = ir_raw_get_allowed_protocols();
    
    
    	IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
    		   (long long)allowed,
    		   (long long)enabled);
    
    	for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
    		if (allowed & enabled & proto_names[i].type)
    			tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
    		else if (allowed & proto_names[i].type)
    			tmp += sprintf(tmp, "%s ", proto_names[i].name);
    	}
    
    	if (tmp != buf)
    		tmp--;
    	*tmp = '\n';
    	return tmp + 1 - buf;
    }
    
    /**
     * store_protocols() - changes the current IR protocol(s)
    
     * @device:	the device descriptor
    
     * @mattr:	the device attribute struct (unused)
     * @buf:	a pointer to the input buffer
     * @len:	length of the input buffer
     *
    
     * This routine is for changing the IR protocol type.
    
     * It is trigged by writing to /sys/class/rc/rc?/protocols.
     * Writing "+proto" will add a protocol to the list of enabled protocols.
     * Writing "-proto" will remove a protocol from the list of enabled protocols.
     * Writing "proto" will enable only "proto".
     * Writing "none" will disable all protocols.
     * Returns -EINVAL if an invalid protocol combination or unknown protocol name
     * is used, otherwise @len.
     */
    
    static ssize_t store_protocols(struct device *device,
    
    			       struct device_attribute *mattr,
    			       const char *data,
    			       size_t len)
    {
    
    	struct rc_dev *dev = to_rc_dev(device);
    
    	bool enable, disable;
    	const char *tmp;
    	u64 type;
    	u64 mask;
    	int rc, i, count = 0;
    	unsigned long flags;
    
    	/* Device is being removed */
    
    	if (dev->driver_type == RC_DRIVER_SCANCODE)
    		type = dev->rc_tab.ir_type;
    	else if (dev->raw)
    		type = dev->raw->enabled_protocols;
    
    	else {
    		IR_dprintk(1, "Protocol switching not supported\n");
    		return -EINVAL;
    	}
    
    	while ((tmp = strsep((char **) &data, " \n")) != NULL) {
    		if (!*tmp)
    			break;
    
    		if (*tmp == '+') {
    			enable = true;
    			disable = false;
    			tmp++;
    		} else if (*tmp == '-') {
    			enable = false;
    			disable = true;
    			tmp++;
    		} else {
    			enable = false;
    			disable = false;
    		}
    
    		if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
    			tmp += sizeof(PROTO_NONE);
    			mask = 0;
    			count++;
    		} else {
    			for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
    				if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
    					tmp += strlen(proto_names[i].name);
    					mask = proto_names[i].type;
    					break;
    				}
    			}
    			if (i == ARRAY_SIZE(proto_names)) {
    				IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
    				return -EINVAL;
    			}
    			count++;
    		}
    
    		if (enable)
    			type |= mask;
    		else if (disable)
    			type &= ~mask;
    		else
    			type = mask;
    	}
    
    	if (!count) {
    		IR_dprintk(1, "Protocol not specified\n");
    		return -EINVAL;
    	}
    
    
    	if (dev->change_protocol) {
    		rc = dev->change_protocol(dev, type);
    
    		if (rc < 0) {
    			IR_dprintk(1, "Error setting protocols to 0x%llx\n",
    				   (long long)type);
    			return -EINVAL;
    		}
    	}
    
    
    	if (dev->driver_type == RC_DRIVER_SCANCODE) {
    		spin_lock_irqsave(&dev->rc_tab.lock, flags);
    		dev->rc_tab.ir_type = type;
    		spin_unlock_irqrestore(&dev->rc_tab.lock, flags);
    
    		dev->raw->enabled_protocols = type;
    
    	}
    
    	IR_dprintk(1, "Current protocol(s): 0x%llx\n",
    		   (long long)type);
    
    	return len;
    }
    
    
    static void rc_dev_release(struct device *device)
    {
    	struct rc_dev *dev = to_rc_dev(device);
    
    	kfree(dev);
    	module_put(THIS_MODULE);
    }
    
    
    #define ADD_HOTPLUG_VAR(fmt, val...)					\
    	do {								\
    		int err = add_uevent_var(env, fmt, val);		\
    		if (err)						\
    			return err;					\
    	} while (0)
    
    static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
    {
    
    	struct rc_dev *dev = to_rc_dev(device);
    
    	if (dev->rc_tab.name)
    		ADD_HOTPLUG_VAR("NAME=%s", dev->rc_tab.name);
    	if (dev->driver_name)
    		ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
    
    
    	return 0;
    }
    
    /*
     * Static device attribute struct with the sysfs attributes for IR's
     */
    static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
    		   show_protocols, store_protocols);
    
    static struct attribute *rc_dev_attrs[] = {
    	&dev_attr_protocols.attr,
    	NULL,
    };
    
    static struct attribute_group rc_dev_attr_grp = {
    	.attrs	= rc_dev_attrs,
    };
    
    static const struct attribute_group *rc_dev_attr_groups[] = {
    	&rc_dev_attr_grp,
    	NULL
    };
    
    static struct device_type rc_dev_type = {
    	.groups		= rc_dev_attr_groups,
    
    struct rc_dev *rc_allocate_device(void)
    
    	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    	if (!dev)
    		return NULL;
    
    	dev->input_dev = input_allocate_device();
    	if (!dev->input_dev) {
    		kfree(dev);
    		return NULL;
    	}
    
    	dev->input_dev->getkeycode_new = ir_getkeycode;
    	dev->input_dev->setkeycode_new = ir_setkeycode;
    	input_set_drvdata(dev->input_dev, dev);
    
    	spin_lock_init(&dev->rc_tab.lock);
    	spin_lock_init(&dev->keylock);
    	setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
    
    	dev->dev.type = &rc_dev_type;
    	dev->dev.class = &ir_input_class;
    	device_initialize(&dev->dev);
    
    	__module_get(THIS_MODULE);
    	return dev;
    }
    EXPORT_SYMBOL_GPL(rc_allocate_device);
    
    void rc_free_device(struct rc_dev *dev)
    
    	if (dev) {
    		input_free_device(dev->input_dev);
    		put_device(&dev->dev);
    	}
    }
    EXPORT_SYMBOL_GPL(rc_free_device);
    
    int rc_register_device(struct rc_dev *dev)
    {
    	static atomic_t devno = ATOMIC_INIT(0);
    	struct ir_scancode_table *rc_tab;
    
    	if (!dev || !dev->map_name)
    		return -EINVAL;
    
    	rc_tab = get_rc_map(dev->map_name);
    	if (!rc_tab)