1fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont/*************************************************************************** 2fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * 3fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * * 4fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * Based on Logitech G13 driver (v0.4) * 5fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * 6fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * * 7fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * This program is free software: you can redistribute it and/or modify * 8fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * it under the terms of the GNU General Public License as published by * 9fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * the Free Software Foundation, version 2 of the License. * 10fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * * 11fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * This driver is distributed in the hope that it will be useful, but * 12fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * WITHOUT ANY WARRANTY; without even the implied warranty of * 13fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * General Public License for more details. * 15fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * * 16fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * You should have received a copy of the GNU General Public License * 17fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont * along with this software. If not see <http://www.gnu.org/licenses/>. * 18fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont ***************************************************************************/ 19fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 20fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/hid.h> 21fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/hid-debug.h> 22fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/input.h> 23fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include "hid-ids.h" 24fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 25fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/fb.h> 26fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/vmalloc.h> 27fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/backlight.h> 28fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/lcd.h> 29fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 30fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/leds.h> 31fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 32fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/seq_file.h> 33fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/debugfs.h> 34fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 35fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/completion.h> 36fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/uaccess.h> 37fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include <linux/module.h> 38ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont#include <media/rc-core.h> 39fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 40fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont#include "hid-picolcd.h" 41fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 42fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 43fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémontint picolcd_raw_cir(struct picolcd_data *data, 44fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont struct hid_report *report, u8 *raw_data, int size) 45fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont{ 46ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont unsigned long flags; 47ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont int i, w, sz; 48ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont DEFINE_IR_RAW_EVENT(rawir); 49ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 50ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont /* ignore if rc_dev is NULL or status is shunned */ 51ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_lock_irqsave(&data->lock, flags); 5202d9be1aa6e93f4819f230a1d570e2ff415fa294Dan Carpenter if (!data->rc_dev || (data->status & PICOLCD_CIR_SHUN)) { 53ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_unlock_irqrestore(&data->lock, flags); 54ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont return 1; 55ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont } 56ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_unlock_irqrestore(&data->lock, flags); 57ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 58ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont /* PicoLCD USB packets contain 16-bit intervals in network order, 59ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * with value negated for pulse. Intervals are in microseconds. 60ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * 61ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * Note: some userspace LIRC code for PicoLCD says negated values 62ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * for space - is it a matter of IR chip? (pulse for my TSOP2236) 63ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * 64ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * In addition, the first interval seems to be around 15000 + base 65ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * interval for non-first report of IR data - thus the quirk below 66ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont * to get RC_CODE to understand Sony and JVC remotes I have at hand 67ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont */ 68ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont sz = size > 0 ? min((int)raw_data[0], size-1) : 0; 69ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont for (i = 0; i+1 < sz; i += 2) { 70ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont init_ir_raw_event(&rawir); 71ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont w = (raw_data[i] << 8) | (raw_data[i+1]); 72ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rawir.pulse = !!(w & 0x8000); 73ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w); 74ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont /* Quirk!! - see above */ 75ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont if (i == 0 && rawir.duration > 15000000) 76ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rawir.duration -= 15000000; 77ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont ir_raw_event_store(data->rc_dev, &rawir); 78ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont } 79ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont ir_raw_event_handle(data->rc_dev); 80ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 81fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont return 1; 82fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont} 83fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 84ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémontstatic int picolcd_cir_open(struct rc_dev *dev) 85ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont{ 86ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont struct picolcd_data *data = dev->priv; 87ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont unsigned long flags; 88ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 89ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_lock_irqsave(&data->lock, flags); 90ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont data->status &= ~PICOLCD_CIR_SHUN; 91ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_unlock_irqrestore(&data->lock, flags); 92ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont return 0; 93ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont} 94ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 95ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémontstatic void picolcd_cir_close(struct rc_dev *dev) 96ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont{ 97ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont struct picolcd_data *data = dev->priv; 98ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont unsigned long flags; 99ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 100ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_lock_irqsave(&data->lock, flags); 101ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont data->status |= PICOLCD_CIR_SHUN; 102ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont spin_unlock_irqrestore(&data->lock, flags); 103ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont} 104ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 105fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont/* initialize CIR input device */ 106fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémontint picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) 107fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont{ 108ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont struct rc_dev *rdev; 109ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont int ret = 0; 110ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 111ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev = rc_allocate_device(); 112ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont if (!rdev) 113ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont return -ENOMEM; 114ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 115ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->priv = data; 116ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->driver_type = RC_DRIVER_IR_RAW; 117c5540fbb9de39ceec108a889133664a887c2f55aDavid Härdeman rdev->allowed_protocols = RC_BIT_ALL; 118ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->open = picolcd_cir_open; 119ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->close = picolcd_cir_close; 120ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->input_name = data->hdev->name; 121ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->input_phys = data->hdev->phys; 122ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->input_id.bustype = data->hdev->bus; 123ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->input_id.vendor = data->hdev->vendor; 124ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->input_id.product = data->hdev->product; 125ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->input_id.version = data->hdev->version; 126ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->dev.parent = &data->hdev->dev; 127ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->driver_name = PICOLCD_NAME; 128ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->map_name = RC_MAP_RC6_MCE; 129ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->timeout = MS_TO_NS(100); 130ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rdev->rx_resolution = US_TO_NS(1); 131ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 132ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont ret = rc_register_device(rdev); 133ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont if (ret) 134ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont goto err; 135ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont data->rc_dev = rdev; 136fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont return 0; 137ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 138ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémonterr: 139ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont rc_free_device(rdev); 140ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont return ret; 141fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont} 142fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 143fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémontvoid picolcd_exit_cir(struct picolcd_data *data) 144fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont{ 145ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont struct rc_dev *rdev = data->rc_dev; 146ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont 147ae08e324146c89f1059e9d3c3898d0260a988795Bruno Prémont data->rc_dev = NULL; 1481cde501bb4655e98fb832194beb88ac73be5a05dBruno Prémont if (rdev) 1491cde501bb4655e98fb832194beb88ac73be5a05dBruno Prémont rc_unregister_device(rdev); 150fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont} 151fabdbf2fd22fa170b4c5340dbdda5c8cd88fb205Bruno Prémont 152