/*************************************************************
 *  arch/ppc/8220_io/1284.c
 *
 *  1284 device driver for the Alaska (MPC8220i-RPC) board.
 *
 *  Author: MontaVista Software, Inc.
 *          source@mvista.com
 *
 *  Copyright 2003 Motorola / WaveMark Technologies, Inc.
 *  Copyright 2003-2004 MontaVista, Software, Inc.
 *
 * 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.
 **************************************************************************/

#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/serial_reg.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/rtc.h>

#include <asm/serial.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/bitops.h>
#include <asm/io.h>
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif

#include <asm/mpc8220.h>
#include <alaska.h>
#include <MCD_dma.h>
#include <8220DmaApi.h>
#include "1284.h"

DECLARE_WAIT_QUEUE_HEAD(alpine1284_read_queue);
DECLARE_WAIT_QUEUE_HEAD(alpine1284_write_queue);

#define DCACHE_LINE_SIZE	32

#ifdef CONFIG_ALASKA_1284_DMA
#define CACHE_ALIGNED_SIZE(a) (a & (0xFFFFFFFF-(DCACHE_LINE_SIZE-1)))
#define CACHE_ALIGN_BUFFER(a) (unsigned char *)((((unsigned int)a) + \
	     DCACHE_LINE_SIZE-1) & (0xFFFFFFFF-(DCACHE_LINE_SIZE-1)))
#else
#define CACHE_ALIGNED_SIZE(a) (a)
#define CACHE_ALIGN_BUFFER(a) (a)
#endif

#define RCV_BUFFER_SIZE   CACHE_ALIGNED_SIZE(0x4000)
#define SEND_BUFFER_SIZE  CACHE_ALIGNED_SIZE(0x1000)
#define ID_BUFFER_SIZE    CACHE_ALIGNED_SIZE(0x100)
#define RCV_OVERFLOW_SIZE ((RCV_BUFFER_SIZE/4)*3)

#define FORWARD_MODE  0
#define REVERSE_MODE  1

/*
 * Parallel port control structure.  This is an implied argument
 * to just about every function in this file.
 */
static s_PPControl PPControl;

static unsigned char *InBuf = NULL;
static unsigned char *OutBuf = NULL;

static unsigned char *IDBuf = NULL;

static struct timer_list alpine1284_timerlist_read;
static struct timer_list alpine1284_timerlist_reverse;

#ifdef CONFIG_ALASKA_1284_DMA
static int DMA_1284_TaskNum;
static void isr_1284_DMA(int irq, void *dev_id, struct pt_regs *regs);
static void DMA_off(void);
#endif
static void xmit_packet(void);
static void resetParallel(void);
static void enable_parallel_intr(void);
static void disable_parallel_intr(void);
static void alpine1284_isr(int irq, void *dev_id, struct pt_regs *regs);
static void clear_fifo(void);

static void
disable_parallel_intr(void)
{
	P1284_BAND_REG_UB(MPC8220_1284INTCTRL, ~INTCTRL_INTEN);
#ifdef CONFIG_ALASKA_1284_DMA
	disable_irq(DMA_1284_TaskNum + MPC8220_SDMA_IRQ_BASE);
#endif
}

static void
enable_parallel_intr(void)
{
	P1284_BOR_REG_UB(MPC8220_1284INTCTRL, INTCTRL_INTEN);
#ifdef CONFIG_ALASKA_1284_DMA
	enable_irq(DMA_1284_TaskNum + MPC8220_SDMA_IRQ_BASE);
#endif
}

#ifdef CONFIG_ALASKA_1284_DMA

static void
getCurrentTime(TimeVal * base)
{
	do_gettimeofday(base);
	return;
}

static unsigned char
timeIsInPast(TimeVal * base)
{
	TimeVal current;

	getCurrentTime(&current);
	if (base->tv_sec < current.tv_sec)
		return 1;
	if (base->tv_sec == current.tv_sec && base->tv_usec < current.tv_usec)
		return 1;

	return 0;
}

#define TimeInSeconds      1
#define TimeInMilliseconds 2
#define TimeInMicroseconds 3

#define TIME_SEC_IN_MICROSECONDS 1000000

static void
makeFutureTime(TimeVal * base, unsigned int val, unsigned char scale)
{
	getCurrentTime(base);

	switch (scale) {
	case TimeInSeconds:
		base->tv_sec += val;
		break;
	case TimeInMilliseconds:
		base->tv_usec += (val % 1000) * 1000;
		base->tv_sec += val / 1000;
		break;
	case TimeInMicroseconds:
		base->tv_usec += val % 1000000;
		base->tv_sec += val / 1000000;
		break;
	}

	if (base->tv_usec > TIME_SEC_IN_MICROSECONDS) {
		base->tv_usec -= TIME_SEC_IN_MICROSECONDS;
		base->tv_sec++;
	}
}
#endif

#ifdef CONFIG_ALASKA_1284_DMA

/*****************  HANDLE STARTING AND RESTARTING DMA  ********************/

static void
start_DMA(void)
{
	int BytesToXfer;

	BytesToXfer = ((PPControl.rcvBufSize - RCV_OVERFLOW_SIZE) -
		       PPControl.bytesInRcvBuf);

	/* Don't allow the transfer to go beyond the end of the buffer */
	if (PPControl.rcvPtr + BytesToXfer >= PPControl.rcvBufEnd) {
		BytesToXfer = PPControl.rcvBufEnd - PPControl.rcvPtr;
	}

	if ((BytesToXfer <= 0)
	    || (BytesToXfer < 1024 && PPControl.bytesInRcvBuf)) {
		return;
	}

	/* Reset the trickle timer */
	PPControl.TrickleTime = 0;

	/* Turn the BUSY line off so that we can get more data. */
	P1284_BAND_REG_UB(MPC8220_1284OUTCTRL, ~OUTCTRL_BUSY);

	invalidate_dcache_range((unsigned long) PPControl.rcvPtr,
				((unsigned long) PPControl.rcvPtr) +
				(BytesToXfer - 1));

	/* Setup DMA transfer */

	PPControl.DMAactive = 1;

	startDma(DMA_1284_TaskNum,	/* Channel Number */
		 (char *) (MPC8220_1284FIFODATA),	/* Source DMA Address */
		 0,		/* No Incrementing Source Addr */
		 (char *) __pa(PPControl.rcvPtr),	/* Dest DMA Address */
		 1,		/* Increment Dest Addr by 1 */
		 BytesToXfer,	/* Transfer Size */
		 1,		/* 8-bit / Byte transfers */
		 22,		/* Initiator */
		 3,		/* Priority */
		 MCD_SINGLE_DMA | MCD_INTERRUPT,
		 MCD_NO_BYTE_SWAP | MCD_NO_BIT_REV | MCD_NO_CSUM,
		 NULL, NULL, NULL);

	getCurrentTime(&PPControl.DMATimeOut);
	makeFutureTime(&PPControl.DMATimeOut, 100, TimeInMilliseconds);

}

#endif				/* CONFIG_ALASKA_1284_DMA */

/************************************************************
 * parallel_update_PnPID() - Updates PnPID. Can be call from
 * outside the 1284 code t/o let the driver know the PnPID
 * has changed.
 ************************************************************/
static void
parallel_update_PnPID(void)
{
	static char DefaultPnpString[128];
	const char idstr[] =
	    "XXMFG:Motorola;MDL:Spaceball;CMD:PJL,PCL,PCLXL;CLS:PRINTER";
	unsigned short IDLen;

	memcpy(DefaultPnpString, idstr, strlen(idstr));
	DefaultPnpString[strlen(idstr)] = 0;
	printk(KERN_INFO "PnP ID: %s\n", DefaultPnpString);
	PPControl.id = &DefaultPnpString[0];
	IDLen = strlen(DefaultPnpString);
	PPControl.id[0] = ((IDLen >> 8) & 0xFF);
	PPControl.id[1] = (IDLen & 0xFF);
	PPControl.idSize = IDLen;
	PPControl.idInCount = IDLen;
}

/*******************  CODE FOR PARALLEL XMIT MODES  ************************/

/*-------------------------------------------------------------------------*/
/* Returns True if we are in a mode for which we need to send back a ID    */
/* string.                                                                 */
/*-------------------------------------------------------------------------*/
static int
isIDmode(unsigned int mode)
{
	if (mode & IDREQ_MODE) {
		return (1);
	}
	return (0);
}

static void
clear_fifo()
{
	/* Save any unsent data in the FIFO */
	if (PPControl.direction == FORWARD_MODE) {
		unsigned char cnt = 32;
#ifdef CONFIG_ALASKA_1284_DMA
		unsigned long addr = (unsigned long) PPControl.rcvPtr;
#endif

		/* Don't over fill the ring buffer */
		if ((PPControl.bytesInRcvBuf + cnt) > PPControl.rcvBufSize) {
			cnt = PPControl.rcvBufSize - PPControl.bytesInRcvBuf;
		}

		while (((P1284_READ_REG_UB(MPC8220_1284BUFSTAT) & BUFSTAT_EMPTY)
			== 0) && cnt) {
			unsigned char data =
			    P1284_READ_REG_UB(MPC8220_1284FIFODATA8);
			WRITEBYTE(&PPControl, data);
			cnt--;
		}

		wake_up(&alpine1284_read_queue);

#ifdef CONFIG_ALASKA_1284_DMA

		if (addr != (unsigned long) PPControl.rcvPtr) {
			if (addr < (unsigned long) PPControl.rcvPtr) {
				flush_dcache_range(addr,
						   (unsigned long) PPControl.
						   rcvPtr - 1);
			} else {
				flush_dcache_range(addr,
						   (unsigned long) PPControl.
						   rcvBufEnd - 1);
				flush_dcache_range((unsigned long) PPControl.
						   rcvBuf,
						   (unsigned long) PPControl.
						   rcvPtr - 1);
			}
		}
#endif
	} else {
		unsigned char count = 0;
		unsigned char wrptr = P1284_READ_REG(MPC8220_1284FIFOWRPTR);
		unsigned char rdptr = P1284_READ_REG(MPC8220_1284FIFORDPTR);

		if (P1284_READ_REG_UB(MPC8220_1284BUFSTAT) & BUFSTAT_FULL) {
			count = 32;
		} else if (wrptr < rdptr) {
			count = 32 - (rdptr - wrptr);
		} else {
			count = wrptr - rdptr;
		}

		if (count > PPControl.XOutCount) {
			count = PPControl.XOutCount;
		}

		/* If there is still data left to send to the 1284 host let the state */
		/* machine know that.                                                 */
		if (count > 0) {
			P1284_BOR_REG_UB(MPC8220_1284OUTSTAT_DATA,
					 OUTSTAT_DATA_ALTER);
		}

		PPControl.XOutCount -= count;
	}
}

static void
Par_negchange(unsigned char isr_stat)
{
	unsigned int new_direction;
	unsigned int new_mode;

	/* Ask the 1284 port which mode it's in. */
	new_mode = P1284_READ_REG_UB(MPC8220_1284MODE);

	switch (new_mode & ~(IDREQ_MODE | RLE_MODE)) {
	case ECP_MODE:
	case EPP_MODE:
		if (isr_stat & ECP_DIR_CHANGE_INT) {
			if (PPControl.direction == REVERSE_MODE) {
				new_direction = FORWARD_MODE;
			} else {
				new_direction = REVERSE_MODE;
			}
		} else {
			new_direction = FORWARD_MODE;
		}
		break;
	case NIBBLE_MODE:
	case BYTE_MODE:
		new_direction = REVERSE_MODE;
		break;
	case COMPAT_MODE:
	default:
		new_direction = FORWARD_MODE;
		break;
	}

	PPControl.currentmode = new_mode;
	PPControl.direction = new_direction;

	if (PPControl.direction == REVERSE_MODE) {	/* change rcv to xmt */

		if (isIDmode(new_mode)) {
			if (PPControl.id != NULL) {
				memcpy(PPControl.idbuffer, PPControl.id,
				       PPControl.idSize);
#ifdef CONFIG_ALASKA_1284_DMA
				flush_dcache_range((unsigned long) PPControl.
						   idbuffer,
						   ((unsigned long) PPControl.
						    idbuffer) +
						   (PPControl.idSize - 1));
#endif				/* CONFIG_ALASKA_1284_DMA */
				/*
				 * Always start at the beginning of the ID string.
				 * There appears to be an implicit assumption that the
				 * ID string will be sent to the host all at once.
				 */

				PPControl.idInCount = PPControl.idSize;
				PPControl.idOutCount = 0;
			} else {
				PPControl.idInCount = PPControl.idOutCount = 0;
			}

			/* If we're going into ID mode, dump any "normal" reverse data */
			PPControl.XOutCount = PPControl.XInCount = 0;

		} else {	/* change from xmit to receive */

			/*
			 * Keep track of whether we were ever put into reverse mode.
			 * This allows us to give up if we can't send data to the
			 * host because the host never asks for the data.
			 */
			PPControl.DidReverse = 1;
		}

		/* Flush FIFO, set transfer direction to Reverse, and start the transfer */
		P1284_WRITE_REG_UB(MPC8220_1284BUFSTAT,
				   BUFSTAT_TRANSDIR | BUFSTAT_START |
				   BUFSTAT_FLUSH);

		/* Turn BUSY line off */
		P1284_BAND_REG_UB(MPC8220_1284OUTCTRL, ~OUTCTRL_BUSY);

		xmit_packet();	/* send whatever data we've got */

	} else {		/* change xmt to rcv */

		/* Flush FIFO and set transfer direction to Forward. */
		P1284_WRITE_REG_UB(MPC8220_1284BUFSTAT, BUFSTAT_FLUSH);

		/*
		 * See if it's time clear out the output buffer.
		 */
		if (PPControl.XOutCount >= PPControl.XInCount) {
			PPControl.XOutCount = PPControl.XInCount = 0;
		}

		/* If we are in ECP or EPP mode then start 1284 protocol engine */
		if (new_mode == ECP_MODE || new_mode == EPP_MODE) {
			P1284_BOR_REG_UB(MPC8220_1284BUFSTAT, BUFSTAT_START);
		}
#ifdef CONFIG_ALASKA_1284_DMA
		/* Turn off FIFO interrupt and clear it. */
		P1284_BAND_REG_UB(MPC8220_1284INTCTRL, ~INTCTRL_THINTEN);
		P1284_BOR_REG_UB(MPC8220_1284INTSTAT, FIFO_INT);

		start_DMA();
#else
		/* Make sure the FIFO interrupt is enabled. */
		P1284_BOR_REG_UB(MPC8220_1284INTCTRL, INTCTRL_THINTEN);

		/* Ask for more data if there is room in the buffer */
		if (PPControl.bytesInRcvBuf <
		    (PPControl.rcvBufSize - RCV_OVERFLOW_SIZE)) {
			/* Turn BUSY line off */
			P1284_BAND_REG_UB(MPC8220_1284OUTCTRL, ~OUTCTRL_BUSY);
		}
#endif				/* CONFIG_ALASKA_1284_DMA */
	}
}

/***********************  SEND TO PARALLEL PORT  ***************************/

/*
 * Transfer a FIFO's worth of data in reverse mode.
 * Assumed to be called with interrupts off!
 */
static void
xmit_packet()
{
	volatile unsigned int *InCount;
	volatile unsigned int *OutCount;
	unsigned char *theBuf;
	unsigned int bytes_left;
	unsigned char *buf_ptr;
	int isID;

	/*
	 * Check if we are sending the ID or normal data.
	 */
	if (isIDmode(PPControl.currentmode)) {
		InCount = &PPControl.idInCount;
		OutCount = &PPControl.idOutCount;
		theBuf = PPControl.idbuffer;
		isID = 1;
	} else {
		InCount = &PPControl.XInCount;
		OutCount = &PPControl.XOutCount;
		theBuf = PPControl.xbuffer;
		isID = 0;
	}

	/* Have to cover the case where the ptr is at an odd address or */
	/* we only have one byte to send.                               */

	bytes_left = (*InCount) - (*OutCount);
	buf_ptr = &(theBuf[*OutCount]);

	if (bytes_left > 0) {
#ifdef CONFIG_ALASKA_1284_DMA
		/* If DMA is already on return from this function */
		if (PPControl.DMAactive) {
			return;
		}

		/* Turn off FIFO interrupt and clear it. */
		P1284_BAND_REG_UB(MPC8220_1284INTCTRL, ~INTCTRL_THINTEN);
		P1284_BOR_REG_UB(MPC8220_1284INTSTAT, FIFO_INT);

		flush_dcache_range((unsigned long) buf_ptr,
				   ((unsigned long) buf_ptr) + (bytes_left -
								1));

		/* Setup DMA transfer */

		PPControl.DMAactive = 1;

		startDma(DMA_1284_TaskNum,	/* Channel Number */
			 (char *) __pa(buf_ptr),	/* Source DMA Address */
			 1,	/* Increment Source Addr by 1 */
			 (char *) (MPC8220_1284FIFODATA),	/* Dest DMA Address */
			 0,	/* No Incrementing Dest Addr */
			 bytes_left,	/* Transfer Size */
			 1,	/* 8-bit / Byte transfers */
			 23,	/* Initiator */
			 3,	/* Priority */
			 MCD_SINGLE_DMA | MCD_INTERRUPT,
			 MCD_NO_BYTE_SWAP | MCD_NO_BIT_REV | MCD_NO_CSUM,
			 NULL, NULL, NULL);

#else				/* CONFIG_ALASKA_1284_DMA */
		while (((P1284_READ_REG_UB(MPC8220_1284BUFSTAT) & BUFSTAT_FULL)
			== 0) && (*InCount > *OutCount)) {
			P1284_WRITE_REG_UB(MPC8220_1284FIFODATA8,
					   theBuf[*OutCount]);
			*OutCount = (*OutCount) + 1;
		}
		/* If there is more data to send enable the fifo empty interrupt */
		/* otherwise disable it. */
		if (*InCount > *OutCount) {
			/* Turn ON FIFO empty Interrupt */
			P1284_BOR_REG_UB(MPC8220_1284INTCTRL, INTCTRL_THINTEN);
		} else {
			/* Turn OFF FIFO empty Interrupt */
			P1284_BAND_REG_UB(MPC8220_1284INTCTRL,
					  ~INTCTRL_THINTEN);
			/* Let the 1284 state machine know that we DO NOT have any data */
			/* to send. */
			P1284_BAND_REG_UB(MPC8220_1284OUTSTAT_DATA,
					  ~OUTSTAT_DATA_ALTER);
		}
#endif				/* CONFIG_ALASKA_1284_DMA */
	} else {
		/* No more data to send; disable the fifo empty interrupt */
		P1284_BAND_REG_UB(MPC8220_1284INTCTRL, ~INTCTRL_THINTEN);
		/* Let the 1284 state machine know that we DO NOT have any data */
		/* to send. */
		P1284_BAND_REG_UB(MPC8220_1284OUTSTAT_DATA,
				  ~OUTSTAT_DATA_ALTER);
	}
}

static void
transfer_buffer_timeout(unsigned long arg)
{
	/* Now disable the 1284 interrupt */
	disable_parallel_intr();
#ifdef CONFIG_ALASKA_1284_DMA
	DMA_off();		/* Turn off DMA */
#endif
	PPControl.XOutCount = PPControl.XInCount = 0;
	PPControl.DidReverse = 0;
	wake_up(&alpine1284_write_queue);
	enable_parallel_intr();
	printk(KERN_INFO
	       "Alpine1284: timed out waiting for space in transmit buffer, reset buffer\n");
}

/***********************  RECEIVE FROM PARALLEL PORT  **********************/

static int
parallelInputNonBlocking(unsigned int BytesRequested, unsigned char *buf)
{
	unsigned int ByteCount;
	unsigned char *ptr;

	if (!PPControl.initialized) {
		/* Hasn't yet been initialized, to no data */
		return (0);
	}

	/* If the host terminated to Compatibility mode without our 1284 */
	/* state machine knowing about it.                               */
	if ((PPControl.currentmode != COMPAT_MODE) &&
	    ((P1284_READ_REG_UB(MPC8220_1284INSTAT) & 0x1) == 0)) {
		unsigned int mode =
		    PPControl.currentmode & ~(IDREQ_MODE | RLE_MODE);
		unsigned short cnt = 1000;

		while (((P1284_READ_REG_UB(MPC8220_1284INSTAT) & 0x1) == 0) &&
		       (mode != COMPAT_MODE) && (mode != EPP_MODE) && cnt) {
			udelay(100);
			mode = PPControl.currentmode & ~(IDREQ_MODE | RLE_MODE);
			cnt--;
		}

		if (cnt == 0) {
			printk(KERN_INFO
			       "1284: Forcing Reset to Compatibility mode.\n");
			disable_parallel_intr();
#ifdef CONFIG_ALASKA_1284_DMA
			DMA_off();
#endif
			clear_fifo();
			resetParallel();
			Par_negchange(0);
#ifdef CONFIG_ALASKA_1284_DMA
			if (!PPControl.DMAactive) {
				start_DMA();
			}
#endif
			enable_parallel_intr();
		}
	}

	ByteCount = 0;

	disable_parallel_intr();

	if (PPControl.direction == FORWARD_MODE) {

		PPControl.busy = 1;

#ifdef CONFIG_ALASKA_1284_DMA

		if (PPControl.DMAactive) {
			MCD_XferProg XferProg;

			/* Check how many new bytes we have received so far */
			MCD_XferProgrQuery(DMA_1284_TaskNum, &XferProg);

			if (XferProg.dmaSize == PPControl.PrevDMACount) {
				if (timeIsInPast(&PPControl.DMATimeOut)) {
					/* Stop DMA and make any new data available */
					DMA_off();
					clear_fifo();
					start_DMA();
				}
			} else {
				PPControl.PrevDMACount = XferProg.dmaSize;
				getCurrentTime(&PPControl.DMATimeOut);
				makeFutureTime(&PPControl.DMATimeOut, 100,
					       TimeInMilliseconds);
			}
		} else {
			start_DMA();
		}

#else				/* Not CONFIG_ALASKA_1284_DMA */

		if (PPControl.bytesInRcvBuf <
		    (PPControl.rcvBufSize - RCV_OVERFLOW_SIZE)) {
			clear_fifo();
		}
#endif				/* CONFIG_ALASKA_1284_DMA */

	}

	/* In Forward mode */
	/* Latch the location of any unread data */
	ptr = (unsigned char *) PPControl.readPtr;

	/* Check how many bytes we can report back */
	if (PPControl.rcvPtr >= PPControl.readPtr) {
		ByteCount = PPControl.rcvPtr - PPControl.readPtr;
		if (BytesRequested < ByteCount) {
			ByteCount = BytesRequested;
		}
		PPControl.readPtr += ByteCount;
	} else {
		ByteCount = PPControl.rcvBufEnd - PPControl.readPtr;
		if (BytesRequested < ByteCount) {
			ByteCount = BytesRequested;
			PPControl.readPtr += ByteCount;
		} else {
			PPControl.readPtr = PPControl.rcvBuf;
		}
	}

	/* Put the new data to the receiving buffer */
	copy_to_user(buf, ptr, ByteCount);

	PPControl.bytesInRcvBuf -= ByteCount;

	enable_parallel_intr();

	PPControl.busy = 0;

	return (ByteCount);
}

/***************************  HANDLE INTERRUPTS  ***************************/

#ifdef CONFIG_ALASKA_1284_DMA

static void
DMA_off(void)
{
	/* Stop DMA */
	MCD_killDma(DMA_1284_TaskNum);

	if (!PPControl.DMAactive) {
		return;
	}

	PPControl.DMAactive = 0;	/* set flag -- DMA is not active */

	if (PPControl.direction == FORWARD_MODE) {
		MCD_XferProg XferProg;

		/* Check how many new bytes we have received so far */
		MCD_XferProgrQuery(DMA_1284_TaskNum, &XferProg);

		PPControl.bytesInRcvBuf += XferProg.dmaSize;
		PPControl.rcvPtr += XferProg.dmaSize;
		if (PPControl.rcvPtr >= PPControl.rcvBufEnd) {
			PPControl.rcvPtr = PPControl.rcvBuf;
		}
		wake_up(&alpine1284_read_queue);
	} else {
		MCD_XferProg XferProg;

		/* Check how many new bytes we have received so far */
		MCD_XferProgrQuery(DMA_1284_TaskNum, &XferProg);

		if (!isIDmode(PPControl.currentmode)) {
			/* Reverse Mode (Not an ID mode) */

			PPControl.XOutCount += XferProg.dmaSize;

			/* If we have sent all the data and that was more than 32 bytes then  */
			/* reset the buffer pointer to the beginning of the buffer + 32 bytes. */
			/* Copy the last 32 bytes into the first 32 bytes of the buffer but   */
			/* mark it as already being sent. This way we can recover a FIFO of   */
			/* data if we need to.                                                */
			if ((PPControl.XOutCount >= PPControl.XInCount) &&
			    (PPControl.XOutCount > 32)) {
				memmove(PPControl.xbuffer,
					&(PPControl.
					  xbuffer[PPControl.XOutCount - 32]),
					32);
				PPControl.XOutCount = 32;
				PPControl.XInCount = 32;
			}
		} else {
			/* Reverse Mode (an ID mode) */
			PPControl.idOutCount = XferProg.dmaSize;
		}
	}
}

static void
isr_1284_DMA(int irq, void *dev_id, struct pt_regs *regs)
{
	unsigned char intctrl;
	unsigned long flags;
	spinlock_t irqlock = SPIN_LOCK_UNLOCKED;

	spin_lock_irqsave(irqlock, flags);

	intctrl = P1284_READ_REG_UB(MPC8220_1284INTCTRL);

	/* Turn off the 1284 interrupt */
	P1284_BAND_REG_UB(MPC8220_1284INTCTRL, ~INTCTRL_INTEN);

	spin_unlock_irqrestore(irqlock, flags);

	MSD_ack(DMA_1284_TaskNum);

	if (!PPControl.DMAactive) {
		/* Restore the state of the 1284 interrupt control register */
		P1284_WRITE_REG_UB(MPC8220_1284INTCTRL, intctrl);
		return;
	}

	DMA_off();

	if (PPControl.direction == FORWARD_MODE) {
		start_DMA();
	} else {
		xmit_packet();
	}

	/* Restore the state of the 1284 interrupt control register */
	P1284_WRITE_REG_UB(MPC8220_1284INTCTRL, intctrl);
}

#endif				/* CONFIG_ALASKA_1284_DMA */

/**************************  INITIALIZATION CODE  **************************/

static void
initParallelControlStruct(void)
{
	/*
	 * Make sure the buffer is aligned on cache-line boundaries
	 */
	PPControl.rcvBuf = CACHE_ALIGN_BUFFER(InBuf);
	PPControl.rcvBufSize = RCV_BUFFER_SIZE - DCACHE_LINE_SIZE;
#ifdef CONFIG_ALASKA_1284_DMA
	if (((unsigned int) (PPControl.rcvBuf)) & (DCACHE_LINE_SIZE - 1)) {
		printk(KERN_INFO
		       "1284: Receive Buffer not cache aligned (addr=%x)\n",
		       (unsigned int) PPControl.rcvBuf);
	}
#endif

	/*
	 * Total buffer has to be bigger than the overflow area.
	 */
	if (PPControl.rcvBufSize < RCV_OVERFLOW_SIZE) {
		printk(KERN_INFO
		       "1284: Buffer has to be bigger than the overflow area. (size=%d)\n",
		       PPControl.rcvBufSize);
	}

	/*
	 * Nominal buffer should be at least 1K
	 */
	if (PPControl.rcvBufSize - RCV_OVERFLOW_SIZE < (1 * 1024)) {
		printk(KERN_INFO
		       "1284: Nominal buffer should be at least 1K. (size=%d)\n",
		       PPControl.rcvBufSize);
	}

	PPControl.DMAactive = 0;
	PPControl.currentmode = COMPAT_MODE;
	PPControl.direction = 0;

	PPControl.rcvPtr = PPControl.readPtr = PPControl.rcvBuf;
	PPControl.bytesInRcvBuf = 0;
	PPControl.rcvBufEnd = PPControl.rcvBuf + PPControl.rcvBufSize;
	printk(KERN_INFO "1284 buffer starts at %x and ends just before %x\n",
	       (unsigned int) PPControl.rcvBuf,
	       (unsigned int) PPControl.rcvBufEnd);

	/* output (xmit) buffer */
	/* Use the uncached addresses when reading and writing the buffer. */
	PPControl.xbuffer = CACHE_ALIGN_BUFFER(OutBuf);
	PPControl.XBufSize = SEND_BUFFER_SIZE - DCACHE_LINE_SIZE;

	/*
	 * Make sure the buffer is cache line size aligned
	 */
#ifdef CONFIG_ALASKA_1284_DMA
	if (((unsigned int) (PPControl.xbuffer)) & (DCACHE_LINE_SIZE - 1)) {
		printk(KERN_INFO
		       "1284: Transmit Buffer not cache aligned (addr=%x)\n",
		       (unsigned int) PPControl.xbuffer);
	}
#endif

	PPControl.XInCount = 0;
	PPControl.XOutCount = 0;
	PPControl.DidReverse = 0;

	/*
	 *  Copy PnP ID string to our buffer.
	 */
	PPControl.id = NULL;
	PPControl.idbuffer = CACHE_ALIGN_BUFFER(IDBuf);
	PPControl.idbuffer_size = ID_BUFFER_SIZE - DCACHE_LINE_SIZE;
	PPControl.idOutCount = 0;

	PPControl.bytesTransmitted = 0;

	PPControl.initialized = 1;
}

#ifdef CONFIG_ALASKA_1284_DMA

static void
initParallelDMA(void)
{
	DMA_1284_TaskNum = MSD_reserveChannel(-1, isr_1284_DMA,
					      "Alpine 1284 DMA ISR", NULL);

	if (DMA_1284_TaskNum < 0) {
		printk(KERN_INFO "Error:  MSD_reserveChannel 1284 ERROR %d\n",
		       DMA_1284_TaskNum);
	}

	/* Setup DMA */
	start_DMA();
}

#endif				/* CONFIG_ALASKA_1284_DMA */

