Dag wrote:

>Where can I look at this icp.c? I cannot remember writing such
>a thing ;-) I wrote the Winbond driver which is used in the
>Netwinder, but other than that, I haven't done much with the
>ARM support.

As it's GPL'd, I've included the driver source below. As you can see, you're
credited with writing this driver, and it's got yopy specific gpio stuff in
there, and some kind of FIR support, even though the comment at the top says
otherwise..

>I tried once to get in touch with the Yopy developers, but gave
>up after sending a lot of emails, and trying to get other
>companies to open up some doors for me. I really wanted to help
>out with IrDA support for the Yopy, but I never got any answer
>back.

Dag, The Linux iPAQ people at www.handhelds.org (particularly me) would be
delighted if you could spare some time to help out on the iPAQ irda driver.
At the moment we're all using the sa1100_ir driver from Russel King, which
has no FIR support currently, but some of the basic framework in place. I
had a go at getting FIR speeds going by adding code to this driver, but (due
to laptop IR hardware problems - doesn't receive at FIR speeds) never got
too far.. then I accidently overwrote all of my driver changes when
untarring a new kernel, and kind of lost the urge to do it all over again.
I've purchased a irda-usb dongle now, so should actually be able to do some
more testing. If you feel like having a crack at this one, I'll do
everything I can to help out.

Anyway, here's the driver.

Many Thanks,

Jim


/*********************************************************************
 *
 * Filename:      icp.c
 * Version:       1.0
 * Description:   Half duplex serial port SIR driver for IrDA.
 * Status:        Experimental.
 * Author:        Dag Brattli <[EMAIL PROTECTED]>
 * Created at:    Sun Aug  3 13:49:59 1997
 * Modified at:   Tue Jun  1 10:02:42 1999
 * Modified by:   Dag Brattli <[EMAIL PROTECTED]>
 * Sources:       serial.c by Linus Torvalds
 *
 *     Copyright (c) 1997, 1998, 1999 Dag Brattli, 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.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *     MA 02111-1307 USA
 *
 *     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.
 *     Eventually it will replace irtty, because of irtty has some
 *     problems that is hard to get around when we don't have control
 *     over the serial driver. This driver may also be used by FIR
 *     drivers to handle SIR mode for them.
 *
 ********************************************************************/

#include <linux/module.h>

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/init.h>

#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/spinlock.h>
#include <linux/wrapper.h>

#include <net/irda/irda.h>
#include <net/irda/irmod.h>
#include <net/irda/wrapper.h>
#include <net/irda/irport.h>

#undef SPEED_MAX
#define SPEED_MAX       (3686400 / 16)
#define SIR_MAX_SPEED   115200

static void icp_start(struct irda_device *idev);
static void icp_stop(struct irda_device *idev);
static void icp_change_speed(struct irda_device *idev, int speed);

struct hssp_regs {
        volatile u32    HSCR0;
        volatile u32    HSCR1;
        volatile u32    Reserved0;
        volatile u32    HSDR;
        volatile u32    Reserved1;
        volatile u32    HSSR0;
        volatile u32    HSSR1;
};

static struct irda_device icp;
static struct irda_device *dev_self = NULL;
static char *driver_name = "icp";

static int icp_open(void);
static int icp_close(struct irda_device *idev);

static int  icp_pio_write(struct uart_regs *uart, __u8 *buf, int len);
static int icp_dma_write(struct irda_device *idev);
static void icp_pio_receive(struct irda_device *idev);
static int icp_dma_receive(struct irda_device *idev);

static int  icp_net_init(struct device *dev);
static int  icp_net_open(struct device *dev);
static int  icp_net_close(struct device *dev);
static int  icp_is_receiving(struct irda_device *idev);
static void icp_wait_until_sent(struct irda_device *idev);
static void icp_set_caddr(struct irda_device *idev);

static int icp_hard_xmit(struct sk_buff *skb, struct device *dev);

//#define FIR_TEST
int __init icp_init(void)
{
#ifdef CONFIG_IRDA_DEBUG
        irda_debug = 2;
#endif
        return icp_open();
}

/*
 * Function icp_cleanup ()
 *
 *    Close all configured ports
 *
 */
#ifdef MODULE
static void icp_cleanup(void)
{
        DEBUG(3, __FUNCTION__ "()\n");

        if (dev_self)
                icp_close(dev_self);
}
#endif /* MODULE */

static int icp_open(void)
{
        struct irda_device *idev;
        int ret;

        DEBUG(2, __FUNCTION__ "()\n");

        /*
         *  Allocate new instance of the driver
         */
        idev = &icp;
        memset(idev, 0, sizeof(struct irda_device));

        /* Need to store self somewhere */
        dev_self = idev;

        /* Initialize IO */
        idev->io.iobase    = SP2_REGS_BASE;
        idev->io.iobase2   = HSSP_REGS_BASE;
        idev->io.io_ext    = UART_REGS_RANGE;
        idev->io.io_ext2   = HSSP_REGS_RANGE;
        idev->io.irq       = IRQ_SP2_ICP;
        idev->io.irq2      = IRQ_DMA_ICP;
        idev->io.dma       = DMA_ICP_UART;
        idev->io.dma2      = DMA_ICP_HSSP;
        idev->io.fifo_size = 16;

        idev->netdev.base_addr = SP2_REGS_BASE;
        idev->netdev.irq = IRQ_SP2_ICP;

        /* Lock the port that we need */
        ret = check_region(idev->io.iobase, idev->io.io_ext);
        if (ret < 0) {
                DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
                      idev->io.iobase);
                /* irport_cleanup(self->idev);  */
                return -ENODEV;
        }
        ret = check_region(idev->io.iobase2, idev->io.io_ext2);
        if (ret < 0) {
                DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
                      idev->io.iobase2);
                /* irport_cleanup(self->idev);  */
                return -ENODEV;
        }
        request_region(idev->io.iobase, idev->io.io_ext, idev->name);
        request_region(idev->io.iobase2, idev->io.io_ext2, idev->name);

        /* Initialize QoS for this device */
        irda_init_max_qos_capabilies(&idev->qos);

        idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200
#ifdef FIR_TEST
                |(IR_4000000 << 8)
#endif
                ;

        idev->qos.min_turn_time.bits = 0x03;
        irda_qos_bits_to_value(&idev->qos);

#ifdef FIR_TEST
        idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
#else
        idev->flags = /*IFF_FIR|*/IFF_SIR|IFF_DMA|IFF_PIO;
#endif

        /* Specify which buffer allocation policy we need */
        idev->rx_buff.truesize = 4000;
        idev->tx_buff.truesize = 4000;
        idev->rx_buff.flags = GFP_KERNEL | GFP_DMA;
        idev->tx_buff.flags = GFP_KERNEL | GFP_DMA;

        /* Initialize callbacks */
        idev->change_speed    = icp_change_speed;
        idev->wait_until_sent = icp_wait_until_sent;
        idev->is_receiving    = icp_is_receiving;

        /* Override the network functions we need to use */
        idev->netdev.init            = icp_net_init;
        idev->netdev.hard_start_xmit = icp_hard_xmit;
        idev->netdev.open            = icp_net_open;
        idev->netdev.stop            = icp_net_close;

        /* Open the IrDA device */
        irda_device_open(idev, driver_name, NULL);

        return 0;
}

static int icp_close(struct irda_device *idev)
{
        DEBUG(2, __FUNCTION__ "()\n");

        ASSERT(idev != NULL, return -1;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);

        /* Release the IO-port that this driver is using */
        DEBUG(0 , __FUNCTION__ "(), Releasing region %03x\n",
              idev->io.iobase2);
        release_region(idev->io.iobase2, idev->io.io_ext2);
        DEBUG(0 , __FUNCTION__ "(), Releasing region %03x\n",
              idev->io.iobase);
        release_region(idev->io.iobase, idev->io.io_ext);

        irda_device_close(idev);

        return 0;
}

#define UART_ENABLE_RX  (UART_UTCR3_RXE|UART_UTCR3_TXE | UART_UTCR3_RIE)
#define UART_ENABLE_TX  (UART_UTCR3_RXE|UART_UTCR3_TXE)

#define HSSP_ENABLE_RX  (HSSP_HSCR0_RXE|HSSP_HSCR0_RIE/* | HSSP_HSCR0_TXE*/ |
HSSP_HSCR0_ITR)
#define HSSP_ENABLE_TX  (HSSP_HSCR0_RXE|HSSP_HSCR0_TXE | HSSP_HSCR0_TIE |
HSSP_HSCR0_ITR)

static void icp_start(struct irda_device *idev)
{
        struct uart_regs *uart = (struct uart_regs *)idev->io.iobase;
        struct hssp_regs *hssp = (struct hssp_regs *)idev->io.iobase2;
        unsigned long flags;

        DEBUG(2, __FUNCTION__ "()\n");

        spin_lock_irqsave(&idev->lock, flags);

        icp_stop(idev);

        /* RXD2 must have inverted polarity */
        outl(HSSP_HSCR2_TXP, HSSP_REGS_BASE + HSSP_HSCR2);

        /* enable HP-SIR mode at 9600bps */
        uart->UTCR4 = SP2_UTCR4_HSE;

        /* Initialize UART */
        uart->UTSR0 = 0xff;
        uart->UTCR0 = UART_UTCR0_DSS;
        uart->UTCR1 = 0;
        uart->UTCR2 = SPEED_MAX/9600 - 1;       /* initial speed : 9600bps */

        /* Turn on receiver */
        uart->UTCR3 = UART_ENABLE_RX;

        spin_unlock_irqrestore(&idev->lock, flags);
}

static void icp_stop(struct irda_device *idev)
{
        struct uart_regs *uart = (struct uart_regs *)idev->io.iobase;
        struct hssp_regs *hssp = (struct hssp_regs *)idev->io.iobase2;
        unsigned long flags;

        DEBUG(3, __FUNCTION__ "()\n");

        spin_lock_irqsave(&idev->lock, flags);

        /* Turn off interrupts */
//      hssp->HSCR0 = 0;
        hssp->HSCR0 &= ~HSSP_HSCR0_ITR;
        hssp->HSSR0 = 0xff;
        uart->UTCR3 = 0;
//      uart->UTCR4 = 0;
        uart->UTSR0 = 0xff;

        /* Reset UART */
        outl(HSSP_HSCR2_TXP|HSSP_HSCR2_RXP, HSSP_REGS_BASE + HSSP_HSCR2);

        yopy_gpio_clear(GPIO_IRDA_FIR);

        spin_unlock_irqrestore(&idev->lock, flags);
}

/*
 * Function icp_change_speed (idev, speed)
 *
 *    Set speed of IrDA port to specified baudrate
 *
 */
static void icp_change_speed(struct irda_device *idev, int speed)
{
        struct uart_regs *uart;
        struct hssp_regs *hssp;
        unsigned long flags;
        int divisor;

        DEBUG(3, __FUNCTION__ "(), Setting speed to: %d\n", speed);

        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);

        uart = (struct uart_regs *)idev->io.iobase;
        hssp = (struct hssp_regs *)idev->io.iobase2;

        /* Update accounting for new speed */
        idev->io.baudrate = speed;

        spin_lock_irqsave(&idev->lock, flags);

        /* Stop the device and flush all FIFOs */
        icp_stop(idev);

        outl(HSSP_HSCR2_TXP, HSSP_REGS_BASE + HSSP_HSCR2);

        switch (speed) {
        case 9600:
        case 19200:
        case 37600:
        case 57600:
        case 115200:
                /* Use HP-SIR mode. icp_stop must have done for it already. */

                /* IrDA port use 8N1 */
                divisor = SPEED_MAX/speed - 1;
                DEBUG(3, "divisor %d\n", divisor);
                uart->UTCR2 = divisor & 0xff; /* Set speed      */
                uart->UTCR1 = divisor >> 8;
                uart->UTCR0 = UART_UTCR0_DSS; /* Set 8N1        */
                uart->UTCR4 = SP2_UTCR4_HSE;

                uart->UTCR3 = UART_ENABLE_RX;
                break;
        case 4000000:
                /* use 4PPM modulation */

                /* This must be done at the very first */
                yopy_gpio_set(GPIO_IRDA_FIR);

        //      hssp->HSCR0 = HSSP_HSCR0_ITR;
                hssp->HSCR1 = 0xff;
                hssp->HSCR0 = HSSP_ENABLE_RX | HSSP_HSCR0_AME;
                break;
        default:
                DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
                break;
        }
#ifdef FIR_TEST
        printk("UTCR0 %02x, UTCR1 %02x, UTCR2 %02x, UTCR3 %02x, "
                "UTCR4 %02x, UTSR0 %02x, UTSR1 %02x\n",
                uart->UTCR0, uart->UTCR1, uart->UTCR2, uart->UTCR3,
                uart->UTCR4, uart->UTSR0, uart->UTSR1);
        printk("HSCR0 %02x, HSCR1 %02x, HSCR2 %08x, HSSR0 %02x, HSSR1 %02x\n",
                hssp->HSCR0, hssp->HSCR1, inl(HSSP_REGS_BASE + HSSP_HSCR2),
                hssp->HSSR0, hssp->HSSR1);
#endif

        idev->netdev.tbusy = 0;

        spin_unlock_irqrestore(&idev->lock, flags);

//      if (speed > SIR_MAX_SPEED)
//              icp_dma_receive(idev);
}

/*
 * Function icp_hard_xmit (skb, dev)
 *
 *    Transmits the frame!
 *
 */
static int icp_hard_xmit(struct sk_buff *skb, struct device *dev)
{
        struct irda_device *idev;
        unsigned long flags;
        struct uart_regs *uart;
        struct hssp_regs *hssp;
        int mtt;

        ASSERT(dev != NULL, return 0;);

        idev = (struct irda_device *) dev->priv;

        ASSERT(idev != NULL, return 0;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);

        DEBUG(4, __FUNCTION__ "(%d)\n", idev->io.baudrate);

        uart = (struct uart_regs *)idev->io.iobase;
        hssp = (struct hssp_regs *)idev->io.iobase2;

        /* Lock transmit buffer */
        if (irda_lock((void *) &dev->tbusy) == FALSE) {
                int tickssofar = jiffies - dev->trans_start;
                if (tickssofar < 5)
                        return -EBUSY;

                WARNING("%s: transmit timed out\n", dev->name);
                icp_start(idev);
                icp_change_speed(idev, idev->io.baudrate);

                dev->trans_start = jiffies;
        }

        idev->tx_buff.data = idev->tx_buff.head;

        spin_lock_irqsave(&idev->lock, flags);

        if (idev->io.baudrate > SIR_MAX_SPEED) {
                memcpy(idev->tx_buff.data, skb->data, skb->len);
                idev->tx_buff.len = skb->len;

                mtt = irda_get_mtt(skb);

                /* Enable transmit interrupt (will fire immediately)  */
                hssp->HSSR0 = 0xff;
                hssp->HSCR0 = HSSP_ENABLE_TX | HSSP_HSCR0_AME;
        } else {
                /* Copy skb to tx_buff with wrapping, stuffing and making CRC */
                idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data,
                                                   idev->tx_buff.truesize);

                /* Enable transmit interrupt (will fire immediately)  */
                uart->UTCR3 = 0;
                uart->UTSR0 = 0xff;
                uart->UTCR3 = UART_ENABLE_TX;
        }
        icp_dma_write(idev);

        spin_unlock_irqrestore(&idev->lock, flags);

        dev_kfree_skb(skb);

        return 0;
}

/*
 * Function icp_pio_write (driver)
 *
 *    Fill Tx FIFO with transmit data
 *
 */
static int icp_pio_write(struct uart_regs *uart, __u8 *buf, int len)
{
        int actual = 0;

        /* Tx FIFO should be empty! */
#if 0
        if (!(uart->UTSR1 & UART_UTSR1_TNF)) {
                DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
                return 0;
        }
#endif

        /* Fill FIFO with current frame */
        while (/*(uart->UTSR1 & UART_UTSR1_TNF) &&*/ (actual < len)) {
                while (!(uart->UTSR1 & UART_UTSR1_TNF));
                /* Transmit next byte */
                uart->UTDR = buf[actual++];
        }

        return actual;
}

/*
 * Function icp_dma_write (struct irda_device *)
 *
 *    Send frame using DMA
 *
 */
static int icp_dma_write(struct irda_device *idev)
{
        dmach_t dma;
        ASSERT(idev != NULL, return -1;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);

        dma_cache_wback(idev->tx_buff.data, idev->tx_buff.len);

        dma = (idev->io.baudrate > SIR_MAX_SPEED) ? idev->io.dma2 :
                                                    idev->io.dma;

        DEBUG(4, __FUNCTION__ "(%d: %p, %d)\n", dma,
                idev->tx_buff.data, idev->tx_buff.len);

#ifdef FIR_TEST
        printk("DDAR %08lx DCSR %08lx\n",
                inl(DMA_CHANNEL1_REGS_BASE),
                inl(DMA_CHANNEL1_REGS_BASE + 0x0c));
#endif
        setup_dma(dma, idev->tx_buff.data, idev->tx_buff.len, DMA_MODE_WRITE);
#ifdef FIR_TEST
        printk("DDAR %08lx DCSR %08lx\n",
                inl(DMA_CHANNEL1_REGS_BASE),
                inl(DMA_CHANNEL1_REGS_BASE + 0x0c));
#endif

        idev->io.direction = IO_XMIT;

        return 0;
}

