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