static void
resetParallel()
{
	/*flush the FIFO */
	P1284_BOR_REG_UB(MPC8220_1284BUFSTAT, BUFSTAT_FLUSH);

	/*set the transfer direction to be forward to prevent data bus conflict */
	P1284_BAND_REG_UB(MPC8220_1284BUFSTAT, ~BUFSTAT_TRANSDIR);

	/*Reset the scP1284 protocol engine to the default mode */
	P1284_BOR_REG_UB(MPC8220_1284MODESUPT, MODESUPT_RESETSM);

	/*set the busy bit */
	P1284_BAND_REG_UB(MPC8220_1284OUTCTRL, ~OUTCTRL_BUSY);
}

/***********************   Linux Driver Entry Points   ***********************/

/* Interrupt handler for Parallel Port */
static void
alpine1284_isr(int irq, void *dev_id, struct pt_regs *regs)
{
	unsigned int isr;
	unsigned char count;
	unsigned char dummy;

	isr = P1284_READ_REG_UB(MPC8220_1284INTSTAT);
	count = 0;

#ifdef CONFIG_ALASKA_1284_DMA
	/* Disable the irq for the DMA channel */
	disable_irq(DMA_1284_TaskNum + MPC8220_SDMA_IRQ_BASE);
#endif

	while (isr && count < 3) {
		count++;

		if (isr & FIFO_INT) {
			if (PPControl.direction == REVERSE_MODE) {
				/* XMIT fifo empty interrupt */
				xmit_packet();
			} else {	/* FORWARD MODE */
#ifdef CONFIG_ALASKA_1284_DMA
				if (!PPControl.DMAactive) {
					clear_fifo();
				}
#else
				clear_fifo();
#endif
				/* If the regular non-overflow part of the receive buffer is full */
				/* then disable the FIFO full interrupt.                          */
				if (PPControl.bytesInRcvBuf >=
				    (PPControl.rcvBufSize -
				     RCV_OVERFLOW_SIZE)) {
					P1284_BAND_REG_UB(MPC8220_1284INTCTRL,
							  ~INTCTRL_THINTEN);
				}
			}
			/* Clear FIFO_INT interrupt */
			P1284_WRITE_REG_UB(MPC8220_1284INTSTAT, FIFO_INT);
		}

		/* Address or Command Received in ECP or EPP mode */
		if (isr & COMMUNICATION_INT) {
			dummy = P1284_READ_REG_UB(MPC8220_1284COMM);
			/* Clear COMMUNICATION_INT interrupt */
			P1284_WRITE_REG_UB(MPC8220_1284INTSTAT,
					   COMMUNICATION_INT);
		}

		/* Handle any nInit interrupt first, then handle negotiation changes */
		if (isr & (TIMEOUT_INT | ABNORMAL_TERM_INT)) {

#ifdef CONFIG_ALASKA_1284_DMA
			DMA_off();
#endif
			clear_fifo();
			resetParallel();
			Par_negchange(isr);
#ifdef CONFIG_ALASKA_1284_DMA
			if (!PPControl.DMAactive) {
				start_DMA();
			}
#endif

			/* Clear TIMEOUT and/or ABNORMAL_TERM interrupt */
			if (isr & TIMEOUT_INT) {
				P1284_WRITE_REG_UB(MPC8220_1284INTSTAT,
						   TIMEOUT_INT);
			}
			if (isr & ABNORMAL_TERM_INT) {
				P1284_WRITE_REG_UB(MPC8220_1284INTSTAT,
						   ABNORMAL_TERM_INT);
			}
		}

		/* If the parallel port mode has changed then do the following */
		if (isr &
		    (CHANGE_MODE_INT | NORMAL_TERM_INT | ECP_DIR_CHANGE_INT)) {

			/* Clear CHANGE_MODE_INT, NORMAL_TERM_INT, and/or */
			/* ECP_DIR_CHANGE_INT interrupt */
			if (isr & CHANGE_MODE_INT) {
				P1284_WRITE_REG_UB(MPC8220_1284INTSTAT,
						   CHANGE_MODE_INT);
			}
			if (isr & NORMAL_TERM_INT) {
				P1284_WRITE_REG_UB(MPC8220_1284INTSTAT,
						   NORMAL_TERM_INT);
			}
			if (isr & ECP_DIR_CHANGE_INT) {
				P1284_WRITE_REG_UB(MPC8220_1284INTSTAT,
						   ECP_DIR_CHANGE_INT);
			}
#ifdef CONFIG_ALASKA_1284_DMA
			DMA_off();
#endif
			clear_fifo();
			Par_negchange(isr);
		}

		/* Check to see if we got any more interrupts while handling this one */
		isr = P1284_READ_REG_UB(MPC8220_1284INTSTAT);

	}

#ifdef CONFIG_ALASKA_1284_DMA
	/* Enable the irq for the DMA channel */
	enable_irq(DMA_1284_TaskNum + MPC8220_SDMA_IRQ_BASE);
#endif

	return;
}

static void
read_timeout(unsigned long args)
{
	PPControl.readTimeout = 1;
	wake_up(&alpine1284_read_queue);
}

