sir_ir.c 10.0 KB
Newer Older
1
/*
2
 * IR SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
3
 *
4
 * sir_ir - Device driver for use with SIR (serial infra red)
5 6 7 8 9 10 11 12
 * mode of IrDA on many notebooks.
 *
 *  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.
 */

13 14
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

15 16 17 18
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/serial_reg.h>
19
#include <linux/ktime.h>
20
#include <linux/delay.h>
21
#include <linux/platform_device.h>
22

23
#include <media/rc-core.h>
24 25 26 27 28

/* SECTION: Definitions */
#define PULSE '['

/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/
29
#define TIME_CONST (9000000ul / 115200ul)
30 31

/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */
32
#define SIR_TIMEOUT	(HZ * 5 / 100)
33 34

/* onboard sir ports are typically com3 */
35 36
static int io = 0x3e8;
static int irq = 4;
37 38 39 40 41
static int threshold = 3;

static DEFINE_SPINLOCK(timer_lock);
static struct timer_list timerlist;
/* time of last signal change detected */
42
static ktime_t last;
43
/* time of last UART data ready interrupt */
44
static ktime_t last_intr_time;
45
static int last_value;
46
static struct rc_dev *rcdev;
47

48
static struct platform_device *sir_ir_dev;
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

static DEFINE_SPINLOCK(hardware_lock);

/* SECTION: Prototypes */

/* Communication with user-space */
static void add_read_queue(int flag, unsigned long val);
static int init_chrdev(void);
/* Hardware */
static irqreturn_t sir_interrupt(int irq, void *dev_id);
static void send_space(unsigned long len);
static void send_pulse(unsigned long len);
static int init_hardware(void);
static void drop_hardware(void);
/* Initialisation */
static int init_port(void);
static void drop_port(void);

static inline unsigned int sinp(int offset)
{
	return inb(io + offset);
}

static inline void soutp(int offset, int value)
{
	outb(value, io + offset);
}

/* SECTION: Communication with user-space */
78 79
static int sir_tx_ir(struct rc_dev *dev, unsigned int *tx_buf,
		     unsigned int count)
80 81
{
	unsigned long flags;
82 83
	int i;

84
	local_irq_save(flags);
85
	for (i = 0; i < count;) {
86 87 88 89 90 91 92 93 94 95 96
		if (tx_buf[i])
			send_pulse(tx_buf[i]);
		i++;
		if (i >= count)
			break;
		if (tx_buf[i])
			send_space(tx_buf[i]);
		i++;
	}
	local_irq_restore(flags);

97
	return count;
98 99 100 101
}

static void add_read_queue(int flag, unsigned long val)
{
102
	DEFINE_IR_RAW_EVENT(ev);
103

104
	pr_debug("add flag %d with val %lu\n", flag, val);
105 106 107 108 109 110 111

	/*
	 * statistically, pulses are ~TIME_CONST/2 too long. we could
	 * maybe make this more exact, but this is good enough
	 */
	if (flag) {
		/* pulse */
112 113
		if (val > TIME_CONST / 2)
			val -= TIME_CONST / 2;
114
		else /* should not ever happen */
115 116
			val = 1;
		ev.pulse = true;
117
	} else {
118
		val += TIME_CONST / 2;
119
	}
120
	ev.duration = US_TO_NS(val);
121

122
	ir_raw_event_store_with_filter(rcdev, &ev);
123 124 125 126
}

static int init_chrdev(void)
{
127 128 129 130
	rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW);
	if (!rcdev)
		return -ENOMEM;

131
	rcdev->input_name = "SIR IrDA port";
132 133 134 135 136 137 138
	rcdev->input_phys = KBUILD_MODNAME "/input0";
	rcdev->input_id.bustype = BUS_HOST;
	rcdev->input_id.vendor = 0x0001;
	rcdev->input_id.product = 0x0001;
	rcdev->input_id.version = 0x0100;
	rcdev->tx_ir = sir_tx_ir;
	rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
139
	rcdev->driver_name = KBUILD_MODNAME;
140 141 142 143 144
	rcdev->map_name = RC_MAP_RC6_MCE;
	rcdev->timeout = IR_DEFAULT_TIMEOUT;
	rcdev->dev.parent = &sir_ir_dev->dev;

	return devm_rc_register_device(&sir_ir_dev->dev, rcdev);
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
}

