summaryrefslogtreecommitdiffstats
path: root/drivers/net/irda/irport.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /drivers/net/irda/irport.c
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'drivers/net/irda/irport.c')
-rw-r--r--drivers/net/irda/irport.c265
1 files changed, 133 insertions, 132 deletions
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index ae8bcb27b..5ea6dba73 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -1,7 +1,7 @@
/*********************************************************************
*
* Filename: irport.c
- * Version: 0.8
+ * Version: 0.9
* Description: Serial driver for IrDA.
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
@@ -9,7 +9,6 @@
* 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.
@@ -25,10 +24,10 @@
*
* NOTICE:
*
- * This driver is ment to be a small serial driver to be used for
- * IR-chipsets that has a UART (16550) compatibility mode. If your
- * chipset is is UART only, you should probably use IrTTY instead since
- * the Linux serial driver is probably more robust and optimized.
+ * This driver is ment to be a small half duplex serial driver to be
+ * used for IR-chipsets that has a UART (16550) compatibility mode. If
+ * your chipset is is UART only, you should probably use IrTTY instead
+ * since the Linux serial driver is probably more robust and optimized.
*
* The functions in this file may be used by FIR drivers, but this
* driver knows nothing about FIR drivers so don't ever insert such
@@ -65,12 +64,12 @@
#define IO_EXTENT 8
-static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 };
-static unsigned int irq[] = { 11, 0, 0, 0 };
+/* static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 }; */
+/* static unsigned int irq[] = { 11, 0, 0, 0 }; */
-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);
+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);
__initfunc(int irport_init(void))
{
@@ -96,7 +95,7 @@ __initfunc(int irport_init(void))
#ifdef MODULE
static void irport_cleanup(void)
{
- int i;
+/* int i; */
DEBUG( 4, __FUNCTION__ "()\n");
@@ -113,17 +112,17 @@ static void irport_cleanup(void)
* Start IO port
*
*/
-int irport_open( int iobase)
+int irport_open(int iobase)
{
- DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase);
+ DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
/* Initialize UART */
- outb( UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */
- outb(( UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
+ outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */
+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
/* Turn on interrups */
- outb(( UART_IER_THRI |UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER);
-
+ outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER);
+
return 0;
}
@@ -133,15 +132,15 @@ int irport_open( int iobase)
* Stop IO port
*
*/
-void irport_close( int iobase)
+void irport_close(int iobase)
{
- DEBUG( 0, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
/* Reset UART */
- outb( 0, iobase+UART_MCR);
+ outb(0, iobase+UART_MCR);
/* Turn off interrupts */
- outb( 0, iobase+UART_IER);
+ outb(0, iobase+UART_IER);
}
/*
@@ -158,10 +157,8 @@ void irport_change_speed( int iobase, int speed)
DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
- DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase);
-
/* Turn off interrupts */
- outb( 0, iobase+UART_IER);
+ outb(0, iobase+UART_IER);
divisor = SPEED_MAX/speed;
@@ -170,55 +167,14 @@ void irport_change_speed( int iobase, int speed)
/* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8;
- outb( UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
- outb( divisor & 0xff, iobase+UART_DLL); /* Set speed */
- outb( divisor >> 8, iobase+UART_DLM);
- outb( lcr, iobase+UART_LCR); /* Set 8N1 */
- outb( fcr, iobase+UART_FCR); /* Enable FIFO's */
-
- /* Turn on interrups */
- outb( 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;
- }
-
- idev->netdev.interrupt = 1;
-
- iobase = idev->io.iobase2;
-
- 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));
-
- idev->netdev.interrupt = 0;
+ outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
+ outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */
+ outb(divisor >> 8, iobase+UART_DLM);
+ outb(lcr, iobase+UART_LCR); /* Set 8N1 */
+ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
+
+ /* Turn on receive interrups */
+ outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER);
}
/*
@@ -228,39 +184,40 @@ void irport_interrupt( int irq, void *dev_id, struct pt_regs *regs)
* more packets to send, we send them here.
*
*/
-static void irport_write_wakeup( struct irda_device *idev)
+static void irport_write_wakeup(struct irda_device *idev)
{
- int actual = 0, count;
-
- DEBUG( 4, __FUNCTION__ "() <%ld>\n", jiffies);
-
- ASSERT( idev != NULL, return;);
- ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+ int actual = 0;
+ int iobase;
- /* Finished with frame? */
- if ( idev->tx_buff.offset == idev->tx_buff.len) {
+ ASSERT(idev != NULL, return;);
+ ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+ /* Finished with frame? */
+ if (idev->tx_buff.len > 0) {
+ /* Write data left in transmit buffer */
+ actual = irport_write(idev->io.iobase2, idev->io.fifo_size,
+ idev->tx_buff.data, idev->tx_buff.len);
+ idev->tx_buff.data += actual;
+ idev->tx_buff.len -= actual;
+ } else {
+ iobase = idev->io.iobase2;
/*
* 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);
+ mark_bh(NET_BH);
- return;
- }
+ outb(UART_FCR_ENABLE_FIFO |
+ UART_FCR_TRIGGER_14 |
+ UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */
- /* Write data left in transmit buffer */
- count = idev->tx_buff.len - idev->tx_buff.offset;
- actual = irport_write( idev->io.iobase2, idev->io.fifo_size,
- idev->tx_buff.head, count);
- idev->tx_buff.offset += actual;
- idev->tx_buff.head += actual;
+ /* Turn on receive interrupts */
+ outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER);
+ }
}
/*
@@ -269,12 +226,12 @@ static void irport_write_wakeup( struct irda_device *idev)
*
*
*/
-static int irport_write( int iobase, int fifo_size, __u8 *buf, int len)
+static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0;
/* Tx FIFO should be empty! */
- if (!(inb( iobase+UART_LSR) & UART_LSR_THRE)) {
+ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
return -1;
}
@@ -287,8 +244,8 @@ static int irport_write( int iobase, int fifo_size, __u8 *buf, int len)
actual++;
}
- DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n",
- fifo_size, actual, len);
+ DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n",
+ fifo_size, actual, len);
return actual;
}
@@ -300,44 +257,41 @@ static int irport_write( int iobase, int fifo_size, __u8 *buf, int len)
* waits until the next transmitt interrupt, and continues until the
* frame is transmited.
*/
-int irport_hard_xmit( struct sk_buff *skb, struct device *dev)
+int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
{
struct irda_device *idev;
- int xbofs;
- int actual;
-
- DEBUG( 4, __FUNCTION__ "()\n");
+ int actual = 0;
+ int iobase;
- ASSERT( dev != NULL, return -1;);
+ DEBUG(5, __FUNCTION__ "(), dev=%p\n", dev);
- if ( dev->tbusy) {
- DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n");
-
- return -EBUSY;
- }
+ ASSERT(dev != NULL, return 0;);
idev = (struct irda_device *) dev->priv;
- ASSERT( idev != NULL, return -1;);
- ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+ ASSERT(idev != NULL, return 0;);
+ ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+ iobase = idev->io.iobase2;
/* Lock transmit buffer */
- if ( irda_lock( (void *) &dev->tbusy) == FALSE)
+ if (irda_lock((void *) &dev->tbusy) == FALSE)
return -EBUSY;
- /*
- * Transfer skb to tx_buff while wrapping, stuffing and making CRC
- */
- idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data,
- idev->tx_buff.truesize);
-
- actual = irport_write( idev->io.iobase2, idev->io.fifo_size,
- idev->tx_buff.data, idev->tx_buff.len);
-
- idev->tx_buff.offset = actual;
- idev->tx_buff.head = idev->tx_buff.data + actual;
+ /* Init tx buffer */
+ idev->tx_buff.data = idev->tx_buff.head;
+
+ /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
+ idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data,
+ idev->tx_buff.truesize);
- dev_kfree_skb( skb);
+ idev->tx_buff.data += actual;
+ idev->tx_buff.len -= actual;
+
+ /* Turn on transmit finished interrupt. Will fire immediately! */
+ outb(UART_IER_THRI, iobase+UART_IER);
+
+ dev_kfree_skb(skb);
return 0;
}
@@ -348,28 +302,75 @@ int irport_hard_xmit( struct sk_buff *skb, struct device *dev)
* Receive one frame from the infrared port
*
*/
-static void irport_receive( struct irda_device *idev)
+static void irport_receive(struct irda_device *idev)
{
int iobase;
+ int boguscount = 0;
- if ( !idev)
+ if (!idev)
return;
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
iobase = idev->io.iobase2;
- if ( idev->rx_buff.len == 0)
- idev->rx_buff.head = idev->rx_buff.data;
-
/*
* Receive all characters in Rx FIFO, unwrap and unstuff them.
* async_unwrap_char will deliver all found frames
*/
do {
- async_unwrap_char( idev, inb( iobase+UART_RX));
+ async_unwrap_char(idev, inb(iobase+UART_RX));
+
+ /* Make sure we don't stay here to long */
+ if (boguscount++ > 32) {
+ DEBUG(0,__FUNCTION__ "(), breaking!\n");
+ break;
+ }
+ } while (inb(iobase+UART_LSR) & UART_LSR_DR);
+}
+
+/*
+ * Function irport_interrupt (irq, dev_id, regs)
+ *
+ * Interrupt handler
+ */
+void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct irda_device *idev = (struct irda_device *) dev_id;
+ int iobase;
+ int iir, lsr;
+ int boguscount = 0;
+
+ if (!idev) {
+ printk(KERN_WARNING __FUNCTION__
+ "() irq %d for unknown device.\n", irq);
+ return;
+ }
+
+ idev->netdev.interrupt = 1;
+
+ iobase = idev->io.iobase2;
+
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+ while (iir) {
+ /* Clear interrupt */
+ lsr = inb(iobase+UART_LSR);
+
+ if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) {
+ /* Transmitter ready for data */
+ irport_write_wakeup(idev);
+ } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
+ /* Receive interrupt */
+ irport_receive(idev);
+ }
- } while ( inb( iobase+UART_LSR) & UART_LSR_DR);
+ /* Make sure we don't stay here to long */
+ if (boguscount++ > 32)
+ break;
+
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+ }
+ idev->netdev.interrupt = 0;
}
#ifdef MODULE