static ssize_t
alpine1284_read(struct file *f, char *buf, size_t count, loff_t * ppos)
{
	size_t cnt;
	unsigned int bytes;

	/* This shouldn't happen but just in case */
	if (count == 0)
		return 0;

	/* loop over the data wanted */
	cnt = 0;

	PPControl.readTimeout = 0;
	alpine1284_timerlist_read.expires = jiffies + (HZ * 2);	/* 2 second timer */
	add_timer(&alpine1284_timerlist_read);

	while (cnt < count && (!(PPControl.readTimeout))) {
		bytes = parallelInputNonBlocking(count - cnt, &(buf[cnt]));
		if (bytes > 0) {
			cnt += bytes;
		} else {
#ifndef CONFIG_ALASKA_1284_DMA
			/* Make sure the FIFO interrupt is enabled. */
			P1284_BOR_REG_UB(MPC8220_1284INTCTRL, INTCTRL_THINTEN);
#endif

			/* If there's no data in the lower buffer, go to sleep until some
			   arrives */
#ifdef CONFIG_ALASKA_1284_DMA
			if (PPControl.bytesInRcvBuf == 0 && PPControl.DMAactive) {
#else
			if (PPControl.bytesInRcvBuf == 0) {
#endif
				wait_event_interruptible(alpine1284_read_queue,
							 ((PPControl.
							   bytesInRcvBuf > 0)
							  || PPControl.
							      readTimeout));
			}
		}
	}

	del_timer_sync(&alpine1284_timerlist_read);
	return (cnt);
}

static ssize_t
alpine1284_write(struct file *f, const char *buf, size_t size, loff_t * ppos)
{
	const char *ptr = buf;
	int retval;

	if (!PPControl.initialized) {
		/* Hasn't yet been initialized, to no data */
		return (0);
	}

	/* If the host terminated to Compatibility mode without our 1284 */
	/* state machine knowing about it.                               */
	if ((PPControl.currentmode != COMPAT_MODE) &&
	    ((P1284_READ_REG_UB(MPC8220_1284INSTAT) & 0x1) == 0)) {
		unsigned int mode =
		    PPControl.currentmode & ~(IDREQ_MODE | RLE_MODE);
		unsigned short cnt = 1000;

		while (((P1284_READ_REG_UB(MPC8220_1284INSTAT) & 0x1) == 0) &&
		       (mode != COMPAT_MODE) && (mode != EPP_MODE) && cnt) {
			udelay(100);
			mode = PPControl.currentmode & ~(IDREQ_MODE | RLE_MODE);
			cnt--;
		}

		if (cnt == 0) {
			printk(KERN_INFO
			       "1284: Forcing Reset to Compatibility mode.\n");
			disable_parallel_intr();
#ifdef CONFIG_ALASKA_1284_DMA
			DMA_off();
#endif
			clear_fifo();
			resetParallel();
			Par_negchange(0);
#ifdef CONFIG_ALASKA_1284_DMA
			if (!PPControl.DMAactive) {
				start_DMA();
			}
#endif
			enable_parallel_intr();
		}
	}

	PPControl.busy = 1;

	/*
	 * If the size of the incoming data is larger than the buffer we will
	 * only send the last buffer worth of data. 32 bytes are reserved so that
	 * we can recover a FIFO of data if we need to.
	 */
	if ((PPControl.XBufSize - 32) < size) {
		ptr += (size - PPControl.XBufSize);
		size = PPControl.XBufSize - 32;
	}

	PPControl.bytesTransmitted += size;
	retval = size;

	/*
	 * If there isn't room for the incoming data we will wait 30 seconds
	 * unless we have already done this since the last time we were in
	 * reverse. After 30 seconds if there still isn't room we will throw
	 * out enough of the oldest data to make room.
	 */

	/* 30 second timer */
	alpine1284_timerlist_reverse.expires = jiffies + (HZ * 30);
	add_timer(&alpine1284_timerlist_reverse);

	while (PPControl.XInCount + size > (PPControl.XBufSize - 32)
	       && PPControl.DidReverse) {
		if (PPControl.XOutCount >= PPControl.XInCount) {
			/* If the output buffer is actually empty, we can continue. */
			break;
		}
		wait_event_interruptible(alpine1284_write_queue,
					 (PPControl.XInCount + size <=
					  (PPControl.XBufSize - 32)));
	}

	del_timer_sync(&alpine1284_timerlist_reverse);

	disable_parallel_intr();	/* Turn off 1284 interrupt */

#ifdef CONFIG_ALASKA_1284_DMA
	DMA_off();		/* Turn off DMA */
#endif				/* CONFIG_ALASKA_1284_DMA */

	/* If we have sent all the data and that was more than 32 bytes then  */
	/* reset the buffer pointer to the beginning of the buffer + 32 bytes. */
	/* Copy the last 32 bytes into the first 32 bytes of the buffer but   */
	/* mark it as already being sent. This way we can recover a FIFO of   */
	/* data if we need to.                                                */
	if ((PPControl.XOutCount >= PPControl.XInCount) &&
	    (PPControl.XOutCount > 32)) {
		memmove(PPControl.xbuffer,
			&PPControl.xbuffer[PPControl.XOutCount - 32], 32);
#ifdef CONFIG_ALASKA_1284_DMA
		flush_dcache_range((unsigned long) PPControl.xbuffer,
				   ((unsigned long) PPControl.xbuffer) + 31);
#endif				/* CONFIG_ALASKA_1284_DMA */
		PPControl.XOutCount = 32;
		PPControl.XInCount = 32;
	}

	/*
	 * If we got this far, then either we already have enough room in the
	 * buffer, or we have to make room.  Check which case it is.
	 */
	if (PPControl.XInCount + size > (PPControl.XBufSize - 32)) {
		/*
		 * There's no room in the buffer.  Toss the current contents.
		 */
		PPControl.XOutCount = PPControl.XInCount = 0;

		/*
		 * We timed out waiting for room in the buffer.
		 * Clear the flag saying we did reverse-mode transfers to the host.
		 */
		PPControl.DidReverse = 0;
	}

	/* copy the new data into the transmit buffer */
	copy_from_user((char *) &(PPControl.xbuffer[PPControl.XInCount]),
		       (char *) ptr, size);
#ifdef CONFIG_ALASKA_1284_DMA
	flush_dcache_range((unsigned long)
			   &(PPControl.xbuffer[PPControl.XInCount]),
			   ((unsigned long)
			    &(PPControl.xbuffer[PPControl.XInCount])) + (size -
									 1));
#endif				/* CONFIG_ALASKA_1284_DMA */
	PPControl.XInCount += size;

	if (PPControl.direction == REVERSE_MODE) {
		xmit_packet();
	} else {
		/* Let the 1284 state machine know that we have data to send */
		P1284_BOR_REG_UB(MPC8220_1284OUTSTAT_DATA, OUTSTAT_DATA_ALTER);
	}

	enable_parallel_intr();

	PPControl.busy = 0;

	return (retval);
}

static int
alpine1284_release(struct inode *node, struct file *filp)
{
	/* decrement the open count. It can't be zero */
	if (PPControl.open) {
		PPControl.open = 0;
		return 0;
	} else {
		printk(KERN_INFO "alpine1284: release WTFO?\n");
		return -ENODEV;
	}
}

static int
alpine1284_open(struct inode *node, struct file *filp)
{
	/* if there is already someone who holds this open, don't let
	   another open have the device */
	if (PPControl.open)
		return -ENODEV;

	PPControl.open = 1;

	return 0;
}

static struct file_operations alpine1284_fops = {
	.read = alpine1284_read,
	.write = alpine1284_write,
	.open = alpine1284_open,
	.release = alpine1284_release,
};

int __init
alpine1284_init(void)
{
#ifndef CONFIG_DEVFS_FS
	int ret;
#endif
	printk(KERN_INFO "Alpine 1284 driver: Copyright Motorola, 2003.\n");

	/* If switch 5 on the board is set, disable 1284 */
	if (in_8((volatile u8 *) CPLD_CFG1) & CPLD_CFG1_CF2) {
		printk(KERN_INFO
		       "1284 disabled due to configuration switch 5\n");
		return -EIO;
	}

	if (!(InBuf = kmalloc(RCV_BUFFER_SIZE, GFP_KERNEL))) {
		printk(KERN_INFO "allocation of InBuf buffer FAILED\n");
		return -ENOMEM;
	}
	if (!(OutBuf = kmalloc(SEND_BUFFER_SIZE, GFP_KERNEL))) {
		printk(KERN_INFO "allocation of OutBuf buffer FAILED\n");
		return -ENOMEM;
	}
	if (!(IDBuf = kmalloc(ID_BUFFER_SIZE, GFP_KERNEL))) {
		printk(KERN_INFO "allocation of IDBuf buffer FAILED\n");
		return -ENOMEM;
	}
#ifdef CONFIG_DEVFS_FS
	if (!
	    (PPControl.de =
	     devfs_register(NULL, "lp0",
			    DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, 0, 0,
			    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
			    &alpine1284_fops, NULL))) {
		printk(KERN_ERR
		       "%s(%d): alpine1284_init() can't be register in devfs\n",
		       __FILE__, __LINE__);
		return -ENODEV;
	}
#else
	if ((ret = register_chrdev(ALPINE1284_MAJOR, ALPINE1284_DEVNAME,
				   &alpine1284_fops)) < 0) {
		printk(KERN_INFO
		       "%s(%d): alpine1284_init() can't get Major %d\n",
		       __FILE__, __LINE__, ALPINE1284_MAJOR);
		return ret;
	}
#endif
	PPControl.initialized = 0;

	/* Print out the MCF5420 1284 port version. */
	printk(KERN_INFO "MCF5420 1284 port version is %x\n",
	       P1284_READ_REG_UB(MPC8220_1284REV));

#ifdef CONFIG_ALASKA_1284_DMA
	P1284_WRITE_REG_UB(MPC8220_1284INTCTRL, 0x1d);

	/* Set FIFO Granularity to 4 -
	 * When DMA transfers to or from CommBuss peripherals are set up, the
	 * programmer must ensure that the CommBuss FIFO granularity matches
	 * the DMA transfer width.  In particular, if the DMA transfer width
	 * is 4 (i.e. 32-bit transfers) the granularity *must* be set to 4.
	 */
	P1284_WRITE_REG(MPC8220_1284FIFOCTRL, 0x1);

#else				/* CONFIG_ALASKA_1284_DMA */
	P1284_WRITE_REG_UB(MPC8220_1284INTCTRL, 0x1f);
#endif				/* CONFIG_ALASKA_1284_DMA */

	/* Set clock speed and minimum allowable time before the 1284 state */
	/* machine will recommize a state change on the 1284 bus. */
	P1284_WRITE_REG_UB(MPC8220_1284PCON,
			   (((((CRYSTAL_HZ / 1000000) / 5) - 2) << 2) | 0x1));

	/*Set the alarm pointer */
#ifdef CONFIG_ALASKA_1284_DMA
	P1284_WRITE_REG_UB(MPC8220_1284FIFOALARM, 0x10);
#else
	P1284_WRITE_REG_UB(MPC8220_1284FIFOALARM, 0x2);
#endif

	/* Turn on support for 1284 modes: NIBBLE, BYTE, ECP, and ECP/RLE. */
	P1284_WRITE_REG_UB(MPC8220_1284MODESUPT,
			   MODESUPT_P1284EN | MODESUPT_BYTE | MODESUPT_ECP |
			   MODESUPT_RLE);
	/* Set the transfer direction to be forward */
	P1284_BAND_REG_UB(MPC8220_1284BUFSTAT, ~BUFSTAT_TRANSDIR);

	/* Reset BUSY line so the host knows we're ready */
	P1284_WRITE_REG_UB(MPC8220_1284OUTCTRL,
			   OUTCTRL_FAULTB_CTRL | OUTCTRL_ACKB_CTRL);

	initParallelControlStruct();

	parallel_update_PnPID();

#ifdef CONFIG_ALASKA_1284_DMA
	/* Enable the DMA stuff for the 1284 */
	initParallelDMA();
#endif				/* CONFIG_ALASKA_1284_DMA */

	if (request_irq
	    (MPC8220_1284_IRQ, alpine1284_isr, 0, "Alpine 1284 read ISR",
	     NULL)) {
		printk(KERN_INFO "Error:  Alpine 1284 ISR already in use\n");
	}

	init_timer(&alpine1284_timerlist_reverse);
	alpine1284_timerlist_reverse.function = transfer_buffer_timeout;

	init_timer(&alpine1284_timerlist_read);
	alpine1284_timerlist_read.function = read_timeout;

	return 0;
}

void __exit
alpine1284_fini(void)
{
	del_timer_sync(&alpine1284_timerlist_read);
	del_timer_sync(&alpine1284_timerlist_reverse);
	free_irq(MPC8220_1284_IRQ, NULL);
#ifdef CONFIG_ALASKA_1284_DMA
	MSD_releaseChannel(DMA_1284_TaskNum);
#endif
#ifdef CONFIG_DEVFS_FS
	devfs_unregister(PPControl.de);
#else
	unregister_chrdev(ALPINE1284_MAJOR, ALPINE1284_DEVNAME);
#endif
	if (InBuf)
		kfree(InBuf);
	if (OutBuf)
		kfree(OutBuf);
	if (IDBuf)
		kfree(IDBuf);
}

module_init(alpine1284_init);
module_exit(alpine1284_fini);
MODULE_DESCRIPTION("Alpine 1284 Driver");
MODULE_AUTHOR("Craig Nadler");
MODULE_LICENSE("GPL");
