lirc_parallel.c revision 0f9313ad068af4156109661fb8e94ee7fcb79001
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#ifdef CONFIG_SMP 28805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#error "--- Sorry, this driver is not SMP safe. ---" 29805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 30805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 31805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/module.h> 32805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/sched.h> 33805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/errno.h> 34805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/signal.h> 35805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/fs.h> 36805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/kernel.h> 37805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/ioport.h> 38805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/time.h> 39805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/mm.h> 40805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/delay.h> 41805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 42805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/io.h> 43805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/signal.h> 44805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/irq.h> 45805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/uaccess.h> 46805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <asm/div64.h> 47805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 48805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/poll.h> 49805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <linux/parport.h> 50805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 51805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <media/lirc.h> 52805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include <media/lirc_dev.h> 53805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 54805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#include "lirc_parallel.h" 55805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 56805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_DRIVER_NAME "lirc_parallel" 57805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 58805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifndef LIRC_IRQ 59805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_IRQ 7 60805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 61805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifndef LIRC_PORT 62805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_PORT 0x378 63805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 64805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifndef LIRC_TIMER 65805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define LIRC_TIMER 65536 66805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 67805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 68805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** Global Variables ***/ 69805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 70805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int debug; 71805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int check_pselecd; 72805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 73805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int irq = LIRC_IRQ; 74805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int io = LIRC_PORT; 75805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER 76805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int timer; 77805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int default_timer = LIRC_TIMER; 78805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 79805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 80805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ 81805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 82805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int rbuf[RBUF_SIZE]; 83805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 84805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonDECLARE_WAIT_QUEUE_HEAD(lirc_wait); 85805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 86805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int rptr; 87805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int wptr; 88805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int lost_irqs; 89805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonint is_open; 90805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 91805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstruct parport *pport; 92805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstruct pardevice *ppdevice; 93805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonint is_claimed; 94805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 95805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonunsigned int tx_mask = 1; 96805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 97805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** Internal Functions ***/ 98805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 99805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int in(int offset) 100805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 101805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson switch (offset) { 102805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_LP_BASE: 103805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return parport_read_data(pport); 104805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_LP_STATUS: 105805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return parport_read_status(pport); 106805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_LP_CONTROL: 107805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return parport_read_control(pport); 108805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 109805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; /* make compiler happy */ 110805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 111805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 112805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void out(int offset, int value) 113805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 114805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson switch (offset) { 115805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_LP_BASE: 116805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_write_data(pport, value); 117805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 118805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_LP_CONTROL: 119805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_write_control(pport, value); 120805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 121805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_LP_STATUS: 122805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_INFO "%s: attempt to write to status register\n", 123805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME); 124805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 125805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 126805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 127805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 128805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int lirc_get_timer(void) 129805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 130805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; 131805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 132805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 133805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int lirc_get_signal(void) 134805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 135805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; 136805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 137805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 138805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void lirc_on(void) 139805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 140805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_PORT_DATA, tx_mask); 141805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 142805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 143805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void lirc_off(void) 144805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 145805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_PORT_DATA, 0); 146805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 147805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 148805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int init_lirc_timer(void) 149805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 150805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson struct timeval tv, now; 151805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int level, newlevel, timeelapsed, newtimer; 152805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int count = 0; 153805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 154805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do_gettimeofday(&tv); 155805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson tv.tv_sec++; /* wait max. 1 sec. */ 156805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson level = lirc_get_timer(); 157805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do { 158805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson newlevel = lirc_get_timer(); 159805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (level == 0 && newlevel != 0) 160805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson count++; 161805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson level = newlevel; 162805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do_gettimeofday(&now); 163805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } while (count < 1000 && (now.tv_sec < tv.tv_sec 164805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson || (now.tv_sec == tv.tv_sec 165805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson && now.tv_usec < tv.tv_usec))); 166805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 167805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 168805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson + (now.tv_usec - tv.tv_usec)); 169805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (count >= 1000 && timeelapsed > 0) { 170805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (default_timer == 0) { 171805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* autodetect timer */ 172805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson newtimer = (1000000*count)/timeelapsed; 173805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_INFO "%s: %u Hz timer detected\n", 174805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME, newtimer); 175805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return newtimer; 176805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } else { 177805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson newtimer = (1000000*count)/timeelapsed; 178805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (abs(newtimer - default_timer) > default_timer/10) { 179805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* bad timer */ 180805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: bad timer: %u Hz\n", 181805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME, newtimer); 182805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: using default timer: " 183805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson "%u Hz\n", 184805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME, default_timer); 185805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return default_timer; 186805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } else { 187805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_INFO "%s: %u Hz timer detected\n", 188805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME, newtimer); 189805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return newtimer; /* use detected value */ 190805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 191805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 192805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } else { 193805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); 194805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 195805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 196805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 197805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 198805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int lirc_claim(void) 199805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 200805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (parport_claim(ppdevice) != 0) { 201805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_WARNING "%s: could not claim port\n", 202805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME); 203805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_WARNING "%s: waiting for port becoming available" 204805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson "\n", LIRC_DRIVER_NAME); 205805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (parport_claim_or_block(ppdevice) < 0) { 206805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: could not claim port, giving" 207805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson " up\n", LIRC_DRIVER_NAME); 208805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 209805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 210805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 211805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); 212805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_claimed = 1; 213805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 1; 214805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 215805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 216805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** interrupt handler ***/ 217805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 218805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void rbuf_write(int signal) 219805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 220805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int nwptr; 221805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 222805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson nwptr = (wptr + 1) & (RBUF_SIZE - 1); 223805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (nwptr == rptr) { 224805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* no new signals will be accepted */ 225805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson lost_irqs++; 226805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); 227805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 228805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 229805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson rbuf[wptr] = signal; 230805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson wptr = nwptr; 231805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 232805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 233805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void irq_handler(void *blah) 234805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 235805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson struct timeval tv; 236805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson static struct timeval lasttv; 237805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson static int init; 238805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson long signal; 239805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int data; 240805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int level, newlevel; 241805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int timeout; 242805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 243805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (!module_refcount(THIS_MODULE)) 244805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 245805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 246805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (!is_claimed) 247805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 248805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 249805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#if 0 250805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* disable interrupt */ 251805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson disable_irq(irq); 252805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); 253805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 254805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (check_pselecd && (in(1) & LP_PSELECD)) 255805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 256805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 257805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER 258805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (init) { 259805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do_gettimeofday(&tv); 260805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 261805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson signal = tv.tv_sec - lasttv.tv_sec; 262805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (signal > 15) 263805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* really long time */ 264805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson data = PULSE_MASK; 265805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson else 266805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson data = (int) (signal*1000000 + 267805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson tv.tv_usec - lasttv.tv_usec + 268805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_SFH506_DELAY); 269805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 270805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson rbuf_write(data); /* space */ 271805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } else { 272805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (timer == 0) { 273805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* 274805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson * wake up; we'll lose this signal, but it will be 275805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson * garbage if the device is turned on anyway 276805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson */ 277805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson timer = init_lirc_timer(); 278805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* enable_irq(irq); */ 279805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 280805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 281805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson init = 1; 282805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 283805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 284805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson timeout = timer/10; /* timeout after 1/10 sec. */ 285805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson signal = 1; 286805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson level = lirc_get_timer(); 287805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do { 288805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson newlevel = lirc_get_timer(); 289805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (level == 0 && newlevel != 0) 290805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson signal++; 291805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson level = newlevel; 292805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 293805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* giving up */ 294805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (signal > timeout 295805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson || (check_pselecd && (in(1) & LP_PSELECD))) { 296805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson signal = 0; 297805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); 298805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 299805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 300805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } while (lirc_get_signal()); 301805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 302805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (signal != 0) { 303805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* ajust value to usecs */ 304805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned long long helper; 305805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 306805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson helper = ((unsigned long long) signal)*1000000; 307805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do_div(helper, timer); 308805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson signal = (long) helper; 309805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 310805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (signal > LIRC_SFH506_DELAY) 311805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson data = signal - LIRC_SFH506_DELAY; 312805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson else 313805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson data = 1; 314805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson rbuf_write(PULSE_BIT|data); /* pulse */ 315805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 316805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do_gettimeofday(&lasttv); 317805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#else 318805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* add your code here */ 319805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 320805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 321805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson wake_up_interruptible(&lirc_wait); 322805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 323805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* enable interrupt */ 324805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* 325805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson enable_irq(irq); 326805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); 327805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson */ 328805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 329805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 330805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** file operations ***/ 331805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 332805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) 333805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 334805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -ESPIPE; 335805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 336805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 337805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) 338805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 339805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int result = 0; 340805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int count = 0; 341805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson DECLARE_WAITQUEUE(wait, current); 342805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 343805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (n % sizeof(int)) 344805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EINVAL; 345805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 346805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson add_wait_queue(&lirc_wait, &wait); 347805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson set_current_state(TASK_INTERRUPTIBLE); 348805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson while (count < n) { 349805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (rptr != wptr) { 350805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (copy_to_user(buf+count, (char *) &rbuf[rptr], 351805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson sizeof(int))) { 352805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = -EFAULT; 353805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 354805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 355805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson rptr = (rptr + 1) & (RBUF_SIZE - 1); 356805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson count += sizeof(int); 357805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } else { 358805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (filep->f_flags & O_NONBLOCK) { 359805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = -EAGAIN; 360805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 361805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 362805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (signal_pending(current)) { 363805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = -ERESTARTSYS; 364805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 365805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 366805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson schedule(); 367805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson set_current_state(TASK_INTERRUPTIBLE); 368805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 369805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 370805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson remove_wait_queue(&lirc_wait, &wait); 371805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson set_current_state(TASK_RUNNING); 372805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return count ? count : result; 373805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 374805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 375805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic ssize_t lirc_write(struct file *filep, const char *buf, size_t n, 376805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson loff_t *ppos) 377805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 378805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int count; 379805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int i; 380805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int level, newlevel; 381805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned long flags; 382805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int counttimer; 383805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int *wbuf; 384805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 385805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (!is_claimed) 386805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EBUSY; 387805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 388805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson count = n / sizeof(int); 389805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 390805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (n % sizeof(int) || count % 2 == 0) 391805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EINVAL; 392805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 393805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson wbuf = memdup_user(buf, n); 394805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (IS_ERR(wbuf)) 395805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return PTR_ERR(wbuf); 396805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 397805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER 398805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (timer == 0) { 399805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* try again if device is ready */ 400805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson timer = init_lirc_timer(); 401805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (timer == 0) 402805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EIO; 403805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 404805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 405805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* adjust values from usecs */ 406805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson for (i = 0; i < count; i++) { 407805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned long long helper; 408805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 409805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson helper = ((unsigned long long) wbuf[i])*timer; 410805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do_div(helper, 1000000); 411805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson wbuf[i] = (int) helper; 412805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 413805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 414805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson local_irq_save(flags); 415805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson i = 0; 416805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson while (i < count) { 417805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson level = lirc_get_timer(); 418805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson counttimer = 0; 419805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson lirc_on(); 420805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson do { 421805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson newlevel = lirc_get_timer(); 422805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (level == 0 && newlevel != 0) 423805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson counttimer++; 424805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson level = newlevel; 425805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (check_pselecd && (in(1) & LP_PSELECD)) { 426805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson lirc_off(); 427805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson local_irq_restore(flags); 428805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EIO; 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); 444805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EIO; 445805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 446805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } while (counttimer < wbuf[i]); 447805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson i++; 448805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 449805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson local_irq_restore(flags); 450805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#else 451805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* place code that handles write without external timer here */ 452805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 453805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return n; 454805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 455805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 456805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic unsigned int lirc_poll(struct file *file, poll_table *wait) 457805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 458805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson poll_wait(file, &lirc_wait, wait); 459805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (rptr != wptr) 460805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return POLLIN | POLLRDNORM; 461805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 462805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 463805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 464805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) 465805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 466805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson int result; 467805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | 468805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; 469805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned long mode; 470805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson unsigned int ivalue; 471805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 472805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson switch (cmd) { 473805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_GET_FEATURES: 474805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = put_user(features, (unsigned long *) arg); 475805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (result) 476805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return result; 477805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 478805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_GET_SEND_MODE: 479805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); 480805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (result) 481805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return result; 482805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 483805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_GET_REC_MODE: 484805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg); 485805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (result) 486805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return result; 487805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 488805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_SET_SEND_MODE: 489805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = get_user(mode, (unsigned long *) arg); 490805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (result) 491805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return result; 492805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (mode != LIRC_MODE_PULSE) 493805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EINVAL; 494805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 495805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_SET_REC_MODE: 496805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = get_user(mode, (unsigned long *) arg); 497805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (result) 498805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return result; 499805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (mode != LIRC_MODE_MODE2) 500805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -ENOSYS; 501805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 502805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson case LIRC_SET_TRANSMITTER_MASK: 503805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson result = get_user(ivalue, (unsigned int *) arg); 504805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (result) 505805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return result; 506805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue) 507805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return LIRC_PARALLEL_MAX_TRANSMITTERS; 508805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson tx_mask = ivalue; 509805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson break; 510805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson default: 511805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -ENOIOCTLCMD; 512805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 513805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 514805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 515805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 516805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int lirc_open(struct inode *node, struct file *filep) 517805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 518805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (module_refcount(THIS_MODULE) || !lirc_claim()) 519805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EBUSY; 520805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 521805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_enable_irq(pport); 522805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 523805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* init read ptr */ 524805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson rptr = 0; 525805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson wptr = 0; 526805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson lost_irqs = 0; 527805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 528805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_open = 1; 529805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 530805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 531805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 532805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int lirc_close(struct inode *node, struct file *filep) 533805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 534805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (is_claimed) { 535805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_claimed = 0; 536805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_release(ppdevice); 537805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 538805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_open = 0; 539805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 540805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 541805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 5420f9313ad068af4156109661fb8e94ee7fcb79001Mauro Carvalho Chehabstatic const struct file_operations lirc_fops = { 543805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .owner = THIS_MODULE, 544805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .llseek = lirc_lseek, 545805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .read = lirc_read, 546805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .write = lirc_write, 547805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .poll = lirc_poll, 548805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .unlocked_ioctl = lirc_ioctl, 549805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .open = lirc_open, 550805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .release = lirc_close 551805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}; 552805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 553805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int set_use_inc(void *data) 554805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 555805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 556805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 557805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 558805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void set_use_dec(void *data) 559805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 560805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 561805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 562805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic struct lirc_driver driver = { 563805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .name = LIRC_DRIVER_NAME, 564805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .minor = -1, 565805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .code_length = 1, 566805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .sample_rate = 0, 567805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .data = NULL, 568805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .add_to_buf = NULL, 569805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .set_use_inc = set_use_inc, 570805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .set_use_dec = set_use_dec, 571805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .fops = &lirc_fops, 572805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .dev = NULL, 573805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson .owner = THIS_MODULE, 574805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson}; 575805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 576805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int pf(void *handle); 577805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void kf(void *handle); 578805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 579805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic struct timer_list poll_timer; 580805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void poll_state(unsigned long ignored); 581805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 582805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void poll_state(unsigned long ignored) 583805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 584805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: time\n", 585805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME); 586805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson del_timer(&poll_timer); 587805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (is_claimed) 588805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 589805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson kf(NULL); 590805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (!is_claimed) { 591805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: could not claim port, giving up\n", 592805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME); 593805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson init_timer(&poll_timer); 594805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson poll_timer.expires = jiffies + HZ; 595805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson poll_timer.data = (unsigned long)current; 596805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson poll_timer.function = poll_state; 597805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson add_timer(&poll_timer); 598805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 599805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 600805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 601805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int pf(void *handle) 602805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 603805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_disable_irq(pport); 604805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_claimed = 0; 605805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 606805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 607805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 608805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void kf(void *handle) 609805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 610805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (!is_open) 611805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 612805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (!lirc_claim()) 613805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return; 614805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_enable_irq(pport); 615805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson lirc_off(); 616805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* this is a bit annoying when you actually print...*/ 617805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson /* 618805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); 619805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson */ 620805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 621805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 622805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson/*** module initialization and cleanup ***/ 623805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 624805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic int __init lirc_parallel_init(void) 625805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 626805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson pport = parport_find_base(io); 627805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (pport == NULL) { 628805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: no port at %x found\n", 629805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME, io); 630805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -ENXIO; 631805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 632805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, 633805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson pf, kf, irq_handler, 0, NULL); 634805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_put_port(pport); 635805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (ppdevice == NULL) { 636805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: parport_register_device() failed\n", 637805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME); 638805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -ENXIO; 639805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 640805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (parport_claim(ppdevice) != 0) 641805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson goto skip_init; 642805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_claimed = 1; 643805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); 644805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 645805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#ifdef LIRC_TIMER 646805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (debug) 647805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_PORT_DATA, tx_mask); 648805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 649805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson timer = init_lirc_timer(); 650805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 651805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#if 0 /* continue even if device is offline */ 652805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (timer == 0) { 653805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_claimed = 0; 654805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_release(pport); 655805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_unregister_device(ppdevice); 656805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EIO; 657805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 658805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 659805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 660805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (debug) 661805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson out(LIRC_PORT_DATA, 0); 662805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson#endif 663805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 664805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson is_claimed = 0; 665805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_release(ppdevice); 666805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson skip_init: 667805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson driver.minor = lirc_register_driver(&driver); 668805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson if (driver.minor < 0) { 669805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_NOTICE "%s: register_chrdev() failed\n", 670805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME); 671805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_unregister_device(ppdevice); 672805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return -EIO; 673805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson } 674805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", 675805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson LIRC_DRIVER_NAME, io, irq); 676805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson return 0; 677805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 678805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 679805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonstatic void __exit lirc_parallel_exit(void) 680805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson{ 681805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson parport_unregister_device(ppdevice); 682805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson lirc_unregister_driver(driver.minor); 683805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson} 684805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 685805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_init(lirc_parallel_init); 686805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_exit(lirc_parallel_exit); 687805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 688805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); 689805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_AUTHOR("Christoph Bartelmus"); 690805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_LICENSE("GPL"); 691805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 692805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(io, int, S_IRUGO); 693805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); 694805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 695805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(irq, int, S_IRUGO); 696805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); 697805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 698805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(tx_mask, int, S_IRUGO); 699805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); 700805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 701805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(debug, bool, S_IRUGO | S_IWUSR); 702805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(debug, "Enable debugging messages"); 703805a8966659563df68ea7bbd94241dafd645c725Jarod Wilson 704805a8966659563df68ea7bbd94241dafd645c725Jarod Wilsonmodule_param(check_pselecd, bool, S_IRUGO | S_IWUSR); 705805a8966659563df68ea7bbd94241dafd645c725Jarod WilsonMODULE_PARM_DESC(debug, "Check for printer (default: 0)"); 706