/* SECTION: Hardware */
static void sir_timeout(unsigned long data)
{
	/*
	 * if last received signal was a pulse, but receiving stopped
	 * within the 9 bit frame, we need to finish this pulse and
	 * simulate a signal change to from pulse to space. Otherwise
	 * upper layers will receive two sequences next time.
	 */

	unsigned long flags;
	unsigned long pulse_end;

	/* avoid interference with interrupt */
	spin_lock_irqsave(&timer_lock, flags);
	if (last_value) {
		/* clear unread bits in UART and restart */
		outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);
		/* determine 'virtual' pulse end: */
166 167
		pulse_end = min_t(unsigned long,
				  ktime_us_delta(last, last_intr_time),
168 169 170
				  IR_MAX_DURATION);
		dev_dbg(&sir_ir_dev->dev, "timeout add %d for %lu usec\n",
			last_value, pulse_end);
171 172
		add_read_queue(last_value, pulse_end);
		last_value = 0;
173
		last = last_intr_time;
174 175
	}
	spin_unlock_irqrestore(&timer_lock, flags);
176
	ir_raw_event_handle(rcdev);
177 178 179 180 181
}

static irqreturn_t sir_interrupt(int irq, void *dev_id)
{
	unsigned char data;
182 183 184
	ktime_t curr_time;
	static unsigned long delt;
	unsigned long deltintr;
185
	unsigned long flags;
186
	int counter = 0;
187 188 189
	int iir, lsr;

	while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
190 191 192 193 194
		if (++counter > 256) {
			dev_err(&sir_ir_dev->dev, "Trapped in interrupt");
			break;
		}

195
		switch (iir & UART_IIR_ID) { /* FIXME toto treba preriedit */
196
		case UART_IIR_MSI:
197
			(void)inb(io + UART_MSR);
198 199 200
			break;
		case UART_IIR_RLSI:
		case UART_IIR_THRI:
201
			(void)inb(io + UART_LSR);
202 203 204 205 206 207 208
			break;
		case UART_IIR_RDI:
			/* avoid interference with timer */
			spin_lock_irqsave(&timer_lock, flags);
			do {
				del_timer(&timerlist);
				data = inb(io + UART_RX);
209 210 211
				curr_time = ktime_get();
				delt = min_t(unsigned long,
					     ktime_us_delta(last, curr_time),
212
					     IR_MAX_DURATION);
213 214 215
				deltintr = min_t(unsigned long,
						 ktime_us_delta(last_intr_time,
								curr_time),
216 217 218
						 IR_MAX_DURATION);
				dev_dbg(&sir_ir_dev->dev, "t %lu, d %d\n",
					deltintr, (int)data);
219 220 221 222
				/*
				 * if nothing came in last X cycles,
				 * it was gap
				 */
223
				if (deltintr > TIME_CONST * threshold) {
224
					if (last_value) {
225
						dev_dbg(&sir_ir_dev->dev, "GAP\n");
226 227
						/* simulate signal change */
						add_read_queue(last_value,
228 229
							       delt -
							       deltintr);
230
						last_value = 0;
231 232
						last = last_intr_time;
						delt = deltintr;
233 234 235 236 237
					}
				}
				data = 1;
				if (data ^ last_value) {
					/*
238
					 * deltintr > 2*TIME_CONST, remember?
239 240 241
					 * the other case is timeout
					 */
					add_read_queue(last_value,
242
						       delt - TIME_CONST);
243
					last_value = data;
244 245 246
					last = curr_time;
					last = ktime_sub_us(last,
							    TIME_CONST);
247
				}
248
				last_intr_time = curr_time;
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
				if (data) {
					/*
					 * start timer for end of
					 * sequence detection
					 */
					timerlist.expires = jiffies +
								SIR_TIMEOUT;
					add_timer(&timerlist);
				}

				lsr = inb(io + UART_LSR);
			} while (lsr & UART_LSR_DR); /* data ready */
			spin_unlock_irqrestore(&timer_lock, flags);
			break;
		default:
			break;
		}
	}
267
	ir_raw_event_handle(rcdev);
268 269 270 271 272
	return IRQ_RETVAL(IRQ_HANDLED);
}

static void send_space(unsigned long len)
{
273
	usleep_range(len, len + 25);
274 275 276 277 278 279
}

static void send_pulse(unsigned long len)
{
	long bytes_out = len / TIME_CONST;

280
	if (bytes_out == 0)
281
		bytes_out++;
282

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	while (bytes_out--) {
		outb(PULSE, io + UART_TX);
		/* FIXME treba seriozne cakanie z char/serial.c */
		while (!(inb(io + UART_LSR) & UART_LSR_THRE))
			;
	}
}