/*
 * Function icp_dma_xmit_complete (idev, error)
 *
 *    The transfer of a frame in finished. This function will only be called
 *    by the interrupt handler
 *
 */
static int icp_dma_xmit_complete(struct irda_device *idev, int error)
{
        struct uart_regs *uart = (struct uart_regs *)idev->io.iobase;
        struct hssp_regs *hssp = (struct hssp_regs *)idev->io.iobase2;
        dmach_t dma;
        unsigned int count;
        unsigned long flags;

        dma = (idev->io.baudrate > SIR_MAX_SPEED) ? idev->io.dma2 :
                                                    idev->io.dma;

        flags = claim_dma_lock();
        disable_dma(dma);
        clear_dma_ff(dma);
        count = idev->tx_buff.len - get_dma_residue(dma);
        release_dma_lock(flags);

        DEBUG(3, "finished %d\n", count);

        if (error) {
                /* on error */
        } else {
                idev->stats.tx_packets++;
                idev->stats.tx_bytes += idev->tx_buff.len;
        }

        /* Unlock tx_buff and request another frame */
        idev->netdev.tbusy = 0; /* Unlock */
        idev->media_busy = FALSE;

        /* Tell the network layer, that we want more frames */
        mark_bh(NET_BH);

        if (idev->io.baudrate > SIR_MAX_SPEED) {
                /* Wait for xmit FIFO empty */
                while (hssp->HSSR1 & HSSP_HSSR1_TBY);

        //      hssp->HSCR0 = HSSP_HSCR0_ITR | HSSP_HSCR0_AME;
                hssp->HSSR0 = 0xff;
                /* Turn on receiver interrupts */
                hssp->HSCR0 = HSSP_ENABLE_RX | HSSP_HSCR0_AME;
        } else {
                /* Wait for xmit FIFO empty */
                while (uart->UTSR1 & UART_UTSR1_TBY);

                /*
                 * Reset Rx FIFO to make sure that all reflected transmit data
                 * will be discarded
                 */
                uart->UTCR3 = 0;
                uart->UTSR0 = 0xff;
                /* Turn on receiver interrupts */
                uart->UTCR3 = UART_ENABLE_RX;
        }

        return 0;
}

/*
 * Function icp_pio_receive (struct irda_device *)
 *
 *    Receive one frame from the infrared port
 *
 */
static void icp_pio_receive(struct irda_device *idev)
{
        struct uart_regs *uart;
        int boguscount = 0;

        ASSERT(idev != NULL, return;);

        DEBUG(5, __FUNCTION__ "()\n");

        uart = (struct uart_regs *)idev->io.iobase;

        /*
         * Receive all characters in Rx FIFO, unwrap and unstuff them.
         * async_unwrap_char will deliver all found frames
         */
        do {
                async_unwrap_char(idev, uart->UTDR);

                /* Make sure we don't stay here to long */
                if (boguscount++ > 32) {
                        DEBUG(0,__FUNCTION__ "(), breaking!\n");
                        break;
                }
        } while (uart->UTSR1 & UART_UTSR1_RNE);
}

/*
 * Function icp_dma_receive (struct irda_device *)
 *
 *    Get ready for receiving a frame. The device will initiate a DMA
 *    if it starts to receive a frame.
 *    Used by HSSP only. UART is hard to use read DMA.
 *
 */
static int icp_dma_receive(struct irda_device *idev)
{
        ASSERT(idev != NULL, return -1;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);

        DEBUG(3, __FUNCTION__ "(%d: %p, %d)\n", idev->io.dma2,
                idev->rx_buff.data, idev->rx_buff.truesize);

        dma_cache_inv(idev->rx_buff.data, idev->rx_buff.truesize);

        setup_dma(idev->io.dma2, idev->rx_buff.data,
                  idev->rx_buff.truesize, DMA_MODE_READ);

        idev->io.direction = IO_RECV;
        idev->rx_buff.data = idev->rx_buff.head;

        return 0;
}

