diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
commit | db7d4daea91e105e3859cf461d7e53b9b77454b2 (patch) | |
tree | 9bb65b95440af09e8aca63abe56970dd3360cc57 /drivers/net/irda/irport.c | |
parent | 9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff) |
Merge with Linux 2.2.8.
Diffstat (limited to 'drivers/net/irda/irport.c')
-rw-r--r-- | drivers/net/irda/irport.c | 265 |
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 |