📄 lirc_parallel.c
字号:
/* $Id: lirc_parallel.c,v 5.15 2002/03/06 12:40:59 lirc Exp $ *//**************************************************************************** ** lirc_parallel.c ********************************************************* **************************************************************************** * * lirc_parallel - device driver for infra-red signal receiving and * transmitting unit built by the author * * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*********************************************************************** ************************* Includes *********************** ***********************************************************************/#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <linux/version.h>#if LINUX_VERSION_CODE >= 0x020100 && LINUX_VERSION_CODE < 0x020200#error "--- Sorry, 2.1.x kernels are not supported. ---"#elif LINUX_VERSION_CODE >= 0x020200#define KERNEL_2_2#include <linux/config.h>#endif#if LINUX_VERSION_CODE >= 0x020400#define KERNEL_2_4#endif#ifdef CONFIG_SMP#error "--- Sorry, this driver is not SMP safe. ---"#endif#include <linux/module.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/config.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/time.h>#include <linux/mm.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/signal.h>#include <asm/irq.h>#ifdef KERNEL_2_2#include <asm/uaccess.h>#include <linux/poll.h>#include <linux/parport.h>#endif#include "drivers/lirc.h"#include "lirc_parallel.h"#define LIRC_DRIVER_NAME "lirc_parallel"/*********************************************************************** ************************* Globale Variablen *********************** ***********************************************************************/unsigned int irq = LIRC_IRQ;unsigned int io = LIRC_PORT;#ifdef LIRC_TIMERunsigned int timer = 0;unsigned int default_timer = LIRC_TIMER;#endif#define WBUF_SIZE (256)#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */static lirc_t wbuf[WBUF_SIZE];static lirc_t rbuf[RBUF_SIZE];#ifdef KERNEL_2_4DECLARE_WAIT_QUEUE_HEAD(lirc_wait);#elsestatic struct wait_queue *lirc_wait=NULL;#endifunsigned int rptr=0,wptr=0;unsigned int lost_irqs=0;int is_open=0;#ifdef KERNEL_2_2struct parport *pport;struct pardevice *ppdevice;int is_claimed=0;#endif/*********************************************************************** ************************* Interne Funktionen *********************** ***********************************************************************/unsigned int __inline__ in(int offset){#ifdef KERNEL_2_2 switch(offset) { case LIRC_LP_BASE: return(parport_read_data(pport)); case LIRC_LP_STATUS: return(parport_read_status(pport)); case LIRC_LP_CONTROL: return(parport_read_control(pport)); } return(0); /* make compiler happy */#else return(inb(io+offset));#endif}void __inline__ out(int offset, int value){#ifdef KERNEL_2_2 switch(offset) { case LIRC_LP_BASE: parport_write_data(pport,value); break; case LIRC_LP_CONTROL: parport_write_control(pport,value); break; case LIRC_LP_STATUS: printk(KERN_INFO "%s: attempt to write to status register\n", LIRC_DRIVER_NAME); break; }#else outb(value,io+offset);#endif}unsigned int __inline__ lirc_get_timer(void){ return(in(LIRC_PORT_TIMER)&LIRC_PORT_TIMER_BIT);}unsigned int __inline__ lirc_get_signal(void){ return(in(LIRC_PORT_SIGNAL)&LIRC_PORT_SIGNAL_BIT);}void __inline__ lirc_on(void){ out(LIRC_PORT_DATA,LIRC_PORT_DATA_BIT);}void __inline__ lirc_off(void){ out(LIRC_PORT_DATA,0);}unsigned int init_lirc_timer(void){ struct timeval tv,now; unsigned int level,newlevel,timeelapsed,newtimer; int count=0; do_gettimeofday(&tv); tv.tv_sec++; /* wait max. 1 sec. */ level=lirc_get_timer(); do { newlevel=lirc_get_timer(); if(level==0 && newlevel!=0) count++; level=newlevel; do_gettimeofday(&now); } while(count<1000 && (now.tv_sec<tv.tv_sec || (now.tv_sec==tv.tv_sec && now.tv_usec<tv.tv_usec))); timeelapsed=((now.tv_sec+1-tv.tv_sec)*1000000 +(now.tv_usec-tv.tv_usec)); if(count>=1000 && timeelapsed>0) { if(default_timer==0) /* autodetect timer */ { newtimer=(1000000*count)/timeelapsed; printk(KERN_INFO "%s: %u Hz timer detected\n", LIRC_DRIVER_NAME,newtimer); return(newtimer); } else { newtimer=(1000000*count)/timeelapsed; if(abs(newtimer-default_timer)> default_timer/10) /* bad timer */ { printk(KERN_NOTICE "%s: bad timer: %u Hz\n", LIRC_DRIVER_NAME,newtimer); printk(KERN_NOTICE "%s: using default timer: " "%u Hz\n", LIRC_DRIVER_NAME,default_timer); return(default_timer); } else { printk(KERN_INFO "%s: %u Hz timer detected\n", LIRC_DRIVER_NAME,newtimer); return(newtimer); /* use detected value */ } } } else { printk(KERN_NOTICE "%s: no timer detected\n",LIRC_DRIVER_NAME); return(0); }}#ifdef KERNEL_2_2int lirc_claim(void){ if(parport_claim(ppdevice)!=0) { printk(KERN_WARNING "%s: could not claim port\n", LIRC_DRIVER_NAME); printk(KERN_WARNING "%s: waiting for port becoming available" "\n",LIRC_DRIVER_NAME); if(parport_claim_or_block(ppdevice)<0) { printk(KERN_NOTICE "%s: could not claim port, giving" " up\n",LIRC_DRIVER_NAME); return(0); } } out(LIRC_LP_CONTROL,LP_PSELECP|LP_PINITP); is_claimed=1; return(1);}#endif/*********************************************************************** ************************* interrupt handler ************************ ***********************************************************************/static inline void rbuf_write(lirc_t signal){ unsigned int nwptr; nwptr=(wptr+1) & (RBUF_SIZE-1); if(nwptr==rptr) /* no new signals will be accepted */ { lost_irqs++; printk(KERN_NOTICE "%s: buffer overrun\n",LIRC_DRIVER_NAME); return; } rbuf[wptr]=signal; wptr=nwptr;}void irq_handler(int i,void *blah,struct pt_regs * regs){ struct timeval tv; static struct timeval lasttv; static int init=0; long signal; lirc_t data; unsigned int level,newlevel; unsigned int timeout; if(!MOD_IN_USE) return;#ifdef KERNEL_2_2 if(!is_claimed) { return; }#endif /* disable interrupt */ /* disable_irq(irq); out(LIRC_PORT_IRQ,in(LIRC_PORT_IRQ)&(~LP_PINTEN)); */ if(in(1)&LP_PSELECD) { return; }#ifdef LIRC_TIMER if(init) { do_gettimeofday(&tv); signal=tv.tv_sec-lasttv.tv_sec; if(signal>15) { data=PULSE_MASK; /* really long time */ } else { data=(lirc_t) (signal*1000000+ tv.tv_usec-lasttv.tv_usec+ LIRC_SFH506_DELAY); }; rbuf_write(data); /* space */ } else { if(timer==0) /* wake up; we'll lose this signal but it will be garbage if the device is turned on anyway */ { timer=init_lirc_timer(); /* enable_irq(irq); */ return; } init=1; } timeout=timer/10; /* timeout after 1/10 sec. */ signal=1; level=lirc_get_timer(); do{ newlevel=lirc_get_timer(); if(level==0 && newlevel!=0) signal++; level=newlevel; /* giving up */ if(signal>timeout || (in(1)&LP_PSELECD)) { signal=0; printk(KERN_NOTICE "%s: timeout\n",LIRC_DRIVER_NAME); break; } } while(lirc_get_signal()); if(signal!=0) { /* ajust value to usecs */ signal=(long) (((unsigned long long) signal)*1000000)/timer; if(signal>LIRC_SFH506_DELAY) { data=signal-LIRC_SFH506_DELAY; } else { data=1; } rbuf_write(PULSE_BIT|data); /* pulse */ } do_gettimeofday(&lasttv);#else /* add your code here */#endif wake_up_interruptible(&lirc_wait); /* enable interrupt */ /* enable_irq(irq); out(LIRC_PORT_IRQ,in(LIRC_PORT_IRQ)|LP_PINTEN); */}/*********************************************************************** ************************** file_operations ************************ ***********************************************************************/#ifdef KERNEL_2_2static loff_t lirc_lseek(struct file *filep,loff_t offset,int orig){ return(-ESPIPE);}#elsestatic int lirc_lseek(struct inode *inode,struct file *filep,off_t offset,int orig){ return(-ESPIPE);}#endif#ifdef KERNEL_2_2static ssize_t lirc_read(struct file *filep,char *buf,size_t n,loff_t *ppos){#elsestatic int lirc_read(struct inode *node,struct file *filep,char *buf,int n){#endif int result; int count=0;#ifdef KERNEL_2_4 DECLARE_WAITQUEUE(wait, current);#else struct wait_queue wait={current,NULL};#endif if(n%sizeof(lirc_t)) return(-EINVAL); result=verify_area(VERIFY_WRITE,buf,n); if(result) return(result); add_wait_queue(&lirc_wait,&wait); current->state=TASK_INTERRUPTIBLE; while(count<n) { if(rptr!=wptr) {#ifdef KERNEL_2_2 copy_to_user(buf+count,(char *) &rbuf[rptr], sizeof(lirc_t));#else memcpy_tofs(buf+count,(char *) &rbuf[rptr], sizeof(lirc_t));#endif rptr=(rptr+1)&(RBUF_SIZE-1); count+=sizeof(lirc_t); } else { if(filep->f_flags & O_NONBLOCK) { result=-EAGAIN; break; }#ifdef KERNEL_2_2 if (signal_pending(current)) { result=-ERESTARTSYS; break; }#else if(current->signal & ~current->blocked) { result=-EINTR; break; }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -