diff --exclude .depend --exclude .hdepend -ur linux-11-08-snay/arch/mips/config.in linux-agenda-www-20020207/arch/mips/config.in
--- linux-11-08-snay/arch/mips/config.in	Sat Mar 31 02:58:17 2001
+++ linux-agenda-www-20020207/arch/mips/config.in	Wed Jan 30 21:43:44 2002
@@ -691,6 +691,7 @@
 
   if [ "$CONFIG_CPU_VR41XX" = "y" -a "$CONFIG_AGENDA_VR3" = "y" ]; then
     bool 'LIRC support' CONFIG_LIRC
+    bool 'LIRC receiver support (alpha,unstable,buggy)' CONFIG_LIRC_LDISC_RECEIVER
   fi
 
   if [ "$CONFIG_CPU_VR41XX" = "y" ]; then
diff --exclude .depend --exclude .hdepend -ur linux-11-08-snay/arch/mips/vr41xx/lirc_vrgpio.c linux-agenda-www-20020207/arch/mips/vr41xx/lirc_vrgpio.c
--- linux-11-08-snay/arch/mips/vr41xx/lirc_vrgpio.c	Thu Apr 26 00:48:23 2001
+++ linux-agenda-www-20020207/arch/mips/vr41xx/lirc_vrgpio.c	Thu Jan 31 15:46:22 2002
@@ -7,6 +7,9 @@
  *
  * Copyright (C) 2001 Chris AtLee <chris@agendacomputing.com>
  *
+ * Receiving part based on SIR receiver added 2002/01/28
+ * Copyright (C) 2002 Milan Pikula <www@terminus.sk>
+ *
  * Based on lirc_serial.c
  * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
  * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
@@ -16,6 +19,22 @@
  */
 
 #define LIRC_MAJOR 61
+
+/* it is OK to turn on the following feature.. ;) */
+#define DIRTY_MULTIFREQUENCY_HACK
+
+/* but the following one makes sense only when you are mad,
+ * brain-damaged and REALLY want the line discipline to
+ * access the UART directly (the second one;). It turns FIFO
+ * off, so that we don't get buffered reads. (we need NO BUFFERING,
+ * because in the other case we won't see the real times between
+ * pulses, thus the receiving part of driver won't work correctly!)
+ *
+ * well, in fact, the real place for such code is serial.c, but that's
+ * itself dirty on MIPS, and we don't want to mess it up with the
+ * irrelevant code.
+ */
+#define ABSOLUTELY_DIRTY_SERIAL_HACK
  
 #include <linux/version.h>
 #if LINUX_VERSION_CODE >= 0x020100
@@ -49,6 +68,14 @@
 #include <linux/poll.h>
 #endif
 
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+#include <linux/tty_ldisc.h>
+#ifndef N_LIRC
+/* !!! THIS IS AS DIRTY AS the ABSOLUTELY_DIRTY_SERIAL_HACK define ABOVE */
+#define N_LIRC N_6PACK	/* TODO+FIXME: register the ldisc number */
+#endif
+#endif
+
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -78,13 +105,34 @@
 
 static int major = LIRC_MAJOR;
 
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+#define PULSE '['
+
 #ifdef KERNEL_2_3
 static DECLARE_WAIT_QUEUE_HEAD(lirc_wait_in);
 #else
 static struct wait_queue *lirc_wait_in = NULL;
 #endif
 
+/* 9bit * 1s/115200bit in micro seconds = 78.125us*/
+#define TIME_CONST (9000000ul/115200ul)
+
+/* timeout for sequences in jiffies (=5 ms) */
+/* must be longer than TIME_CONST */
+#define SIR_TIMEOUT     (HZ*5000/1000000)
+
+/* time of last signal change detected */
+static struct timeval last_tv = {0, 0};
+/* time of last UART data ready interrupt */
+static struct timeval last_intr_tv = {0, 0};
+static int last_value = 0;
+
+static spinlock_t timer_lock = SPIN_LOCK_UNLOCKED;
+static struct timer_list timerlist;
+
 static int rbh, rbt;
+static lirc_t rbuf[RBUF_LEN];
+#endif
 static lirc_t wbuf[WBUF_LEN];
 
 /* 1 is substracted from the actual value to compensate the port
@@ -98,28 +146,62 @@
 unsigned int freq = 38000;      /* modulation frequency */
 unsigned int duty_cycle = 50;   /* duty cycle of 50% */
 
-#ifdef LIRC_SERIAL_ANIMAX
-#define LIRC_OFF (UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2)
-
-#elif defined(LIRC_SERIAL_IRDEO)
-#define LIRC_OFF (UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2)
-#define LIRC_ON  UART_MCR_OUT2
-
-#else
 #define LIRC_OFF (UART_MCR_RTS|UART_MCR_OUT2)
 #define LIRC_ON  (LIRC_OFF|UART_MCR_DTR)
-#endif
 
-void on(void)
+static void on(void)
 {
 	*VR41XX_GPDATLREG |= (VR41XX_GPDATLREG_GPIO6); // CIR is high active
 }
   
-void off(void)
+static void off(void)
 {
 	*VR41XX_GPDATLREG &= ~(VR41XX_GPDATLREG_GPIO6); 
 }
 
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif 
+
+static long delta_usecs(struct timeval * tv1, struct timeval * tv2)
+{
+        unsigned long deltv;
+         
+        deltv = tv2->tv_sec - tv1->tv_sec;
+        if (deltv > 15)
+                deltv = 0xFFFFFF;
+        else
+                deltv = deltv*1000000 +
+                        tv2->tv_usec -
+                        tv1->tv_usec;
+        return deltv;
+}
+
+
+static inline void safe_udelay(unsigned long usecs)
+{
+        while(usecs>MAX_UDELAY_US)
+        {
+                udelay(MAX_UDELAY_US);
+                usecs-=MAX_UDELAY_US;
+        }
+        udelay(usecs);
+}
+
+static void substract_usec(struct timeval * tv, unsigned long usecs)
+{
+	tv->tv_sec -= (usecs/1000000);
+	usecs %= 1000000;
+	if (tv->tv_usec >= usecs) {
+		tv->tv_usec -= usecs;
+	} else {
+		tv->tv_sec--;
+		tv->tv_usec += 1000000-usecs;
+	}
+}
+
 void send_pulse(unsigned long length)
 {
 	unsigned long k,delay;
@@ -141,7 +223,7 @@
 			on();
 			delay=pulse_width;
 		}
-		udelay(delay);
+		safe_udelay(delay);
 	}
 }
 
@@ -149,9 +231,10 @@
 {
 	if(length==0) return;
 	off();
-	udelay(length);
+	safe_udelay(length);
 }
 
+
 static int Device_Open = 0;
 
 static int lirc_open(struct inode *ino, struct file *filep)
@@ -173,9 +256,11 @@
 #ifdef KERNEL_2_1
 static unsigned int lirc_poll(struct file *file, poll_table * wait)
 {
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
 	poll_wait(file, &lirc_wait_in, wait);
 	if (rbh != rbt)
 		return POLLIN | POLLRDNORM;
+#endif
 	return 0;
 }
 #else
@@ -184,13 +269,78 @@
 {
 	if (sel_type != SEL_IN)
 		return 0;
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
 	if (rbh != rbt)
 		return 1;
 	select_wait(&lirc_wait_in, wait);
+#endif
 	return 0;
 }
 #endif
 
+static ssize_t lirc_read(struct file * file, char * buf, size_t count, loff_t * ppos)
+{
+        int n=0;
+        int retval = 0;
+#ifdef KERNEL_2_3
+        DECLARE_WAITQUEUE(wait,current);
+#else
+        struct wait_queue wait={current,NULL};
+#endif
+
+        if(n%sizeof(lirc_t)) return(-EINVAL);
+
+        add_wait_queue(&lirc_wait_in,&wait);
+        current->state=TASK_INTERRUPTIBLE;
+        while(n<count)
+        {
+                if(rbh!=rbt)
+                {
+                        retval=verify_area(VERIFY_WRITE,
+                                           (void *) buf+n,sizeof(lirc_t));
+                        if (retval)
+                        {
+                                return retval;
+                        }
+#ifdef KERNEL_2_1
+                        copy_to_user((void *) buf+n,(void *) (rbuf+rbh),
+                                     sizeof(lirc_t));
+#else
+                        memcpy_tofs((void *) buf+n,(void *) (rbuf+rbh),
+                                    sizeof(lirc_t));
+#endif
+                        rbh=(rbh+1)&(RBUF_LEN-1);
+                        n+=sizeof(lirc_t);
+                }
+                else
+                {
+                        if(file->f_flags & O_NONBLOCK)
+                        {
+                                retval=-EAGAIN;
+                                break;
+                        }
+#                       ifdef KERNEL_2_1
+                        if(signal_pending(current))
+                        {
+                                retval=-ERESTARTSYS;
+                                break;
+                        }
+#                       else
+                        if(current->signal & ~current->blocked)
+                        {
+                                retval=-EINTR;
+                                break;
+                        }
+#                       endif
+                        schedule();
+                        current->state=TASK_INTERRUPTIBLE;
+                }
+        }
+        remove_wait_queue(&lirc_wait_in,&wait);
+        current->state=TASK_RUNNING;
+        return (n ? n : retval);
+}
+
 static int lirc_write(struct file *file, const char *buf, size_t n, loff_t* offset)
 {
 	int retval,i,count;
@@ -229,10 +379,8 @@
 #       ifdef LIRC_SERIAL_TRANSMITTER
 #       ifdef LIRC_SERIAL_SOFTCARRIER
 	LIRC_CAN_SET_SEND_DUTY_CYCLE|
-#       ifndef LIRC_SERIAL_IRDEO
 	LIRC_CAN_SET_SEND_CARRIER|
 #       endif
-#       endif
 	LIRC_CAN_SEND_PULSE|
 #       endif
 	LIRC_CAN_REC_MODE2;
@@ -349,40 +497,205 @@
 	return(0);
 }
 
+static void add_read_queue(int flag, unsigned long val)
+{
+        unsigned int new_rbt;
+        lirc_t newval;
+
+#ifdef DEBUG_SIGNAL 
+        printk(KERN_DEBUG LIRC_DRIVER_NAME
+                ": add flag %d with val %lu\n",
+                flag,val);
+#endif 
+
+        newval = val & PULSE_MASK;
+
+        /* statistically pulses are ~TIME_CONST/2 too long: we could
+           maybe make this more exactly but this is good enough */
+        if(flag) /* pulse */
+        {
+                if(newval>TIME_CONST/2)
+                {
+                        newval-=TIME_CONST/2;
+                }
+                else /* should not ever happen */
+                {
+                        newval=1;
+                }
+                newval|=PULSE_BIT;
+        }
+        else
+        {
+                newval+=TIME_CONST/2;
+        }
+        new_rbt = (rbt + 1) & (RBUF_LEN - 1);
+        if (new_rbt == rbh) {
+#               ifdef DEBUG
+                printk(KERN_WARNING LIRC_DRIVER_NAME ": Buffer overrun.\n");
+#               endif
+                return;
+        }
+        rbuf[rbt] = newval;
+        rbt = new_rbt;
+}
+
+static void try_shorten_read_queue(unsigned long n)
+{
+	int last_rbt;
+
+	if (rbt == rbh) /* they already taken that pulse */
+		return;
+	last_rbt = (rbt-1) & (RBUF_LEN - 1);
+	if ((rbuf[last_rbt]&PULSE_MASK) > n)
+		rbuf[last_rbt] = ((rbuf[last_rbt]&PULSE_MASK) - n) | (rbuf[last_rbt] & ~PULSE_MASK);
+	else
+		rbuf[last_rbt] = 1 | (rbuf[last_rbt] & ~PULSE_MASK);
+}
+
 static struct file_operations lirc_fops =
 {
-	read:    0,
 	write:   lirc_write,
 #       ifdef KERNEL_2_1
 	poll:    lirc_poll,
 #       else
 	select:  lirc_select,
 #       endif
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+	read:	 lirc_read,
+#else
+	read:	NULL,
+#endif
 	ioctl:   lirc_ioctl,
 	open:    lirc_open,
 	release: lirc_close
 };
 
-#ifdef MODULE
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+static void sir_timeout(unsigned long data) 
+{
+        /* if last received signal was a pulse, but receiving stopped
+           within the 9 bit frame, we need to finish this pulse and
+           simulate a signal change to from pulse to space. Otherwise
+           upper layers will receive two sequences next time. */
+         
+        unsigned long flags;
+        unsigned long pulse_end;
+         
+        /* avoid interference with interrupt */
+        spin_lock_irqsave(&timer_lock, flags);
+        if (last_value)
+        {
+                /* determine 'virtual' pulse end: */
+                pulse_end = delta_usecs(&last_tv, &last_intr_tv);
+                add_read_queue(last_value,pulse_end);
+                last_value = 0;
+                last_tv=last_intr_tv;
+        }
+        spin_unlock_irqrestore(&timer_lock, flags);
+        wake_up_interruptible(&lirc_wait_in);
+}
+
+void lirc_receive_character(struct tty_struct * tty, char c)
+{
+        unsigned char data;
+        struct timeval curr_tv;
+        unsigned long deltv;
+        unsigned long deltintrtv;
+        unsigned long flags;
+
+	/* avoid interference with timer */
+	spin_lock_irqsave(&timer_lock, flags);
+
+	del_timer(&timerlist);
+	do_gettimeofday(&curr_tv);
+	deltv = delta_usecs(&last_tv, &curr_tv);
+	deltintrtv = delta_usecs(&last_intr_tv, &curr_tv);
+
+	/* if nothing came in last 2 cycles, it was gap */
+	if (deltintrtv > TIME_CONST * 2) {
+		if (last_value) {
+			/* simulate signal change */
+			add_read_queue(last_value,deltv-deltintrtv);
+			last_value = 0;
+			last_tv.tv_sec = last_intr_tv.tv_sec;
+			last_tv.tv_usec = last_intr_tv.tv_usec;
+			deltv = deltintrtv;
+		}
+	} else
+	/* if the interrupt occurs too frequently, we suffer from buffering */
+	if (deltintrtv < TIME_CONST) {
+		try_shorten_read_queue(TIME_CONST-deltintrtv);
+		substract_usec(&last_tv, TIME_CONST-deltintrtv);
+		substract_usec(&last_intr_tv, TIME_CONST-deltintrtv);
+		deltv+=(TIME_CONST-deltintrtv);
+		deltintrtv=TIME_CONST;
+	}
+#ifdef DIRTY_MULTIFREQUENCY_HACK
+	data = 1;
+#else
+	data = (data == PULSE);
+#endif
+	if (data ^ last_value) {
+		add_read_queue(last_value, deltv-TIME_CONST);
+		last_value = data;
+		last_tv = curr_tv;
+		substract_usec(&last_tv, TIME_CONST);
+	}
+	last_intr_tv = curr_tv;
+	if (data) {
+		/* start timer for end of sequence detection */
+		timerlist.expires = jiffies + SIR_TIMEOUT;
+		add_timer(&timerlist);
+	}
 
-#if LINUX_VERSION_CODE >= 0x020100
-MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus");
-MODULE_DESCRIPTION("Infrared receiver driver for serial ports.");
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
 
-/*
-MODULE_PARM(port, "i");
-MODULE_PARM_DESC(port, "I/O address (0x3f8 or 0x2f8)");
-
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
-
-MODULE_PARM(sense, "i");
-MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
-		 " (0 = active high, 1 = active low )");
-*/
+/* line discipline routines for SIR receiver */
 
-EXPORT_NO_SYMBOLS;
+static int ldisc_open(struct tty_struct * tty)
+{
+	rbh = rbt = 0;
+#ifdef ABSOLUTELY_DIRTY_SERIAL_HACK
+	tty->low_latency = 1;
+#else
+	if (!tty->low_latency) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": The serial port must be low_latency to use with CIR module! Use setserial to change!\n");
+	}
+#endif
+	return 0;
+}
+static void ldisc_close(struct tty_struct * tty)
+{
+	del_timer(&timerlist);
+#ifdef ABSOLUTELY_DIRTY_SERIAL_HACK
+		*VR41XX_SIUFC_2 = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+#endif
+}
+
+static void ldisc_receive_buf(struct tty_struct * tty,
+		const unsigned char * cp,
+		char * fp, int count)
+{
+	if (count > 1) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": ldisc input overrun (%d)\n", count);
+#ifdef ABSOLUTELY_DIRTY_SERIAL_HACK
+		tty->low_latency = 1;
+		*VR41XX_SIUFC_2 = 0;
+		//*VR41XX_SIUFC_2 = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 #endif
+	}
+
+	// lirc_receive_character(tty, *cp);
+}
+
+static int ldisc_receive_room(struct tty_struct * tty)
+{
+	return 1;
+}
+
+
+struct tty_ldisc lirc_ldisc;
 #endif
 
 int lirc_init(void)
@@ -391,7 +704,34 @@
 		printk(KERN_ERR  LIRC_DRIVER_NAME  ": register_chrdev failed!\n");
 		return -EIO;
 	}
-	printk("LIRC registered\n");
+
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+	memset(&lirc_ldisc, 0, sizeof(lirc_ldisc));
+	lirc_ldisc.magic	= TTY_LDISC_MAGIC;
+	lirc_ldisc.name		= LIRC_DRIVER_NAME;
+	lirc_ldisc.open		= ldisc_open;
+	lirc_ldisc.close	= ldisc_close;
+	lirc_ldisc.receive_buf	= ldisc_receive_buf;
+	lirc_ldisc.receive_room	= ldisc_receive_room;
+	/* lirc_ldisc.write_wakeup	= ldisc_write_wakeup; */
+
+#if 1
+	if (tty_register_ldisc(N_LIRC, &lirc_ldisc)) {
+		printk (KERN_ERR LIRC_DRIVER_NAME ": tty_register_ldisc failed!\n");
+		unregister_chrdev(major, LIRC_DRIVER_NAME);
+		return -EIO;
+	}
+#endif /* 0 */
+	init_timer(&timerlist);
+	timerlist.function = sir_timeout;
+	timerlist.data = 0xabadcafe;
+#endif /* CONFIG_LIRC_LDISC_RECEIVER */
+	
+#ifdef ABSOLUTELY_DIRTY_SERIAL_HACK
+	*VR41XX_SIUFC_2 = 0;
+	//*VR41XX_SIUFC_2 = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#endif
+	printk(KERN_INFO "LIRC registered\n");
 	return 0;
 }
 
@@ -402,6 +742,17 @@
 	printk(KERN_INFO  LIRC_DRIVER_NAME  ": cleaned up module\n");
 #       endif
 }
+
+#ifdef MODULE
+
+#if LINUX_VERSION_CODE >= 0x020100
+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus, Milan Pikula");
+MODULE_DESCRIPTION("Infrared receiver driver for serial ports.");
+
+EXPORT_NO_SYMBOLS;
+#endif
+#endif
+
 
 module_init(lirc_init);
 module_exit(lirc_fini);
diff --exclude .depend --exclude .hdepend -ur linux-11-08-snay/arch/mips/vr41xx/serial.c linux-agenda-www-20020207/arch/mips/vr41xx/serial.c
--- linux-11-08-snay/arch/mips/vr41xx/serial.c	Thu May 17 09:14:47 2001
+++ linux-agenda-www-20020207/arch/mips/vr41xx/serial.c	Thu Jan 31 15:45:20 2002
@@ -88,6 +88,10 @@
 #include <asm/vr41xx.h>
 #include <asm/vr41xx-platdep.h>
 
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+void lirc_receive_character(struct tty_struct * tty, char c);
+#endif
+
 static unsigned int serial_powered_on;
 
 #define UART_CONFIG_NAME "16550A"
@@ -151,7 +155,7 @@
 	{ "8250", 1, 0 },
 	{ "16450", 1, 0 },
 	{ "16550", 1, 0 },
-	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
+	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },   // < irq17
 	{ "cirrus", 1, 0 },     /* usurped by cyclades.c */
 	{ "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH },
 	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
@@ -519,6 +523,10 @@
 	icount = &info->state->icount;
 	do {
 		ch = serial_inp(info, UART_RX);
+#if CONFIG_LIRC_LDISC_RECEIVER
+		if (info->line == 1)
+			lirc_receive_character(tty, ch);
+#endif
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			goto ignore_char;
 		*tty->flip.char_buf_ptr = ch;
@@ -739,7 +747,7 @@
 
 	do {
 		if (!info->tty ||
-		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
+		    (serial_in(info, UART_IIR) & (UART_IIR_NO_INT|0x08))==0x09 ) {
 			if (!end_mark)
 				end_mark = info;
 			goto next;
@@ -1140,7 +1148,7 @@
 	/*
 	 * Finally, enable interrupts
 	 */
-	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI/*WWW*/;
 	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */
 	
 	/*
@@ -1379,7 +1387,12 @@
 		if ((info->state->baud_base / quot) < 2400)
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 		else
-			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+#ifdef CONFIG_LIRC_LDISC_RECEIVER
+		if (info->line > 0)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | 6/* WWW ??? */;
+		else
+#endif
+		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
 	
 	/* CTS flow control flag and modem status interrupts */
 	info->IER &= ~UART_IER_MSI;