/*
 * Function icp_dma_receive_complete (idev, error)
 *
 *    Finished with receiving frames
 *
 */
static int icp_dma_receive_complete(struct irda_device *idev, int error)
{
        struct sk_buff *skb;
        dmach_t dma;
        unsigned int count;
        unsigned long flags;

        dma = idev->io.dma2;

        flags = claim_dma_lock();
        disable_dma(dma);
        clear_dma_ff(dma);
        count = idev->rx_buff.truesize - get_dma_residue(dma);

        DEBUG(3, __FUNCTION__ "(cnt %d)\n", count);

        skb = dev_alloc_skb(count + 1);
        if (skb == NULL) {
        }

        release_dma_lock(flags);

        return 0;
}

static void icp_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
        struct irda_device *idev = (struct irda_device *) dev_id;

        DEBUG(5, __FUNCTION__ "()\n");

        if (idev->io.direction == IO_XMIT) {
                icp_dma_xmit_complete(idev, 0);
        } else {
                icp_dma_receive_complete(idev, 0);
        }
}

#define UTSR0_MASK      (UART_UTSR0_RFS|UART_UTSR0_RID| \
                         UART_UTSR0_RBB|UART_UTSR0_REB| \
                         UART_UTSR0_EIF)

static void icp_uart_interrupt(struct irda_device *idev)
{
        struct uart_regs *uart = (struct uart_regs *)idev->io.iobase;
        int utsr0, utsr1;
        int boguscount = 0;

        while ((utsr0 = (uart->UTSR0 & UTSR0_MASK))) {
                /* Clear interrupt */
                utsr1 = uart->UTSR1;

                DEBUG(5, __FUNCTION__ "(), utsr0=%02x, utsr1=%02x\n",
                      utsr0, utsr1);

                if (utsr0 & UART_UTSR0_RBB) {
                        uart->UTSR0 = UART_UTSR0_RBB;
                }
                if (utsr0 & UART_UTSR0_REB) {
                        uart->UTSR0 = UART_UTSR0_REB;
                }
                if (utsr0 & UART_UTSR0_RID)
                        uart->UTSR0 = UART_UTSR0_RID;

                if (utsr1 & UART_UTSR1_RNE)
                        /* Receive interrupt */
                        icp_pio_receive(idev);

                /* Make sure we don't stay here to long */
                if (boguscount++ > 32)
                        break;
        }
}

static void icp_hssp_interrupt(struct irda_device *idev)
{
        struct hssp_regs *hssp = (struct hssp_regs *)idev->io.iobase2;
        int hssr0, hssr1;
        char data;

        while ((hssr0 = hssp->HSSR0)) {
                DEBUG(3, __FUNCTION__ "(), hssr0=%02x, hssr1=%02x\n",
                      hssr0, hssp->HSSR1);

                if (hssr0 & HSSP_HSSR0_EIF) {
                        int i= 0;
                        printk("EIF");
                        while (hssp->HSSR0 & HSSP_HSSR0_EIF) {
                                data = hssp->HSDR;
                                i++;
                        }
                        printk("%d bytes\n", i);
                }
                if (hssr0 & HSSP_HSSR0_RAB) {
                        printk("RAB");
                        hssp->HSSR0 = HSSP_HSSR0_RAB;
                }
                if (hssr0 & HSSP_HSSR0_FRE) {
                        printk("FRE");
                        hssp->HSSR0 = HSSP_HSSR0_FRE;
                }
                if (hssr0 & HSSP_HSSR0_RFS) {
                        printk("RFS");
                }
        }
}

/*
 * Function icp_interrupt (irq, dev_id, regs)
 *
 *    Interrupt handler
 */
static void icp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
        struct irda_device *idev = (struct irda_device *) dev_id;

        if (!idev) {
                WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
                return;
        }

        spin_lock(&idev->lock);

        idev->netdev.interrupt = 1;

        if (idev->io.baudrate > SIR_MAX_SPEED) {
                icp_hssp_interrupt(idev);
        } else {
                icp_uart_interrupt(idev);
        }

        idev->netdev.interrupt = 0;

        spin_unlock(&idev->lock);
}

static int icp_net_init(struct device *dev)
{
        DEBUG(2, __FUNCTION__ "()\n");

        /* Set up to be a normal IrDA network device driver */
        irda_device_setup(dev);

        /* Insert overrides below this line! */

        return 0;
}

