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
- Lines: 362
- Date:
Thu Dec 17 09:01:03 1998
- Orig file:
v2.1.131/linux/drivers/net/irda/irport.c
- Orig date:
Wed Dec 31 16:00:00 1969
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