static int init_hardware(void)
{
	unsigned long flags;

	spin_lock_irqsave(&hardware_lock, flags);
	/* reset UART */
	outb(0, io + UART_MCR);
	outb(0, io + UART_IER);
	/* init UART */
	/* set DLAB, speed = 115200 */
	outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR);
	outb(1, io + UART_DLL); outb(0, io + UART_DLM);
	/* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */
	outb(UART_LCR_WLEN7, io + UART_LCR);
	/* FIFO operation */
	outb(UART_FCR_ENABLE_FIFO, io + UART_FCR);
	/* interrupts */
	/* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */
	outb(UART_IER_RDI, io + UART_IER);
	/* turn on UART */
311
	outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, io + UART_MCR);
312 313 314 315 316 317 318 319 320 321 322 323
	spin_unlock_irqrestore(&hardware_lock, flags);
	return 0;
}

static void drop_hardware(void)
{
	unsigned long flags;

	spin_lock_irqsave(&hardware_lock, flags);

	/* turn off interrupts */
	outb(0, io + UART_IER);
324

325 326 327 328 329 330 331 332 333
	spin_unlock_irqrestore(&hardware_lock, flags);
}

/* SECTION: Initialisation */

static int init_port(void)
{
	int retval;

334 335
	setup_timer(&timerlist, sir_timeout, 0);

336
	/* get I/O port access and IRQ line */
337
	if (!devm_request_region(&sir_ir_dev->dev, io, 8, KBUILD_MODNAME)) {
338
		pr_err("i/o port 0x%.4x already in use.\n", io);
339 340
		return -EBUSY;
	}
341 342
	retval = devm_request_irq(&sir_ir_dev->dev, irq, sir_interrupt, 0,
				  KBUILD_MODNAME, NULL);
343
	if (retval < 0) {
344
		pr_err("IRQ %d already in use.\n", irq);
345 346
		return retval;
	}
347
	pr_info("I/O port 0x%.4x, IRQ %d.\n", io, irq);
348 349 350 351 352 353 354 355 356

	return 0;
}

static void drop_port(void)
{
	del_timer_sync(&timerlist);
}

357
static int init_sir_ir(void)
358 359 360 361 362 363 364 365 366 367
{
	int retval;

	retval = init_port();
	if (retval < 0)
		return retval;
	init_hardware();
	return 0;
}

368
static int sir_ir_probe(struct platform_device *dev)
369
{
370 371 372 373 374 375 376
	int retval;

	retval = init_chrdev();
	if (retval < 0)
		return retval;

	return init_sir_ir();
377 378
}

379
static int sir_ir_remove(struct platform_device *dev)
380
{
381 382
	drop_hardware();
	drop_port();
383 384 385
	return 0;
}

386 387 388
static struct platform_driver sir_ir_driver = {
	.probe		= sir_ir_probe,
	.remove		= sir_ir_remove,
389
	.driver		= {
390
		.name	= "sir_ir",
391 392
	},
};
393

394
static int __init sir_ir_init(void)
395 396 397
{
	int retval;

398
	retval = platform_driver_register(&sir_ir_driver);
399 400
	if (retval)
		return retval;
401

402 403
	sir_ir_dev = platform_device_alloc("sir_ir", 0);
	if (!sir_ir_dev) {
404 405 406 407
		retval = -ENOMEM;
		goto pdev_alloc_fail;
	}

408
	retval = platform_device_add(sir_ir_dev);
409
	if (retval)
410 411
		goto pdev_add_fail;

412
	return 0;
413 414

pdev_add_fail:
415
	platform_device_put(sir_ir_dev);
416
pdev_alloc_fail:
417
	platform_driver_unregister(&sir_ir_driver);
418
	return retval;
419 420
}

421
static void __exit sir_ir_exit(void)
422
{
423 424
	platform_device_unregister(sir_ir_dev);
	platform_driver_unregister(&sir_ir_driver);
425 426
}

427 428
module_init(sir_ir_init);
module_exit(sir_ir_exit);
429 430 431 432 433

MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
MODULE_AUTHOR("Milan Pikula");
MODULE_LICENSE("GPL");

434
module_param(io, int, 0444);
435 436
MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");

437
module_param(irq, int, 0444);
438 439
MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");

440
module_param(threshold, int, 0444);
441
MODULE_PARM_DESC(threshold, "space detection threshold (3)");