cx231xx-input.c 6.3 KB
Newer Older
1 2 3 4
/*
  handle cx231xx IR remotes via linux kernel input layer.

  Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
5
		Based on em28xx driver
6

7
		< This is a place holder for IR now.>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

  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; either version 2 of the License, or
  (at your option) any later version.

  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.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/usb.h>
30
#include <linux/slab.h>
31 32 33 34 35 36 37

#include "cx231xx.h"

static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");

38 39
#define MODULE_NAME "cx231xx"

40 41
#define i2cdprintk(fmt, arg...) \
	if (ir_debug) { \
42
		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
	}

#define dprintk(fmt, arg...) \
	if (ir_debug) { \
		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
	}

/**********************************************************
 Polling structure used by cx231xx IR's
 **********************************************************/

struct cx231xx_ir_poll_result {
	unsigned int toggle_bit:1;
	unsigned int read_count:7;
	u8 rc_address;
	u8 rc_data[4];
};

struct cx231xx_IR {
	struct cx231xx *dev;
	struct input_dev *input;
64
	struct ir_input_state ir;
65 66 67 68 69 70 71
	char name[32];
	char phys[32];

	/* poll external decoder */
	int polling;
	struct work_struct work;
	struct timer_list timer;
72
	unsigned int last_toggle:1;
73
	unsigned int last_readcount;
74
	unsigned int repeat_interval;
75

76
	int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *);
77 78 79 80 81 82 83 84 85
};

/**********************************************************
 Polling code for cx231xx
 **********************************************************/

static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
{
	int result;
86
	int do_sendkey = 0;
87 88 89 90 91 92 93 94 95 96 97 98 99
	struct cx231xx_ir_poll_result poll_result;

	/* read the registers containing the IR status */
	result = ir->get_key(ir, &poll_result);
	if (result < 0) {
		dprintk("ir->get_key() failed %d\n", result);
		return;
	}

	dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
		poll_result.toggle_bit, poll_result.read_count,
		ir->last_readcount, poll_result.rc_data[0]);

100
	if (ir->dev->chip_id == CHIP_ID_EM2874) {
101 102 103 104 105 106
		/* The em2874 clears the readcount field every time the
		   register is read.  The em2860/2880 datasheet says that it
		   is supposed to clear the readcount, but it doesn't.  So with
		   the em2874, we are looking for a non-zero read count as
		   opposed to a readcount that is incrementing */
		ir->last_readcount = 0;
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	}

	if (poll_result.read_count == 0) {
		/* The button has not been pressed since the last read */
	} else if (ir->last_toggle != poll_result.toggle_bit) {
		/* A button has been pressed */
		dprintk("button has been pressed\n");
		ir->last_toggle = poll_result.toggle_bit;
		ir->repeat_interval = 0;
		do_sendkey = 1;
	} else if (poll_result.toggle_bit == ir->last_toggle &&
		   poll_result.read_count > 0 &&
		   poll_result.read_count != ir->last_readcount) {
		/* The button is still being held down */
		dprintk("button being held down\n");

		/* Debouncer for first keypress */
		if (ir->repeat_interval++ > 9) {
			/* Start repeating after 1 second */
			do_sendkey = 1;
		}
	}
129

130 131 132 133
	if (do_sendkey) {
		dprintk("sending keypress\n");
		ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0]);
		ir_input_nokey(ir->input, &ir->ir);
134
	}
135 136 137

	ir->last_readcount = poll_result.read_count;
	return;
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
}

static void ir_timer(unsigned long data)
{
	struct cx231xx_IR *ir = (struct cx231xx_IR *)data;

	schedule_work(&ir->work);
}

static void cx231xx_ir_work(struct work_struct *work)
{
	struct cx231xx_IR *ir = container_of(work, struct cx231xx_IR, work);

	cx231xx_ir_handle_key(ir);
	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}

void cx231xx_ir_start(struct cx231xx_IR *ir)
{
	setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
	INIT_WORK(&ir->work, cx231xx_ir_work);
	schedule_work(&ir->work);
}

static void cx231xx_ir_stop(struct cx231xx_IR *ir)
{
	del_timer_sync(&ir->timer);
	flush_scheduled_work();
}

int cx231xx_ir_init(struct cx231xx *dev)
{
	struct cx231xx_IR *ir;
	struct input_dev *input_dev;
	u8 ir_config;
	int err = -ENOMEM;

	if (dev->board.ir_codes == NULL) {
		/* No remote control support */
		return 0;
	}

	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
	input_dev = input_allocate_device();
	if (!ir || !input_dev)
		goto err_out_free;

	ir->input = input_dev;

	/* Setup the proper handler based on the chip */
	switch (dev->chip_id) {
189 190 191
	default:
		printk("Unrecognized cx231xx chip id: IR not supported\n");
		goto err_out_free;
192 193 194
	}

	/* This is how often we ask the chip for IR information */
195
	ir->polling = 100;	/* ms */
196 197

	/* init input device */
198
	snprintf(ir->name, sizeof(ir->name), "cx231xx IR (%s)", dev->name);
199 200 201 202

	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
	strlcat(ir->phys, "/input0", sizeof(ir->phys));

203 204 205 206
	err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
	if (err < 0)
		goto err_out_free;

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
	input_dev->name = ir->name;
	input_dev->phys = ir->phys;
	input_dev->id.bustype = BUS_USB;
	input_dev->id.version = 1;
	input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
	input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);

	input_dev->dev.parent = &dev->udev->dev;
	/* record handles to ourself */
	ir->dev = dev;
	dev->ir = ir;

	cx231xx_ir_start(ir);

	/* all done */
222
	err = ir_input_register(ir->input, dev->board.ir_codes,
223
				NULL, MODULE_NAME);
224 225 226 227
	if (err)
		goto err_out_stop;

	return 0;
228
err_out_stop:
229 230
	cx231xx_ir_stop(ir);
	dev->ir = NULL;
231
err_out_free:
232 233 234 235 236 237 238 239 240 241 242 243 244
	kfree(ir);
	return err;
}

int cx231xx_ir_fini(struct cx231xx *dev)
{
	struct cx231xx_IR *ir = dev->ir;

	/* skip detach on non attached boards */
	if (!ir)
		return 0;

	cx231xx_ir_stop(ir);
245
	ir_input_unregister(ir->input);
246 247 248 249 250 251
	kfree(ir);

	/* done */
	dev->ir = NULL;
	return 0;
}