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 "rc-core-priv.h" 214924a311SDavid Härdeman 224924a311SDavid Härdeman /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ 234924a311SDavid Härdeman static LIST_HEAD(ir_raw_client_list); 244924a311SDavid Härdeman 254924a311SDavid Härdeman /* Used to handle IR raw handler extensions */ 264924a311SDavid Härdeman static DEFINE_MUTEX(ir_raw_handler_lock); 274924a311SDavid Härdeman static LIST_HEAD(ir_raw_handler_list); 2837e90a22SHeiner Kallweit static atomic64_t available_protocols = ATOMIC64_INIT(0); 294924a311SDavid Härdeman 304924a311SDavid Härdeman static int ir_raw_event_thread(void *data) 314924a311SDavid Härdeman { 324924a311SDavid Härdeman struct ir_raw_event ev; 334924a311SDavid Härdeman struct ir_raw_handler *handler; 344924a311SDavid Härdeman struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; 354924a311SDavid Härdeman 3674d47d75SHeiner Kallweit while (1) { 374924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 3874d47d75SHeiner Kallweit while (kfifo_out(&raw->kfifo, &ev, 1)) { 394924a311SDavid Härdeman list_for_each_entry(handler, &ir_raw_handler_list, list) 4074d47d75SHeiner Kallweit if (raw->dev->enabled_protocols & 4174d47d75SHeiner Kallweit handler->protocols || !handler->protocols) 424924a311SDavid Härdeman handler->decode(raw->dev, ev); 434924a311SDavid Härdeman raw->prev_ev = ev; 4474d47d75SHeiner Kallweit } 454924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 4674d47d75SHeiner Kallweit 4774d47d75SHeiner Kallweit set_current_state(TASK_INTERRUPTIBLE); 4874d47d75SHeiner Kallweit 4974d47d75SHeiner Kallweit if (kthread_should_stop()) { 5074d47d75SHeiner Kallweit __set_current_state(TASK_RUNNING); 5174d47d75SHeiner Kallweit break; 5274d47d75SHeiner Kallweit } else if (!kfifo_is_empty(&raw->kfifo)) 5374d47d75SHeiner Kallweit set_current_state(TASK_RUNNING); 5474d47d75SHeiner Kallweit 5574d47d75SHeiner Kallweit schedule(); 564924a311SDavid Härdeman } 574924a311SDavid Härdeman 584924a311SDavid Härdeman return 0; 594924a311SDavid Härdeman } 604924a311SDavid Härdeman 614924a311SDavid Härdeman /** 624924a311SDavid Härdeman * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders 634924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 644924a311SDavid Härdeman * @ev: the struct ir_raw_event descriptor of the pulse/space 654924a311SDavid Härdeman * 664924a311SDavid Härdeman * This routine (which may be called from an interrupt context) stores a 674924a311SDavid Härdeman * pulse/space duration for the raw ir decoding state machines. Pulses are 684924a311SDavid Härdeman * signalled as positive values and spaces as negative values. A zero value 694924a311SDavid Härdeman * will reset the decoding state machines. 704924a311SDavid Härdeman */ 714924a311SDavid Härdeman int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) 724924a311SDavid Härdeman { 734924a311SDavid Härdeman if (!dev->raw) 744924a311SDavid Härdeman return -EINVAL; 754924a311SDavid Härdeman 764924a311SDavid Härdeman IR_dprintk(2, "sample: (%05dus %s)\n", 774924a311SDavid Härdeman TO_US(ev->duration), TO_STR(ev->pulse)); 784924a311SDavid Härdeman 79464254e5SHeiner Kallweit if (!kfifo_put(&dev->raw->kfifo, *ev)) { 80464254e5SHeiner Kallweit dev_err(&dev->dev, "IR event FIFO is full!\n"); 81464254e5SHeiner Kallweit return -ENOSPC; 82464254e5SHeiner Kallweit } 834924a311SDavid Härdeman 844924a311SDavid Härdeman return 0; 854924a311SDavid Härdeman } 864924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store); 874924a311SDavid Härdeman 884924a311SDavid Härdeman /** 894924a311SDavid Härdeman * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space 904924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 914924a311SDavid Härdeman * @type: the type of the event that has occurred 924924a311SDavid Härdeman * 934924a311SDavid Härdeman * This routine (which may be called from an interrupt context) is used to 944924a311SDavid Härdeman * store the beginning of an ir pulse or space (or the start/end of ir 954924a311SDavid Härdeman * reception) for the raw ir decoding state machines. This is used by 964924a311SDavid Härdeman * hardware which does not provide durations directly but only interrupts 974924a311SDavid Härdeman * (or similar events) on state change. 984924a311SDavid Härdeman */ 994924a311SDavid Härdeman int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) 1004924a311SDavid Härdeman { 1014924a311SDavid Härdeman ktime_t now; 1024924a311SDavid Härdeman s64 delta; /* ns */ 1034924a311SDavid Härdeman DEFINE_IR_RAW_EVENT(ev); 1044924a311SDavid Härdeman int rc = 0; 1054924a311SDavid Härdeman int delay; 1064924a311SDavid Härdeman 1074924a311SDavid Härdeman if (!dev->raw) 1084924a311SDavid Härdeman return -EINVAL; 1094924a311SDavid Härdeman 1104924a311SDavid Härdeman now = ktime_get(); 1114924a311SDavid Härdeman delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); 1124924a311SDavid Härdeman delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]); 1134924a311SDavid Härdeman 1144924a311SDavid Härdeman /* Check for a long duration since last event or if we're 1154924a311SDavid Härdeman * being called for the first time, note that delta can't 1164924a311SDavid Härdeman * possibly be negative. 1174924a311SDavid Härdeman */ 1184924a311SDavid Härdeman if (delta > delay || !dev->raw->last_type) 1194924a311SDavid Härdeman type |= IR_START_EVENT; 1204924a311SDavid Härdeman else 1214924a311SDavid Härdeman ev.duration = delta; 1224924a311SDavid Härdeman 1234924a311SDavid Härdeman if (type & IR_START_EVENT) 1244924a311SDavid Härdeman ir_raw_event_reset(dev); 1254924a311SDavid Härdeman else if (dev->raw->last_type & IR_SPACE) { 1264924a311SDavid Härdeman ev.pulse = false; 1274924a311SDavid Härdeman rc = ir_raw_event_store(dev, &ev); 1284924a311SDavid Härdeman } else if (dev->raw->last_type & IR_PULSE) { 1294924a311SDavid Härdeman ev.pulse = true; 1304924a311SDavid Härdeman rc = ir_raw_event_store(dev, &ev); 1314924a311SDavid Härdeman } else 1324924a311SDavid Härdeman return 0; 1334924a311SDavid Härdeman 1344924a311SDavid Härdeman dev->raw->last_event = now; 1354924a311SDavid Härdeman dev->raw->last_type = type; 1364924a311SDavid Härdeman return rc; 1374924a311SDavid Härdeman } 1384924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); 1394924a311SDavid Härdeman 1404924a311SDavid Härdeman /** 1414924a311SDavid Härdeman * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing 1424924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 1434924a311SDavid Härdeman * @type: the type of the event that has occurred 1444924a311SDavid Härdeman * 1454924a311SDavid Härdeman * This routine (which may be called from an interrupt context) works 1464924a311SDavid Härdeman * in similar manner to ir_raw_event_store_edge. 1474924a311SDavid Härdeman * This routine is intended for devices with limited internal buffer 1484924a311SDavid Härdeman * It automerges samples of same type, and handles timeouts. Returns non-zero 1494924a311SDavid Härdeman * if the event was added, and zero if the event was ignored due to idle 1504924a311SDavid Härdeman * processing. 1514924a311SDavid Härdeman */ 1524924a311SDavid Härdeman int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev) 1534924a311SDavid Härdeman { 1544924a311SDavid Härdeman if (!dev->raw) 1554924a311SDavid Härdeman return -EINVAL; 1564924a311SDavid Härdeman 1574924a311SDavid Härdeman /* Ignore spaces in idle mode */ 1584924a311SDavid Härdeman if (dev->idle && !ev->pulse) 1594924a311SDavid Härdeman return 0; 1604924a311SDavid Härdeman else if (dev->idle) 1614924a311SDavid Härdeman ir_raw_event_set_idle(dev, false); 1624924a311SDavid Härdeman 1634924a311SDavid Härdeman if (!dev->raw->this_ev.duration) 1644924a311SDavid Härdeman dev->raw->this_ev = *ev; 1654924a311SDavid Härdeman else if (ev->pulse == dev->raw->this_ev.pulse) 1664924a311SDavid Härdeman dev->raw->this_ev.duration += ev->duration; 1674924a311SDavid Härdeman else { 1684924a311SDavid Härdeman ir_raw_event_store(dev, &dev->raw->this_ev); 1694924a311SDavid Härdeman dev->raw->this_ev = *ev; 1704924a311SDavid Härdeman } 1714924a311SDavid Härdeman 1724924a311SDavid Härdeman /* Enter idle mode if nessesary */ 1734924a311SDavid Härdeman if (!ev->pulse && dev->timeout && 1744924a311SDavid Härdeman dev->raw->this_ev.duration >= dev->timeout) 1754924a311SDavid Härdeman ir_raw_event_set_idle(dev, true); 1764924a311SDavid Härdeman 1774924a311SDavid Härdeman return 1; 1784924a311SDavid Härdeman } 1794924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); 1804924a311SDavid Härdeman 1814924a311SDavid Härdeman /** 1824924a311SDavid Härdeman * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not 1834924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 1844924a311SDavid Härdeman * @idle: whether the device is idle or not 1854924a311SDavid Härdeman */ 1864924a311SDavid Härdeman void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) 1874924a311SDavid Härdeman { 1884924a311SDavid Härdeman if (!dev->raw) 1894924a311SDavid Härdeman return; 1904924a311SDavid Härdeman 1914924a311SDavid Härdeman IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); 1924924a311SDavid Härdeman 1934924a311SDavid Härdeman if (idle) { 1944924a311SDavid Härdeman dev->raw->this_ev.timeout = true; 1954924a311SDavid Härdeman ir_raw_event_store(dev, &dev->raw->this_ev); 1964924a311SDavid Härdeman init_ir_raw_event(&dev->raw->this_ev); 1974924a311SDavid Härdeman } 1984924a311SDavid Härdeman 1994924a311SDavid Härdeman if (dev->s_idle) 2004924a311SDavid Härdeman dev->s_idle(dev, idle); 2014924a311SDavid Härdeman 2024924a311SDavid Härdeman dev->idle = idle; 2034924a311SDavid Härdeman } 2044924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); 2054924a311SDavid Härdeman 2064924a311SDavid Härdeman /** 2074924a311SDavid Härdeman * ir_raw_event_handle() - schedules the decoding of stored ir data 2084924a311SDavid Härdeman * @dev: the struct rc_dev device descriptor 2094924a311SDavid Härdeman * 2104924a311SDavid Härdeman * This routine will tell rc-core to start decoding stored ir data. 2114924a311SDavid Härdeman */ 2124924a311SDavid Härdeman void ir_raw_event_handle(struct rc_dev *dev) 2134924a311SDavid Härdeman { 214963761a0SSean Young if (!dev->raw || !dev->raw->thread) 2154924a311SDavid Härdeman return; 2164924a311SDavid Härdeman 2174924a311SDavid Härdeman wake_up_process(dev->raw->thread); 2184924a311SDavid Härdeman } 2194924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_handle); 2204924a311SDavid Härdeman 2214924a311SDavid Härdeman /* used internally by the sysfs interface */ 2224924a311SDavid Härdeman u64 2234924a311SDavid Härdeman ir_raw_get_allowed_protocols(void) 2244924a311SDavid Härdeman { 22537e90a22SHeiner Kallweit return atomic64_read(&available_protocols); 2264924a311SDavid Härdeman } 2274924a311SDavid Härdeman 2284924a311SDavid Härdeman static int change_protocol(struct rc_dev *dev, u64 *rc_type) 2294924a311SDavid Härdeman { 2304924a311SDavid Härdeman /* the caller will update dev->enabled_protocols */ 2314924a311SDavid Härdeman return 0; 2324924a311SDavid Härdeman } 2334924a311SDavid Härdeman 23493cffffcSHeiner Kallweit static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols) 23593cffffcSHeiner Kallweit { 23693cffffcSHeiner Kallweit mutex_lock(&dev->lock); 23793cffffcSHeiner Kallweit dev->enabled_protocols &= ~protocols; 23893cffffcSHeiner Kallweit mutex_unlock(&dev->lock); 23993cffffcSHeiner Kallweit } 24093cffffcSHeiner Kallweit 2413875233dSJames Hogan /** 242844a4f45SAntti Seppälä * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation. 243844a4f45SAntti Seppälä * @ev: Pointer to pointer to next free event. *@ev is incremented for 244844a4f45SAntti Seppälä * each raw event filled. 245844a4f45SAntti Seppälä * @max: Maximum number of raw events to fill. 246844a4f45SAntti Seppälä * @timings: Manchester modulation timings. 247844a4f45SAntti Seppälä * @n: Number of bits of data. 248844a4f45SAntti Seppälä * @data: Data bits to encode. 249844a4f45SAntti Seppälä * 250844a4f45SAntti Seppälä * Encodes the @n least significant bits of @data using Manchester (bi-phase) 251844a4f45SAntti Seppälä * modulation with the timing characteristics described by @timings, writing up 252844a4f45SAntti Seppälä * to @max raw IR events using the *@ev pointer. 253844a4f45SAntti Seppälä * 254844a4f45SAntti Seppälä * Returns: 0 on success. 255844a4f45SAntti Seppälä * -ENOBUFS if there isn't enough space in the array to fit the 256844a4f45SAntti Seppälä * full encoded data. In this case all @max events will have been 257844a4f45SAntti Seppälä * written. 258844a4f45SAntti Seppälä */ 259844a4f45SAntti Seppälä int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, 260844a4f45SAntti Seppälä const struct ir_raw_timings_manchester *timings, 261b73bc16dSSean Young unsigned int n, u64 data) 262844a4f45SAntti Seppälä { 263844a4f45SAntti Seppälä bool need_pulse; 264b73bc16dSSean Young u64 i; 265844a4f45SAntti Seppälä int ret = -ENOBUFS; 266844a4f45SAntti Seppälä 267b73bc16dSSean Young i = BIT_ULL(n - 1); 268844a4f45SAntti Seppälä 269844a4f45SAntti Seppälä if (timings->leader) { 270844a4f45SAntti Seppälä if (!max--) 271844a4f45SAntti Seppälä return ret; 272844a4f45SAntti Seppälä if (timings->pulse_space_start) { 273844a4f45SAntti Seppälä init_ir_raw_event_duration((*ev)++, 1, timings->leader); 274844a4f45SAntti Seppälä 275844a4f45SAntti Seppälä if (!max--) 276844a4f45SAntti Seppälä return ret; 277844a4f45SAntti Seppälä init_ir_raw_event_duration((*ev), 0, timings->leader); 278844a4f45SAntti Seppälä } else { 279844a4f45SAntti Seppälä init_ir_raw_event_duration((*ev), 1, timings->leader); 280844a4f45SAntti Seppälä } 281844a4f45SAntti Seppälä i >>= 1; 282844a4f45SAntti Seppälä } else { 283844a4f45SAntti Seppälä /* continue existing signal */ 284844a4f45SAntti Seppälä --(*ev); 285844a4f45SAntti Seppälä } 286844a4f45SAntti Seppälä /* from here on *ev will point to the last event rather than the next */ 287844a4f45SAntti Seppälä 288844a4f45SAntti Seppälä while (n && i > 0) { 289844a4f45SAntti Seppälä need_pulse = !(data & i); 290844a4f45SAntti Seppälä if (timings->invert) 291844a4f45SAntti Seppälä need_pulse = !need_pulse; 292844a4f45SAntti Seppälä if (need_pulse == !!(*ev)->pulse) { 293844a4f45SAntti Seppälä (*ev)->duration += timings->clock; 294844a4f45SAntti Seppälä } else { 295844a4f45SAntti Seppälä if (!max--) 296844a4f45SAntti Seppälä goto nobufs; 297844a4f45SAntti Seppälä init_ir_raw_event_duration(++(*ev), need_pulse, 298844a4f45SAntti Seppälä timings->clock); 299844a4f45SAntti Seppälä } 300844a4f45SAntti Seppälä 301844a4f45SAntti Seppälä if (!max--) 302844a4f45SAntti Seppälä goto nobufs; 303844a4f45SAntti Seppälä init_ir_raw_event_duration(++(*ev), !need_pulse, 304844a4f45SAntti Seppälä timings->clock); 305844a4f45SAntti Seppälä i >>= 1; 306844a4f45SAntti Seppälä } 307844a4f45SAntti Seppälä 308844a4f45SAntti Seppälä if (timings->trailer_space) { 309844a4f45SAntti Seppälä if (!(*ev)->pulse) 310844a4f45SAntti Seppälä (*ev)->duration += timings->trailer_space; 311844a4f45SAntti Seppälä else if (!max--) 312844a4f45SAntti Seppälä goto nobufs; 313844a4f45SAntti Seppälä else 314844a4f45SAntti Seppälä init_ir_raw_event_duration(++(*ev), 0, 315844a4f45SAntti Seppälä timings->trailer_space); 316844a4f45SAntti Seppälä } 317844a4f45SAntti Seppälä 318844a4f45SAntti Seppälä ret = 0; 319844a4f45SAntti Seppälä nobufs: 320844a4f45SAntti Seppälä /* point to the next event rather than last event before returning */ 321844a4f45SAntti Seppälä ++(*ev); 322844a4f45SAntti Seppälä return ret; 323844a4f45SAntti Seppälä } 324844a4f45SAntti Seppälä EXPORT_SYMBOL(ir_raw_gen_manchester); 325844a4f45SAntti Seppälä 326844a4f45SAntti Seppälä /** 327caec0984SJames Hogan * ir_raw_gen_pd() - Encode data to raw events with pulse-distance modulation. 328caec0984SJames Hogan * @ev: Pointer to pointer to next free event. *@ev is incremented for 329caec0984SJames Hogan * each raw event filled. 330caec0984SJames Hogan * @max: Maximum number of raw events to fill. 331caec0984SJames Hogan * @timings: Pulse distance modulation timings. 332caec0984SJames Hogan * @n: Number of bits of data. 333caec0984SJames Hogan * @data: Data bits to encode. 334caec0984SJames Hogan * 335caec0984SJames Hogan * Encodes the @n least significant bits of @data using pulse-distance 336caec0984SJames Hogan * modulation with the timing characteristics described by @timings, writing up 337caec0984SJames Hogan * to @max raw IR events using the *@ev pointer. 338caec0984SJames Hogan * 339caec0984SJames Hogan * Returns: 0 on success. 340caec0984SJames Hogan * -ENOBUFS if there isn't enough space in the array to fit the 341caec0984SJames Hogan * full encoded data. In this case all @max events will have been 342caec0984SJames Hogan * written. 343caec0984SJames Hogan */ 344caec0984SJames Hogan int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max, 345caec0984SJames Hogan const struct ir_raw_timings_pd *timings, 346caec0984SJames Hogan unsigned int n, u64 data) 347caec0984SJames Hogan { 348caec0984SJames Hogan int i; 349caec0984SJames Hogan int ret; 350caec0984SJames Hogan unsigned int space; 351caec0984SJames Hogan 352caec0984SJames Hogan if (timings->header_pulse) { 353caec0984SJames Hogan ret = ir_raw_gen_pulse_space(ev, &max, timings->header_pulse, 354caec0984SJames Hogan timings->header_space); 355caec0984SJames Hogan if (ret) 356caec0984SJames Hogan return ret; 357caec0984SJames Hogan } 358caec0984SJames Hogan 359caec0984SJames Hogan if (timings->msb_first) { 360caec0984SJames Hogan for (i = n - 1; i >= 0; --i) { 361caec0984SJames Hogan space = timings->bit_space[(data >> i) & 1]; 362caec0984SJames Hogan ret = ir_raw_gen_pulse_space(ev, &max, 363caec0984SJames Hogan timings->bit_pulse, 364caec0984SJames Hogan space); 365caec0984SJames Hogan if (ret) 366caec0984SJames Hogan return ret; 367caec0984SJames Hogan } 368caec0984SJames Hogan } else { 369caec0984SJames Hogan for (i = 0; i < n; ++i, data >>= 1) { 370caec0984SJames Hogan space = timings->bit_space[data & 1]; 371caec0984SJames Hogan ret = ir_raw_gen_pulse_space(ev, &max, 372caec0984SJames Hogan timings->bit_pulse, 373caec0984SJames Hogan space); 374caec0984SJames Hogan if (ret) 375caec0984SJames Hogan return ret; 376caec0984SJames Hogan } 377caec0984SJames Hogan } 378caec0984SJames Hogan 379caec0984SJames Hogan ret = ir_raw_gen_pulse_space(ev, &max, timings->trailer_pulse, 380caec0984SJames Hogan timings->trailer_space); 381caec0984SJames Hogan return ret; 382caec0984SJames Hogan } 383caec0984SJames Hogan EXPORT_SYMBOL(ir_raw_gen_pd); 384caec0984SJames Hogan 385caec0984SJames Hogan /** 386103293beSSean Young * ir_raw_gen_pl() - Encode data to raw events with pulse-length modulation. 387103293beSSean Young * @ev: Pointer to pointer to next free event. *@ev is incremented for 388103293beSSean Young * each raw event filled. 389103293beSSean Young * @max: Maximum number of raw events to fill. 390103293beSSean Young * @timings: Pulse distance modulation timings. 391103293beSSean Young * @n: Number of bits of data. 392103293beSSean Young * @data: Data bits to encode. 393103293beSSean Young * 394103293beSSean Young * Encodes the @n least significant bits of @data using space-distance 395103293beSSean Young * modulation with the timing characteristics described by @timings, writing up 396103293beSSean Young * to @max raw IR events using the *@ev pointer. 397103293beSSean Young * 398103293beSSean Young * Returns: 0 on success. 399103293beSSean Young * -ENOBUFS if there isn't enough space in the array to fit the 400103293beSSean Young * full encoded data. In this case all @max events will have been 401103293beSSean Young * written. 402103293beSSean Young */ 403103293beSSean Young int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max, 404103293beSSean Young const struct ir_raw_timings_pl *timings, 405103293beSSean Young unsigned int n, u64 data) 406103293beSSean Young { 407103293beSSean Young int i; 408103293beSSean Young int ret = -ENOBUFS; 409103293beSSean Young unsigned int pulse; 410103293beSSean Young 411103293beSSean Young if (!max--) 412103293beSSean Young return ret; 413103293beSSean Young 414103293beSSean Young init_ir_raw_event_duration((*ev)++, 1, timings->header_pulse); 415103293beSSean Young 416103293beSSean Young if (timings->msb_first) { 417103293beSSean Young for (i = n - 1; i >= 0; --i) { 418103293beSSean Young if (!max--) 419103293beSSean Young return ret; 420103293beSSean Young init_ir_raw_event_duration((*ev)++, 0, 421103293beSSean Young timings->bit_space); 422103293beSSean Young if (!max--) 423103293beSSean Young return ret; 424103293beSSean Young pulse = timings->bit_pulse[(data >> i) & 1]; 425103293beSSean Young init_ir_raw_event_duration((*ev)++, 1, pulse); 426103293beSSean Young } 427103293beSSean Young } else { 428103293beSSean Young for (i = 0; i < n; ++i, data >>= 1) { 429103293beSSean Young if (!max--) 430103293beSSean Young return ret; 431103293beSSean Young init_ir_raw_event_duration((*ev)++, 0, 432103293beSSean Young timings->bit_space); 433103293beSSean Young if (!max--) 434103293beSSean Young return ret; 435103293beSSean Young pulse = timings->bit_pulse[data & 1]; 436103293beSSean Young init_ir_raw_event_duration((*ev)++, 1, pulse); 437103293beSSean Young } 438103293beSSean Young } 439103293beSSean Young 440103293beSSean Young if (!max--) 441103293beSSean Young return ret; 442103293beSSean Young 443103293beSSean Young init_ir_raw_event_duration((*ev)++, 0, timings->trailer_space); 444103293beSSean Young 445103293beSSean Young return 0; 446103293beSSean Young } 447103293beSSean Young EXPORT_SYMBOL(ir_raw_gen_pl); 448103293beSSean Young 449103293beSSean Young /** 4503875233dSJames Hogan * ir_raw_encode_scancode() - Encode a scancode as raw events 4513875233dSJames Hogan * 4523875233dSJames Hogan * @protocol: protocol 4533875233dSJames Hogan * @scancode: scancode filter describing a single scancode 4543875233dSJames Hogan * @events: array of raw events to write into 4553875233dSJames Hogan * @max: max number of raw events 4563875233dSJames Hogan * 4573875233dSJames Hogan * Attempts to encode the scancode as raw events. 4583875233dSJames Hogan * 4593875233dSJames Hogan * Returns: The number of events written. 4603875233dSJames Hogan * -ENOBUFS if there isn't enough space in the array to fit the 4613875233dSJames Hogan * encoding. In this case all @max events will have been written. 4623875233dSJames Hogan * -EINVAL if the scancode is ambiguous or invalid, or if no 4633875233dSJames Hogan * compatible encoder was found. 4643875233dSJames Hogan */ 4653875233dSJames Hogan int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode, 4663875233dSJames Hogan struct ir_raw_event *events, unsigned int max) 4673875233dSJames Hogan { 4683875233dSJames Hogan struct ir_raw_handler *handler; 4693875233dSJames Hogan int ret = -EINVAL; 4703875233dSJames Hogan u64 mask = 1ULL << protocol; 4713875233dSJames Hogan 4723875233dSJames Hogan mutex_lock(&ir_raw_handler_lock); 4733875233dSJames Hogan list_for_each_entry(handler, &ir_raw_handler_list, list) { 4743875233dSJames Hogan if (handler->protocols & mask && handler->encode) { 4753875233dSJames Hogan ret = handler->encode(protocol, scancode, events, max); 4763875233dSJames Hogan if (ret >= 0 || ret == -ENOBUFS) 4773875233dSJames Hogan break; 4783875233dSJames Hogan } 4793875233dSJames Hogan } 4803875233dSJames Hogan mutex_unlock(&ir_raw_handler_lock); 4813875233dSJames Hogan 4823875233dSJames Hogan return ret; 4833875233dSJames Hogan } 4843875233dSJames Hogan EXPORT_SYMBOL(ir_raw_encode_scancode); 4853875233dSJames Hogan 4864924a311SDavid Härdeman /* 4874924a311SDavid Härdeman * Used to (un)register raw event clients 4884924a311SDavid Härdeman */ 4894924a311SDavid Härdeman int ir_raw_event_register(struct rc_dev *dev) 4904924a311SDavid Härdeman { 4914924a311SDavid Härdeman int rc; 4924924a311SDavid Härdeman struct ir_raw_handler *handler; 493963761a0SSean Young struct task_struct *thread; 4944924a311SDavid Härdeman 4954924a311SDavid Härdeman if (!dev) 4964924a311SDavid Härdeman return -EINVAL; 4974924a311SDavid Härdeman 4984924a311SDavid Härdeman dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL); 4994924a311SDavid Härdeman if (!dev->raw) 5004924a311SDavid Härdeman return -ENOMEM; 5014924a311SDavid Härdeman 5024924a311SDavid Härdeman dev->raw->dev = dev; 5034924a311SDavid Härdeman dev->change_protocol = change_protocol; 504464254e5SHeiner Kallweit INIT_KFIFO(dev->raw->kfifo); 5054924a311SDavid Härdeman 506d5083677SAndi Shyti /* 507d5083677SAndi Shyti * raw transmitters do not need any event registration 508d5083677SAndi Shyti * because the event is coming from userspace 509d5083677SAndi Shyti */ 510d5083677SAndi Shyti if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { 511963761a0SSean Young thread = kthread_run(ir_raw_event_thread, dev->raw, "rc%u", 512963761a0SSean Young dev->minor); 5134924a311SDavid Härdeman 514963761a0SSean Young if (IS_ERR(thread)) { 515963761a0SSean Young rc = PTR_ERR(thread); 5164924a311SDavid Härdeman goto out; 5174924a311SDavid Härdeman } 518963761a0SSean Young 519963761a0SSean Young dev->raw->thread = thread; 520d5083677SAndi Shyti } 5214924a311SDavid Härdeman 5224924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 5234924a311SDavid Härdeman list_add_tail(&dev->raw->list, &ir_raw_client_list); 5244924a311SDavid Härdeman list_for_each_entry(handler, &ir_raw_handler_list, list) 5254924a311SDavid Härdeman if (handler->raw_register) 5264924a311SDavid Härdeman handler->raw_register(dev); 5274924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 5284924a311SDavid Härdeman 5294924a311SDavid Härdeman return 0; 5304924a311SDavid Härdeman 5314924a311SDavid Härdeman out: 5324924a311SDavid Härdeman kfree(dev->raw); 5334924a311SDavid Härdeman dev->raw = NULL; 5344924a311SDavid Härdeman return rc; 5354924a311SDavid Härdeman } 5364924a311SDavid Härdeman 5374924a311SDavid Härdeman void ir_raw_event_unregister(struct rc_dev *dev) 5384924a311SDavid Härdeman { 5394924a311SDavid Härdeman struct ir_raw_handler *handler; 5404924a311SDavid Härdeman 5414924a311SDavid Härdeman if (!dev || !dev->raw) 5424924a311SDavid Härdeman return; 5434924a311SDavid Härdeman 5444924a311SDavid Härdeman kthread_stop(dev->raw->thread); 5454924a311SDavid Härdeman 5464924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 5474924a311SDavid Härdeman list_del(&dev->raw->list); 5484924a311SDavid Härdeman list_for_each_entry(handler, &ir_raw_handler_list, list) 5494924a311SDavid Härdeman if (handler->raw_unregister) 5504924a311SDavid Härdeman handler->raw_unregister(dev); 5514924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 5524924a311SDavid Härdeman 5534924a311SDavid Härdeman kfree(dev->raw); 5544924a311SDavid Härdeman dev->raw = NULL; 5554924a311SDavid Härdeman } 5564924a311SDavid Härdeman 5574924a311SDavid Härdeman /* 5584924a311SDavid Härdeman * Extension interface - used to register the IR decoders 5594924a311SDavid Härdeman */ 5604924a311SDavid Härdeman 5614924a311SDavid Härdeman int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) 5624924a311SDavid Härdeman { 5634924a311SDavid Härdeman struct ir_raw_event_ctrl *raw; 5644924a311SDavid Härdeman 5654924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 5664924a311SDavid Härdeman list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); 5674924a311SDavid Härdeman if (ir_raw_handler->raw_register) 5684924a311SDavid Härdeman list_for_each_entry(raw, &ir_raw_client_list, list) 5694924a311SDavid Härdeman ir_raw_handler->raw_register(raw->dev); 57037e90a22SHeiner Kallweit atomic64_or(ir_raw_handler->protocols, &available_protocols); 5714924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 5724924a311SDavid Härdeman 5734924a311SDavid Härdeman return 0; 5744924a311SDavid Härdeman } 5754924a311SDavid Härdeman EXPORT_SYMBOL(ir_raw_handler_register); 5764924a311SDavid Härdeman 5774924a311SDavid Härdeman void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) 5784924a311SDavid Härdeman { 5794924a311SDavid Härdeman struct ir_raw_event_ctrl *raw; 58093cffffcSHeiner Kallweit u64 protocols = ir_raw_handler->protocols; 5814924a311SDavid Härdeman 5824924a311SDavid Härdeman mutex_lock(&ir_raw_handler_lock); 5834924a311SDavid Härdeman list_del(&ir_raw_handler->list); 58493cffffcSHeiner Kallweit list_for_each_entry(raw, &ir_raw_client_list, list) { 58593cffffcSHeiner Kallweit ir_raw_disable_protocols(raw->dev, protocols); 5864924a311SDavid Härdeman if (ir_raw_handler->raw_unregister) 5874924a311SDavid Härdeman ir_raw_handler->raw_unregister(raw->dev); 58893cffffcSHeiner Kallweit } 58937e90a22SHeiner Kallweit atomic64_andnot(protocols, &available_protocols); 5904924a311SDavid Härdeman mutex_unlock(&ir_raw_handler_lock); 5914924a311SDavid Härdeman } 5924924a311SDavid Härdeman EXPORT_SYMBOL(ir_raw_handler_unregister); 593