1805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*
2805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson * lirc_parallel.c
3805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *
4805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson * lirc_parallel - device driver for infra-red signal receiving and
5805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *                 transmitting unit built by the author
6805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *
7805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
8805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *
9805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  This program is free software; you can redistribute it and/or modify
10805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  it under the terms of the GNU General Public License as published by
11805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  the Free Software Foundation; either version 2 of the License, or
12805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  (at your option) any later version.
13805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *
14805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  This program is distributed in the hope that it will be useful,
15805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  GNU General Public License for more details.
18805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *
19805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  You should have received a copy of the GNU General Public License
20805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  along with this program; if not, write to the Free Software
21805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson *
23805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson */
24805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
25805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** Includes ***/
26805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
27805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/module.h>
28805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/sched.h>
29805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/errno.h>
30805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/signal.h>
31805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/fs.h>
32805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/kernel.h>
33805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/ioport.h>
34805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/time.h>
35805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/mm.h>
36805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/delay.h>
37805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
38805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/io.h>
39805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/irq.h>
40805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/uaccess.h>
41805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <asm/div64.h>
42805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
43805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/poll.h>
44805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/parport.h>
455d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger#include <linux/platform_device.h>
46805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
47805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <media/lirc.h>
48805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <media/lirc_dev.h>
49805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
50805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include "lirc_parallel.h"
51805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
52805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_DRIVER_NAME "lirc_parallel"
53805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
54805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifndef LIRC_IRQ
55805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_IRQ 7
56805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
57805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifndef LIRC_PORT
58805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_PORT 0x378
59805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
60805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifndef LIRC_TIMER
61805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_TIMER 65536
62805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
63805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
64805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** Global Variables ***/
65805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
6690ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug;
6790ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool check_pselecd;
68805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
69805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int irq = LIRC_IRQ;
70805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int io = LIRC_PORT;
71805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER
72805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int timer;
73805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int default_timer = LIRC_TIMER;
74805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
75805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
76805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
77805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
78805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int rbuf[RBUF_SIZE];
79805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
80805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonDECLARE_WAIT_QUEUE_HEAD(lirc_wait);
81805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
82805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int rptr;
83805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int wptr;
84805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int lost_irqs;
85805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonint is_open;
86805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
87805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstruct parport *pport;
88805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstruct pardevice *ppdevice;
89805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonint is_claimed;
90805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
91805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int tx_mask = 1;
92805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
93805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** Internal Functions ***/
94805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
95805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int in(int offset)
96805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
97805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	switch (offset) {
98805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_LP_BASE:
99805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return parport_read_data(pport);
100805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_LP_STATUS:
101805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return parport_read_status(pport);
102805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_LP_CONTROL:
103805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return parport_read_control(pport);
104805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
105805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0; /* make compiler happy */
106805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
107805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
108805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void out(int offset, int value)
109805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
110805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	switch (offset) {
111805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_LP_BASE:
112805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		parport_write_data(pport, value);
113805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
114805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_LP_CONTROL:
115805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		parport_write_control(pport, value);
116805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
117805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_LP_STATUS:
118805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_INFO "%s: attempt to write to status register\n",
119805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		       LIRC_DRIVER_NAME);
120805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
121805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
122805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
123805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
124805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int lirc_get_timer(void)
125805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
126805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
127805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
128805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
129805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int lirc_get_signal(void)
130805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
131805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
132805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
133805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
134805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void lirc_on(void)
135805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
136805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	out(LIRC_PORT_DATA, tx_mask);
137805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
138805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
139805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void lirc_off(void)
140805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
141805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	out(LIRC_PORT_DATA, 0);
142805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
143805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
144805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int init_lirc_timer(void)
145805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
146805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	struct timeval tv, now;
147805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned int level, newlevel, timeelapsed, newtimer;
148805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int count = 0;
149805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
150805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	do_gettimeofday(&tv);
151805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	tv.tv_sec++;                     /* wait max. 1 sec. */
152805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	level = lirc_get_timer();
153805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	do {
154805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		newlevel = lirc_get_timer();
155805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (level == 0 && newlevel != 0)
156805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			count++;
157805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		level = newlevel;
158805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		do_gettimeofday(&now);
159805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	} while (count < 1000 && (now.tv_sec < tv.tv_sec
160805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			     || (now.tv_sec == tv.tv_sec
161805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				 && now.tv_usec < tv.tv_usec)));
162805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
163805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
164805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		     + (now.tv_usec - tv.tv_usec));
165805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (count >= 1000 && timeelapsed > 0) {
166805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (default_timer == 0) {
167805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			/* autodetect timer */
168805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			newtimer = (1000000*count)/timeelapsed;
169805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			printk(KERN_INFO "%s: %u Hz timer detected\n",
170805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			       LIRC_DRIVER_NAME, newtimer);
171805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return newtimer;
172805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		}  else {
173805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			newtimer = (1000000*count)/timeelapsed;
174805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (abs(newtimer - default_timer) > default_timer/10) {
175805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				/* bad timer */
176805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
177805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				       LIRC_DRIVER_NAME, newtimer);
178805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				printk(KERN_NOTICE "%s: using default timer: "
179805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				       "%u Hz\n",
180805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				       LIRC_DRIVER_NAME, default_timer);
181805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				return default_timer;
182805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			} else {
183805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				printk(KERN_INFO "%s: %u Hz timer detected\n",
184805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				       LIRC_DRIVER_NAME, newtimer);
185805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				return newtimer; /* use detected value */
186805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			}
187805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		}
188805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	} else {
189805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
190805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return 0;
191805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
192805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
193805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
194805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int lirc_claim(void)
195805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
196805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (parport_claim(ppdevice) != 0) {
197805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_WARNING "%s: could not claim port\n",
198805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		       LIRC_DRIVER_NAME);
199805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_WARNING "%s: waiting for port becoming available"
200805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		       "\n", LIRC_DRIVER_NAME);
201805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (parport_claim_or_block(ppdevice) < 0) {
202805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			printk(KERN_NOTICE "%s: could not claim port, giving"
203805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			       " up\n", LIRC_DRIVER_NAME);
204805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return 0;
205805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		}
206805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
207805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
208805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	is_claimed = 1;
209805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 1;
210805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
211805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
212805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** interrupt handler ***/
213805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
214805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void rbuf_write(int signal)
215805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
216805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned int nwptr;
217805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
218805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	nwptr = (wptr + 1) & (RBUF_SIZE - 1);
219805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (nwptr == rptr) {
220805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		/* no new signals will be accepted */
221805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		lost_irqs++;
222805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
223805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return;
224805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
225805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	rbuf[wptr] = signal;
226805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	wptr = nwptr;
227805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
228805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
229805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void irq_handler(void *blah)
230805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
231805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	struct timeval tv;
232805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	static struct timeval lasttv;
233805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	static int init;
234805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	long signal;
235805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int data;
236805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned int level, newlevel;
237805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned int timeout;
238805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
23982ce67bf262b3f47ecb5a0ca31cace8ac72b7c98Jarod Wilson	if (!is_open)
240805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return;
241805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
242805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (!is_claimed)
243805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return;
244805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
245805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#if 0
246805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* disable interrupt */
247805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	  disable_irq(irq);
248805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	  out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
249805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
250805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (check_pselecd && (in(1) & LP_PSELECD))
251805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return;
252805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
253805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER
254805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (init) {
255805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		do_gettimeofday(&tv);
256805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
257805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		signal = tv.tv_sec - lasttv.tv_sec;
258805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (signal > 15)
259805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			/* really long time */
260805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			data = PULSE_MASK;
261805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		else
262805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			data = (int) (signal*1000000 +
263805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson					 tv.tv_usec - lasttv.tv_usec +
264805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson					 LIRC_SFH506_DELAY);
265805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
266805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		rbuf_write(data); /* space */
267805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	} else {
268805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (timer == 0) {
269805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			/*
270805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			 * wake up; we'll lose this signal, but it will be
271805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			 * garbage if the device is turned on anyway
272805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			 */
273805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			timer = init_lirc_timer();
274805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			/* enable_irq(irq); */
275805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return;
276805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		}
277805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		init = 1;
278805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
279805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
280805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	timeout = timer/10;	/* timeout after 1/10 sec. */
281805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	signal = 1;
282805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	level = lirc_get_timer();
283805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	do {
284805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		newlevel = lirc_get_timer();
285805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (level == 0 && newlevel != 0)
286805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			signal++;
287805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		level = newlevel;
288805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
289805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		/* giving up */
290805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (signal > timeout
291805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		    || (check_pselecd && (in(1) & LP_PSELECD))) {
292805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			signal = 0;
293805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
294805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			break;
295805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		}
296805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	} while (lirc_get_signal());
297805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
298805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (signal != 0) {
299dca488b87efcae6f2b21ebe61922289b6093db2cUwe Kleine-König		/* adjust value to usecs */
300a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		__u64 helper;
301805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
302a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		helper = ((__u64) signal)*1000000;
303805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		do_div(helper, timer);
304805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		signal = (long) helper;
305805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
306805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (signal > LIRC_SFH506_DELAY)
307805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			data = signal - LIRC_SFH506_DELAY;
308805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		else
309805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			data = 1;
310805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		rbuf_write(PULSE_BIT|data); /* pulse */
311805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
312805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	do_gettimeofday(&lasttv);
313805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#else
314805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* add your code here */
315805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
316805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
317805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	wake_up_interruptible(&lirc_wait);
318805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
319805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* enable interrupt */
320805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/*
321805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	  enable_irq(irq);
322805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	  out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
323805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	*/
324805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
325805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
326805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** file operations ***/
327805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
328805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
329805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
330805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return -ESPIPE;
331805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
332805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
333805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
334805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
335805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int result = 0;
336805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int count = 0;
337805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	DECLARE_WAITQUEUE(wait, current);
338805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
339805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (n % sizeof(int))
340805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return -EINVAL;
341805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
342805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	add_wait_queue(&lirc_wait, &wait);
343805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	set_current_state(TASK_INTERRUPTIBLE);
344805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	while (count < n) {
345805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (rptr != wptr) {
346805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (copy_to_user(buf+count, (char *) &rbuf[rptr],
347805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson					 sizeof(int))) {
348805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				result = -EFAULT;
349805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				break;
350805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			}
351805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			rptr = (rptr + 1) & (RBUF_SIZE - 1);
352805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			count += sizeof(int);
353805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		} else {
354805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (filep->f_flags & O_NONBLOCK) {
355805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				result = -EAGAIN;
356805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				break;
357805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			}
358805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (signal_pending(current)) {
359805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				result = -ERESTARTSYS;
360805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				break;
361805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			}
362805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			schedule();
363805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			set_current_state(TASK_INTERRUPTIBLE);
364805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		}
365805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
366805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	remove_wait_queue(&lirc_wait, &wait);
367805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	set_current_state(TASK_RUNNING);
368805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return count ? count : result;
369805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
370805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
371805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
372805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			  loff_t *ppos)
373805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
374805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int count;
375805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned int i;
376805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned int level, newlevel;
377805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	unsigned long flags;
378805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int counttimer;
379805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int *wbuf;
38088914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson	ssize_t ret;
381805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
382805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (!is_claimed)
383805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return -EBUSY;
384805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
385805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	count = n / sizeof(int);
386805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
387805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (n % sizeof(int) || count % 2 == 0)
388805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return -EINVAL;
389805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
390805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	wbuf = memdup_user(buf, n);
391805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (IS_ERR(wbuf))
392805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return PTR_ERR(wbuf);
393805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
394805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER
395805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (timer == 0) {
396805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		/* try again if device is ready */
397805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		timer = init_lirc_timer();
39888914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson		if (timer == 0) {
39988914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson			ret = -EIO;
40088914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson			goto out;
40188914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson		}
402805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
403805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
404805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* adjust values from usecs */
405805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	for (i = 0; i < count; i++) {
406a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		__u64 helper;
407805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
408a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		helper = ((__u64) wbuf[i])*timer;
409805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		do_div(helper, 1000000);
410805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		wbuf[i] = (int) helper;
411805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
412805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
413805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	local_irq_save(flags);
414805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	i = 0;
415805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	while (i < count) {
416805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		level = lirc_get_timer();
417805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		counttimer = 0;
418805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		lirc_on();
419805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		do {
420805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			newlevel = lirc_get_timer();
421805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (level == 0 && newlevel != 0)
422805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				counttimer++;
423805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			level = newlevel;
424805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (check_pselecd && (in(1) & LP_PSELECD)) {
425805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				lirc_off();
426805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				local_irq_restore(flags);
42788914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson				ret = -EIO;
42888914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson				goto out;
429805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			}
430805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		} while (counttimer < wbuf[i]);
431805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		i++;
432805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
433805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		lirc_off();
434805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (i == count)
435805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			break;
436805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		counttimer = 0;
437805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		do {
438805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			newlevel = lirc_get_timer();
439805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (level == 0 && newlevel != 0)
440805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				counttimer++;
441805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			level = newlevel;
442805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			if (check_pselecd && (in(1) & LP_PSELECD)) {
443805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson				local_irq_restore(flags);
44488914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson				ret = -EIO;
44588914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson				goto out;
446805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			}
447805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		} while (counttimer < wbuf[i]);
448805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		i++;
449805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
450805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	local_irq_restore(flags);
451805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#else
452805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* place code that handles write without external timer here */
453805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
45488914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson	ret = n;
45588914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilsonout:
45688914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson	kfree(wbuf);
45788914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson
45888914bdf8c677ebd7e797adac05e47303fd6ac77Jarod Wilson	return ret;
459805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
460805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
461805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int lirc_poll(struct file *file, poll_table *wait)
462805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
463805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	poll_wait(file, &lirc_wait, wait);
464805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (rptr != wptr)
465805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return POLLIN | POLLRDNORM;
466805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
467805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
468805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
469805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
470805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
471805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	int result;
472a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson	__u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
473a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson			 LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
474a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson	__u32 mode;
475a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson	__u32 value;
476805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
477805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	switch (cmd) {
478805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_GET_FEATURES:
479a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		result = put_user(features, (__u32 *) arg);
480805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (result)
481805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return result;
482805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
483805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_GET_SEND_MODE:
484a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		result = put_user(LIRC_MODE_PULSE, (__u32 *) arg);
485805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (result)
486805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return result;
487805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
488805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_GET_REC_MODE:
489a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		result = put_user(LIRC_MODE_MODE2, (__u32 *) arg);
490805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (result)
491805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return result;
492805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
493805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_SET_SEND_MODE:
494a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		result = get_user(mode, (__u32 *) arg);
495805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (result)
496805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return result;
497805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (mode != LIRC_MODE_PULSE)
498805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return -EINVAL;
499805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
500805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_SET_REC_MODE:
501a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		result = get_user(mode, (__u32 *) arg);
502805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (result)
503805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return result;
504805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (mode != LIRC_MODE_MODE2)
505805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return -ENOSYS;
506805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
507805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	case LIRC_SET_TRANSMITTER_MASK:
508a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		result = get_user(value, (__u32 *) arg);
509805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		if (result)
510805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return result;
511a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
512805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson			return LIRC_PARALLEL_MAX_TRANSMITTERS;
513a126681810a327bee60a58ac5ad77f4518cf7a5fJarod Wilson		tx_mask = value;
514805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		break;
515805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	default:
516805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return -ENOIOCTLCMD;
517805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
518805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
519805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
520805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
521805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int lirc_open(struct inode *node, struct file *filep)
522805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
52382ce67bf262b3f47ecb5a0ca31cace8ac72b7c98Jarod Wilson	if (is_open || !lirc_claim())
524805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return -EBUSY;
525805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
526805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	parport_enable_irq(pport);
527805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
528805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* init read ptr */
529805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	rptr = 0;
530805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	wptr = 0;
531805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	lost_irqs = 0;
532805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
533805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	is_open = 1;
534805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
535805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
536805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
537805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int lirc_close(struct inode *node, struct file *filep)
538805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
539805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (is_claimed) {
540805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		is_claimed = 0;
541805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		parport_release(ppdevice);
542805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
543805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	is_open = 0;
544805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
545805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
546805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
5470f9313ad068af4156109661fb8e94ee7fcb79001Mauro Carvalho Chehabstatic const struct file_operations lirc_fops = {
548805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.owner		= THIS_MODULE,
549805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.llseek		= lirc_lseek,
550805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.read		= lirc_read,
551805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.write		= lirc_write,
552805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.poll		= lirc_poll,
553805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.unlocked_ioctl	= lirc_ioctl,
5548be292cc035ebc3422f08e84682626dd8ed8334bJarod Wilson#ifdef CONFIG_COMPAT
5558be292cc035ebc3422f08e84682626dd8ed8334bJarod Wilson	.compat_ioctl	= lirc_ioctl,
5568be292cc035ebc3422f08e84682626dd8ed8334bJarod Wilson#endif
557805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.open		= lirc_open,
558805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	.release	= lirc_close
559805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson};
560805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
561805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int set_use_inc(void *data)
562805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
563805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
564805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
565805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
566805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void set_use_dec(void *data)
567805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
568805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
569805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
570805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic struct lirc_driver driver = {
571d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.name		= LIRC_DRIVER_NAME,
572d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.minor		= -1,
573d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.code_length	= 1,
574d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.sample_rate	= 0,
575d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.data		= NULL,
576d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.add_to_buf	= NULL,
577d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.set_use_inc	= set_use_inc,
578d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.set_use_dec	= set_use_dec,
579d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.fops		= &lirc_fops,
580d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.dev		= NULL,
581d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche	.owner		= THIS_MODULE,
582805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson};
583805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
5845d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerstatic struct platform_device *lirc_parallel_dev;
5855d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
5865d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerstatic int __devinit lirc_parallel_probe(struct platform_device *dev)
5875d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger{
5885d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	return 0;
5895d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger}
5905d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
5915d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerstatic int __devexit lirc_parallel_remove(struct platform_device *dev)
5925d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger{
5935d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	return 0;
5945d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger}
5955d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
5965d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerstatic int lirc_parallel_suspend(struct platform_device *dev,
597d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche					pm_message_t state)
5985d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger{
5995d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	return 0;
6005d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger}
6015d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
6025d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerstatic int lirc_parallel_resume(struct platform_device *dev)
6035d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger{
6045d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	return 0;
6055d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger}
6065d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
6075d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerstatic struct platform_driver lirc_parallel_driver = {
6085d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	.probe	= lirc_parallel_probe,
6095d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	.remove	= __devexit_p(lirc_parallel_remove),
6105d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	.suspend	= lirc_parallel_suspend,
6115d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	.resume	= lirc_parallel_resume,
6125d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	.driver	= {
6135d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		.name	= LIRC_DRIVER_NAME,
6145d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		.owner	= THIS_MODULE,
6155d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	},
6165d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger};
6175d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
618805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int pf(void *handle)
619805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
620805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	parport_disable_irq(pport);
621805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	is_claimed = 0;
622805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
623805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
624805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
625805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void kf(void *handle)
626805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
627805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (!is_open)
628805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return;
629805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (!lirc_claim())
630805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		return;
631805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	parport_enable_irq(pport);
632805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	lirc_off();
633805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/* this is a bit annoying when you actually print...*/
634805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	/*
635805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
636805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	*/
637805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
638805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
639805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** module initialization and cleanup ***/
640805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
641805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int __init lirc_parallel_init(void)
642805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
6435d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	int result;
6445d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
6455d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	result = platform_driver_register(&lirc_parallel_driver);
6465d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	if (result) {
647d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche		printk(KERN_NOTICE "platform_driver_register"
648d713680f2a7a91864e3722420222952f30a0346eGreg Dietsche					" returned %d\n", result);
6495d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		return result;
6505d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	}
6515d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
6525d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
6535d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	if (!lirc_parallel_dev) {
6545d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		result = -ENOMEM;
6555d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		goto exit_driver_unregister;
6565d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	}
6575d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
6585d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	result = platform_device_add(lirc_parallel_dev);
6595d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	if (result)
6605d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		goto exit_device_put;
6615d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
662805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	pport = parport_find_base(io);
663805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (pport == NULL) {
664805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_NOTICE "%s: no port at %x found\n",
665805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		       LIRC_DRIVER_NAME, io);
6665d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		result = -ENXIO;
6675d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		goto exit_device_put;
668805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
669805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
670805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson					   pf, kf, irq_handler, 0, NULL);
671805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	parport_put_port(pport);
672805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (ppdevice == NULL) {
673805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_NOTICE "%s: parport_register_device() failed\n",
674805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		       LIRC_DRIVER_NAME);
6755d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		result = -ENXIO;
6765d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		goto exit_device_put;
677805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
678805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (parport_claim(ppdevice) != 0)
679805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		goto skip_init;
680805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	is_claimed = 1;
681805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
682805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
683805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER
684805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (debug)
685805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		out(LIRC_PORT_DATA, tx_mask);
686805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
687805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	timer = init_lirc_timer();
688805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
689805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#if 0	/* continue even if device is offline */
690805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (timer == 0) {
691805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		is_claimed = 0;
692805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		parport_release(pport);
693805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		parport_unregister_device(ppdevice);
6945d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		result = -EIO;
6955d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		goto exit_device_put;
696805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
697805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
698805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
699805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (debug)
700805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		out(LIRC_PORT_DATA, 0);
701805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif
702805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
703805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	is_claimed = 0;
704805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	parport_release(ppdevice);
705805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson skip_init:
7065d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	driver.dev = &lirc_parallel_dev->dev;
707805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	driver.minor = lirc_register_driver(&driver);
708805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	if (driver.minor < 0) {
709805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		printk(KERN_NOTICE "%s: register_chrdev() failed\n",
710805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		       LIRC_DRIVER_NAME);
711805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson		parport_unregister_device(ppdevice);
7125d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		result = -EIO;
7135d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger		goto exit_device_put;
714805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	}
715805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
716805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	       LIRC_DRIVER_NAME, io, irq);
717805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	return 0;
7185d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger
7195d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerexit_device_put:
7205d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	platform_device_put(lirc_parallel_dev);
7215d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehwegerexit_driver_unregister:
7225d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	platform_driver_unregister(&lirc_parallel_driver);
7235d884b97c5143f0d4097cefefbf9f7f755fd54faThomas Viehweger	return result;
724805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
725805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
726805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void __exit lirc_parallel_exit(void)
727805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{
728805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	parport_unregister_device(ppdevice);
729805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson	lirc_unregister_driver(driver.minor);
7307cf131cb240fb0959f3b56155781f4d4de4608d1Dave Jones
7317cf131cb240fb0959f3b56155781f4d4de4608d1Dave Jones	platform_device_unregister(lirc_parallel_dev);
7327cf131cb240fb0959f3b56155781f4d4de4608d1Dave Jones	platform_driver_unregister(&lirc_parallel_driver);
733805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}
734805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
735805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_init(lirc_parallel_init);
736805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_exit(lirc_parallel_exit);
737805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
738805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
739805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_AUTHOR("Christoph Bartelmus");
740805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_LICENSE("GPL");
741805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
742805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(io, int, S_IRUGO);
743805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
744805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
745805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(irq, int, S_IRUGO);
746805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
747805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
748805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(tx_mask, int, S_IRUGO);
749805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
750805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
751805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(debug, bool, S_IRUGO | S_IWUSR);
752805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(debug, "Enable debugging messages");
753805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson
754805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
755f17dda94d48b654c793da6632f65654476291ba5Rusty RussellMODULE_PARM_DESC(check_pselecd, "Check for printer (default: 0)");
756