14924a311SDavid Härdeman /* rc-ir-raw.c - handle IR pulse/space events 24924a311SDavid Härdeman * 34924a311SDavid Härdeman * Copyright (C) 2010 by Mauro Carvalho Chehab 44924a311SDavid Härdeman * 54924a311SDavid Härdeman * This program is free software; you can redistribute it and/or modify 64924a311SDavid Härdeman * it under the terms of the GNU General Public License as published by 74924a311SDavid Härdeman * the Free Software Foundation version 2 of the License. 84924a311SDavid Härdeman * 94924a311SDavid Härdeman * This program is distributed in the hope that it will be useful, 104924a311SDavid Härdeman * but WITHOUT ANY WARRANTY; without even the implied warranty of 114924a311SDavid Härdeman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 124924a311SDavid Härdeman * GNU General Public License for more details. 134924a311SDavid Härdeman */ 144924a311SDavid Härdeman 154924a311SDavid Härdeman #include <linux/export.h> 164924a311SDavid Härdeman #include <linux/kthread.h> 174924a311SDavid Härdeman #include <linux/mutex.h> 184924a311SDavid Härdeman #include <linux/kmod.h> 194924a311SDavid Härdeman #include <linux/sched.h> 204924a311SDavid Härdeman #include <linux/freezer.h> 214924a311SDavid Härdeman #include "rc-core-priv.h" 224924a311SDavid Härdeman 234924a311SDavid Härdeman /* Define the max number of pulse/space transitions to buffer */ 244924a311SDavid Härdeman #define MAX_IR_EVENT_SIZE 512 254924a311SDavid Härdeman 264924a311SDavid Härdeman /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ 274924a311SDavid Härdeman static LIST_HEAD(ir_raw_client_list); 284924a311SDavid Härdeman 294924a311SDavid Härdeman /* Used to handle IR raw handler extensions */ 304924a311SDavid Härdeman static DEFINE_MUTEX(ir_raw_handler_lock); 314924a311SDavid Härdeman static LIST_HEAD(ir_raw_handler_list); 324924a311SDavid Härdeman static u64 available_protocols; 334924a311SDavid Härdeman 344924a311SDavid Härdeman static int ir_raw_event_thread(void *data) 354924a311SDavid Härdeman { 364924a311SDavid Härdeman struct ir_raw_event ev; 374924a311SDavid Härdeman struct ir_raw_handler *handler; 384924a311SDavid Härdeman struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; 394924a311SDavid Härdeman int retval; 404924a311SDavid Härdeman 414924a311SDavid Härdeman while (!kthread_should_stop()) { 424924a311SDavid Härdeman 434924a311SDavid Härdeman spin_lock_irq(&raw->lock); 444924a311SDavid Härdeman retval = kfifo_len(&raw->kfifo); 454924a311SDavid Härdeman 464924a311SDavid Härdeman if (retval < sizeof(ev)) { 474924a311SDavid Härdeman set_current_state(TASK_INTERRUPTIBLE); 484924a311SDavid Härdeman 494924a311SDavid Härdeman if (kthread_should_stop()) 504924a311SDavid Härdeman set_current_state(TASK_RUNNING); 514924a311SDavid Härdeman 524924a311SDavid Härdeman spin_unlock_irq(&raw->lock); 534924a311SDavid Härdeman schedule(); 544924a311SDavid Härdeman continue; 554924a311SDavid Härdeman } 564924a311SDavid Härdeman 574924a311SDavid Härdeman retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); 584924a311SDavid Härdeman spin_unlock_irq(&raw->lock); 594924a311SDavid Härdeman 604924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 614924a311SDavid Härdeman list_for_each_entry(handler, &ir_raw_handler_list, list) 624924a311SDavid Härdeman handler->decode(raw->dev, ev); 634924a311SDavid Härdeman raw->prev_ev = ev; 644924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 654924a311SDavid Härdeman } 664924a311SDavid Härdeman 674924a311SDavid Härdeman return 0; 684924a311SDavid Härdeman } 694924a311SDavid Härdeman 704924a311SDavid Härdeman /** 714924a311SDavid Härdeman * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders 724924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 734924a311SDavid Härdeman * @ev: the struct ir_raw_event descriptor of the pulse/space 744924a311SDavid Härdeman * 754924a311SDavid Härdeman * This routine (which may be called from an interrupt context) stores a 764924a311SDavid Härdeman * pulse/space duration for the raw ir decoding state machines. Pulses are 774924a311SDavid Härdeman * signalled as positive values and spaces as negative values. A zero value 784924a311SDavid Härdeman * will reset the decoding state machines. 794924a311SDavid Härdeman */ 804924a311SDavid Härdeman int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) 814924a311SDavid Härdeman { 824924a311SDavid Härdeman if (!dev->raw) 834924a311SDavid Härdeman return -EINVAL; 844924a311SDavid Härdeman 854924a311SDavid Härdeman IR_dprintk(2, "sample: (%05dus %s)\n", 864924a311SDavid Härdeman TO_US(ev->duration), TO_STR(ev->pulse)); 874924a311SDavid Härdeman 884924a311SDavid Härdeman if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) 894924a311SDavid Härdeman return -ENOMEM; 904924a311SDavid Härdeman 914924a311SDavid Härdeman return 0; 924924a311SDavid Härdeman } 934924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store); 944924a311SDavid Härdeman 954924a311SDavid Härdeman /** 964924a311SDavid Härdeman * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space 974924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 984924a311SDavid Härdeman * @type: the type of the event that has occurred 994924a311SDavid Härdeman * 1004924a311SDavid Härdeman * This routine (which may be called from an interrupt context) is used to 1014924a311SDavid Härdeman * store the beginning of an ir pulse or space (or the start/end of ir 1024924a311SDavid Härdeman * reception) for the raw ir decoding state machines. This is used by 1034924a311SDavid Härdeman * hardware which does not provide durations directly but only interrupts 1044924a311SDavid Härdeman * (or similar events) on state change. 1054924a311SDavid Härdeman */ 1064924a311SDavid Härdeman int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) 1074924a311SDavid Härdeman { 1084924a311SDavid Härdeman ktime_t now; 1094924a311SDavid Härdeman s64 delta; /* ns */ 1104924a311SDavid Härdeman DEFINE_IR_RAW_EVENT(ev); 1114924a311SDavid Härdeman int rc = 0; 1124924a311SDavid Härdeman int delay; 1134924a311SDavid Härdeman 1144924a311SDavid Härdeman if (!dev->raw) 1154924a311SDavid Härdeman return -EINVAL; 1164924a311SDavid Härdeman 1174924a311SDavid Härdeman now = ktime_get(); 1184924a311SDavid Härdeman delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); 1194924a311SDavid Härdeman delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]); 1204924a311SDavid Härdeman 1214924a311SDavid Härdeman /* Check for a long duration since last event or if we're 1224924a311SDavid Härdeman * being called for the first time, note that delta can't 1234924a311SDavid Härdeman * possibly be negative. 1244924a311SDavid Härdeman */ 1254924a311SDavid Härdeman if (delta > delay || !dev->raw->last_type) 1264924a311SDavid Härdeman type |= IR_START_EVENT; 1274924a311SDavid Härdeman else 1284924a311SDavid Härdeman ev.duration = delta; 1294924a311SDavid Härdeman 1304924a311SDavid Härdeman if (type & IR_START_EVENT) 1314924a311SDavid Härdeman ir_raw_event_reset(dev); 1324924a311SDavid Härdeman else if (dev->raw->last_type & IR_SPACE) { 1334924a311SDavid Härdeman ev.pulse = false; 1344924a311SDavid Härdeman rc = ir_raw_event_store(dev, &ev); 1354924a311SDavid Härdeman } else if (dev->raw->last_type & IR_PULSE) { 1364924a311SDavid Härdeman ev.pulse = true; 1374924a311SDavid Härdeman rc = ir_raw_event_store(dev, &ev); 1384924a311SDavid Härdeman } else 1394924a311SDavid Härdeman return 0; 1404924a311SDavid Härdeman 1414924a311SDavid Härdeman dev->raw->last_event = now; 1424924a311SDavid Härdeman dev->raw->last_type = type; 1434924a311SDavid Härdeman return rc; 1444924a311SDavid Härdeman } 1454924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); 1464924a311SDavid Härdeman 1474924a311SDavid Härdeman /** 1484924a311SDavid Härdeman * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing 1494924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 1504924a311SDavid Härdeman * @type: the type of the event that has occurred 1514924a311SDavid Härdeman * 1524924a311SDavid Härdeman * This routine (which may be called from an interrupt context) works 1534924a311SDavid Härdeman * in similar manner to ir_raw_event_store_edge. 1544924a311SDavid Härdeman * This routine is intended for devices with limited internal buffer 1554924a311SDavid Härdeman * It automerges samples of same type, and handles timeouts. Returns non-zero 1564924a311SDavid Härdeman * if the event was added, and zero if the event was ignored due to idle 1574924a311SDavid Härdeman * processing. 1584924a311SDavid Härdeman */ 1594924a311SDavid Härdeman int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev) 1604924a311SDavid Härdeman { 1614924a311SDavid Härdeman if (!dev->raw) 1624924a311SDavid Härdeman return -EINVAL; 1634924a311SDavid Härdeman 1644924a311SDavid Härdeman /* Ignore spaces in idle mode */ 1654924a311SDavid Härdeman if (dev->idle && !ev->pulse) 1664924a311SDavid Härdeman return 0; 1674924a311SDavid Härdeman else if (dev->idle) 1684924a311SDavid Härdeman ir_raw_event_set_idle(dev, false); 1694924a311SDavid Härdeman 1704924a311SDavid Härdeman if (!dev->raw->this_ev.duration) 1714924a311SDavid Härdeman dev->raw->this_ev = *ev; 1724924a311SDavid Härdeman else if (ev->pulse == dev->raw->this_ev.pulse) 1734924a311SDavid Härdeman dev->raw->this_ev.duration += ev->duration; 1744924a311SDavid Härdeman else { 1754924a311SDavid Härdeman ir_raw_event_store(dev, &dev->raw->this_ev); 1764924a311SDavid Härdeman dev->raw->this_ev = *ev; 1774924a311SDavid Härdeman } 1784924a311SDavid Härdeman 1794924a311SDavid Härdeman /* Enter idle mode if nessesary */ 1804924a311SDavid Härdeman if (!ev->pulse && dev->timeout && 1814924a311SDavid Härdeman dev->raw->this_ev.duration >= dev->timeout) 1824924a311SDavid Härdeman ir_raw_event_set_idle(dev, true); 1834924a311SDavid Härdeman 1844924a311SDavid Härdeman return 1; 1854924a311SDavid Härdeman } 1864924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); 1874924a311SDavid Härdeman 1884924a311SDavid Härdeman /** 1894924a311SDavid Härdeman * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not 1904924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 1914924a311SDavid Härdeman * @idle: whether the device is idle or not 1924924a311SDavid Härdeman */ 1934924a311SDavid Härdeman void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) 1944924a311SDavid Härdeman { 1954924a311SDavid Härdeman if (!dev->raw) 1964924a311SDavid Härdeman return; 1974924a311SDavid Härdeman 1984924a311SDavid Härdeman IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); 1994924a311SDavid Härdeman 2004924a311SDavid Härdeman if (idle) { 2014924a311SDavid Härdeman dev->raw->this_ev.timeout = true; 2024924a311SDavid Härdeman ir_raw_event_store(dev, &dev->raw->this_ev); 2034924a311SDavid Härdeman init_ir_raw_event(&dev->raw->this_ev); 2044924a311SDavid Härdeman } 2054924a311SDavid Härdeman 2064924a311SDavid Härdeman if (dev->s_idle) 2074924a311SDavid Härdeman dev->s_idle(dev, idle); 2084924a311SDavid Härdeman 2094924a311SDavid Härdeman dev->idle = idle; 2104924a311SDavid Härdeman } 2114924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); 2124924a311SDavid Härdeman 2134924a311SDavid Härdeman /** 2144924a311SDavid Härdeman * ir_raw_event_handle() - schedules the decoding of stored ir data 2154924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 2164924a311SDavid Härdeman * 2174924a311SDavid Härdeman * This routine will tell rc-core to start decoding stored ir data. 2184924a311SDavid Härdeman */ 2194924a311SDavid Härdeman void ir_raw_event_handle(struct rc_dev *dev) 2204924a311SDavid Härdeman { 2214924a311SDavid Härdeman unsigned long flags; 2224924a311SDavid Härdeman 2234924a311SDavid Härdeman if (!dev->raw) 2244924a311SDavid Härdeman return; 2254924a311SDavid Härdeman 2264924a311SDavid Härdeman spin_lock_irqsave(&dev->raw->lock, flags); 2274924a311SDavid Härdeman wake_up_process(dev->raw->thread); 2284924a311SDavid Härdeman spin_unlock_irqrestore(&dev->raw->lock, flags); 2294924a311SDavid Härdeman } 2304924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_handle); 2314924a311SDavid Härdeman 2324924a311SDavid Härdeman /* used internally by the sysfs interface */ 2334924a311SDavid Härdeman u64 2344924a311SDavid Härdeman ir_raw_get_allowed_protocols(void) 2354924a311SDavid Härdeman { 2364924a311SDavid Härdeman u64 protocols; 2374924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 2384924a311SDavid Härdeman protocols = available_protocols; 2394924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 2404924a311SDavid Härdeman return protocols; 2414924a311SDavid Härdeman } 2424924a311SDavid Härdeman 2434924a311SDavid Härdeman static int change_protocol(struct rc_dev *dev, u64 *rc_type) 2444924a311SDavid Härdeman { 2454924a311SDavid Härdeman /* the caller will update dev->enabled_protocols */ 2464924a311SDavid Härdeman return 0; 2474924a311SDavid Härdeman } 2484924a311SDavid Härdeman 2494924a311SDavid Härdeman /* 2504924a311SDavid Härdeman * Used to (un)register raw event clients 2514924a311SDavid Härdeman */ 2524924a311SDavid Härdeman int ir_raw_event_register(struct rc_dev *dev) 2534924a311SDavid Härdeman { 2544924a311SDavid Härdeman int rc; 2554924a311SDavid Härdeman struct ir_raw_handler *handler; 2564924a311SDavid Härdeman 2574924a311SDavid Härdeman if (!dev) 2584924a311SDavid Härdeman return -EINVAL; 2594924a311SDavid Härdeman 2604924a311SDavid Härdeman dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL); 2614924a311SDavid Härdeman if (!dev->raw) 2624924a311SDavid Härdeman return -ENOMEM; 2634924a311SDavid Härdeman 2644924a311SDavid Härdeman dev->raw->dev = dev; 2654924a311SDavid Härdeman dev->enabled_protocols = ~0; 2664924a311SDavid Härdeman dev->change_protocol = change_protocol; 2674924a311SDavid Härdeman rc = kfifo_alloc(&dev->raw->kfifo, 2684924a311SDavid Härdeman sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, 2694924a311SDavid Härdeman GFP_KERNEL); 2704924a311SDavid Härdeman if (rc < 0) 2714924a311SDavid Härdeman goto out; 2724924a311SDavid Härdeman 2734924a311SDavid Härdeman spin_lock_init(&dev->raw->lock); 2744924a311SDavid Härdeman dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, 2754924a311SDavid Härdeman "rc%ld", dev->devno); 2764924a311SDavid Härdeman 2774924a311SDavid Härdeman if (IS_ERR(dev->raw->thread)) { 2784924a311SDavid Härdeman rc = PTR_ERR(dev->raw->thread); 2794924a311SDavid Härdeman goto out; 2804924a311SDavid Härdeman } 2814924a311SDavid Härdeman 2824924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 2834924a311SDavid Härdeman list_add_tail(&dev->raw->list, &ir_raw_client_list); 2844924a311SDavid Härdeman list_for_each_entry(handler, &ir_raw_handler_list, list) 2854924a311SDavid Härdeman if (handler->raw_register) 2864924a311SDavid Härdeman handler->raw_register(dev); 2874924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 2884924a311SDavid Härdeman 2894924a311SDavid Härdeman return 0; 2904924a311SDavid Härdeman 2914924a311SDavid Härdeman out: 2924924a311SDavid Härdeman kfree(dev->raw); 2934924a311SDavid Härdeman dev->raw = NULL; 2944924a311SDavid Härdeman return rc; 2954924a311SDavid Härdeman } 2964924a311SDavid Härdeman 2974924a311SDavid Härdeman void ir_raw_event_unregister(struct rc_dev *dev) 2984924a311SDavid Härdeman { 2994924a311SDavid Härdeman struct ir_raw_handler *handler; 3004924a311SDavid Härdeman 3014924a311SDavid Härdeman if (!dev || !dev->raw) 3024924a311SDavid Härdeman return; 3034924a311SDavid Härdeman 3044924a311SDavid Härdeman kthread_stop(dev->raw->thread); 3054924a311SDavid Härdeman 3064924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 3074924a311SDavid Härdeman list_del(&dev->raw->list); 3084924a311SDavid Härdeman list_for_each_entry(handler, &ir_raw_handler_list, list) 3094924a311SDavid Härdeman if (handler->raw_unregister) 3104924a311SDavid Härdeman handler->raw_unregister(dev); 3114924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 3124924a311SDavid Härdeman 3134924a311SDavid Härdeman kfifo_free(&dev->raw->kfifo); 3144924a311SDavid Härdeman kfree(dev->raw); 3154924a311SDavid Härdeman dev->raw = NULL; 3164924a311SDavid Härdeman } 3174924a311SDavid Härdeman 3184924a311SDavid Härdeman /* 3194924a311SDavid Härdeman * Extension interface - used to register the IR decoders 3204924a311SDavid Härdeman */ 3214924a311SDavid Härdeman 3224924a311SDavid Härdeman int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) 3234924a311SDavid Härdeman { 3244924a311SDavid Härdeman struct ir_raw_event_ctrl *raw; 3254924a311SDavid Härdeman 3264924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 3274924a311SDavid Härdeman list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); 3284924a311SDavid Härdeman if (ir_raw_handler->raw_register) 3294924a311SDavid Härdeman list_for_each_entry(raw, &ir_raw_client_list, list) 3304924a311SDavid Härdeman ir_raw_handler->raw_register(raw->dev); 3314924a311SDavid Härdeman available_protocols |= ir_raw_handler->protocols; 3324924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 3334924a311SDavid Härdeman 3344924a311SDavid Härdeman return 0; 3354924a311SDavid Härdeman } 3364924a311SDavid Härdeman EXPORT_SYMBOL(ir_raw_handler_register); 3374924a311SDavid Härdeman 3384924a311SDavid Härdeman void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) 3394924a311SDavid Härdeman { 3404924a311SDavid Härdeman struct ir_raw_event_ctrl *raw; 3414924a311SDavid Härdeman 3424924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 3434924a311SDavid Härdeman list_del(&ir_raw_handler->list); 3444924a311SDavid Härdeman if (ir_raw_handler->raw_unregister) 3454924a311SDavid Härdeman list_for_each_entry(raw, &ir_raw_client_list, list) 3464924a311SDavid Härdeman ir_raw_handler->raw_unregister(raw->dev); 3474924a311SDavid Härdeman available_protocols &= ~ir_raw_handler->protocols; 3484924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 3494924a311SDavid Härdeman } 3504924a311SDavid Härdeman EXPORT_SYMBOL(ir_raw_handler_unregister); 3514924a311SDavid Härdeman 3524924a311SDavid Härdeman void ir_raw_init(void) 3534924a311SDavid Härdeman { 3544924a311SDavid Härdeman /* Load the decoder modules */ 3554924a311SDavid Härdeman 3564924a311SDavid Härdeman load_nec_decode(); 3574924a311SDavid Härdeman load_rc5_decode(); 3584924a311SDavid Härdeman load_rc6_decode(); 3594924a311SDavid Härdeman load_jvc_decode(); 3604924a311SDavid Härdeman load_sony_decode(); 3614924a311SDavid Härdeman load_sanyo_decode(); 3624924a311SDavid Härdeman load_sharp_decode(); 3634924a311SDavid Härdeman load_mce_kbd_decode(); 3644924a311SDavid Härdeman load_lirc_codec(); 3654924a311SDavid Härdeman 3664924a311SDavid Härdeman /* If needed, we may later add some init code. In this case, 3674924a311SDavid Härdeman it is needed to change the CONFIG_MODULE test at rc-core.h 3684924a311SDavid Härdeman */ 3694924a311SDavid Härdeman } 370