⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lirc_serial.c

📁 很少见的linux下的红外口的工具
💻 C
📖 第 1 页 / 共 3 页
字号:
/*      $Id: lirc_serial.c,v 5.39 2002/10/02 18:35:32 lirc Exp $      *//**************************************************************************** ** lirc_serial.c *********************************************************** **************************************************************************** * * lirc_serial - Device driver that records pulse- and pause-lengths *               (space-lengths) between DDCD event on a serial port. * * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de> * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu> * Copyright (C) 1998 Ben Pfaff <blp@gnu.org> * Copyright (C) 1999 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 * *//* Steve's changes to improve transmission fidelity:     - for systems with the rdtsc instruction and the clock counter, a        send_pule that times the pulses directly using the counter.       This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is       not needed. Measurement shows very stable waveform, even where       PCI activity slows the access to the UART, which trips up other       versions.     - For other system, non-integer-microsecond pulse/space lengths,       done using fixed point binary. So, much more accurate carrier       frequency.     - fine tuned transmitter latency, taking advantage of fractional       microseconds in previous change     - Fixed bug in the way transmitter latency was accounted for by       tuning the pulse lengths down - the send_pulse routine ignored       this overhead as it timed the overall pulse length - so the       pulse frequency was right but overall pulse length was too       long. Fixed by accounting for latency on each pulse/space       iteration.   Steve Davies <steve@daviesfam.org>  July 2001*/#ifdef HAVE_CONFIG_H# include <config.h>#endif #include <linux/version.h>#if LINUX_VERSION_CODE >= 0x020100#define KERNEL_2_1#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)#define KERNEL_2_3#endif#endif#if LINUX_VERSION_CODE >= 0x020212#define LIRC_LOOPS_PER_JIFFY#endif#include <linux/config.h>#ifndef CONFIG_SERIAL_MODULE#warning "******************************************"#warning " Your serial port driver is compiled into "#warning " the kernel. You will have to release the "#warning " port you want to use for LIRC with:      "#warning "    setserial /dev/ttySx uart none        "#warning "******************************************"#endif#include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/serial_reg.h>#include <linux/time.h>#include <linux/string.h>#include <linux/types.h>#include <linux/wait.h>#include <linux/mm.h>#include <linux/delay.h>#ifdef KERNEL_2_1#include <linux/poll.h>#endif#include <asm/system.h>#include <asm/segment.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/fcntl.h>#include "drivers/lirc.h"#if defined(LIRC_SERIAL_SOFTCARRIER) && !defined(LIRC_SERIAL_TRANSMITTER)#warning "Software carrier only affects transmitting"#endif#if defined(rdtsc) && defined(KERNEL_2_1)#define USE_RDTSC#warning "Note: using rdtsc instruction"#endif#ifdef LIRC_SERIAL_ANIMAX#ifdef LIRC_SERIAL_TRANSMITTER#warning "******************************************"#warning " This receiver does not have a            "#warning " transmitter diode                        "#warning "******************************************"#endif#endifstruct lirc_serial{	int type;	int signal_pin;	int signal_pin_change;	int on;	int off;	long (*send_pulse)(unsigned long length);	void (*send_space)(long length);	int features;};#define LIRC_HOMEBREW        0#define LIRC_IRDEO           1#define LIRC_IRDEO_REMOTE    2#define LIRC_ANIMAX          3#ifdef LIRC_SERIAL_IRDEOint type=LIRC_IRDEO;#elif defined(LIRC_SERIAL_IRDEO_REMOTE)int type=LIRC_IRDEO_REMOTE;#elif defined(LIRC_SERIAL_ANIMAX)int type=LIRC_ANIMAX;#elseint type=LIRC_HOMEBREW;#endif#ifdef LIRC_SERIAL_SOFTCARRIERint softcarrier=1;#elseint softcarrier=0;#endif/* forward declarations */long send_pulse_irdeo(unsigned long length);long send_pulse_homebrew(unsigned long length);void send_space_irdeo(long length);void send_space_homebrew(long length);struct lirc_serial hardware[]={	/* home-brew receiver/transmitter */	{		LIRC_HOMEBREW,		UART_MSR_DCD,		UART_MSR_DDCD,		UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR,		UART_MCR_RTS|UART_MCR_OUT2,		send_pulse_homebrew,		send_space_homebrew,		(#ifdef LIRC_SERIAL_TRANSMITTER		 LIRC_CAN_SET_SEND_DUTY_CYCLE|		 LIRC_CAN_SET_SEND_CARRIER|		 LIRC_CAN_SEND_PULSE|#endif		 LIRC_CAN_REC_MODE2)	},		/* IRdeo classic */	{		LIRC_IRDEO,		UART_MSR_DSR,		UART_MSR_DDSR,		UART_MCR_OUT2,		UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2,		send_pulse_irdeo,		send_space_irdeo,		(LIRC_CAN_SET_SEND_DUTY_CYCLE|		 LIRC_CAN_SEND_PULSE|		 LIRC_CAN_REC_MODE2)	},		/* IRdeo remote */	{		LIRC_IRDEO_REMOTE,		UART_MSR_DSR,		UART_MSR_DDSR,		UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2,		UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2,		send_pulse_irdeo,		send_space_irdeo,		(LIRC_CAN_SET_SEND_DUTY_CYCLE|		 LIRC_CAN_SEND_PULSE|		 LIRC_CAN_REC_MODE2)	},		/* AnimaX */	{		LIRC_ANIMAX,		UART_MSR_DCD,		UART_MSR_DDCD,		0,		UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2,		NULL,		NULL,		LIRC_CAN_REC_MODE2	}};#define LIRC_DRIVER_NAME "lirc_serial"#define RS_ISR_PASS_LIMIT 256/* A long pulse code from a remote might take upto 300 bytes.  The   daemon should read the bytes as soon as they are generated, so take   the number of keys you think you can push before the daemon runs   and multiply by 300.  The driver will warn you if you overrun this   buffer.  If you have a slow computer or non-busmastering IDE disks,   maybe you will need to increase this.  *//* This MUST be a power of two!  It has to be larger than 1 as well. */#define RBUF_LEN 256#define WBUF_LEN 256static int major = LIRC_MAJOR;static int sense = -1;   /* -1 = auto, 0 = active high, 1 = active low */#ifdef KERNEL_2_3static DECLARE_WAIT_QUEUE_HEAD(lirc_wait_in);#elsestatic struct wait_queue *lirc_wait_in = NULL;#endif#ifdef KERNEL_2_1static spinlock_t lirc_lock = SPIN_LOCK_UNLOCKED;#endifstatic int io = LIRC_PORT;static int irq = LIRC_IRQ;static struct timeval lasttv = {0, 0};static lirc_t rbuf[RBUF_LEN];static int rbh, rbt;static lirc_t wbuf[WBUF_LEN];unsigned int freq = 38000;unsigned int duty_cycle = 50;#ifdef USE_RDTSC/* This version does sub-microsecond timing using rdtsc instruction, * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY * Implicitly i586 architecture...  - Steve *//* When we use the rdtsc instruction to measure clocks, we keep the * pulse and space widths as clock cycles.  As this is CPU speed * dependent, the widths must be calculated in init_port and ioctl * time */unsigned long period = 0;unsigned long pulse_width = 0;unsigned long space_width = 0;/* So send_pulse can quickly convert microseconds to clocks */unsigned long conv_us_to_clocks = 0;#else /* USE_RDTSC *//* Version using udelay() *//* period, pulse/space width are kept with 8 binary places -   IE multiplied by 256. */unsigned long period = 6736; /* 256*1000000L/freq; */unsigned long pulse_width = 3368; /* (period*duty_cycle/100) */unsigned long space_width = 3368; /* (period - pulse_width) */#if defined(__i386__)/*  From:  Linux I/O port programming mini-HOWTO  Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>  v, 28 December 1997    [...]  Actually, a port I/O instruction on most ports in the 0-0x3ff range  takes almost exactly 1 microsecond, so if you're, for example, using  the parallel port directly, just do additional inb()s from that port  to delay.  [...]*//* transmitter latency 1.5625us 0x1.90 - this figure arrived at from * comment above plus trimming to match actual measured frequency. * This will be sensitive to cpu speed, though hopefully most of the 1.5us * is spent in the uart access.  Still - for reference test machine was a * 1.13GHz Athlon system - Steve *//* changed from 400 to 450 as this works better on slower machines;   faster machines will use the rdtsc code anyway */#define LIRC_SERIAL_TRANSMITTER_LATENCY 450#else/* does anybody have information on other platforms ? *//* 256 = 1<<8 */#define LIRC_SERIAL_TRANSMITTER_LATENCY 256#endif  /* __i386__ */#endif /* USE_RDTSC */static inline unsigned int sinp(int offset){	return inb(io + offset);}static inline void soutp(int offset, int value){	outb(value, io + offset);}void on(void){	soutp(UART_MCR,hardware[type].on);}  void off(void){	soutp(UART_MCR,hardware[type].off);}#ifndef MAX_UDELAY_MS#define MAX_UDELAY_US 5000#else#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)#endifstatic inline void safe_udelay(unsigned long usecs){	while(usecs>MAX_UDELAY_US)	{		udelay(MAX_UDELAY_US);		usecs-=MAX_UDELAY_US;	}	udelay(usecs);}#ifdef USE_RDTSC/* This is an overflow/precision juggle, complicated in that we can't   do long long divide in the kernel */void calc_pulse_lengths_in_clocks(void){	unsigned long long loops_per_sec,work;#ifdef LIRC_LOOPS_PER_JIFFY	loops_per_sec=current_cpu_data.loops_per_jiffy;	loops_per_sec*=HZ;#else	loops_per_sec=current_cpu_data.loops_per_sec;#endif		/* How many clocks in a microsecond?, avoiding long long divide */	work=loops_per_sec;	work*=4295;  /* 4295 = 2^32 / 1e6 */	conv_us_to_clocks=(work>>32);		/* Carrier period in clocks, approach good up to 32GHz clock,           gets carrier frequency within 8Hz */	period=loops_per_sec>>3;	period/=(freq>>3);	/* Derive pulse and space from the period */	pulse_width = period*duty_cycle/100;	space_width = period - pulse_width;#ifdef DEBUG#ifdef LIRC_LOOPS_PER_JIFFY	printk(KERN_INFO LIRC_DRIVER_NAME	       ": in calc_pulse_lengths_in_clocks, freq=%d, duty_cycle=%d, "	       "clk/jiffy=%ld, pulse=%ld, space=%ld, conv_us_to_clocks=%ld\n",	       freq, duty_cycle, current_cpu_data.loops_per_jiffy,	       pulse_width, space_width, conv_us_to_clocks);#else	printk(KERN_INFO LIRC_DRIVER_NAME	       ": in calc_pulse_lengths_in_clocks, freq=%d, duty_cycle=%d, "	       "clk/sec=%ld, pulse=%ld, space=%ld, conv_us_to_clocks=%ld\n",	       freq, duty_cycle, current_cpu_data.loops_per_sec,	       pulse_width, space_width, conv_us_to_clocks);#endif#endif}#endif/* return value: space length delta */long send_pulse_irdeo(unsigned long length){	long rawbits;	int i;	unsigned char output;	unsigned char chunk,shifted;		/* how many bits have to be sent ? */	rawbits=length*1152/10000;	if(duty_cycle>50) chunk=3;	else chunk=1;	for(i=0,output=0x7f;rawbits>0;rawbits-=3)	{		shifted=chunk<<(i*3);		shifted>>=1;		output&=(~shifted);		i++;		if(i==3)		{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -