patch-2.1.132 linux/drivers/net/irda/irport.c

Next file: linux/drivers/net/irda/irtty.c
Previous file: linux/drivers/net/irda/esi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.131/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
@@ -0,0 +1,361 @@
+/*********************************************************************
+ *		  
+ * Filename:	  irport.c
+ * Version:	  0.1
+ * Description:   Serial driver for IrDA. The functions in this file
+ *                may be used by FIR drivers, but this file knows
+ *                nothing about FIR drivers!!!
+ * Status:	  Experimental.
+ * Author:	  Dag Brattli <dagb@cs.uit.no>
+ * Created at:	  Sun Aug  3 13:49:59 1997
+ * Modified at:   Sat May 23 23:15:20 1998
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Sources:	  serial.c by Linus Torvalds 
+ *		  serial_serial.c by Aage Kvalnes <aage@cs.uit.no>
+ * 
+ *     Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
+ *     All Rights Reserved.
+ *     
+ *     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.
+ *
+ *     Neither Dag Brattli nor University of Tromsų admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+/* #include <linux/module.h> */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+
+#include <linux/skbuff.h>
+#include <linux/serial_reg.h>
+
+#include "irda.h"
+#include "ircompat.h"
+#include "irport.h"
+#include "timer.h"
+#include "crc.h"
+#include "wrapper.h"
+#include "irlap_frame.h"
+
+#define IO_EXTENT	8
+
+static void irport_write_wakeup( struct irda_device *idev);
+static int irport_write( int iobase, int fifo_size, __u8 *buf, int len);
+static void irport_receive( struct irda_device *idev);
+
+/*
+ * Function irport_open (void)
+ *
+ *    Start IO port 
+ *
+ */
+int irport_open( int iobase)
+{
+	/* Initialize UART */
+	outb_p( UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
+	outb_p(( UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), 
+	       iobase+UART_MCR);
+	
+	/* Turn on interrups */
+	outb_p(( UART_IER_THRI |UART_IER_RLSI | UART_IER_RDI), 
+	       iobase+UART_IER); 
+	
+	return 0;
+}
+
+/*
+ * Function irport_cleanup ()
+ *
+ *    Stop IO port
+ *
+ */
+void irport_close( int iobase) 
+{
+	DEBUG( 0, __FUNCTION__ "()\n");
+
+	/* Reset UART */
+	outb_p( 0, iobase+UART_MCR);
+
+	/* Turn off interrupts */
+	outb_p( 0, iobase+UART_IER); 
+}
+
+/*
+ * Function irport_change_speed (idev, speed)
+ *
+ *    Set speed of port to specified baudrate
+ *
+ */
+void irport_change_speed( int iobase, int speed) 
+{
+	int fcr;    /* FIFO control reg */
+	int lcr;    /* Line control reg */
+	int divisor;
+
+	DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+
+	/* Turn off interrupts */
+	outb_p( 0, iobase+UART_IER); 
+
+	divisor = SPEED_MAX/speed;
+	
+	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+        
+	/* IrDA ports use 8N1 */
+	lcr = UART_LCR_WLEN8;
+	
+	outb_p( UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
+	outb_p( divisor & 0xff,      iobase+UART_DLL); /* Set speed	*/
+	outb_p( divisor >> 8,	     iobase+UART_DLM);
+	outb_p( lcr,		     iobase+UART_LCR); /* Set 8N1	*/
+	outb_p( fcr,		     iobase+UART_FCR); /* Enable FIFO's */
+
+	/* Turn on interrups */
+	outb_p(( UART_IER_THRI |UART_IER_RLSI | UART_IER_RDI), 
+	       iobase+UART_IER); 
+}
+
+/*
+ * Function irport_interrupt (irq, dev_id, regs)
+ *
+ *    
+ */
+void irport_interrupt( int irq, void *dev_id, struct pt_regs *regs) 
+{
+	struct irda_device *idev = (struct irda_device *) dev_id;
+
+	int iobase, status;
+	int iir;
+
+	DEBUG( 4, __FUNCTION__ "(), irq %d\n", irq);
+
+	if ( !idev) {
+		printk( KERN_WARNING __FUNCTION__ 
+			"() irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	iobase = idev->io.iobase;
+	iir    = inb( iobase + UART_IIR);
+
+	do {
+		status = inb( iobase+UART_LSR);
+		
+		if ( status & UART_LSR_DR) {
+	       		/* Receive interrupt */
+			irport_receive( idev);
+		}
+		if ( status & UART_LSR_THRE) {
+	       		/* Transmitter ready for data */
+			irport_write_wakeup( idev);
+		}
+	} while ( !(inb( iobase+UART_IIR) & UART_IIR_NO_INT));
+}
+
+/*
+ * Function irport_write_wakeup (tty)
+ *
+ *    Called by the driver when there's room for more data.  If we have
+ *    more packets to send, we send them here.
+ *
+ */
+static void irport_write_wakeup( struct irda_device *idev)
+{
+	int actual = 0, count;
+	
+	DEBUG( 4, __FUNCTION__ "() <%ld>\n", jiffies);
+	
+	/* 
+	 *  First make sure we're connected. 
+	 */
+	ASSERT( idev != NULL, return;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+	/*
+	 *  Finished with frame?
+	 */
+	if ( idev->tx.ptr == idev->tx.len)  {
+
+		/* 
+		 *  Now serial buffer is almost free & we can start 
+		 *  transmission of another packet 
+		 */
+		DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
+
+		idev->netdev.tbusy = 0; /* Unlock */
+		idev->stats.tx_packets++;
+
+		/* Schedule network layer, so we can get some more frames */
+		mark_bh( NET_BH);
+		return;
+	}
+	/*
+	 *  Write data left in transmit buffer
+	 */
+	count = idev->tx.len - idev->tx.ptr;
+	actual = irport_write( idev->io.iobase, idev->io.fifo_size, 
+			       idev->tx.head, count);
+	idev->tx.ptr += actual;
+	idev->tx.head += actual;
+}
+
+/*
+ * Function irport_write (driver)
+ *
+ *    
+ *
+ */
+static int irport_write( int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+
+	if (!(inb_p( iobase+UART_LSR) & UART_LSR_THRE)) {
+		DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		return -1;
+	}
+        
+	/* Fill FIFO with current frame */
+	while (( fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb( buf[actual], iobase+UART_TX);
+
+		actual++;
+	}
+        
+	DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+	       fifo_size, actual, len);
+
+	return actual;
+}
+
+/*
+ * Function irport_xmit (void)
+ *
+ *    Transmits the current frame until FIFO is full, then
+ *    waits until the next transmitt interrupt, and continues until the
+ *    frame is transmited.
+ */
+int irport_hard_xmit( struct sk_buff *skb, struct device *dev)
+{
+	struct irda_device *idev;
+	int xbofs;
+	int actual;
+
+	DEBUG( 4, __FUNCTION__ "()\n");
+
+	ASSERT( dev != NULL, return -1;);
+
+	if ( dev->tbusy) {
+		DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n");
+		
+		return -EBUSY;
+	}
+	
+	idev = (struct irda_device *)  dev->priv;
+
+	ASSERT( idev != NULL, return -1;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+	if ( skb == NULL) {
+		DEBUG( 0, __FUNCTION__ "(), skb==NULL\n");
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+		dev_tint(dev); 
+#endif
+		return 0;
+	}
+
+	/* Lock transmit buffer */
+	if ( irda_lock( (void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+	
+        /*  
+	 *  Transfer skb to tx_buff while wrapping, stuffing and making CRC 
+	 */
+	idev->tx.len = async_wrap_skb( skb, idev->tx.buff, idev->tx.buffsize);
+
+	actual = irport_write( idev->io.iobase, idev->io.fifo_size, 
+			       idev->tx.buff, idev->tx.len);
+
+	idev->tx.ptr = actual;
+	idev->tx.head = idev->tx.buff + actual;
+
+	IS_SKB( skb, return 0;);
+	FREE_SKB_MAGIC( skb);
+	DEV_KFREE_SKB( skb, FREE_WRITE);
+
+	return 0;
+}
+        
+/*
+ * Function irport_receive (void)
+ *
+ *    Receive one frame from the infrared port
+ *
+ */
+static void irport_receive( struct irda_device *idev) 
+{
+	__u8 byte = 0x00;
+	int iobase;
+
+	if ( !idev)
+		return;
+
+	DEBUG( 0, __FUNCTION__ "()\n");
+
+	iobase = idev->io.iobase;
+
+	if ( idev->rx.len == 0) {
+		idev->rx.head = idev->rx.buff;
+	}
+
+	/* 
+	 *  Receive all characters in FIFO 
+	 */
+	do {
+		byte = inb_p( iobase+UART_RX);
+		async_unwrap_char( idev, byte);
+		
+	} while ( inb_p( iobase+UART_LSR) & UART_LSR_DR);	
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    
+ *
+ */
+/* void cleanup_module(void) */
+/* { */
+/* 	DEBUG( 3, "IrPORT: cleanup_module!\n"); */
+/* 	irport_cleanup(irport_drv); */
+/* } */
+
+/*
+ * Function init_module (void)
+ *
+ *    
+ *
+ */
+/* int init_module(void) */
+/* { */
+/* 	if (irport_init() < 0) { */
+/* 		cleanup_module(); */
+/* 		return 1; */
+/* 	} */
+/* 	return(0); */
+/* } */
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov