/* $Id: etrax100par.c,v 1.6 2000/10/09 17:01:11 johana Exp $
 * 
 * Elinux parallel port driver
 * NOTE!
 *   Since par0 shares DMA with ser2 and par 1 shares DMA with ser3
 *   this should be handled if both are enabled at the same time.
 *   THIS IS NOT HANDLED YET!
 *
 * Copyright (c) 2000 Axis Communications AB
 * 
 * Authors: Jonas Dellenvall
 *
 * $Log: etrax100par.c,v $
 * Revision 1.6  2000/10/09 17:01:11  johana
 * Enable/disable rx int when going from/to manual mode.
 *
 * Revision 1.5  2000/10/04 16:32:11  bjornw
 * * Use virt_to_phys for DMA addresses
 * * Parallel is not spelled parallell
 * * Indentation fix
 * * Bumped revision to 1.0 since I assume this does actually work
 *
 *
 */

#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <asm/irq.h>
#include <asm/io.h>

#include <linux/malloc.h>
#include <linux/interrupt.h>

#include <asm/segment.h>
#include <asm/system.h>

#include <asm/svinto.h>
#include <linux/etraxgpio.h>
#include "etrax100par.h"
#include <linux/etraxpario.h>

/*
 * Etrax100 DMAchannels:
 * Par0 out : DMA2
 * Par0 in  : DMA3
 * Par1 out : DMA4
 * Par1 in  : DMA5
 * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding
 *       DMA and DMA irq
 */

#define CONFIG_PAR0_INT 1
#define CONFIG_PAR1_INT 1

#define DINT(x)  /* Debug for interrupt (non DMA) */
#define DPARIO(x)  /* Debug for I/O */

#ifndef MAX
#define MAX(x, y) (((x) > (y))? (x):(y))
#endif

#ifndef MIN
#define MIN(x, y) (((x) < (y))? (x):(y))
#endif


/* Always have the complete structs here, even if the port is not used!
 *  (that way we can index this by the minor number)
 */
static struct etrax100par_struct lp_table[] = {
#if 1 /*def CONFIG_ETRAX100_PARALLEL_PORT0*/
	{ R_PAR0_CTRL_DATA,
	  R_PAR0_CTRL,
	  R_PAR0_STATUS_DATA,
	  R_PAR0_CONFIG,
	  R_PAR0_DELAY,
	  2,
	  1U << 4, /* uses DMA 2 and 3 */


	  R_DMA_CH2_CLR_INTR,
	  R_DMA_CH2_FIRST,
	  R_DMA_CH2_CMD,
	  R_DMA_CH3_CLR_INTR,
	  R_DMA_CH3_FIRST,
	  R_DMA_CH3_CMD,
	  R_DMA_CH3_STATUS,
	  R_DMA_CH3_HWSW,
	/* Non DMA interrupt stuff */
	  R_IRQ_MASK0_RD,
	  R_IRQ_MASK0_CLR,
	  R_IRQ_READ0,
	  R_IRQ_MASK0_SET,
	  1U << R_IRQ_MASK0_RD__par0_ready__BITNR, /* tx (ready)*/
	  1U << R_IRQ_MASK0_RD__par0_data__BITNR, /* rx (data)*/
	  1U << R_IRQ_MASK0_RD__par0_ecp_cmd__BITNR, /* ecp_cmd */
	  1U << R_IRQ_MASK0_RD__par0_peri__BITNR, /* peri */
	  0 },  /* lp0 */
#endif 
#if 1 /*def CONFIG_ETRAX100_PARALLEL_PORT1*/
	{ R_PAR1_CTRL_DATA,
	  R_PAR1_CTRL,
	  R_PAR1_STATUS_DATA,
	  R_PAR1_CONFIG,
	  R_PAR1_DELAY,
	  4,
	  1U << 8, /* uses DMA 4 and 5 */

	  R_DMA_CH4_CLR_INTR,
	  R_DMA_CH4_FIRST,
	  R_DMA_CH4_CMD,
	  R_DMA_CH5_CLR_INTR,
	  R_DMA_CH5_FIRST,
	  R_DMA_CH5_CMD,
	  R_DMA_CH5_STATUS,
	  R_DMA_CH5_HWSW,
	/* Non DMA interrupt stuff */
	  R_IRQ_MASK1_RD,
	  R_IRQ_MASK1_CLR,
	  R_IRQ_READ1,
	  R_IRQ_MASK1_SET,
	  1U << R_IRQ_MASK1_RD__par1_ready__BITNR, /* tx (ready) */
	  1U << R_IRQ_MASK1_RD__par1_data__BITNR, /* rx (data) */
	  1U << R_IRQ_MASK1_RD__par1_ecp_cmd__BITNR, /* ecp_cmd */
	  1U << R_IRQ_MASK1_RD__par1_peri__BITNR, /* peri */
	  1 },  /* lp1 */
#endif 
};


#define NR_PORTS (sizeof(lp_table)/sizeof(struct etrax100par_struct))

static int max_lp; /* the real number of devices */
static int lp_error;

#define LP_DEBUG 
#undef LP_DEBUG 

static void 
tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
	/* this routine is called when a DMA transfer is complete */	
	struct e100_parallel *info;
	unsigned long ireg;
	int i;
	
	ireg = *R_IRQ_MASK2_RD;
	for (i = 0; i < NR_PORTS; i++) {
		if (ireg & lp_table[i].irq) {
			*lp_table[i].oclrintradr = 3;
			/* wake up the waiting process */
			wake_up_interruptible(&lp_table[i].lp_wait_q);
			return;
		}
	}
}



#if defined(CONFIG_ETRAX100_PAR0_DMA) || defined(CONFIG_ETRAX100_PAR1_DMA)
static int
lp_write_dma(struct inode *inode, struct file *file,
	     const char *buf, int count)
{
	int i;
	struct etrax100par_struct *info;
	struct etrax_dma_descr *adescr;
	unsigned int flags;
	int dev = MINOR(inode->i_rdev);
        struct wait_queue wait = { current, NULL };
	
	info = &lp_table[dev];
	adescr = &info->tr_descr;
	
	/* set up the descriptor correctly for output */  
	adescr->ctrl = d_int | d_eol | d_eop;
	adescr->sw_len = count ;
	/* cast to avoid a warning, we wont return until we are ready with
           buf anyway */
	adescr->buf = virt_to_phys(buf);
	adescr->status = 0;

	/* this will sleep until the tr_interrupt routine wakes us up, OR a 
	 * signal arrives, this is used so it's possible to kill a process that
	 * has hung inside this device driver
	 */
        
        current->state = TASK_INTERRUPTIBLE;
        add_wait_queue(&info->lp_wait_q, &wait);
        
        *info->ofirstadr = virt_to_phys(adescr); /* write to R_DMAx_FIRST */
        *info->ocmdadr = 1;       /* dma command start -> R_DMAx_CMD */
        
        schedule();
        remove_wait_queue(&info->lp_wait_q, &wait);
		
	/* DMA is now running (hopefully) */
	
	/* 
	 * Assumed bug: if an error occurs we do not detect it, we just
         * report that all charcters have been written succesfully
	 */

	return count;
}
#endif

static void 
tr_int_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
	/* this routine is called when one char is sent */	
	static unsigned long cnt = 0;
	struct etrax100par_struct *info;
	
	unsigned long ireg;
	int i;
	cnt++;
	DINT(printk("tr_int_int:%lu\n", cnt));
	for (i = 0; i < NR_PORTS; i++) {
		info = &lp_table[i];
		ireg = *info->irq_mask_rd;
		if (ireg & info->irq_mask_tx) {
			DINT(printk("par%i txint: %lu\n", i, 
			       info->tr_buf_last - info->tr_buf_curr));
			/* Send next char if available or wake process */
			info->tr_buf_curr++;
			if (info->tr_buf_curr < info->tr_buf_last){
				info->reg_ctrl_data_shadow &= ~0xFF;
				info->reg_ctrl_data_shadow |= 
				  *info->tr_buf_curr;
				*info->reg_ctrl_data = 
				  info->reg_ctrl_data_shadow;
			}
			else{
				/* Last byte sent */
				DINT(printk("last sent!\n"));
				info->tr_running = 0;
				/* Disable int */
				*info->irq_mask_clr = info->irq_mask_tx;
				/* wake up the waiting process */
				wake_up_interruptible(&info->lp_wait_q);
				return;
			}
		}
		if (ireg & info->irq_mask_rx) {
			/* Clear interrupt by reading data */
			unsigned long status = *info->reg_status_data;
			unsigned char data =  *((unsigned char*)info->reg_status_data);
			printk("par%i rxint, status: 0x%08X 0x%02X ctrl: 0x%08X config: 0x%08X\n", 
			       i, status, data, info->reg_ctrl_data_shadow,
			       info->reg_config_shadow);
	        	if (IO_EXTRACT(R_PAR0_STATUS_DATA, mode, status) == 
			    IO_STATE_VALUE(R_PAR0_STATUS_DATA, mode, manual)){
			    /* Manual mode triggers rxint's */
				printk("manual mode\n");
				info->reg_config_shadow |= 
				IO_STATE(R_PAR0_CONFIG, mode, centronics)|
				IO_STATE(R_PAR0_CONFIG, force, on);
				*info->reg_config = info->reg_config_shadow;
			}
		}
		if (ireg & info->irq_mask_peri) {
			unsigned long status = *info->reg_status_data;
			printk("peri int\n");
			/* Acknowledge by writing peri_int bit in ctrl_data  */
			/* Don't set it in the shadow reg */
			*info->reg_ctrl_data = info->reg_ctrl_data_shadow |
			  IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack);
		}
		if (ireg & info->irq_mask_ecp_cmd) {
			/* Read status to acknowledge */
			unsigned long status = *info->reg_status_data;
			printk("ecp_cmd\n");
		}
	}
}

void 
print_par(int port, struct etrax_pario *par)
{
  
	printk("par%i: ctrl: 0x%08X status: 0x%08X config: 0x%08X delay:0x%08X \n",
	       port, par->ctrl_data, par->status_data, par->config, par->delay);
	printk("par%i: ctrl: oe:%u seli:%d autofd:%d strb:%d init:%d data: 0x%02X (%i)\n",
	       port,
	       IO_EXTRACT(R_PAR0_CTRL_DATA, oe, par->ctrl_data),
	       IO_EXTRACT(R_PAR0_CTRL_DATA, seli, par->ctrl_data),
	       IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, par->ctrl_data),
	       IO_EXTRACT(R_PAR0_CTRL_DATA, strb, par->ctrl_data),
	       IO_EXTRACT(R_PAR0_CTRL_DATA, init, par->ctrl_data),
	       IO_EXTRACT(R_PAR0_CTRL_DATA, data, par->ctrl_data));
	
  
	printk("par%i: status: mode: %i perr: %i ack: %i busy: %i fault: %i sel: %i\n"
	       "             tr_rdy: %i dav: %i ecp_cmd: %i data: 0x%02X (%i)\n",
	       port,
	       IO_EXTRACT(R_PAR0_STATUS_DATA, mode, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, perr, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, ack, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, busy, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, fault, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, sel, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, tr_rdy, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, dav, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, ecp_cmd, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, data, par->status_data),
	       IO_EXTRACT(R_PAR0_STATUS_DATA, data, par->status_data));
}

/* Write to port using interrupt byte by byte */
static int
lp_write_int(struct inode *inode, struct file *file,
	     const char *buf, int count)
{	
	unsigned long flags;
	int i;
	int num_written = count;
	struct etrax100par_struct *info;
	struct etrax_dma_descr *adescr;
	int dev = MINOR(inode->i_rdev);
        struct wait_queue wait = { current, NULL };
		
	info = &lp_table[dev];

	if ((file->f_flags & O_NONBLOCK)){
		DINT(printk("par NONBLOCK write\n"));
		if (!info->tr_running){
			info->tr_buf_last = info->tr_buf;
			info->tr_buf_curr = info->tr_buf;		
		}
		num_written = MIN(count, 
		  LP_BUFFER_SIZE - (info->tr_buf_last - info->tr_buf));
		if (num_written == 0){
			return -EAGAIN;
		}
		/* Copy data */
		memcpy((unsigned char*)info->tr_buf_last, buf, num_written);
		save_flags(flags);
    		cli();   
		/* Advance end pointer while ints are off */
		info->tr_buf_last += num_written;

		if (!info->tr_running){ 
		    if ((*info->reg_status_data) & 
			IO_MASK(R_PAR0_STATUS_DATA, tr_rdy)){
			/* Write using interrupts */
			info->tr_running = 1;
			info->reg_ctrl_data_shadow &= ~0xFF;
			info->reg_ctrl_data_shadow |= *info->tr_buf_curr;
			/* Enable int */
			*info->irq_mask_set = info->irq_mask_tx;
			*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
			restore_flags(flags);
			return num_written;
		   } else{
			/* Busy, but no transmit in progress! Strange */
			restore_flags(flags);
			return -EIO;
		   }
		}else{
			/* Let the interrupt handle it */
			restore_flags(flags);
			return num_written;		
		}
	}else{
		DINT(printk("par BLOCKING write: %lu\n", count));
		if (info->tr_running){
			num_written = MIN(count, 
			  LP_BUFFER_SIZE - (info->tr_buf_last - info->tr_buf));
			/* Copy data */
			memcpy((unsigned char*)info->tr_buf_last, buf, num_written);
			info->tr_buf_last += num_written;
		}
		else{
			/* Use zero copy */
			info->tr_buf_curr = buf;
			info->tr_buf_last = buf + count;
			num_written = count;
		}
	}

	if ((*info->reg_status_data) & IO_MASK(R_PAR0_STATUS_DATA, tr_rdy)){

		struct etrax_pario par;

		DINT(printk("Enable par%i int\n", dev));
		/* Write using interrupts */
		info->tr_running = 1;
		info->reg_ctrl_data_shadow &= ~0xFF;
		info->reg_ctrl_data_shadow |= *info->tr_buf_curr;
		/* Enable int */
		save_flags(flags);
    		cli();   
		*info->irq_mask_set = info->irq_mask_tx;
		*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
		DINT(
		  /* DEBUG: */
		  par.ctrl_data = info->reg_ctrl_data_shadow;
		  par.config = info->reg_config_shadow;
		  par.delay = info->reg_delay_shadow;
		  par.status_data = *info->reg_status_data;
		  print_par(dev, &par);
		  printk("irq read: 0x%08X rd: 0x%08X\n",
			*info->irq_read, *info->irq_mask_rd)
		); 
	}else{
		/* Busy, transmit in progress - let interrupt handle it */
		DINT(printk("par - transmit in progress\n"));
		return -EBUSY;
	}
		

	/* this will sleep until the tr_interrupt routine wakes us up, OR a 
	 * signal arrives, this is used so it's possible to kill a process that
	 * has hung inside this device driver
	 */
       	current->state = TASK_INTERRUPTIBLE;
       	add_wait_queue(&info->lp_wait_q, &wait);
	DINT(printk("schedule()\n"));	
       	schedule();
	current->state = TASK_RUNNING;
	DINT(printk("awake wrote: %lu\n", num_written));	
       	remove_wait_queue(&info->lp_wait_q, &wait);
	restore_flags(flags);
	return num_written;
}

static int
lp_write(struct inode *inode, struct file *file,
	     const char *buf, int count)
{
	int dev = MINOR(inode->i_rdev);

	if (dev == 0){
#ifdef CONFIG_ETRAX100_PAR0_DMA
		return lp_write_dma(inode, file, buf, count);
#endif
	} else if (dev == 1){
#ifdef CONFIG_ETRAX100_PAR1_DMA
		return lp_write_dma(inode, file, buf, count);
#endif
	}
	/* Do interrupt driven output */
	return lp_write_int(inode, file, buf, count);

	
	printk("etrax100par: lp_write not implemented unless DMA\n");
	return -EINVAL;
}

static int
lp_lseek(struct inode *inode, struct file *file,
	 off_t offset, int origin)
{
	return -ESPIPE;
}

static int
lp_open(struct inode *inode, struct file *file)
{
	int dev = MINOR(inode->i_rdev);
	if ( dev < 0 
#ifndef CONFIG_ETRAX100_PARALLEL_PORT0
	     ||	dev == 0
#endif
#ifndef CONFIG_ETRAX100_PARALLEL_PORT1
	     ||	dev == 1
#endif
	     || dev >= NR_PORTS
	   )	
		return -ENODEV;

	if (lp_table[dev].flags & LP_BUSY)
		return -EBUSY;
	lp_table[dev].flags |= LP_BUSY;
	return 0;
}

static void
lp_release(struct inode *inode, struct file *file)
{
	lp_table[MINOR(inode->i_rdev)].flags &= ~LP_BUSY;
}

static int
lp_ioctl(struct inode *inode, struct file *file,
	 unsigned int cmd, unsigned long arg)
{
	unsigned int minor = MINOR(inode->i_rdev);
	struct etrax100par_struct *info;
	int retval = 0;
	struct gpio_private *priv = (struct gpio_private *)file->private_data;


#ifdef LP_DEBUG
	printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
#endif
	if (minor >= max_lp) 
		return -ENODEV;
	info = &lp_table[minor];
	if(_IOC_TYPE(cmd) == ETRAXGPIO_IOCTYPE) {
	/* Handle gpio type ioctl's */
		switch (_IOC_NR(cmd)) {
		case IO_READBITS:
			/* Go to manual mode */
			*info->reg_config = 
			  info->reg_config_shadow &= 
			    ~IO_MASK(R_PAR0_CONFIG, mode) | 
			    IO_STATE(R_PAR0_CONFIG, mode, manual);
			/* Disable OE */
			*info->reg_ctrl_data = info->reg_ctrl_data_shadow &= 
			  ~IO_STATE(R_PAR0_CTRL_DATA, oe, enable);
			/* read the port */	
			return (*info->reg_status_data & 0xFF);
		case IO_SETBITS:
			/* Go to manual mode */
			*info->reg_config = 
			  info->reg_config_shadow &= 
			    ~IO_MASK(R_PAR0_CONFIG, mode) | 
			    IO_STATE(R_PAR0_CONFIG, mode, manual);
			/* set bits with a 1 in arg */
			*info->reg_ctrl_data = 
			  info->reg_ctrl_data_shadow |= (unsigned char)arg |
			    IO_STATE(R_PAR0_CTRL_DATA, oe, enable);
			break;
		case IO_CLRBITS:
			/* Go to manual mode */
			*info->reg_config = 
			  info->reg_config_shadow &= 
			    ~IO_MASK(R_PAR0_CONFIG, mode) | 
			    IO_STATE(R_PAR0_CONFIG, mode, manual);
			/* clear bits with a 1 in arg */
			*info->reg_ctrl_data = 
			  info->reg_ctrl_data_shadow &= ~(unsigned char)arg |
			    IO_STATE(R_PAR0_CTRL_DATA, oe, enable);
			break;
#if 0
		case IO_HIGHALARM:
			// set alarm when bits with 1 in arg go high
			priv->highalarm |= (unsigned char)arg;
			break;
		case IO_LOWALARM:
			// set alarm when bits with 1 in arg go low
			priv->lowalarm |= (unsigned char)arg;
			break;
		case IO_CLRALARM:
			// clear alarm for bits with 1 in arg
			priv->highalarm &= ~(unsigned char)arg;
			priv->lowalarm  &= ~(unsigned char)arg;
			break;
#endif
		default:
			retval = -EINVAL;
		}/* switch */
	}else{
	/* Handle parX specific ioctl's */
		
		struct etrax_pario par; 
		int retval;
		switch (cmd) {
		case  PARIO_GET_STRUCT:
			DPARIO(printk("PARIO_GET_STRUCT\n"));
			retval = verify_area(VERIFY_WRITE, 
			                     (struct etrax_pario*)arg,
			                     sizeof(struct etrax_pario));
			if (retval !=0 ){
				printk("PARIO_GET_STRUCT: VERIFY_WRITE error: %i\n", retval);	
				return retval;
			}
			par.ctrl_data = info->reg_ctrl_data_shadow;
			par.status_data = *info->reg_status_data;
			par.config = info->reg_config_shadow;
			par.delay  = info->reg_delay_shadow;
			par.assign_ctrl = 0;
			par.assign_config = 0;
			par.assign_delay = 0;
			memcpy_tofs((struct etrax_pario*)arg, &par, 
			            sizeof(struct etrax_pario));
			return 0;
		break;
		case  PARIO_SET_STRUCT:

			retval = verify_area(VERIFY_READ, 
			                     (struct etrax_pario*)arg,
			                     sizeof(struct etrax_pario));
			if (retval !=0 )
				return retval;
			memcpy_fromfs(&par, (struct etrax_pario*)arg, 
			              sizeof(struct etrax_pario));
			DPARIO(printk("PARIO_SET_STRUCT\n"));
			if (par.assign_ctrl){
				DPARIO(printk("assign ctrl: 0x%08X\n", 
				  par.ctrl_data));
				*info->reg_ctrl_data = 
				  info->reg_ctrl_data_shadow = par.ctrl_data;
			}
			if (par.assign_config){
				/* Turn off interrupt if entering manual mode*/
				if (IO_EXTRACT(R_PAR0_CONFIG, mode, par.config) ==
				  IO_STATE_VALUE(R_PAR0_CONFIG, mode, manual)){
					printk("Setting manual mode, disable rx ints\n");
					*info->irq_mask_clr = info->irq_mask_rx;	
				}
				else
				{
					/* If not manual, enable rx int */
					*info->irq_mask_set = info->irq_mask_rx;
				}
				

				*info->reg_config = 
				  info->reg_config_shadow = par.config;
			}
			if (par.assign_delay){
				*info->reg_delay = 
				  info->reg_delay_shadow = par.delay;
			}
			return 0;
		break;
		default:
			retval = -EINVAL;
		} /* switch */
	}
	return retval;
}


static struct file_operations lp_fops = {
	lp_lseek,
	NULL,		/* lp_read */
	lp_write,
	NULL,		/* lp_readdir */
	NULL,		/* lp_select */
	lp_ioctl,
	NULL,		/* lp_mmap */
	lp_open,
	lp_release
};

void parallel_init ()
{
	struct etrax100par_struct *info = &lp_table[0];
	unsigned int tmp;
	int mode;
	printk("Initializing parallel port registers... ");
	
	/* The different times below will be (value*160 + 20) ns,    */
	/* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6),    */
	/* the setup time will be (6*160+20) = 980ns.                */

	max_lp = 0;  

#ifdef CONFIG_ETRAX100_PARALLEL_PORT0
	printk("par0 ");  
	max_lp++;
	info->reg_ctrl_data_shadow = 
		IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop)      |
		IO_STATE(R_PAR0_CTRL_DATA, oe, disable)       |
		IO_STATE(R_PAR0_CTRL_DATA, seli, inactive)     |
		IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive)     |
		IO_STATE(R_PAR0_CTRL_DATA, strb, inactive)     |
		IO_STATE(R_PAR0_CTRL_DATA, init, inactive)     |
		IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data)     |
		IO_FIELD(R_PAR0_CTRL_DATA, data, 0);
	*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
	/* Clear peri int without setting shadow */
	*info->reg_ctrl_data = info->reg_ctrl_data_shadow |
			  IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack);

	info->reg_delay_shadow = 
		IO_FIELD(R_PAR0_DELAY, setup, 5)      |
		IO_FIELD(R_PAR0_DELAY, strobe, 5)     |
		IO_FIELD(R_PAR0_DELAY, hold, 5);
	*info->reg_delay = info->reg_delay_shadow;

	/* Set PAR0 to centronics mode, use force.                   */

	info->reg_config_shadow = 
#ifdef CONFIG_ETRAX100_PAR0_DMA
		IO_STATE(R_PAR0_CONFIG, dma, enable)      |
#else
		IO_STATE(R_PAR0_CONFIG, dma, disable)     |
#endif
		IO_STATE(R_PAR0_CONFIG, iseli, inv)       |
		IO_STATE(R_PAR0_CONFIG, iautofd, inv)     |
		IO_STATE(R_PAR0_CONFIG, istrb, inv)       |
		IO_STATE(R_PAR0_CONFIG, iinit, inv)       |
		IO_STATE(R_PAR0_CONFIG, rle_in, disable)  |
		IO_STATE(R_PAR0_CONFIG, rle_out, disable) |
		IO_STATE(R_PAR0_CONFIG, enable, on)       |
		IO_STATE(R_PAR0_CONFIG, force, on)        |
		IO_STATE(R_PAR0_CONFIG, ign_ack, wait)    |
		IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe)  |
		IO_STATE(R_PAR0_CONFIG, mode, centronics);
	*info->reg_config = info->reg_config_shadow;
#ifdef CONFIG_ETRAX100_PAR0_DMA
	RESET_DMA(2);
	WAIT_DMA(2);
#ifdef CONFIG_ETRAX100_SERIAL_PORT2
	printk(" Warning - ser2!");
#endif /* SERIAL_PORT2 */
#endif /* DMA */
#endif /* PORT0 */
	info++;
#ifdef CONFIG_ETRAX100_PARALLEL_PORT1

	printk("par1 ");
	max_lp++;

	info->reg_ctrl_data_shadow = 
		IO_STATE(R_PAR1_CTRL_DATA, peri_int, nop)      |
		IO_STATE(R_PAR1_CTRL_DATA, oe, disable)       |
		IO_STATE(R_PAR1_CTRL_DATA, seli, inactive)     |
		IO_STATE(R_PAR1_CTRL_DATA, autofd, inactive)     |
		IO_STATE(R_PAR1_CTRL_DATA, strb, inactive)     |
		IO_STATE(R_PAR1_CTRL_DATA, init, inactive)     |
		IO_STATE(R_PAR1_CTRL_DATA, ecp_cmd, data)     |
		IO_FIELD(R_PAR1_CTRL_DATA, data, 0);
	*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
	/* Clear peri int without setting shadow */
	*info->reg_ctrl_data = info->reg_ctrl_data_shadow |
			  IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack);

	info->reg_delay_shadow = 	
	        IO_FIELD(R_PAR1_DELAY, setup, 5)      |
		IO_FIELD(R_PAR1_DELAY, strobe, 5)     |
		IO_FIELD(R_PAR1_DELAY, hold, 5);
	*info->reg_delay = info->reg_delay_shadow;	
	/* Set PAR0 to centronics mode, use force.                   */

	info->reg_config_shadow = 	
#ifdef CONFIG_ETRAX100_PAR1_DMA
		IO_STATE(R_PAR1_CONFIG, dma, enable)      |
#else
		IO_STATE(R_PAR1_CONFIG, dma, disable)     |
#endif
		IO_STATE(R_PAR1_CONFIG, iseli, inv)       |
		IO_STATE(R_PAR1_CONFIG, iautofd, inv)     |
		IO_STATE(R_PAR1_CONFIG, istrb, inv)       |
		IO_STATE(R_PAR1_CONFIG, iinit, inv)       |
		IO_STATE(R_PAR1_CONFIG, rle_in, disable)  |
		IO_STATE(R_PAR1_CONFIG, rle_out, disable) |
		IO_STATE(R_PAR1_CONFIG, enable, on)       |
		IO_STATE(R_PAR1_CONFIG, force, on)        |
		IO_STATE(R_PAR1_CONFIG, ign_ack, wait)    |
		IO_STATE(R_PAR1_CONFIG, oe_ack, wait_oe)  |
		IO_STATE(R_PAR1_CONFIG, mode, centronics);
	*info->reg_config = info->reg_config_shadow;	
