diff -u -r -N lirc-0.8.1-orig/configure lirc-0.8.1-ser/configure --- lirc-0.8.1-orig/configure 2007-01-07 23:45:16.000000000 +1100 +++ lirc-0.8.1-ser/configure 2007-05-03 18:51:31.000000000 +1000 @@ -22962,7 +22962,7 @@ (lirc_dev lirc_mceusb2) \ (lirc_dev lirc_parallel) \ (lirc_dev lirc_sasem) \ - (lirc_dev lirc_serial) \ + (lirc_dev lirc_serial2) \ (lirc_dev lirc_sir) \ (lirc_dev lirc_streamzap)" fi @@ -24451,7 +24451,7 @@ ;; lirc_dev-lirc_sasem) ;; - lirc_dev-lirc_serial) + lirc_dev-lirc_serial2) ;; lirc_dev-lirc_sir) ;; @@ -24556,7 +24556,7 @@ fi if test "$driver" = "animax"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" lircd_conf="animax/lircd.conf.animax" lircmd_conf="animax/lircmd.conf.animax" cat >>confdefs.h <<\_ACEOF @@ -24665,25 +24665,25 @@ fi if test "$driver" = "com1"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x3f8 irq=4 fi if test "$driver" = "com2"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x2f8 irq=3 fi if test "$driver" = "com3"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x3e8 irq=4 fi if test "$driver" = "com4"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x2e8 irq=3 fi @@ -24813,7 +24813,7 @@ fi if test "$driver" = "irdeo"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" cat >>confdefs.h <<\_ACEOF #define LIRC_SERIAL_IRDEO 1 _ACEOF @@ -24821,7 +24821,7 @@ fi if test "$driver" = "irdeo_remote"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" cat >>confdefs.h <<\_ACEOF #define LIRC_SERIAL_IRDEO_REMOTE 1 _ACEOF @@ -24958,7 +24958,7 @@ fi if test "$driver" = "nslu2"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" cat >>confdefs.h <<\_ACEOF #define LIRC_SERIAL_NSLU2 1 _ACEOF @@ -24966,7 +24966,7 @@ fi if test "$driver" = "packard_bell"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" lircd_conf="packard_bell/lircd.conf.packard_bell" fi @@ -25045,7 +25045,7 @@ fi if test "$driver" = "serial"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" fi if test "$driver" = "silitek"; then @@ -25259,7 +25259,7 @@ lirc_mceusb2 \ lirc_parallel \ lirc_sasem \ - lirc_serial \ + lirc_serial2 \ lirc_sir \ lirc_streamzap" fi @@ -25576,7 +25576,7 @@ - ac_config_files="$ac_config_files Makefile drivers/Makefile drivers/lirc_atiusb/Makefile drivers/lirc_bt829/Makefile drivers/lirc_cmdir/Makefile drivers/lirc_dev/Makefile drivers/lirc_gpio/Makefile drivers/lirc_i2c/Makefile drivers/lirc_igorplugusb/Makefile drivers/lirc_imon/Makefile drivers/lirc_it87/Makefile drivers/lirc_mceusb/Makefile drivers/lirc_mceusb2/Makefile drivers/lirc_parallel/Makefile drivers/lirc_sasem/Makefile drivers/lirc_serial/Makefile drivers/lirc_sir/Makefile drivers/lirc_streamzap/Makefile daemons/Makefile tools/Makefile doc/Makefile doc/man/Makefile" + ac_config_files="$ac_config_files Makefile drivers/Makefile drivers/lirc_atiusb/Makefile drivers/lirc_bt829/Makefile drivers/lirc_cmdir/Makefile drivers/lirc_dev/Makefile drivers/lirc_gpio/Makefile drivers/lirc_i2c/Makefile drivers/lirc_igorplugusb/Makefile drivers/lirc_imon/Makefile drivers/lirc_it87/Makefile drivers/lirc_mceusb/Makefile drivers/lirc_mceusb2/Makefile drivers/lirc_parallel/Makefile drivers/lirc_sasem/Makefile drivers/lirc_serial2/Makefile drivers/lirc_sir/Makefile drivers/lirc_streamzap/Makefile daemons/Makefile tools/Makefile doc/Makefile doc/man/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -26128,7 +26128,7 @@ "drivers/lirc_mceusb2/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_mceusb2/Makefile" ;; "drivers/lirc_parallel/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_parallel/Makefile" ;; "drivers/lirc_sasem/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_sasem/Makefile" ;; - "drivers/lirc_serial/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_serial/Makefile" ;; + "drivers/lirc_serial2/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_serial2/Makefile" ;; "drivers/lirc_sir/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_sir/Makefile" ;; "drivers/lirc_streamzap/Makefile" ) CONFIG_FILES="$CONFIG_FILES drivers/lirc_streamzap/Makefile" ;; "daemons/Makefile" ) CONFIG_FILES="$CONFIG_FILES daemons/Makefile" ;; diff -u -r -N lirc-0.8.1-orig/configure.in lirc-0.8.1-ser/configure.in --- lirc-0.8.1-orig/configure.in 2007-01-07 23:42:49.000000000 +1100 +++ lirc-0.8.1-ser/configure.in 2007-05-03 18:52:26.000000000 +1000 @@ -180,7 +180,7 @@ (lirc_dev lirc_mceusb2) \ (lirc_dev lirc_parallel) \ (lirc_dev lirc_sasem) \ - (lirc_dev lirc_serial) \ + (lirc_dev lirc_serial2) \ (lirc_dev lirc_sir) \ (lirc_dev lirc_streamzap)" fi @@ -408,7 +408,7 @@ ;; lirc_dev-lirc_sasem) ;; - lirc_dev-lirc_serial) + lirc_dev-lirc_serial2) ;; lirc_dev-lirc_sir) ;; @@ -507,7 +507,7 @@ fi if test "$driver" = "animax"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" lircd_conf="animax/lircd.conf.animax" lircmd_conf="animax/lircmd.conf.animax" AC_DEFINE(LIRC_SERIAL_ANIMAX) @@ -613,25 +613,25 @@ fi if test "$driver" = "com1"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x3f8 irq=4 fi if test "$driver" = "com2"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x2f8 irq=3 fi if test "$driver" = "com3"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x3e8 irq=4 fi if test "$driver" = "com4"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" port=0x2e8 irq=3 fi @@ -758,12 +758,12 @@ fi if test "$driver" = "irdeo"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" AC_DEFINE(LIRC_SERIAL_IRDEO) fi if test "$driver" = "irdeo_remote"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" AC_DEFINE(LIRC_SERIAL_IRDEO_REMOTE) fi @@ -897,12 +897,12 @@ fi if test "$driver" = "nslu2"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" AC_DEFINE(LIRC_SERIAL_NSLU2) fi if test "$driver" = "packard_bell"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" lircd_conf="packard_bell/lircd.conf.packard_bell" fi @@ -978,7 +978,7 @@ fi if test "$driver" = "serial"; then - lirc_driver="lirc_dev lirc_serial" + lirc_driver="lirc_dev lirc_serial2" fi if test "$driver" = "silitek"; then @@ -1151,7 +1151,7 @@ lirc_mceusb2 \ lirc_parallel \ lirc_sasem \ - lirc_serial \ + lirc_serial2 \ lirc_sir \ lirc_streamzap" fi diff -u -r -N lirc-0.8.1-orig/drivers/lirc_serial/lirc_serial.c lirc-0.8.1-ser/drivers/lirc_serial/lirc_serial.c --- lirc-0.8.1-orig/drivers/lirc_serial/lirc_serial.c 2006-12-28 07:59:25.000000000 +1100 +++ lirc-0.8.1-ser/drivers/lirc_serial/lirc_serial.c 1970-01-01 10:00:00.000000000 +1000 @@ -1,1268 +0,0 @@ -/* $Id: lirc_serial.c,v 5.72 2006/12/27 20:59:25 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 - * Copyright (C) 1998 Trent Piepho - * Copyright (C) 1998 Ben Pfaff - * Copyright (C) 1999 Christoph Bartelmus - * - * 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 July 2001 -*/ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) -#error "**********************************************************" -#error " Sorry, this driver needs kernel version 2.2.18 or higher " -#error "**********************************************************" -#endif - -#include - -#if defined(CONFIG_SERIAL) || defined(CONFIG_SERIAL_8250) -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if defined(LIRC_SERIAL_NSLU2) -#include -/* From Intel IXP42X Developer's Manual (#252480-005): */ -/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ -#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ -#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ -#endif - -#include "drivers/lirc.h" -#include "drivers/kcompat.h" -#include "drivers/lirc_dev/lirc_dev.h" - -#if defined(LIRC_SERIAL_SOFTCARRIER) && !defined(LIRC_SERIAL_TRANSMITTER) -#warning "Software carrier only affects transmitting" -#endif - -#if defined(rdtsc) - -#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 -#endif - -#define LIRC_DRIVER_NAME "lirc_serial" - -struct lirc_serial -{ - 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 -#define LIRC_IGOR 4 -#define LIRC_NSLU2 5 - -#ifdef LIRC_SERIAL_IRDEO -static int type=LIRC_IRDEO; -#elif defined(LIRC_SERIAL_IRDEO_REMOTE) -static int type=LIRC_IRDEO_REMOTE; -#elif defined(LIRC_SERIAL_ANIMAX) -static int type=LIRC_ANIMAX; -#elif defined(LIRC_SERIAL_IGOR) -static int type=LIRC_IGOR; -#elif defined(LIRC_SERIAL_NSLU2) -static int type=LIRC_NSLU2; -#else -static int type=LIRC_HOMEBREW; -#endif - -/* Set defaults for NSLU2 */ -#if defined(LIRC_SERIAL_NSLU2) -#ifndef LIRC_IRQ -#define LIRC_IRQ IRQ_IXP4XX_UART2 -#endif -#ifndef LIRC_PORT -#define LIRC_PORT (IXP4XX_UART2_BASE_VIRT + REG_OFFSET) -#endif -#ifndef LIRC_IOMMAP -#define LIRC_IOMMAP IXP4XX_UART2_BASE_PHYS -#endif -#ifndef LIRC_IOSHIFT -#define LIRC_IOSHIFT 2 -#endif -#ifndef LIRC_ALLOW_MMAPPED_IO -#define LIRC_ALLOW_MMAPPED_IO -#endif -#endif - -#if defined(LIRC_ALLOW_MMAPPED_IO) -#ifndef LIRC_IOMMAP -#define LIRC_IOMMAP 0 -#endif -#ifndef LIRC_IOSHIFT -#define LIRC_IOSHIFT 0 -#endif -static int iommap = LIRC_IOMMAP; -static int ioshift = LIRC_IOSHIFT; -#endif - -#ifdef LIRC_SERIAL_SOFTCARRIER -static int softcarrier=1; -#else -static int softcarrier=0; -#endif - -static int share_irq = 0; -static int debug = 0; - -#define dprintk(fmt, args...) \ - do{ \ - if(debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - }while(0) - -/* forward declarations */ -static long send_pulse_irdeo(unsigned long length); -static long send_pulse_homebrew(unsigned long length); -static void send_space_irdeo(long length); -static void send_space_homebrew(long length); - -static struct lirc_serial hardware[]= -{ - /* home-brew receiver/transmitter */ - { - 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 */ - { - 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 */ - { - 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 */ - { - UART_MSR_DCD, - UART_MSR_DDCD, - 0, - UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, - NULL, - NULL, - LIRC_CAN_REC_MODE2 - }, - - /* home-brew receiver/transmitter (Igor Cesko's variation) */ - { - UART_MSR_DSR, - UART_MSR_DDSR, - 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) - }, - -#if defined(LIRC_SERIAL_NSLU2) - /* Modified Linksys Network Storage Link USB 2.0 (NSLU2): - We receive on CTS of the 2nd serial port (R142,LHS), we - transmit with a IR diode between GPIO[1] (green status LED), - and ground (Matthias Goebl ). - See also http://www.nslu2-linux.org for this device */ - { - UART_MSR_CTS, - UART_MSR_DCTS, - 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) - }, -#endif - -}; - -#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 256 - -static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -static int txsense = 0; /* 0 = active high, 1 = active low */ - -#ifndef LIRC_IRQ -#define LIRC_IRQ 4 -#endif -#ifndef LIRC_PORT -#define LIRC_PORT 0x3f8 -#endif - -static int io = LIRC_PORT; -static int irq = LIRC_IRQ; - -static struct timeval lasttv = {0, 0}; - -static struct lirc_buffer rbuf; - -static lirc_t wbuf[WBUF_LEN]; - -static unsigned int freq = 38000; -static unsigned int duty_cycle = 50; - -/* Initialized in init_timing_params() */ -static unsigned long period = 0; -static unsigned long pulse_width = 0; -static unsigned long space_width = 0; - -#if defined(__i386__) -/* - From: - Linux I/O port programming mini-HOWTO - Author: Riku Saikkonen - 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__ */ - -static inline unsigned int sinp(int offset) -{ -#if defined(LIRC_ALLOW_MMAPPED_IO) - if(iommap != 0) /* the register is memory-mapped */ - { - offset <<= ioshift; - return readb(io + offset); - } -#endif - return inb(io + offset); -} - -static inline void soutp(int offset, int value) -{ -#if defined(LIRC_ALLOW_MMAPPED_IO) - if(iommap != 0) /* the register is memory-mapped */ - { - offset <<= ioshift; - writeb(value, io + offset); - } -#endif - outb(value, io + offset); -} - -static inline void on(void) -{ -#if defined(LIRC_SERIAL_NSLU2) - /* On NSLU2, we put the transmit diode between the output of the green - status LED and ground */ - if(type == LIRC_NSLU2) - { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); - return; - } -#endif - if (txsense) - { - soutp(UART_MCR,hardware[type].off); - } - else - { - soutp(UART_MCR,hardware[type].on); - } -} - -static inline void off(void) -{ -#if defined(LIRC_SERIAL_NSLU2) - if(type == LIRC_NSLU2) - { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); - return; - } -#endif - if (txsense) - { - soutp(UART_MCR,hardware[type].on); - } - else - { - soutp(UART_MCR,hardware[type].off); - } -} - -#ifndef MAX_UDELAY_MS -#define MAX_UDELAY_US 5000 -#else -#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -#endif - -static 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 */ - -/* 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 - */ - -/* So send_pulse can quickly convert microseconds to clocks */ -static unsigned long conv_us_to_clocks = 0; - -static inline int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ - unsigned long long loops_per_sec,work; - - duty_cycle=new_duty_cycle; - freq=new_freq; - - loops_per_sec=current_cpu_data.loops_per_jiffy; - loops_per_sec*=HZ; - - /* 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; - dprintk("in init_timing_params, 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); - return 0; -} -#else /* ! USE_RDTSC */ -static inline int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ -/* period, pulse/space width are kept with 8 binary places - - * IE multiplied by 256. */ - if(256*1000000L/new_freq*new_duty_cycle/100<= - LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); - if(256*1000000L/new_freq*(100-new_duty_cycle)/100<= - LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); - duty_cycle=new_duty_cycle; - freq=new_freq; - period=256*1000000L/freq; - pulse_width=period*duty_cycle/100; - space_width=period-pulse_width; - dprintk("in init_timing_params, freq=%d pulse=%ld, " - "space=%ld\n", freq, pulse_width, space_width); - return 0; -} -#endif /* USE_RDTSC */ - - -/* return value: space length delta */ - -static 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) - { - soutp(UART_TX,output); - while(!(sinp(UART_LSR) & UART_LSR_THRE)); - output=0x7f; - i=0; - } - } - if(i!=0) - { - soutp(UART_TX,output); - while(!(sinp(UART_LSR) & UART_LSR_TEMT)); - } - - if(i==0) - { - return((-rawbits)*10000/1152); - } - else - { - return((3-i)*3*10000/1152+(-rawbits)*10000/1152); - } -} - -#ifdef USE_RDTSC -/* Version that uses Pentium rdtsc instruction to measure clocks */ - -/* This version does sub-microsecond timing using rdtsc instruction, - * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY - * Implicitly i586 architecture... - Steve - */ - -static inline long send_pulse_homebrew_softcarrier(unsigned long length) -{ - int flag; - unsigned long target, start, now; - - /* Get going quick as we can */ - rdtscl(start);on(); - /* Convert length from microseconds to clocks */ - length*=conv_us_to_clocks; - /* And loop till time is up - flipping at right intervals */ - now=start; - target=pulse_width; - flag=1; - while((now-start)>8; - /* Note - we've checked in ioctl that the pulse/space - widths are big enough so that d is > 0 */ - udelay(d); - actual+=(d<<8)+LIRC_SERIAL_TRANSMITTER_LATENCY; - flag=!flag; - } - return((actual-length)>>8); -} -#endif /* USE_RDTSC */ - -static long send_pulse_homebrew(unsigned long length) -{ - if(length<=0) return 0; - if(softcarrier) - { - return send_pulse_homebrew_softcarrier(length); - } - else - { - on(); - safe_udelay(length); - return(0); - } -} - -static void send_space_irdeo(long length) -{ - if(length<=0) return; - safe_udelay(length); -} - -static void send_space_homebrew(long length) -{ - off(); - if(length<=0) return; - safe_udelay(length); -} - -static void inline rbwrite(lirc_t l) -{ - if(lirc_buffer_full(&rbuf)) /* no new signals will be accepted */ - { - dprintk("Buffer overrun\n"); - return; - } - _lirc_buffer_write_1(&rbuf, (void *)&l); -} - -static void inline frbwrite(lirc_t l) -{ - /* simple noise filter */ - static lirc_t pulse=0L,space=0L; - static unsigned int ptr=0; - - if(ptr>0 && (l&PULSE_BIT)) - { - pulse+=l&PULSE_MASK; - if(pulse>250) - { - rbwrite(space); - rbwrite(pulse|PULSE_BIT); - ptr=0; - pulse=0; - } - return; - } - if(!(l&PULSE_BIT)) - { - if(ptr==0) - { - if(l>20000) - { - space=l; - ptr++; - return; - } - } - else - { - if(l>20000) - { - space+=pulse; - if(space>PULSE_MASK) space=PULSE_MASK; - space+=l; - if(space>PULSE_MASK) space=PULSE_MASK; - pulse=0; - return; - } - rbwrite(space); - rbwrite(pulse|PULSE_BIT); - ptr=0; - pulse=0; - } - } - rbwrite(l); -} - -static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) -{ - struct timeval tv; - int status,counter,dcd; - long deltv; - lirc_t data; - - if((sinp(UART_IIR) & UART_IIR_NO_INT)) - { - /* not our interrupt */ - return IRQ_RETVAL(IRQ_NONE); - } - - counter=0; - do{ - counter++; - status=sinp(UART_MSR); - if(counter>RS_ISR_PASS_LIMIT) - { - printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " - "We're caught!\n"); - break; - } - if((status&hardware[type].signal_pin_change) && sense!=-1) - { - /* get current time */ - do_gettimeofday(&tv); - - /* New mode, written by Trent Piepho - . */ - - /* The old format was not very portable. - We now use the type lirc_t to pass pulses - and spaces to user space. - - If PULSE_BIT is set a pulse has been - received, otherwise a space has been - received. The driver needs to know if your - receiver is active high or active low, or - the space/pulse sense could be - inverted. The bits denoted by PULSE_MASK are - the length in microseconds. Lengths greater - than or equal to 16 seconds are clamped to - PULSE_MASK. All other bits are unused. - This is a much simpler interface for user - programs, as well as eliminating "out of - phase" errors with space/pulse - autodetection. */ - - /* calculate time since last interrupt in - microseconds */ - dcd=(status & hardware[type].signal_pin) ? 1:0; - - deltv=tv.tv_sec-lasttv.tv_sec; - if(deltv>15) - { - dprintk("AIEEEE: %d %d %lx %lx %lx %lx\n", - dcd,sense, - tv.tv_sec,lasttv.tv_sec, - tv.tv_usec,lasttv.tv_usec); - data=PULSE_MASK; /* really long time */ - if(!(dcd^sense)) /* sanity check */ - { - /* detecting pulse while this - MUST be a space! */ - sense=sense ? 0:1; - } - } - else - { - data=(lirc_t) (deltv*1000000+ - tv.tv_usec- - lasttv.tv_usec); - }; - if(tv.tv_sec 115200 Baud */ - soutp(UART_DLM,0); - soutp(UART_DLL,1); - /* Set DLAB 0 + 7N1 */ - soutp(UART_LCR,UART_LCR_WLEN7); - /* THR interrupt already disabled at this point */ - break; - default: - break; - } - - local_irq_restore(flags); - - /* Initialize pulse/space widths */ - init_timing_params(duty_cycle, freq); - - /* If pin is high, then this must be an active low receiver. */ - if(sense==-1) - { - /* wait 1 sec for the power supply */ - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - - sense=(sinp(UART_MSR) & hardware[type].signal_pin) ? 1:0; - printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " - "%s receiver\n",sense ? "low":"high"); - } - else - { - printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " - "%s receiver\n",sense ? "low":"high"); - }; - - return 0; -} - -static int set_use_inc(void* data) -{ - int result; - unsigned long flags; - - /* Init read buffer. */ - if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0) - return -ENOMEM; - - /* initialize timestamp */ - do_gettimeofday(&lasttv); - - result=request_irq(irq,irq_handler, - SA_INTERRUPT | (share_irq ? SA_SHIRQ:0), - LIRC_DRIVER_NAME,(void *)&hardware); - - switch(result) - { - case -EBUSY: - printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); - lirc_buffer_free(&rbuf); - return -EBUSY; - case -EINVAL: - printk(KERN_ERR LIRC_DRIVER_NAME - ": Bad irq number or handler\n"); - lirc_buffer_free(&rbuf); - return -EINVAL; - default: - dprintk("Interrupt %d, port %04x obtained\n", irq, io); - break; - }; - - local_irq_save(flags); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); - - local_irq_restore(flags); - - MOD_INC_USE_COUNT; - return 0; -} - -static void set_use_dec(void* data) -{ unsigned long flags; - - local_irq_save(flags); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* First of all, disable all interrupts */ - soutp(UART_IER, sinp(UART_IER)& - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); - local_irq_restore(flags); - - free_irq(irq, (void *)&hardware); - - dprintk("freed IRQ %d\n", irq); - lirc_buffer_free(&rbuf); - - MOD_DEC_USE_COUNT; -} - -static ssize_t lirc_write(struct file *file, const char *buf, - size_t n, loff_t * ppos) -{ - int i,count; - unsigned long flags; - long delta=0; - - if(!(hardware[type].features&LIRC_CAN_SEND_PULSE)) - { - return(-EBADF); - } - - if(n%sizeof(lirc_t)) return(-EINVAL); - count=n/sizeof(lirc_t); - if(count>WBUF_LEN || count%2==0) return(-EINVAL); - if(copy_from_user(wbuf,buf,n)) return -EFAULT; - local_irq_save(flags); - if(type == LIRC_IRDEO) - { - /* DTR, RTS down */ - on(); - } - for(i=0;i100) return(-EINVAL); - return init_timing_params(ivalue, freq); - break; - - case LIRC_SET_SEND_CARRIER: - dprintk("SET_SEND_CARRIER\n"); - if(!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) - { - return(-ENOIOCTLCMD); - } - - result=get_user(ivalue,(unsigned int *) arg); - if(result) return(result); - if(ivalue>500000 || ivalue<20000) return(-EINVAL); - return init_timing_params(duty_cycle, ivalue); - break; - - default: - return(-ENOIOCTLCMD); - } - return(0); -} - -static struct file_operations lirc_fops = -{ - write: lirc_write, -}; - -static struct lirc_plugin plugin = { - name: LIRC_DRIVER_NAME, - minor: -1, - code_length: 1, - sample_rate: 0, - data: NULL, - add_to_buf: NULL, - get_queue: NULL, - rbuf: &rbuf, - set_use_inc: set_use_inc, - set_use_dec: set_use_dec, - ioctl: lirc_ioctl, - fops: &lirc_fops, - owner: THIS_MODULE, -}; - -#ifdef MODULE - -int init_module(void) -{ - int result; - - switch(type) - { - case LIRC_HOMEBREW: - case LIRC_IRDEO: - case LIRC_IRDEO_REMOTE: - case LIRC_ANIMAX: - case LIRC_IGOR: -#if defined(LIRC_SERIAL_NSLU2) - case LIRC_NSLU2: -#endif - break; - default: - return -EINVAL; - } - if(!softcarrier) - { - switch(type) - { - case LIRC_HOMEBREW: - case LIRC_IGOR: - case LIRC_NSLU2: - hardware[type].features&= - ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| - LIRC_CAN_SET_SEND_CARRIER); - break; - } - } - if((result = init_port()) < 0) - { - return result; - } - plugin.features = hardware[type].features; - if ((plugin.minor = lirc_register_plugin(&plugin)) < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": register_chrdev failed!\n"); - release_region(io, 8); - return -EIO; - } - return 0; -} - -void cleanup_module(void) -{ -#if defined(LIRC_ALLOW_MMAPPED_IO) - if(iommap != 0) - { - release_mem_region(iommap, 8< + * Copyright (C) 1998 Trent Piepho + * Copyright (C) 1998 Ben Pfaff + * Copyright (C) 1999 Christoph Bartelmus + * + * 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 July 2001 +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif + +#include + +#if defined(CONFIG_SERIAL) || defined(CONFIG_SERIAL_8250) +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(LIRC_SERIAL_NSLU2) +#include +/* From Intel IXP42X Developer's Manual (#252480-005): */ +/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ +#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ +#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ +#endif + +#include "drivers/lirc.h" +#include "drivers/kcompat.h" +#include "drivers/lirc_dev/lirc_dev.h" + +#if defined(LIRC_SERIAL_SOFTCARRIER) && !defined(LIRC_SERIAL_TRANSMITTER) +#warning "Software carrier only affects transmitting" +#endif + +#if defined(rdtsc) + +#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 +#endif + +#define LIRC_DRIVER_NAME "lirc_serial2" + +struct lirc_serial2 +{ + 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 +#define LIRC_IGOR 4 +#define LIRC_NSLU2 5 + +#ifdef LIRC_SERIAL_IRDEO +static int type=LIRC_IRDEO; +#elif defined(LIRC_SERIAL_IRDEO_REMOTE) +static int type=LIRC_IRDEO_REMOTE; +#elif defined(LIRC_SERIAL_ANIMAX) +static int type=LIRC_ANIMAX; +#elif defined(LIRC_SERIAL_IGOR) +static int type=LIRC_IGOR; +#elif defined(LIRC_SERIAL_NSLU2) +static int type=LIRC_NSLU2; +#else +static int type=LIRC_HOMEBREW; +#endif + +/* Set defaults for NSLU2 */ +#if defined(LIRC_SERIAL_NSLU2) +#ifndef LIRC_IRQ +#define LIRC_IRQ IRQ_IXP4XX_UART2 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT (IXP4XX_UART2_BASE_VIRT + REG_OFFSET) +#endif +#ifndef LIRC_IOMMAP +#define LIRC_IOMMAP IXP4XX_UART2_BASE_PHYS +#endif +#ifndef LIRC_IOSHIFT +#define LIRC_IOSHIFT 2 +#endif +#ifndef LIRC_ALLOW_MMAPPED_IO +#define LIRC_ALLOW_MMAPPED_IO +#endif +#endif + +#if defined(LIRC_ALLOW_MMAPPED_IO) +#ifndef LIRC_IOMMAP +#define LIRC_IOMMAP 0 +#endif +#ifndef LIRC_IOSHIFT +#define LIRC_IOSHIFT 0 +#endif +static int iommap = LIRC_IOMMAP; +static int ioshift = LIRC_IOSHIFT; +#endif + +#ifdef LIRC_SERIAL_SOFTCARRIER +static int softcarrier=1; +#else +static int softcarrier=0; +#endif + +static int share_irq = 0; +static int debug = 0; + +#define dprintk(fmt, args...) \ + do{ \ + if(debug) \ + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ + fmt, ## args); \ + }while(0) + +/* forward declarations */ +static long send_pulse_irdeo(unsigned long length); +static long send_pulse_homebrew(unsigned long length); +static void send_space_irdeo(long length); +static void send_space_homebrew(long length); + +static struct lirc_serial2 hardware[]= +{ + /* home-brew receiver/transmitter */ + { + 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 */ + { + 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 */ + { + 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 */ + { + UART_MSR_DCD, + UART_MSR_DDCD, + 0, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + NULL, + NULL, + LIRC_CAN_REC_MODE2 + }, + + /* home-brew receiver/transmitter (Igor Cesko's variation) */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + 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) + }, + +#if defined(LIRC_SERIAL_NSLU2) + /* Modified Linksys Network Storage Link USB 2.0 (NSLU2): + We receive on CTS of the 2nd serial port (R142,LHS), we + transmit with a IR diode between GPIO[1] (green status LED), + and ground (Matthias Goebl ). + See also http://www.nslu2-linux.org for this device */ + { + UART_MSR_CTS, + UART_MSR_DCTS, + 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) + }, +#endif + +}; + +#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 256 + +static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ +static int txsense = 0; /* 0 = active high, 1 = active low */ + +#ifndef LIRC_IRQ +#define LIRC_IRQ 4 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT 0x3f8 +#endif + +static int io = LIRC_PORT; +static int irq = LIRC_IRQ; + +static struct timeval lasttv = {0, 0}; + +static struct lirc_buffer rbuf; + +static lirc_t wbuf[WBUF_LEN]; + +static unsigned int freq = 38000; +static unsigned int duty_cycle = 50; + +/* Initialized in init_timing_params() */ +static unsigned long period = 0; +static unsigned long pulse_width = 0; +static unsigned long space_width = 0; + +#if defined(__i386__) +/* + From: + Linux I/O port programming mini-HOWTO + Author: Riku Saikkonen + 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__ */ + +static inline unsigned int sinp(int offset) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if(iommap != 0) /* the register is memory-mapped */ + { + offset <<= ioshift; + return readb(io + offset); + } +#endif + return inb(io + offset); +} + +static inline void soutp(int offset, int value) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if(iommap != 0) /* the register is memory-mapped */ + { + offset <<= ioshift; + writeb(value, io + offset); + } +#endif + outb(value, io + offset); +} + +static inline void on(void) +{ +#if defined(LIRC_SERIAL_NSLU2) + /* On NSLU2, we put the transmit diode between the output of the green + status LED and ground */ + if(type == LIRC_NSLU2) + { + gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); + return; + } +#endif + if (txsense) + { + soutp(UART_MCR,hardware[type].off); + } + else + { + soutp(UART_MCR,hardware[type].on); + } +} + +static inline void off(void) +{ +#if defined(LIRC_SERIAL_NSLU2) + if(type == LIRC_NSLU2) + { + gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); + return; + } +#endif + if (txsense) + { + soutp(UART_MCR,hardware[type].on); + } + else + { + soutp(UART_MCR,hardware[type].off); + } +} + +#ifndef MAX_UDELAY_MS +#define MAX_UDELAY_US 5000 +#else +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) +#endif + +static 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 */ + +/* 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 + */ + +/* So send_pulse can quickly convert microseconds to clocks */ +static unsigned long conv_us_to_clocks = 0; + +static inline int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ + unsigned long long loops_per_sec,work; + + duty_cycle=new_duty_cycle; + freq=new_freq; + + loops_per_sec=current_cpu_data.loops_per_jiffy; + loops_per_sec*=HZ; + + /* 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; + dprintk("in init_timing_params, 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); + return 0; +} +#else /* ! USE_RDTSC */ +static inline int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ +/* period, pulse/space width are kept with 8 binary places - + * IE multiplied by 256. */ + if(256*1000000L/new_freq*new_duty_cycle/100<= + LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); + if(256*1000000L/new_freq*(100-new_duty_cycle)/100<= + LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); + duty_cycle=new_duty_cycle; + freq=new_freq; + period=256*1000000L/freq; + pulse_width=period*duty_cycle/100; + space_width=period-pulse_width; + dprintk("in init_timing_params, freq=%d pulse=%ld, " + "space=%ld\n", freq, pulse_width, space_width); + return 0; +} +#endif /* USE_RDTSC */ + + +/* return value: space length delta */ + +static 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) + { + soutp(UART_TX,output); + while(!(sinp(UART_LSR) & UART_LSR_THRE)); + output=0x7f; + i=0; + } + } + if(i!=0) + { + soutp(UART_TX,output); + while(!(sinp(UART_LSR) & UART_LSR_TEMT)); + } + + if(i==0) + { + return((-rawbits)*10000/1152); + } + else + { + return((3-i)*3*10000/1152+(-rawbits)*10000/1152); + } +} + +#ifdef USE_RDTSC +/* Version that uses Pentium rdtsc instruction to measure clocks */ + +/* This version does sub-microsecond timing using rdtsc instruction, + * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY + * Implicitly i586 architecture... - Steve + */ + +static inline long send_pulse_homebrew_softcarrier(unsigned long length) +{ + int flag; + unsigned long target, start, now; + + /* Get going quick as we can */ + rdtscl(start);on(); + /* Convert length from microseconds to clocks */ + length*=conv_us_to_clocks; + /* And loop till time is up - flipping at right intervals */ + now=start; + target=pulse_width; + flag=1; + while((now-start)>8; + /* Note - we've checked in ioctl that the pulse/space + widths are big enough so that d is > 0 */ + udelay(d); + actual+=(d<<8)+LIRC_SERIAL_TRANSMITTER_LATENCY; + flag=!flag; + } + return((actual-length)>>8); +} +#endif /* USE_RDTSC */ + +static long send_pulse_homebrew(unsigned long length) +{ + if(length<=0) return 0; + if(softcarrier) + { + return send_pulse_homebrew_softcarrier(length); + } + else + { + on(); + safe_udelay(length); + return(0); + } +} + +static void send_space_irdeo(long length) +{ + if(length<=0) return; + safe_udelay(length); +} + +static void send_space_homebrew(long length) +{ + off(); + if(length<=0) return; + safe_udelay(length); +} + +static void inline rbwrite(lirc_t l) +{ + if(lirc_buffer_full(&rbuf)) /* no new signals will be accepted */ + { + dprintk("Buffer overrun\n"); + return; + } + _lirc_buffer_write_1(&rbuf, (void *)&l); +} + +static void inline frbwrite(lirc_t l) +{ + /* simple noise filter */ + static lirc_t pulse=0L,space=0L; + static unsigned int ptr=0; + + if(ptr>0 && (l&PULSE_BIT)) + { + pulse+=l&PULSE_MASK; + if(pulse>250) + { + rbwrite(space); + rbwrite(pulse|PULSE_BIT); + ptr=0; + pulse=0; + } + return; + } + if(!(l&PULSE_BIT)) + { + if(ptr==0) + { + if(l>20000) + { + space=l; + ptr++; + return; + } + } + else + { + if(l>20000) + { + space+=pulse; + if(space>PULSE_MASK) space=PULSE_MASK; + space+=l; + if(space>PULSE_MASK) space=PULSE_MASK; + pulse=0; + return; + } + rbwrite(space); + rbwrite(pulse|PULSE_BIT); + ptr=0; + pulse=0; + } + } + rbwrite(l); +} + +static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) +{ + struct timeval tv; + int status,counter,dcd; + long deltv; + lirc_t data; + + if((sinp(UART_IIR) & UART_IIR_NO_INT)) + { + /* not our interrupt */ + return IRQ_RETVAL(IRQ_NONE); + } + + counter=0; + do{ + counter++; + status=sinp(UART_MSR); + if(counter>RS_ISR_PASS_LIMIT) + { + printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " + "We're caught!\n"); + break; + } + if((status&hardware[type].signal_pin_change) && sense!=-1) + { + /* get current time */ + do_gettimeofday(&tv); + + /* New mode, written by Trent Piepho + . */ + + /* The old format was not very portable. + We now use the type lirc_t to pass pulses + and spaces to user space. + + If PULSE_BIT is set a pulse has been + received, otherwise a space has been + received. The driver needs to know if your + receiver is active high or active low, or + the space/pulse sense could be + inverted. The bits denoted by PULSE_MASK are + the length in microseconds. Lengths greater + than or equal to 16 seconds are clamped to + PULSE_MASK. All other bits are unused. + This is a much simpler interface for user + programs, as well as eliminating "out of + phase" errors with space/pulse + autodetection. */ + + /* calculate time since last interrupt in + microseconds */ + dcd=(status & hardware[type].signal_pin) ? 1:0; + + deltv=tv.tv_sec-lasttv.tv_sec; + if(deltv>15) + { + dprintk("AIEEEE: %d %d %lx %lx %lx %lx\n", + dcd,sense, + tv.tv_sec,lasttv.tv_sec, + tv.tv_usec,lasttv.tv_usec); + data=PULSE_MASK; /* really long time */ + if(!(dcd^sense)) /* sanity check */ + { + /* detecting pulse while this + MUST be a space! */ + sense=sense ? 0:1; + } + } + else + { + data=(lirc_t) (deltv*1000000+ + tv.tv_usec- + lasttv.tv_usec); + }; + if(tv.tv_sec 115200 Baud */ + soutp(UART_DLM,0); + soutp(UART_DLL,1); + /* Set DLAB 0 + 7N1 */ + soutp(UART_LCR,UART_LCR_WLEN7); + /* THR interrupt already disabled at this point */ + break; + default: + break; + } + + local_irq_restore(flags); + + /* Initialize pulse/space widths */ + init_timing_params(duty_cycle, freq); + + /* If pin is high, then this must be an active low receiver. */ + if(sense==-1) + { + /* wait 1 sec for the power supply */ + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + sense=(sinp(UART_MSR) & hardware[type].signal_pin) ? 1:0; + printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " + "%s receiver\n",sense ? "low":"high"); + } + else + { + printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " + "%s receiver\n",sense ? "low":"high"); + }; + + return 0; +} + +static int set_use_inc(void* data) +{ + int result; + unsigned long flags; + + /* Init read buffer. */ + if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0) + return -ENOMEM; + + /* initialize timestamp */ + do_gettimeofday(&lasttv); + + result=request_irq(irq,irq_handler, + SA_INTERRUPT | (share_irq ? SA_SHIRQ:0), + LIRC_DRIVER_NAME,(void *)&hardware); + + switch(result) + { + case -EBUSY: + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); + lirc_buffer_free(&rbuf); + return -EBUSY; + case -EINVAL: + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + lirc_buffer_free(&rbuf); + return -EINVAL; + default: + dprintk("Interrupt %d, port %04x obtained\n", irq, io); + break; + }; + + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + + local_irq_restore(flags); + + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void* data) +{ unsigned long flags; + + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER)& + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + local_irq_restore(flags); + + free_irq(irq, (void *)&hardware); + + dprintk("freed IRQ %d\n", irq); + lirc_buffer_free(&rbuf); + + MOD_DEC_USE_COUNT; +} + +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t * ppos) +{ + int i,count; + unsigned long flags; + long delta=0; + + if(!(hardware[type].features&LIRC_CAN_SEND_PULSE)) + { + return(-EBADF); + } + + if(n%sizeof(lirc_t)) return(-EINVAL); + count=n/sizeof(lirc_t); + if(count>WBUF_LEN || count%2==0) return(-EINVAL); + if(copy_from_user(wbuf,buf,n)) return -EFAULT; + local_irq_save(flags); + if(type == LIRC_IRDEO) + { + /* DTR, RTS down */ + on(); + } + for(i=0;i100) return(-EINVAL); + return init_timing_params(ivalue, freq); + break; + + case LIRC_SET_SEND_CARRIER: + dprintk("SET_SEND_CARRIER\n"); + if(!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) + { + return(-ENOIOCTLCMD); + } + + result=get_user(ivalue,(unsigned int *) arg); + if(result) return(result); + if(ivalue>500000 || ivalue<20000) return(-EINVAL); + return init_timing_params(duty_cycle, ivalue); + break; + + default: + return(-ENOIOCTLCMD); + } + return(0); +} + +static struct file_operations lirc_fops = +{ + write: lirc_write, +}; + +static struct lirc_plugin plugin = { + name: LIRC_DRIVER_NAME, + minor: -1, + code_length: 1, + sample_rate: 0, + data: NULL, + add_to_buf: NULL, + get_queue: NULL, + rbuf: &rbuf, + set_use_inc: set_use_inc, + set_use_dec: set_use_dec, + ioctl: lirc_ioctl, + fops: &lirc_fops, + owner: THIS_MODULE, +}; + +#ifdef MODULE + +int init_module(void) +{ + int result; + + switch(type) + { + case LIRC_HOMEBREW: + case LIRC_IRDEO: + case LIRC_IRDEO_REMOTE: + case LIRC_ANIMAX: + case LIRC_IGOR: +#if defined(LIRC_SERIAL_NSLU2) + case LIRC_NSLU2: +#endif + break; + default: + return -EINVAL; + } + if(!softcarrier) + { + switch(type) + { + case LIRC_HOMEBREW: + case LIRC_IGOR: + case LIRC_NSLU2: + hardware[type].features&= + ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER); + break; + } + } + if((result = init_port()) < 0) + { + return result; + } + plugin.features = hardware[type].features; + if ((plugin.minor = lirc_register_plugin(&plugin)) < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": register_chrdev failed!\n"); + release_region(io, 8); + return -EIO; + } + return 0; +} + +void cleanup_module(void) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if(iommap != 0) + { + release_mem_region(iommap, 8<