static void icp_free_resources(struct irda_device *idev)
{
        free_dma(idev->io.dma2);
        free_dma(idev->io.dma);
        free_irq(idev->io.irq2, idev);
        free_irq(idev->io.irq, idev);
}

/*
 * Function icp_net_open (dev)
 *
 *
 *
 */
static int icp_net_open(struct device *dev)
{
        struct irda_device *idev;

        ASSERT(dev != NULL, return -1;);
        idev = (struct irda_device *) dev->priv;

        DEBUG(2, __FUNCTION__ "()\n");

        if (request_irq(idev->io.irq, icp_interrupt, 0, idev->name,
                        (void *) idev)) {
                goto error;
        }
        if (request_irq(idev->io.irq2, icp_dma_interrupt, 0, idev->name,
                        (void *) idev)) {
                goto error;
        }
        /*
         * Always allocate the DMA channel after the IRQ,
         * and clean up on failure.
         */
        if (request_dma(idev->io.dma, idev->name)) {
                goto error;
        }
        if (request_dma(idev->io.dma2, idev->name)) {
                goto error;
        }

        MOD_INC_USE_COUNT;

        /* Ready to play! */
        dev->tbusy = 0;
        dev->interrupt = 0;
        dev->start = 1;

        /* Power up IrDA tranceiver */
        yopy_gpio_clear(GPIO_IRDA_POWER);

        icp_start(idev);

        return 0;
error:
        icp_free_resources(idev);

        return -EAGAIN;
}

/*
 * Function icp_net_close (idev)
 *
 *
 *
 */
static int icp_net_close(struct device *dev)
{
        struct irda_device *idev;

        DEBUG(2, __FUNCTION__ "()\n");

        ASSERT(dev != NULL, return -1;);
        idev = (struct irda_device *) dev->priv;

        ASSERT(idev != NULL, return 0;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);

        /* Stop device */
        dev->tbusy = 1;
        dev->start = 0;

        icp_stop(idev);

        /* Lower power comsumption of IrDA tranceiver */
        yopy_gpio_set(GPIO_IRDA_POWER);

        icp_free_resources(idev);

        MOD_DEC_USE_COUNT;

        return 0;
}

/*
 * Function icp_wait_until_sent (idev)
 *
 *    Delay exectution until finished transmitting
 *
 */
static void icp_wait_until_sent(struct irda_device *idev)
{
        struct uart_regs *uart = (struct uart_regs *)idev->io.iobase;
        struct hssp_regs *hssp = (struct hssp_regs *)idev->io.iobase2;

        DEBUG(4, __FUNCTION__ "()\n");

        /* Wait until Tx FIFO is empty */
        while (1) {
                if (idev->io.baudrate > SIR_MAX_SPEED) {
                        if (!(hssp->HSSR1 & HSSP_HSSR1_TBY))
                                break;
                } else {
                //      if (!(uart->UTSR1 & UART_UTSR1_TBY))
                //              break;
                        while ((uart->UTSR1 & UART_UTSR1_TBY));
                                break;
                }
                DEBUG(3, __FUNCTION__ "(), waiting!\n");
                current->state = TASK_INTERRUPTIBLE;
                schedule_timeout(MSECS_TO_JIFFIES(60));
        }
}

/*
 * Function icp_is_receiving (idev)
 *
 *    Returns true is we are currently receiving data
 *
 */
static int icp_is_receiving(struct irda_device *idev)
{
        ASSERT(idev != NULL, return FALSE;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);

        DEBUG(2, __FUNCTION__ ": dma count = %d\n",
              get_dma_residue(idev->io.dma));

        return (idev->rx_buff.state != OUTSIDE_FRAME);
}

#ifdef MODULE

MODULE_AUTHOR("G-MATE, Inc.");
MODULE_DESCRIPTION("SA-1100/1110 ICP driver");

/*
 * Function cleanup_module (void)
 *
 *
 *
 */
void cleanup_module(void)
{
        icp_cleanup();
}

/*
 * Function init_module (void)
 *
 *
 */
int init_module(void)
{
        return icp_init();
}

#endif /* MODULE */

_______________________________________________
Linux-IrDA mailing list  -  [EMAIL PROTECTED]
http://www.pasta.cs.UiT.No/mailman/listinfo/linux-irda

Reply via email to