#ifdef CONFIG_ETRAX100_PAR1_DMA
	RESET_DMA(4);
	WAIT_DMA(4);
#ifdef CONFIG_ETRAX100_SERIAL_PORT3
	printk(" Warning - ser3!");
#endif /* SERIAL_PORT3 */
#endif /* DMA */
#endif /* PORT1 */
	printk(" done \n");
	
} 

static void 
show_parallel_version(void)
{
	printk("Etrax/100 DMA parallel port driver v1.0, (c) 2000 Axis Communications AB\r\n");
}


int
lp_e100_init(void)
{
	int i;
	struct etrax100par_struct *info;
	show_parallel_version();
	
	if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) {
		printk("unable to get major %d for line printer\n", LP_MAJOR);
		return -EBUSY;
	}

	/* setup Etrax parport register */

	parallel_init();
	
	for (i = 0, info = lp_table; i < NR_PORTS; i++,info++) {
		info->tr_running = 0;
		info->flags = 0;
		info->stats.chars = 0;
		info->stats.sleeps = 0;
		info->stats.maxrun = 0;
		info->stats.maxwait = 0;
		info->stats.meanwait = 0;
		info->stats.mdev = 0;
		info->line = i;
		init_waitqueue(&info->lp_wait_q);
		info->tr_buf_curr = info->tr_buf_last = info->tr_buf;

		//    printk(KERN_INFO "lp%d at 0x%x is using DMA\n",
		//           info->line, info->reg_ctrl_data);
	}
	info = &lp_table[0];
#ifdef CONFIG_ETRAX100_PARALLEL_PORT0
#ifdef CONFIG_ETRAX100_PAR0_DMA
	*R_DMA_CH2_CLR_INTR = 3 ; //clear all pending interrupts

	if(request_irq(18, tr_interrupt, SA_SHIRQ, "parallel 0 dma tr", NULL))
		panic("irq18");
	//	if(request_irq(19, rec_interrupt, SA_INTERRUPT, "parallel 0 dma rec", NULL))
	//		panic("irq19");
	
	*R_IRQ_MASK2_SET =
		IO_STATE(R_IRQ_MASK2_SET, dma2_eop,   set) | 
		IO_STATE(R_IRQ_MASK2_SET, dma2_descr, set);
#else
   /* No DMA */
#endif	
#if CONFIG_PAR0_INT
	if(request_irq(4, tr_int_interrupt, SA_SHIRQ,"parallel 0 tx+rx", NULL))
		panic("irq4");
	/* Enable TX, RX and peri irq */
	*info->irq_mask_set = info->irq_mask_tx | info->irq_mask_rx |
	                      info->irq_mask_peri;
#endif
#endif
	info = &lp_table[1];	
#ifdef CONFIG_ETRAX100_PARALLEL_PORT1
#ifdef CONFIG_ETRAX100_PAR1_DMA
	*R_DMA_CH2_CLR_INTR = 3 ; //clear all pending interrupts

	if(request_irq(20, tr_interrupt, SA_SHIRQ, "parallel 1 dma tr", NULL))
		panic("irq20");
	//	if(request_irq(21, rec_interrupt, SA_INTERRUPT, "parallel 1 dma rec", NULL))
	//		panic("irq21");

	*R_IRQ_MASK2_SET =
		IO_STATE(R_IRQ_MASK2_SET, dma4_eop,   set) | 
		IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set);
#endif		
#if CONFIG_PAR1_INT
	if(request_irq(5, tr_int_interrupt, SA_SHIRQ,"parallel 1 tx+rx", NULL))
		panic("irq5");
	/* Enable TX, RX and peri irq */
	*info->irq_mask_set = info->irq_mask_tx | info->irq_mask_rx |
	                      info->irq_mask_peri;
#endif
#endif
}

/*
 * Currently we do not accept any lp-parameters, but that may change.
 */
void
lp_setup(char *str, int *ints)
{	
}
