Skip to content
Snippets Groups Projects
rc-main.c 31.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • };
    
    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 = ir_getkeycode;
    	dev->input_dev->setkeycode = ir_setkeycode;
    
    	input_set_drvdata(dev->input_dev, dev);
    
    
    	spin_lock_init(&dev->rc_map.lock);
    
    	spin_lock_init(&dev->keylock);
    
    	mutex_init(&dev->lock);
    
    	setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
    
    	dev->dev.type = &rc_dev_type;
    
    	dev->dev.class = &rc_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)
    
    		input_free_device(dev->input_dev);
    
    
    	put_device(&dev->dev);
    
    	kfree(dev);
    	module_put(THIS_MODULE);
    
    }
    EXPORT_SYMBOL_GPL(rc_free_device);
    
    int rc_register_device(struct rc_dev *dev)
    {
    
    	static bool raw_init = false; /* raw decoders loaded? */
    
    	static atomic_t devno = ATOMIC_INIT(0);
    
    	struct rc_map *rc_map;
    
    	if (!dev || !dev->map_name)
    		return -EINVAL;
    
    	rc_map = rc_map_get(dev->map_name);
    
    		rc_map = rc_map_get(RC_MAP_EMPTY);
    
    	if (!rc_map || !rc_map->scan || rc_map->size == 0)
    
    		return -EINVAL;
    
    	set_bit(EV_KEY, dev->input_dev->evbit);
    	set_bit(EV_REP, dev->input_dev->evbit);
    	set_bit(EV_MSC, dev->input_dev->evbit);
    	set_bit(MSC_SCAN, dev->input_dev->mscbit);
    	if (dev->open)
    		dev->input_dev->open = ir_open;
    	if (dev->close)
    		dev->input_dev->close = ir_close;
    
    
    	/*
    	 * Take the lock here, as the device sysfs node will appear
    	 * when device_add() is called, which may trigger an ir-keytable udev
    
    	 * rule, which will in turn call show_protocols and access
    	 * dev->enabled_protocols before it has been initialized.
    
    	dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
    	dev_set_name(&dev->dev, "rc%ld", dev->devno);
    	dev_set_drvdata(&dev->dev, dev);
    	rc = device_add(&dev->dev);
    	if (rc)
    
    	rc = ir_setkeytable(dev, rc_map);
    
    	if (rc)
    		goto out_dev;
    
    	dev->input_dev->dev.parent = &dev->dev;
    	memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
    	dev->input_dev->phys = dev->input_phys;
    	dev->input_dev->name = dev->input_name;
    
    
    	/* input_register_device can call ir_open, so unlock mutex here */
    	mutex_unlock(&dev->lock);
    
    
    	rc = input_register_device(dev->input_dev);
    
    Lucas De Marchi's avatar
    Lucas De Marchi committed
    	 * Default delay of 250ms is too short for some protocols, especially
    
    	 * since the timeout is currently set to 250ms. Increase it to 500ms,
    	 * to avoid wrong repetition of the keycodes. Note that this must be
    	 * set after the call to input_register_device().
    	 */
    	dev->input_dev->rep[REP_DELAY] = 500;
    
    
    	/*
    	 * As a repeat event on protocols like RC-5 and NEC take as long as
    	 * 110/114ms, using 33ms as a repeat period is not the right thing
    	 * to do.
    	 */
    	dev->input_dev->rep[REP_PERIOD] = 125;
    
    
    	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    
    	printk(KERN_INFO "%s: %s as %s\n",
    
    		dev_name(&dev->dev),
    		dev->input_name ? dev->input_name : "Unspecified device",
    
    	if (dev->driver_type == RC_DRIVER_IR_RAW) {
    
    		/* Load raw decoders, if they aren't already */
    		if (!raw_init) {
    			IR_dprintk(1, "Loading raw decoders\n");
    			ir_raw_init();
    			raw_init = true;
    		}
    
    		rc = ir_raw_event_register(dev);
    		if (rc < 0)
    			goto out_input;
    	}
    
    	if (dev->change_protocol) {
    
    		u64 rc_type = (1 << rc_map->rc_type);
    		rc = dev->change_protocol(dev, &rc_type);
    
    		dev->enabled_protocols = rc_type;
    
    	mutex_unlock(&dev->lock);
    
    
    	IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
    		   dev->devno,
    		   dev->driver_name ? dev->driver_name : "unknown",
    
    		   rc_map->name ? rc_map->name : "unknown",
    
    		   dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
    
    
    
    out_raw:
    	if (dev->driver_type == RC_DRIVER_IR_RAW)
    		ir_raw_event_unregister(dev);
    out_input:
    	input_unregister_device(dev->input_dev);
    	dev->input_dev = NULL;
    out_table:
    
    	ir_free_table(&dev->rc_map);
    
    out_unlock:
    	mutex_unlock(&dev->lock);
    
    EXPORT_SYMBOL_GPL(rc_register_device);
    
    void rc_unregister_device(struct rc_dev *dev)
    
    	del_timer_sync(&dev->timer_keyup);
    
    	if (dev->driver_type == RC_DRIVER_IR_RAW)
    		ir_raw_event_unregister(dev);
    
    
    	/* Freeing the table should also call the stop callback */
    	ir_free_table(&dev->rc_map);
    	IR_dprintk(1, "Freed keycode table\n");
    
    
    	input_unregister_device(dev->input_dev);
    	dev->input_dev = NULL;
    
    
    EXPORT_SYMBOL_GPL(rc_unregister_device);
    
    
    /*
     * Init/exit code for the module. Basically, creates/removes /sys/class/rc
     */
    
    
    static int __init rc_core_init(void)
    
    	int rc = class_register(&rc_class);
    
    		printk(KERN_ERR "rc_core: unable to register rc class\n");
    
    	rc_map_register(&empty_map);
    
    static void __exit rc_core_exit(void)
    
    	class_unregister(&rc_class);
    
    	rc_map_unregister(&empty_map);
    
    subsys_initcall(rc_core_init);
    
    module_exit(rc_core_exit);
    
    int rc_core_debug;    /* ir_debug level (0,1,2) */
    EXPORT_SYMBOL_GPL(rc_core_debug);
    module_param_named(debug, rc_core_debug, int, 0644);
    
    
    MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
    MODULE_LICENSE("GPL");