/*
 * 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
 */


/*************************************************************************
 ***
 *** Project Name: MosChip
 ***
 *** Module Name: Mos7715
 ***
 *** File: mos7715.c 
 ***		
 ***
 *** File Revision: 1.0
 ***
 *** Revision Date:  10/06/05 
 ***
 *** Purpose	  : It gives an interface between USB to Serial 
 ***                and serves as a Serial Driver for the high 
 ***		        level layers /applications.
 ***
 *** Change History:
 ***
 ***
 *** LEGEND	  :
 ***
 *** 
 *** DBG - Code inserted due to as part of debugging
 *** DPRINTK - Debug Print statement
 ***
 *************************************************************************/

/* all file inclusion goes here */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/serial.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/usb.h>

#include <linux/socket.h>
#include <linux/parport.h>

#include "mos7715.h"            /* MCS7715 Defines    */
#include "16C50.h"		/* 16C50 UART defines */

/* all defines goes here */

/*
 * Debug related defines 
 */

/* 1: Enables the debugging -- 0: Disable the debugging */

#define ASP_DEBUG	0

#if ASP_DEBUG
	static int debug = 1;
	#define DPRINTK(fmt, args...) printk( "%s: " fmt, __FUNCTION__ , ## args)

#else
	static int debug = 0;
	#define DPRINTK(fmt, args...)

#endif

#include "usb-serial.h"			/*usb-serial defines*/

/*
 * Version Information
 */
#define DRIVER_VERSION "1.0.0.3FC4"
#define DRIVER_DESC "Moschip USB Serial Driver"

/*
 * Defines used for sending commands to port 
 */

#define WAIT_FOR_EVER   (HZ * 0 ) /* timeout urb is wait for ever*/
#define MOS_WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
                                                                                                                             
#define MOS_PORT1       0x0200          /* Serial Port 1 */
#define MOS_PORT2       0x0300          /* Serial Port 2 */
#define MOS_VENREG      0x0000          /* Vendor Specific Cmd */
#define MOS_MAX_PORT    0x02            /* Number of Serial Ports */
#define MOS_WRITE       0x0E            /* Write Request */
#define MOS_READ        0x0D            /* Read Request */                                                                                                
/* parport */
/* --------------------------------------------------------------------- */

static int restore_state_thread(void *);
static pid_t thread_pid;
wait_queue_head_t restore_state_event;
int ThreadState = 0,thread_cond=0;
unsigned char dcr,ecr;

char flag_ser_par;

/* parport private structure */
struct parport_mos7715_private 
{
	struct usb_device *usbdev;
	void *irqhandle;
	unsigned int irqpipe;
	unsigned char reg[7];  /* USB registers */
};

static struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function);
static int serial_paranoia_check (struct usb_serial *serial, const char *function);
static int port_paranoia_check (struct usb_serial_port *port, const char *function);

/****************************************************************************
 * moschip7720_2port_device
 *              Structure defining MCS7720, usb serail device
 ****************************************************************************/
	
static struct usb_serial_device_type moschip7715_2port_device = {
	.owner			= THIS_MODULE,
	.name			= "Moschip 2 port adapter",
	.short_name		= "Moschip7715",
//	.id_table		= moschip_port_id_table7715,
	.id_table               = id_table_combined7715,
	.num_interrupt_in	= 1,
	.num_bulk_in		= 2,
	.num_bulk_out		= 2,
	.num_ports		= 2,
	.open			= mos7720_open,
	.close			= mos7720_close,
	.throttle		= mos7720_throttle,
	.unthrottle		= mos7720_unthrottle,
	.attach			= mos7720_startup,
	.shutdown		= mos7720_shutdown,
	.ioctl			= mos7720_ioctl,
	.set_termios		= mos7720_set_termios,
	.write			= mos7720_write,
	.write_room		= mos7720_write_room,
	.chars_in_buffer	= mos7720_chars_in_buffer,
	.break_ctl		= mos7720_break,
	.read_bulk_callback	= mos7720_bulk_in_callback, 
};

static struct usb_driver io_driver = {
	.owner =	THIS_MODULE,
	.name =		"moschip7715",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table_combined7715,
};

/************************************************************************/
/************************************************************************/
/*             I N T E R F A C E   F U N C T I O N S			*/
/*             I N T E R F A C E   F U N C T I O N S			*/
/************************************************************************/
/************************************************************************/

static inline void set_serial_private(struct usb_serial *serial, struct moschip_serial *data)
{
		usb_set_serial_data(serial, (void *)data );
}

static inline struct moschip_serial * get_serial_private(struct usb_serial *serial)
{
		return (struct moschip_serial*) usb_get_serial_data(serial);
}

static inline void set_port_private(struct usb_serial_port *port, struct moschip_port *data)
{
		usb_set_serial_port_data(port, (void*)data );
}

static inline struct moschip_port * get_port_private(struct usb_serial_port *port)
{
		return (struct moschip_port*) usb_get_serial_port_data(port);
}


#if 0
/* Inline functions to check the sanity of a pointer that is passed to us */
static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
{
	if (!serial) 
	{
		dbg("%s - serial == NULL", function);
		return -1;
	}
	if (!serial->type) 
	{
		dbg("%s - serial->type == NULL!", function);
		return -1;
	}

	return 0;
}


static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
{
	if (!port) 
	{
		dbg("%s - port == NULL", function);
		return -1;
	}
	if (!port->serial) 
	{
		dbg("%s - port->serial == NULL", function);
		return -1;
	}
	if (!port->tty) 
	{
		dbg("%s - port->tty == NULL", function);
		return -1;
	}

	return 0;
}


static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) 
{ 
	/* if no port was specified, or it fails a paranoia check */
	if (!port || port_paranoia_check (port, function) ||
	     serial_paranoia_check (port->serial, function)) 
	{
		return NULL;
	}

	return port->serial;
}


#endif
/************************************************************************/
/************************************************************************/
/*            U S B   P A R P O R T   F U N C T I O N S                 */
/*            U S B   P A R P O R T   F U N C T I O N S                 */
/************************************************************************/
/************************************************************************/


/*****************************************************************************
 * ECR modes
 *****************************************************************************/

#define ECR_SPP 00
#define ECR_PS2 01
#define ECR_PPF 02
#define ECR_ECP 03
#define ECR_EPP 04

/*****************************************************************************
 * change_mode_mos
 *	this function will be used to change ECR modes
 * Input : 2 Input
 *			pointer to the parport,
 *		        mode to switch to	
 *****************************************************************************/


static void change_mode_mos(struct parport *pp, int m)
{
	unsigned char data;

	DPRINTK("%s\n","Entering...");

        data = 0x00;
        SendMosCmd(pp,MOS_READ,0,0x0A, &data);

	data = data | (m<<5);	
        SendMosCmd(pp,MOS_WRITE,0,0x0A, &data);

}

/*****************************************************************************
 * clear_epp_timeout
 *	this function will be used to clear TIMEOUT BIT in EPP MODE
 * Input : 1 Input
 *			pointer to the parport,
 *****************************************************************************/
 
static int clear_epp_timeout(struct parport *pp)
{
	unsigned char stat;

	DPRINTK("%s\n","Entering...");

	stat = 0x00;
	SendMosCmd(pp,MOS_READ,0,0x01, &stat);

	return stat & 1;

}

/*****************************************************************************
 * mos7715_irq - Future Use
 *	
 * Input : 4 Input
 *			
 *****************************************************************************/
#if 0
static int mos7715_irq(int usbstatus, void *buffer, int len, void *dev_id)
{
	struct parport *pp = (struct parport *)dev_id;
	struct parport_mos7715_private *priv = pp->private_data;	

	if (usbstatus != USB_ST_NOERROR || len < 4 || !buffer)
		return 1;
	memcpy(priv->reg, buffer, 4);
	/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
	if (priv->reg[2] & priv->reg[1] & 0x10)
		parport_generic_irq(0, pp, NULL);
	return 1;
}
#endif

/*****************************************************************************
 * parport_mos7715_write_data
 *	this function will be used to write data to Reg0 - Data Reg 
 * Input : 2 Input
 *			pointer to the parport,
 *			character to be written
 *****************************************************************************/

static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
{
	//DPRINTK("%s\n","Entering...");

	/* SendMosCmd(pp,MOS_WRITE,0,0x00, &d); */

	//DPRINTK("%s\n","Leaving...");

}

/*****************************************************************************
 * parport_mos7715_read_data
 *	this function will be used to read data from Reg0 - Data Reg 
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/

static unsigned char parport_mos7715_read_data(struct parport *pp)
{
	unsigned char ret;

	DPRINTK("%s\n","Entering...");

	SendMosCmd(pp,MOS_READ,0,0x00, &ret);
	
	DPRINTK("%s\n","Leaving...");
	return ret;

}

/*****************************************************************************
 * parport_mos7715_write_control 
 *	this function will be used to write DCR Reg 
 * Input : 2 Input
 *			pointer to the parport,
 *			value to be written
 *****************************************************************************/

static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
{
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");

	d = (d & 0xf) | (priv->reg[1] & 0xf0);
        
	SendMosCmd(pp,MOS_WRITE,0,0x02, &d);

	priv->reg[1] = d;

	DPRINTK("%s\n","Leaving...");
}

/*****************************************************************************
 * parport_mos7715_read_control 
 *	this function will be used to read DCR Reg 
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/

static unsigned char parport_mos7715_read_control(struct parport *pp)
{
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");

	return priv->reg[1] & 0xf; /* Use sft cpy */

	DPRINTK("%s\n","Leaving...");
}

/*****************************************************************************
 * parport_mos7715_frob_control 
 *	this function will be used to alter ECR Reg 
 * Input : 3 Input
 *			pointer to the parport,
 *			mask value,
 *			value to be written		
 *****************************************************************************/

static unsigned char parport_mos7715_frob_control(struct parport *pp, unsigned char mask, unsigned char val)
{
	unsigned char d;
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");

	DPRINTK("%x	%x\n",(unsigned int)pp,(unsigned int)priv);

	mask &= 0x0f;
	val &= 0x0f;
	d = (priv->reg[1] & (~mask)) ^ val;

	SendMosCmd(pp,MOS_WRITE,0,0x02, &d);
	priv->reg[1] = d;

	DPRINTK("%s\n","Leaving...");

	return d & 0xf;

}

/*****************************************************************************
 * parport_mos7715_read_status 
 *	this function will be used to read DSR Reg
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/

static unsigned char parport_mos7715_read_status(struct parport *pp)
{
	unsigned char data;

//	DPRINTK("%s\n","Entering...");

        SendMosCmd(pp,MOS_READ,0,0x01, &data);

//	DPRINTK("%s\n","Leaving...");

	return data & 0xf8;

}


/*****************************************************************************
 * parport_mos7715_disable_irq - Future Use
 *	this function will be used to disable irq 
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/
static void parport_mos7715_disable_irq(struct parport *pp)
{
 #if 0
	unsigned char d;
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");
 #endif
}

/*****************************************************************************
 * parport_mos7715_enable_irq - Future Use
 *	this function will be used to enable irq 
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/

static void parport_mos7715_enable_irq(struct parport *pp)
{
 #if 0
	unsigned char d;
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");
#endif
}

/*****************************************************************************
 * parport_mos7715_data_forward
 *	this function will be used to set P[0-7] to O/P mode
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/

static void parport_mos7715_data_forward (struct parport *pp)
{
	unsigned char d;
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");

	d = priv->reg[1] & ~0x20;

	SendMosCmd(pp,MOS_WRITE,0,0x02, &d);
	priv->reg[1] = d;

	DPRINTK("%s\n","Leaving...");
}

/*****************************************************************************
 * parport_mos7715_data_reverse
 *	this function will be used to set P[0-7] to I/P mode
 * Input : 1 Input
 *			pointer to the parport
 *****************************************************************************/
static void parport_mos7715_data_reverse (struct parport *pp)
{
	unsigned char d;
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");

	d = priv->reg[1] | 0x20;

	SendMosCmd(pp,MOS_WRITE,0,0x02, &d);

	priv->reg[1] = d;

	DPRINTK("%s\n","Leaving...");

}

/*****************************************************************************
 * parport_mos7715_init_state
 *	this function will be used to set DCR & ECR to initial values
 * Input : 2 Input
 *			pointer to pardevice
 *			pointer to parport_state
 *****************************************************************************/

static void parport_mos7715_init_state(struct pardevice *dev, struct parport_state *s)
{
	DPRINTK("%s\n","Entering...");

	s->u.pc.ctr = 0xcc | (dev->irq_func ? 0x10 : 0x0);
	s->u.pc.ecr = 0x45;

	DPRINTK("%s\n","Leaving...");
}

/*****************************************************************************
 * parport_mos7715_save_state
 *	this function will be used to save DCR & ECR values
 * Input : 2 Input
 *			pointer to parport
 *			pointer to parport_state
 *****************************************************************************/

static void parport_mos7715_save_state(struct parport *pp, struct parport_state *s)
{
	unsigned char data;	
	struct parport_mos7715_private *priv = pp->private_data;	

	DPRINTK("%s\n","Entering...");
        
	data = 0x00;
        SendMosCmd(pp,MOS_READ,0,0x02, &data);
	s->u.pc.ctr = data;
	priv->reg[1] = data;

	data = 0x00;
        SendMosCmd(pp,MOS_READ,0,0x0A, &data);
	s->u.pc.ecr = data;
	priv->reg[2] = data; 

	DPRINTK("%s\n","Leaving...");
}

static int restore_state_thread(void *vpp)
{
	struct parport *pp;
	pp=vpp;

	daemonize("otg_hcd_thread");
	allow_signal(SIGKILL);

	DPRINTK("%s \n","thread ...\n");
	while ( 1 ) {
//		interruptible_sleep_on(&restore_state_event);
		thread_cond = 0;
		wait_event_interruptible(restore_state_event,(thread_cond==1));

       		DPRINTK("%s \n","restore_state_thread:Thread Wait...\n");
		if(ThreadState) {
			ThreadState = 0;
          		DPRINTK("%s \n","Stopping restore_state_thread thread ...");
          		break;
       		}

		SendMosCmd(pp,MOS_WRITE,0,0x02, &dcr);
		SendMosCmd(pp,MOS_WRITE,0,0x0A, &ecr);
	}
	return 0;
}
/*****************************************************************************
 * parport_mos7715_restore_state
 *	this function will be used torestore DCR & ECR values  
 * Input : 2 Input
 *			pointer to parport
 *			pointer to parport_state
 *****************************************************************************/

static void parport_mos7715_restore_state(struct parport *pp, struct parport_state *s)
{
	unsigned char data;	

	DPRINTK("%s\n","Entering...");

	if(s==NULL)
	  return;

	data = s->u.pc.ctr;
//        SendMosCmd(pp,MOS_WRITE,0,0x02, &data);
	DPRINTK("%s %x\n","val restrd DCR=",data);
	dcr = data;

	data = s->u.pc.ecr;
//        SendMosCmd(pp,MOS_WRITE,0,0x0A, &data);
	DPRINTK("%s %x\n","val restrd ECR=",data);
	ecr = data;

//	wake_up_interruptible(&restore_state_event);
	wake_up(&restore_state_event);
	thread_cond = 1;

	DPRINTK("%s\n","Leaving...");

}

/*****************************************************************************
 * parport_mos7715_epp_read_data
 *	this function will be used to read data in EPP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
{
	size_t got = 0;
	unsigned char data;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_EPP);

	for (; got < length; got++) 
	{
	
        	SendMosCmd(pp,MOS_WRITE,0,0x04,(unsigned char *) buf);

		    buf++;

        	SendMosCmd(pp,MOS_READ,0,0x01,&data);

		if (data & 0x01) 
		{
			clear_epp_timeout(pp);
			break;
		}
	}
	
	change_mode_mos(pp, ECR_PS2);
	
	DPRINTK("%s\n","Leaving...");

	return got;

}

/*****************************************************************************
 * parport_mos7715_epp_write_data
 *	this function will be used to write data in EPP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags)
{
	int i;
	int rlen;
	struct parport_mos7715_private *priv = pp->private_data;
	struct usb_device *usbdev = priv->usbdev;

	if (!usbdev)
		return 0;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_EPP);

	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), (void *)buf, length, &rlen, HZ*20);
	if (i)
		printk(KERN_ERR "mos7715: sendbulk ep 2 buf %p len %Zu rlen %u\n", buf, length, rlen);

	change_mode_mos(pp, ECR_PS2); 

	DPRINTK("%s\n","Leaving...");

	return rlen;
}

/*****************************************************************************
 * parport_mos7715_epp_read_addr
 *	this function will be used to read addrs in EPP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags)
{
	size_t got = 0;
	unsigned char data;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_EPP);

	for (; got < length; got++) 
	{
        	SendMosCmd(pp,MOS_READ,0,0x03, (unsigned char *)buf);

			buf++;

			data = 0x00;
        	SendMosCmd(pp,MOS_READ,0,0x01, &data);

		if (data & 0x01) 
		{
			clear_epp_timeout(pp);
			break;
		}
	}

	change_mode_mos(pp, ECR_PS2);

	DPRINTK("%s\n","Leaving...");
	return got;

}

/*****************************************************************************
 * parport_mos7715_epp_write_addr
 *	this function will be used to write addrs in EPP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags)
{
	unsigned char data;
	size_t written = 0;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_EPP);

	for (; written < length; written++) 
	{

        	SendMosCmd(pp,MOS_WRITE,0,0x03,(unsigned char *) buf);

			buf++;

			data = 0x00;
        	SendMosCmd(pp,MOS_READ,0,0x01, &data);

		if (data & 0x01) 
		{
			clear_epp_timeout(pp);
			break;
		}
	}
	change_mode_mos(pp, ECR_PS2);

	DPRINTK("%s\n","Leaving...");
	return written;

}

/*****************************************************************************
 * parport_mos7715_ecp_write_data
 *	this function will be used to write data in ECP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags)
{
	int i;
	int rlen;
	struct parport_mos7715_private *priv = pp->private_data;
	struct usb_device *usbdev = priv->usbdev;

	if (!usbdev)
		return 0;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_ECP);


	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), (void *)buffer, len, &rlen, HZ*20);
	if (i)
		printk(KERN_ERR "mos7715: sendbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen);

	change_mode_mos(pp, ECR_PS2);

	DPRINTK("%s\n","Leaving...");
	return rlen;
}

/*****************************************************************************
 * parport_mos7715_ecp_read_data
 *	this function will be used to read data in ECP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags)
{
	int i;
	int rlen;
	struct parport_mos7715_private *priv = pp->private_data;
	struct usb_device *usbdev = priv->usbdev;

	if (!usbdev)
		return 0;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_ECP);

	i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 1), buffer, len, &rlen, HZ*20);
	if (i)
		printk(KERN_ERR "mos7715: recvbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);

	change_mode_mos(pp, ECR_PS2);

	DPRINTK("%s\n","Leaving...");
	return rlen;
}

/*****************************************************************************
 * parport_mos7715_ecp_write_addr
 * This function will be used to write addrs in ECP mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/

static size_t parport_mos7715_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
{
	size_t written = 0;

	DPRINTK("%s\n","Entering...");

	change_mode_mos(pp, ECR_ECP);

	for (; written < len; written++) 
	{

        	SendMosCmd(pp,MOS_WRITE,0,0x08, (void *)buffer);

			buffer++;

	}

	change_mode_mos(pp, ECR_PS2);

	DPRINTK("%s\n","Leaving...");
	return written;

}

/*****************************************************************************
 * parport_mos7715_write_compat
 *	this function will be used to write data in PPF/CB-FIFO mode
 * Input : 4 Input
 *			pointer to the parport
 *			buffer
 *			length
 *			flags
 *****************************************************************************/
static size_t parport_mos7715_write_compat(struct parport *pp, const void *buffer, size_t len, int flags)
{
	int i;
	int rlen;
	struct parport_mos7715_private *priv = pp->private_data;
	struct usb_device *usbdev = priv->usbdev;


	if (!usbdev)
		return 0;

	change_mode_mos(pp, ECR_PPF);

	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), (void *)buffer, len, &rlen, HZ*20);

	DPRINTK("%s %x\n","length = ",len);
	if (i)
		printk(KERN_ERR "mos7715: sendbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen);

	change_mode_mos(pp, ECR_PS2);

	DPRINTK("%s\n","Leaving...");
	return rlen;
}

/****************************************************************************
 * parport_mos7715_ops
 *	this structure holds the function names of all the possible 
 *      operations on parport
****************************************************************************/
static struct parport_operations parport_mos7715_ops = 
{
        .owner =                THIS_MODULE,
        .write_data =           parport_mos7715_write_data,
        .read_data =            parport_mos7715_read_data,

        .write_control =        parport_mos7715_write_control,
        .read_control =         parport_mos7715_read_control,
        .frob_control =         parport_mos7715_frob_control,

        .read_status =          parport_mos7715_read_status,

        .enable_irq =           parport_mos7715_enable_irq,
        .disable_irq =          parport_mos7715_disable_irq,

        .data_forward =         parport_mos7715_data_forward,
        .data_reverse =         parport_mos7715_data_reverse,

        .init_state =           parport_mos7715_init_state,
        .save_state =           parport_mos7715_save_state,
        .restore_state =        parport_mos7715_restore_state,

        .epp_write_data =       parport_mos7715_epp_write_data,
        .epp_read_data =        parport_mos7715_epp_read_data,
        .epp_write_addr =       parport_mos7715_epp_write_addr,
        .epp_read_addr =        parport_mos7715_epp_read_addr,

        .ecp_write_data =       parport_mos7715_ecp_write_data,
        .ecp_read_data =        parport_mos7715_ecp_read_data,
        .ecp_write_addr =       parport_mos7715_ecp_write_addr,

        .compat_write_data =    parport_mos7715_write_compat,
        .nibble_read_data =     parport_ieee1284_read_nibble,
        .byte_read_data =       parport_ieee1284_read_byte,
};

/************************************************************************/
/************************************************************************/
/*            U S B  C A L L B A C K   F U N C T I O N S                */
/*            U S B  C A L L B A C K   F U N C T I O N S                */
/************************************************************************/
/************************************************************************/

/*****************************************************************************
 * mos7720_interrupt_callback
 *	this is the callback function for when we have received data on the 
 *	interrupt endpoint.
 * Input : 1 Input
 *			pointer to the URB packet,
 *
 *****************************************************************************/

static void mos7720_interrupt_callback (struct urb *urb,struct pt_regs *regs)
{
	int result;
	int length ;
	__u32 *data ;
	struct moschip_port   *mos7720_port;
	unsigned int status;
	__u8 sp1,st;

//		DPRINTK("%s"," : Entering\n");

	if(!urb)
	{
		DPRINTK("%s","Invalid Pointer !!!!:\n");
		return;
	}


	switch (urb->status) 
	{
		case 0:
			/* success */
			break;
		case -ECONNRESET:
		case -ENOENT:
		case -ESHUTDOWN:
			/* this urb is terminated, clean up */
			dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
			return;
		default:
			dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
			goto exit;
	}

	length = urb->actual_length;
	data = urb->transfer_buffer;
	
	mos7720_port= (struct moschip_port*)urb->context;
	
	if(!mos7720_port)
        {
                DPRINTK("%s","NULL mos7720_serial pointer \n");
                return ;
        }

	/*  Moschip 4 bytes
	    Byte-1: Interrupt Identification register of Serial Port
 	    Byte-2: Reserved (Unused)
	    Byte-3: Device status register of the parallel / printer port (DSR) 
	    Byte-4: FIFO status of both the parallel port and the serial port.  */

	if(length && length>4)
	{
		DPRINTK("%s \n","Wrong data !!!");
		return;
	}

/* MATRIX */
	status=*data;
	
		sp1=(status & 0xff000000)>>24;
		st =status & 0x000000ff;
	
	if(sp1 & 0x01)
	DPRINTK("No Interrupt !!!");
	/* No Interrupt Pending in both the ports */
	else
	{
		switch(sp1 & 0x0f)
		{
	       case  SERIAL_IIR_RLS: DPRINTK("Serial Port 1: Receiver status error or address bit detected in 9-bit mode\n");
				break;
		case SERIAL_IIR_CTI: DPRINTK("Serial Port 1: Receiver time out\n");
                                break;
		case SERIAL_IIR_MS:  //DPRINTK("Serial Port 1: Modem status change\n");
                                break;
		}
	}

exit:

	result = usb_submit_urb (urb, GFP_ATOMIC);
	if (result) 
	{
		dev_err(&urb->dev->dev, "%s - Error %d submitting control urb\n", __FUNCTION__, result);
	}

	return;

}

/*****************************************************************************
 * mos7720_bulk_in_callback
 *	this is the callback function for when we have received data on the 
 *	bulk in endpoint.
 * Input : 1 Input
 *			pointer to the URB packet,
 *
 *****************************************************************************/

static void mos7720_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
{
	int			status;
	unsigned char		*data ;
	struct usb_serial	*serial;
	struct usb_serial_port	*port;
	struct moschip_serial	*mos7720_serial;
	struct moschip_port	*mos7720_port;
	struct tty_struct *tty;
	int i;


	if(!urb)
	{
		DPRINTK("%s","Invalid Pointer !!!!:\n");
		return;
	}

	if (urb->status) 
	{
		DPRINTK("nonzero read bulk status received: %d",urb->status);
		return;
	}

	mos7720_port= (struct moschip_port*)urb->context;
	if(!mos7720_port)
	{
		DPRINTK("%s","NULL mos7720_port pointer \n");
		return ;
	}

	port = (struct usb_serial_port *)mos7720_port->port;
	if (port_paranoia_check (port, __FUNCTION__)) 
	{
		DPRINTK("%s","Port Paranoia failed \n");
		return;
	}

	serial  = get_usb_serial(port,__FUNCTION__);	
	if(!serial)
	{
		DPRINTK("%s\n","Bad serial pointer ");
		return;
	}

//	DPRINTK("%s\n","Entering... \n");

	data = urb->transfer_buffer;
	mos7720_serial = get_serial_private(serial);

	if (urb->actual_length) 
	{
//MATRIX
		tty = mos7720_port->port->tty;
		if (tty) 
		{
			for (i = 0; i < urb->actual_length; ++i) 
			{
			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
				if(tty->flip.count >= TTY_FLIPBUF_SIZE) 
				{
						tty_flip_buffer_push(tty);
				}
			/* this doesn't actually push the data through unless tty->low_latency is set */
				tty_insert_flip_char(tty, data[i], 0);
	//				DPRINTK(" %c \n",data[i]);
			}
				tty_flip_buffer_push(tty);
		}
//MATRIX
	}

	if(!mos7720_port->read_urb)
	{
		DPRINTK("%s","URB KILLED !!!\n");
		return;
	}

	if(mos7720_port->read_urb->status!=-EINPROGRESS)
	{
		mos7720_port->read_urb->dev = serial->dev;

		status = usb_submit_urb(mos7720_port->read_urb, GFP_ATOMIC);

		if (status) 
		{
			DPRINTK(" usb_submit_urb(read bulk) failed, status = %d", status);
		}
	}
}

/*****************************************************************************
 * mos7720_bulk_out_data_callback
 *	this is the callback function for when we have finished sending serial data
 *	on the bulk out endpoint.
 * Input : 1 Input
 *			pointer to the URB packet,
 *
 *****************************************************************************/

static void mos7720_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs)
{
	struct moschip_port *mos7720_port ;
	struct tty_struct *tty;

	if(!urb)
	{
		DPRINTK("%s","Invalid Pointer !!!!:\n");
		return;
	}

	if (urb->status) 
	{
		DPRINTK("nonzero write bulk status received:%d\n", urb->status);
		return;
	}

	mos7720_port = (struct moschip_port *)urb->context;
	if(!mos7720_port)
	{
		DPRINTK("%s","NULL mos7720_port pointer \n");
		return ;
	}

	if (port_paranoia_check (mos7720_port->port, __FUNCTION__)) 
	{
		DPRINTK("%s","Port Paranoia failed \n");
		return;
	}

//	DPRINTK("%s \n","Entering .........");

	tty = mos7720_port->port->tty;

	if (tty && mos7720_port->open) 
	{
		/* let the tty driver wakeup if it has a special *
		 * write_wakeup function 			 */

		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
			(tty->ldisc.write_wakeup)(tty);
		}

		/* tell the tty driver that something has changed */
		wake_up_interruptible(&tty->write_wait);
	}

	/* Release the Write URB */
	mos7720_port->write_in_progress = FALSE;

//schedule_work(&mos7720_port->port->work);
	
}

/*****************************************************************************
 * SendMosCmd
 *	this function will be used for sending command to device
 * Input : 5 Input
 *			pointer to the serial device,
 *			request type
 *			value
 *			register index
 *			pointer to data/buffer
 *****************************************************************************/


static int SendMosCmd(void *pp, __u8 request, __u16 value, __u16 index, void *data)
{
        int timeout;
        int status;
        __u8 requesttype;
        __u16 size;
	unsigned int Pipe;
	struct usb_device *usbdev;
	
	if(value) /* value -- 0 == Parport   1: Serail */
	{

		if (serial_paranoia_check ((struct usb_serial *)pp, __FUNCTION__)) 
		{
			DPRINTK("%s","Serial Paranoia failed \n");
			return -1;
		}
		
		usbdev = (struct usb_device *)(( struct usb_serial *)pp)->dev;

	}
	else
	{
		struct parport_mos7715_private *priv =(struct parport_mos7715_private *)((struct parport *)pp)->private_data;
		usbdev = priv->usbdev;

	}

        size = 0x00;
        timeout = MOS_WDR_TIMEOUT;

        if(value < MOS_MAX_PORT)
                value = (value+1)*0x100 ;
        else
                value = 0x0000;

        if(request==MOS_WRITE)
    	{
            request = (__u8)MOS_WRITE;
            requesttype = (__u8)0x40;
            value  = value + (__u16)*((unsigned char *)data);
            data = NULL;
	    Pipe = usb_sndctrlpipe(usbdev, 0);
	}
    	else
    	{
            request = (__u8)MOS_READ;
            requesttype = (__u8)0xC0;
     	    size = 0x01;
	    Pipe = usb_rcvctrlpipe(usbdev,0); 
    	}


    status = usb_control_msg(                       \
    usbdev,                                         \
    Pipe,			                    \
    request,                                        \
    requesttype,                                    \
    value,                                          \
    index,                                          \
    data,                                           \
    size,                                           \
    timeout );


    if(status<0)
    {
	DPRINTK("Write fail-Val %x index %x-status:%d\n",value,index,status);
    }

/*        if(request==MOS_READ)
                DPRINTK("responded data %x \n",*((unsigned char*) data));
*/
        return status;
}

/************************************************************************/
/************************************************************************/
/*       D R I V E R  T T Y  I N T E R F A C E  F U N C T I O N S       */
/*       D R I V E R  T T Y  I N T E R F A C E  F U N C T I O N S       */
/************************************************************************/
/************************************************************************/


/*****************************************************************************
 * Driver tty interface functions
 *****************************************************************************/

/*****************************************************************************
 * SerialOpen
 *	this function is called by the tty driver when a port is opened
 *	If successful, we return 0
 *	Otherwise we return a negative error number.
 *****************************************************************************/

static int mos7720_open (struct usb_serial_port *port, struct file * filp)
{
    int response;
    char data;
    int j;
    struct usb_serial *serial;
    struct usb_serial_port *port0;
    struct urb *urb;

    struct moschip_serial *mos7720_serial;
    struct moschip_port *mos7720_port;
                                                                                                                         
	if (port_paranoia_check (port, __FUNCTION__))
	{
		DPRINTK("%s","Port Paranoia failed \n");
		return -ENODEV;
	}

/* parport */

	if(!port->number)
	{
		DPRINTK("%d %s",port->number,"not supported on this Device\n");
		flag_ser_par='p';
		//return -1;
		return -EACCES;
	}

DPRINTK("%s","****************************************************\n");

    serial = port->serial;

    if (serial_paranoia_check (serial, __FUNCTION__))
	{
		DPRINTK("%s","Serial Paranoia failed \n");
		return -ENODEV;
	}

//	mos7720_port = get_port_private(port); 
	mos7720_port = usb_get_serial_port_data(port); 

	if (mos7720_port == NULL)
		return -ENODEV;

	port0 = serial->port[0];

	//mos7720_serial = get_serial_private(serial);
	mos7720_serial = usb_get_serial_port_data(port);

	if (mos7720_serial == NULL || port0 == NULL) 
	{
		return -ENODEV;
	}

     flag_ser_par='s';
     //usb_clear_halt(serial->dev, port->write_urb->pipe);
     //usb_clear_halt(serial->dev, port->read_urb->pipe);
	
	DPRINTK("port is %x \n",(unsigned int)serial->port[0]);
        DPRINTK("port is %x \n",(unsigned int)serial->port[1]);
        DPRINTK("port is %x \n",(unsigned int)mos7720_port);

		 /* Initialising the write urb pool */
                 for (j = 0; j < NUM_URBS; ++j)
                 {
                        //urb = usb_alloc_urb(0,SLAB_ATOMIC);
                        urb = usb_alloc_urb(0,GFP_KERNEL);
                        mos7720_port->write_urb_pool[j] = urb;
                                                                                                                             
                        if (urb == NULL)
                        {
                                err("No more urbs???");
                                continue;
                        }
                                                                                                                                                                                                                                                           
                        urb->transfer_buffer = NULL;
                        urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
                        if (!urb->transfer_buffer)
                        {
                                err("%s-out of memory for urb buffers.", __FUNCTION__);
                                continue;
                        }
                }


/*****************************************************************************
 * Initialize MCS7720 -- Write Init values to corresponding Registers
 *
 * Register Index
 * 1 : IER
 * 2 : FCR
 * 3 : LCR
 * 4 : MCR
 *
 * 0x08 : SP1/2 Control Reg
 *****************************************************************************/

	DPRINTK("%s", "Sending Command .......... \n");
	DPRINTK("%d\n",port->number - port->serial->minor);

	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);
	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x02, &data);

	data = 0x0CF;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x02, &data);
	data = 0x003;
        mos7720_port->shadowLCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);
	data = 0x00b;
        mos7720_port->shadowMCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);
	data = 0x00b;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);

	data = 0x000;
	SendMosCmd(port->serial,MOS_READ,MOS_MAX_PORT,0x08, &data);
	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x08, &data);
//	data = 0x000;
//	SendMosCmd(port->serial,MOS_READ,MOS_MAX_PORT,port->number - port->serial->minor + 1, &data);

	data = 0x02;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x01, &data);
	
/*	data = 0x003;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,port->number - port->serial->minor + 1, &data);
	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,port->number - port->serial->minor + 1, &data);
*/
	data = 0x000;
	SendMosCmd(port->serial,MOS_READ,MOS_MAX_PORT,0x08, &data);
	data = data | (port->number - port->serial->minor + 1);
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x08, &data);

	data = 0x083;
        mos7720_port->shadowLCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);
	data = 0x00c;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x00, &data);
	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);
	data = 0x003;
        mos7720_port->shadowLCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);
	data = 0x00c;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);
	data = 0x00c;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);

	//do_loopback(port);
	
	/* force low_latency on so that our tty_push actually forces  *
	 * the data through,otherwise it is scheduled, and with high  *
	 * data rates (like with OHCI) data can get lost.             */
        
	if (port->tty)
		port->tty->low_latency = 1;                                                                                                                     
    	/* see if we've set up our endpoint info yet   *
	 * (can't set it up in mos7720_startup as the  *
	 * structures were not set up at that time.)   */

#ifdef abc
    if (mos7720_serial->interrupt_in_buffer == NULL) 
    {
	DPRINTK("%s \n","Interrupt buffer NULL !!!");

	/* not set up yet, so do it now */

	mos7720_serial->interrupt_in_buffer = port0->interrupt_in_buffer;

	mos7720_serial->interrupt_in_endpoint = port->interrupt_in_endpointAddress;
	mos7720_serial->interrupt_read_urb = port0->interrupt_in_urb;

	DPRINTK("%s \n","To Submit URB !!!");

	/* set up our interrupt urb */

	usb_fill_int_urb(					\
		mos7720_serial->interrupt_read_urb,		\
		serial->dev,					\
		usb_rcvintpipe(serial->dev,			\
		port->interrupt_in_endpointAddress),		\
		port0->interrupt_in_buffer,			\
		mos7720_serial->interrupt_read_urb->transfer_buffer_length,\
		mos7720_interrupt_callback, mos7720_port,\
		mos7720_serial->interrupt_read_urb->interval );


	/* start interrupt read for this mos7720 this interrupt * 
         * will continue as long as the mos7720 is connected    */

	DPRINTK("%s \n","Submit URB over !!!");

	response =usb_submit_urb(mos7720_serial->interrupt_read_urb,GFP_KERNEL);

	if (response) 
	{
	err("%s - Error %d submitting control urb", __FUNCTION__, response);
	}
   }
#endif
	mos7720_port->bulk_in_buffer    = port->bulk_in_buffer;
    	mos7720_port->bulk_in_endpoint  = port->bulk_in_endpointAddress;
	mos7720_port->read_urb          = port->read_urb;
	mos7720_port->bulk_out_endpoint = port->bulk_out_endpointAddress;

	/* set up our bulk in urb */

	usb_fill_bulk_urb(  
		mos7720_port->read_urb, 				\
		serial->dev,						\
		usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),\
		port->bulk_in_buffer,					\
		mos7720_port->read_urb->transfer_buffer_length,		\
		mos7720_bulk_in_callback, mos7720_port);	
	

	response = usb_submit_urb (mos7720_port->read_urb,GFP_KERNEL);

	if (response) 
	{
		err("%s - Error %d submitting control urb", __FUNCTION__, response);
	}

	/* initialize our wait queues */
	init_waitqueue_head(&mos7720_port->wait_open);
	init_waitqueue_head(&mos7720_port->wait_chase);
	init_waitqueue_head(&mos7720_port->delta_msr_wait);
	init_waitqueue_head(&mos7720_port->wait_command);

	/* initialize our icount structure */
	memset (&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));

	/* initialize our port settings */
	mos7720_port->shadowMCR  = MCR_MASTER_IE; /* Must set to enable ints! */
	mos7720_port->chaseResponsePending = FALSE;                                                                                                
	/* send a open port command */
	mos7720_port->openPending = FALSE;
	mos7720_port->open        = TRUE;                                                                                                                     
	mos7720_port->rxBytesAvail = 0x0;	


	DPRINTK("\n\nusb_serial serial:%x	mos7720_port:%x\nmos7720_serial:%x	usb_serial_port port:%x\n\n",(unsigned int)serial,(unsigned int)mos7720_port,(unsigned int)mos7720_serial,(unsigned int)port);
	DPRINTK("\n\nusb_serial port0:%x	port1:%x\n",(unsigned int)serial->port[0],(unsigned int)serial->port[1]);


	//SendMosCmd(port->serial,MOS_READ,mos7720_port->port->number - mos7720_port->port->serial->minor,LSR, &data);
	//DPRINTK("\nSS::%x               LSR:%x\n",(unsigned int)mos7720_port,data);

	return 0;
}

/*****************************************************************************
 * mos7720_close
 *	this function is called by the tty driver when a port is closed
 *****************************************************************************/

static void mos7720_close (struct usb_serial_port *port, struct file * filp)
{
	struct usb_serial *serial;
	struct moschip_serial *mos7720_serial;
	struct moschip_port *mos7720_port;
	char data;
	int j;
	
	DPRINTK("%s\n","mos7720_close:entering...");
	
	if(flag_ser_par=='p')
	return;

	if (port_paranoia_check (port, __FUNCTION__))
	{
		DPRINTK("%s","Port Paranoia failed \n");
		return;
	}
		 
	serial = get_usb_serial (port, __FUNCTION__);
	if (!serial)
	{
		DPRINTK("%s","Serial Paranoia failed \n");
		return;
	}

	mos7720_serial = get_serial_private(serial);
	mos7720_port = get_port_private(port);
	
	if ((mos7720_serial == NULL) || (mos7720_port == NULL))
	{
		return;
	}

	
	for (j = 0; j < NUM_URBS; ++j)
		usb_kill_urb (mos7720_port->write_urb_pool[j]);


	   /* Freeing Write URBs*/
	   for (j = 0; j < NUM_URBS; ++j)
 	   {
                if (mos7720_port->write_urb_pool[j])
                {
                    if (mos7720_port->write_urb_pool[j]->transfer_buffer)
                            kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
                                                                                                                             
                    usb_free_urb (mos7720_port->write_urb_pool[j]);
                }
          }


	if (serial->dev) 
	{
		/* flush and block until tx is empty*/
		block_until_tx_empty(mos7720_port);
	}

	/* While closing port, shutdown all bulk read, write  *
	 * and interrupt read if they exists                  */

	if (serial->dev)
	{


		if (mos7720_port->write_urb) 
		{
			DPRINTK("%s","Shutdown bulk write\n");
			usb_kill_urb (mos7720_port->write_urb);
		}
		
		if (mos7720_port->read_urb) 
		{
			DPRINTK("%s","Shutdown bulk read\n");
			usb_kill_urb (mos7720_port->read_urb);
		}
	}


	if (mos7720_port->write_urb) 
	{
		/* if this urb had a transfer buffer already (old tx) free it */

		if (mos7720_port->write_urb->transfer_buffer != NULL) 
		{
			kfree(mos7720_port->write_urb->transfer_buffer);
		}
		usb_free_urb(mos7720_port->write_urb);
	}


	data = 0x00;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);

	data = 0x00;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);

	mos7720_port->open         = FALSE;
	mos7720_port->closePending = FALSE;
	mos7720_port->openPending  = FALSE;

	DPRINTK("%s \n","Leaving ............");
}   


/*****************************************************************************
 * SerialBreak
 *	this function sends a break to the port
 *****************************************************************************/
static void mos7720_break (struct usb_serial_port *port, int break_state)
{
        unsigned char data;
	struct usb_serial *serial;
	struct moschip_serial *mos7720_serial;
	struct moschip_port *mos7720_port;
	
	DPRINTK("%s \n","Entering ...........");

	if (port_paranoia_check (port, __FUNCTION__))
	{
		DPRINTK("%s","Port Paranoia failed \n");
		return;
	}
		 
	serial = get_usb_serial (port, __FUNCTION__);
	if (!serial)
	{
		DPRINTK("%s","Serial Paranoia failed \n");
		return;
	}

	mos7720_serial = get_serial_private(serial);
	mos7720_port = get_port_private(port);
	
	if ((mos7720_serial == NULL) || (mos7720_port == NULL))
	{
		return;
	}
	
	/* flush and chase */
	mos7720_port->chaseResponsePending = TRUE;

	if (serial->dev) 
	{

		/* flush and block until tx is empty*/
		block_until_chase_response(mos7720_port);
	}

        if(break_state == -1)
        {
                data = mos7720_port->shadowLCR | LCR_SET_BREAK;
        }
        else
        {
                data = mos7720_port->shadowLCR & ~LCR_SET_BREAK;
        }

        mos7720_port->shadowLCR  = data;
        SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);

	return;
}


/************************************************************************
 *
 * block_until_chase_response
 *
 *	This function will block the close until one of the following:
 *		1. Response to our Chase comes from mos7720
 *		2. A timout of 10 seconds without activity has expired
 *		   (1K of mos7720 data @ 2400 baud ==> 4 sec to empty)
 *
 ************************************************************************/

static void block_until_chase_response(struct moschip_port *mos7720_port)
{
	int timeout = 1*HZ;
	int wait = 10;
	int count ;


	while (1) 
	{
		count = mos7720_chars_in_buffer(mos7720_port->port);
		
		/* Check for Buffer status */
		if(count<=0)
		{
			mos7720_port->chaseResponsePending = FALSE;
			return;
		}

		/* Block the thread for a while */
		interruptible_sleep_on_timeout (&mos7720_port->wait_chase, timeout);
                /* No activity.. count down section */
		wait--;
		if (wait == 0) 
		{
			dbg("%s - TIMEOUT", __FUNCTION__);
			return;
		}
		else 
		{
	                /* Reset timout value back to seconds */	
			wait = 10;
		}
	}

}


/************************************************************************
 *
 * block_until_tx_empty
 *
 *	This function will block the close until one of the following:
 *		1. TX count are 0
 *		2. The mos7720 has stopped
 *		3. A timout of 3 seconds without activity has expired
 *
 ************************************************************************/
static void block_until_tx_empty (struct moschip_port *mos7720_port)
{
	int timeout = HZ/10;
	int wait = 30;
	int count;

	while (1) 
	{

		count = mos7720_chars_in_buffer(mos7720_port->port);

                /* Check for Buffer status */
		if(count<=0)
		{
			return;
		}

                /* Block the thread for a while */
		interruptible_sleep_on_timeout (&mos7720_port->wait_chase, timeout);

                /* No activity.. count down section */
		wait--;
		if (wait == 0) 
		{
			dbg("%s - TIMEOUT", __FUNCTION__);
			return;
		}
		else 
		{
	                /* Reset timout value back to seconds */
			wait = 30;
		}
	}
}

/*****************************************************************************
 * mos7720_write_room
 *	this function is called by the tty driver when it wants to know how many
 *	bytes of data we can accept for a specific port.
 *	If successful, we return the amount of room that we have for this port
 *	Otherwise we return a negative error number.
 *****************************************************************************/

static int mos7720_write_room (struct usb_serial_port *port)
{
    int i;
    int room = 0;
    struct moschip_port *mos7720_port;


        if(port_paranoia_check(port,__FUNCTION__) )
        {
                DPRINTK("%s","Invalid port \n");
                DPRINTK("%s \n"," mos7720_write_room:leaving ...........");
                return -1;
        }

        mos7720_port = get_port_private(port);
        if (mos7720_port == NULL)
        {
                DPRINTK("%s \n","mos7720_break:leaving ...........");
                return -1;
        }
                                                                                                                             
        for (i = 0; i < NUM_URBS; ++i) 
	{
                if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) 
		{
                        room += URB_TRANSFER_BUFFER_SIZE;
                }
        }
       
        dbg("%s - returns %d", __FUNCTION__, room);
        return (room);

}


/*****************************************************************************
 * mos7720_chars_in_buffer
 *	this function is called by the tty driver when it wants to know how many
 *	bytes of data we currently have outstanding in the port (data that has
 *	been written, but hasn't made it out the port yet)
 *	If successful, we return the number of bytes left to be written in the 
 *	system, 
 *	Otherwise we return a negative error number.
 *****************************************************************************/

static int mos7720_chars_in_buffer (struct usb_serial_port *port)
{
	int i;
    	int chars = 0;
 	struct moschip_port *mos7720_port;


	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return -1;
	}
                                                                                                                             
        mos7720_port = get_port_private(port);
        if (mos7720_port == NULL)
        {
                DPRINTK("%s \n","mos7720_break:leaving ...........");
                return -1;
        }
                                                                                                                       
    	for (i = 0; i < NUM_URBS; ++i) 
    	{
        	if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) 
	    	{
                	chars += URB_TRANSFER_BUFFER_SIZE;
            	}
    	}                                                                                                                         
    	dbg("%s - returns %d", __FUNCTION__, chars);
    	return (chars);

}


/*****************************************************************************
 * SerialWrite
 *	this function is called by the tty driver when data should be written to
 *	the port.
 *	If successful, we return the number of bytes written, otherwise we 
 *      return a negative error number.
 *****************************************************************************/

//static int mos7720_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count)
static int mos7720_write (struct usb_serial_port *port, const unsigned char *data, int count)
{
	int status;
	int i;
	int bytes_sent = 0;
	int transfer_size;
	int from_user=0;

	struct moschip_port *mos7720_port;
	struct usb_serial *serial;
	struct moschip_serial *mos7720_serial;
	struct urb    *urb;

	const unsigned char *current_position = data;
	
//	DPRINTK("%s \n","entering ...........");

	if (port_paranoia_check (port, __FUNCTION__))
	{
		DPRINTK("%s","Port Paranoia failed \n");
		return -1;
	}

	serial = port->serial;
	if (serial_paranoia_check (serial, __FUNCTION__))
	{
		DPRINTK("%s","Serial Paranoia failed \n");
		return -1;
	}

	mos7720_port = get_port_private(port);
	if(mos7720_port==NULL)
	{
		DPRINTK("%s","mos7720_port is NULL\n");
		return -1;
	}

	mos7720_serial =get_serial_private(serial);
	if(mos7720_serial==NULL)
	{
		DPRINTK("%s","mos7720_serial is NULL \n");
		return -1;
	}

	
        	/* try to find a free urb in the list */
        	urb = NULL;

        	for (i = 0; i < NUM_URBS; ++i) 
		{
                	if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) 
			{
                        	urb = mos7720_port->write_urb_pool[i];
//				DPRINTK("\nURB:%d",i);
                        	break;
                	}
        	}

	        if (urb == NULL) 
		{
                	dbg("%s - no more free urbs", __FUNCTION__);
                	goto exit;
        	}

        	if (urb->transfer_buffer == NULL) 
		{
          	urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);

                	if (urb->transfer_buffer == NULL) 
			{
                        	err("%s no more kernel memory...", __FUNCTION__);
                        	goto exit;
                	}
        	}                                                                                                                   
        	transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);

        	if (from_user) 
		{
                	if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) 	{
                        	bytes_sent = -EFAULT;
	                       	goto exit;
            		}
        	} 
		else 
		{
                	memcpy (urb->transfer_buffer, current_position, transfer_size);
        	}                                                                                                                  
        	//usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer);

		/* fill urb with data and submit  */

           	usb_fill_bulk_urb (urb,
		 mos7720_serial->serial->dev,
		 usb_sndbulkpipe(mos7720_serial->serial->dev,
		 port->bulk_out_endpointAddress),
		 urb->transfer_buffer, 
		 transfer_size,
		 mos7720_bulk_out_data_callback,
		 mos7720_port);


        	/* send it down the pipe */
        	status = usb_submit_urb(urb,GFP_ATOMIC);

        	if (status) 
		{
                	err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status);
                	bytes_sent = status;
			goto exit;
        	}
        	bytes_sent = transfer_size;
    	 
exit:
	return bytes_sent;

}

/*****************************************************************************
 * SerialThrottle
 *	this function is called by the tty driver when it wants to stop the data
 *	being read from the port.
 *****************************************************************************/

static void mos7720_throttle (struct usb_serial_port *port)
{
	struct moschip_port *mos7720_port;
	struct tty_struct *tty;
	int status;

	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return;
	}

	DPRINTK("- port %d\n", port->number);

	mos7720_port = get_port_private(port); 

	if (mos7720_port == NULL)
		return;

	if (!mos7720_port->open) 
	{
		DPRINTK("%s\n","port not opened");
		return;
	}

	DPRINTK("%s","Entering .......... \n");

	tty = port->tty;
	if (!tty) 
	{
		dbg ("%s - no tty available", __FUNCTION__);
		return;
	}

	/* if we are implementing XON/XOFF, send the stop character */
	if (I_IXOFF(tty)) 
	{
		unsigned char stop_char = STOP_CHAR(tty);
		status = mos7720_write (port,&stop_char, 1);
		if (status <= 0) 
		{
			return;
		}
	}

	/* if we are implementing RTS/CTS, toggle that line */
	if (tty->termios->c_cflag & CRTSCTS) 
	{
		mos7720_port->shadowMCR &= ~MCR_RTS;
		status = SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,MCR, &mos7720_port->shadowMCR);
		if (status != 0) 
		{
			return;
		}
	}

	return;
}


/*****************************************************************************
 * mos7720_unthrottle
 *	this function is called by the tty driver when it wants to resume the data
 *	being read from the port (called after SerialThrottle is called)
 *****************************************************************************/
static void mos7720_unthrottle (struct usb_serial_port *port)
{
	struct tty_struct *tty;
	int status;
	struct moschip_port *mos7720_port = get_port_private(port); 

	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return;
	}

	if (mos7720_port == NULL)
		return;

	if (!mos7720_port->open) {
		dbg("%s - port not opened", __FUNCTION__);
		return;
	}

	DPRINTK("%s","Entering .......... \n");

	tty = port->tty;
	if (!tty) 
	{
		dbg ("%s - no tty available", __FUNCTION__);
		return;
	}

	/* if we are implementing XON/XOFF, send the start character */
	if (I_IXOFF(tty)) 
	{
		unsigned char start_char = START_CHAR(tty);
		status = mos7720_write (port, &start_char, 1);
		if (status <= 0) 
		{
			return;
		}
	}

	/* if we are implementing RTS/CTS, toggle that line */
	if (tty->termios->c_cflag & CRTSCTS) 
	{
		mos7720_port->shadowMCR |= MCR_RTS;
		status = SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,MCR, &mos7720_port->shadowMCR);
		if (status != 0) 
		{
			return;
		}
	}

	return;
}


/*****************************************************************************
 * SerialSetTermios
 *	this function is called by the tty driver when it wants to change the termios structure
 *****************************************************************************/
static void mos7720_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
	int status;
	unsigned int cflag;
	struct usb_serial *serial;
	struct moschip_port *mos7720_port;
	struct tty_struct *tty;
	
	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return;
	}

	serial = port->serial;

	if(serial_paranoia_check(serial,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid Serial \n");
		return;
	}

	mos7720_port = get_port_private(port); 

	if (mos7720_port == NULL)
		return;

	tty = port->tty;

	if (!port->tty || !port->tty->termios)
	{
		dbg ("%s - no tty or termios", __FUNCTION__);
		return;
	}

	if (!mos7720_port->open) 
	{
		dbg("%s - port not opened", __FUNCTION__);
		return;
	}

	DPRINTK("%s\n","setting termios ");

	cflag = tty->termios->c_cflag;

	if (!cflag)
	{
           printk("%s %s\n",__FUNCTION__,"cflag is NULL");
	   return;
	}            

	/* check that they really want us to change something */
	if (old_termios)
	{
		if ((cflag == old_termios->c_cflag) &&
		    (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) 
		{
			DPRINTK("%s\n","Nothing to change");
			return;
		}
	}

	dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
	    tty->termios->c_cflag,
	    RELEVANT_IFLAG(tty->termios->c_iflag));
	
	if (old_termios) 
	{
		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
		    old_termios->c_cflag,
		    RELEVANT_IFLAG(old_termios->c_iflag));
	}

	dbg("%s - port %d", __FUNCTION__, port->number);

	/* change the port settings to the new ones specified */

	change_port_settings (mos7720_port, old_termios);

	if(!mos7720_port->read_urb)
	{
		DPRINTK("%s","URB KILLED !!!!!\n");
		return;
	}

	if(mos7720_port->read_urb->status!=-EINPROGRESS)
	{
		mos7720_port->read_urb->dev = serial->dev;
	 	status = usb_submit_urb(mos7720_port->read_urb, GFP_ATOMIC);
		if (status) 
		{
			DPRINTK(" usb_submit_urb(read bulk) failed, status = %d", status);
		}
	}
	return;
}


/*****************************************************************************
 * get_lsr_info - get line status register info
 *
 * Purpose: Let user call ioctl() to get info when the UART physically
 * 	    is emptied.  On bus types like RS485, the transmitter must
 * 	    release the bus after transmitting. This must be done when
 * 	    the transmit shift register is empty, not be done when the
 * 	    transmit holding register is empty.  This functionality
 * 	    allows an RS485 driver to be written in user space. 
 *****************************************************************************/

static int get_lsr_info(struct moschip_port *mos7720_port, unsigned int *value)
{
	int count;
	unsigned int result = 0;

        count = mos7720_chars_in_buffer(mos7720_port->port);
        if(count == 0)
	{
		dbg("%s -- Empty", __FUNCTION__);
		result = TIOCSER_TEMT;
	}

	if (copy_to_user(value, &result, sizeof(int)))
		return -EFAULT;
	return 0;
}

/*****************************************************************************
 * get_number_bytes_avail - get number of bytes available
 *
 * Purpose: Let user call ioctl to get the count of number of bytes available.
 *****************************************************************************/

static int get_number_bytes_avail(struct moschip_port *mos7720_port, unsigned int *value)
{
	unsigned int result = 0;
	struct tty_struct *tty = mos7720_port->port->tty;

	if (!tty)
		return -ENOIOCTLCMD;

	result = tty->read_cnt;

	dbg("%s(%d) = %d", __FUNCTION__,  mos7720_port->port->number, result);
	if (copy_to_user(value, &result, sizeof(int)))
		return -EFAULT;

	return -ENOIOCTLCMD;
}
/*****************************************************************************
 * set_higher_rates
 *      function to set for Higher rates
 *****************************************************************************/

static int set_higher_rates(struct moschip_port *mos7720_port, unsigned int *value)
{
	unsigned int arg;
	unsigned char data;

	struct usb_serial_port *port;
	struct usb_serial *serial;


	if (mos7720_port == NULL)
		return -1;

	port = (struct usb_serial_port*)mos7720_port->port;
	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return -1;
	}

	serial = (struct usb_serial*)port->serial;
	if(serial_paranoia_check(serial,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid Serial \n");
		return -1;
	}

	/*if (copy_from_user(&arg, value, sizeof(int)))
		return -EFAULT;*/
	arg=*value;

        /***********************************************
         *      Init Sequence for higher rates
         ***********************************************/

	DPRINTK("%s", "Sending Setting Commands .......... \n");

	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);
	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x02, &data);
	data = 0x0CF;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x02, &data);
	data = 0x00b;
        mos7720_port->shadowMCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);
	data = 0x00b;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);
	
	data = 0x000;
	SendMosCmd(port->serial,MOS_READ,MOS_MAX_PORT,0x08, &data);
	data = 0x000;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x08, &data);

        /***********************************************
         *              Set for higher rates           *
         ***********************************************/

	data = arg * 0x10;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,port->number - port->serial->minor + 1,&data);

	data = 0x003;
	SendMosCmd(port->serial,MOS_READ,MOS_MAX_PORT,0x08, &data);
	data = 0x003;
	SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x08, &data);


	data = 0x02b;
        mos7720_port->shadowMCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);
	data = 0x02b;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);

        /***********************************************
         *              Set DLL/DLM
         ***********************************************/

	data = mos7720_port->shadowLCR | LCR_DL_ENABLE;
        mos7720_port->shadowLCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);

	data =  0x001; /* DLL */
        SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x00, &data);
	data =  0x000; /* DLM */
        SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);

	data = mos7720_port->shadowLCR & ~LCR_DL_ENABLE;
        mos7720_port->shadowLCR  = data;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);


	return 0;
}

/*****************************************************************************
 * set_modem_info
 *      function to set modem info
 *****************************************************************************/

static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, unsigned int *value)
{
	unsigned int mcr ;
	unsigned int arg;
	unsigned char data;

	struct usb_serial_port *port;

	if (mos7720_port == NULL)
		return -1;


	port = (struct usb_serial_port*)mos7720_port->port;
	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return -1;
	}

	mcr = mos7720_port->shadowMCR;

	/*if (copy_from_user(&arg, value, sizeof(int)))
		return -EFAULT;*/
	arg = *value;
	switch (cmd) {
		case TIOCMBIS:
			if (arg & TIOCM_RTS)
				mcr |= MCR_RTS;
			if (arg & TIOCM_DTR)
				mcr |= MCR_RTS;
			if (arg & TIOCM_LOOP)
				mcr |= MCR_LOOPBACK;
			break;

		case TIOCMBIC:
			if (arg & TIOCM_RTS)
				mcr &= ~MCR_RTS;
			if (arg & TIOCM_DTR)
				mcr &= ~MCR_RTS;
			if (arg & TIOCM_LOOP)
				mcr &= ~MCR_LOOPBACK;
			break;

		case TIOCMSET:
			/* turn off the RTS and DTR and LOOPBACK 
			 * and then only turn on what was asked to */
			mcr &=  ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
			mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
			mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
			mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
			break;
	}

	mos7720_port->shadowMCR = mcr;

	data = mos7720_port->shadowMCR;
	SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,MCR,&data);

	return 0;
}

/*****************************************************************************
 * get_modem_info
 *      function to get modem info
 *****************************************************************************/

static int get_modem_info(struct moschip_port *mos7720_port, unsigned int *value)
{
	unsigned int result = 0;
	unsigned int msr = mos7720_port->shadowMSR;
	unsigned int mcr = mos7720_port->shadowMCR;

	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
		  | ((msr & MOS7720_MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
		  | ((msr & MOS7720_MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
		  | ((msr & MOS7720_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
		  | ((msr & MOS7720_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */


	dbg("%s -- %x", __FUNCTION__, result);

	if (copy_to_user(value, &result, sizeof(int)))
		return -EFAULT;
	return 0;
}

/*****************************************************************************
 * get_serial_info
 *      function to get information about serial port
 *****************************************************************************/

static int get_serial_info(struct moschip_port *mos7720_port, struct serial_struct * retinfo)
{
	struct serial_struct tmp;

	if (mos7720_port == NULL)
		return -1;


	if (!retinfo)
		return -EFAULT;

	memset(&tmp, 0, sizeof(tmp));

	tmp.type		= PORT_16550A;
	tmp.line		= mos7720_port->port->serial->minor;
	tmp.port		= mos7720_port->port->number;
	tmp.irq			= 0;
	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
	tmp.xmit_fifo_size	= NUM_URBS * URB_TRANSFER_BUFFER_SIZE; 
	tmp.baud_base		= 9600;
	tmp.close_delay		= 5*HZ;
	tmp.closing_wait	= 30*HZ;


	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
		return -EFAULT;
	return 0;
}

/*****************************************************************************
 * SerialIoctl
 *	this function handles any ioctl calls to the driver
 *****************************************************************************/
static int mos7720_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct moschip_port *mos7720_port;

	struct async_icount cnow;
	struct async_icount cprev;
	struct serial_icounter_struct icount;

	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return -1;
	}

	mos7720_port = get_port_private(port); 
	if (mos7720_port == NULL)
		return -1;

	dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);

	switch (cmd) 
	{
                /* return number of bytes available */
	
		case TIOCINQ:
			dbg("%s (%d) TIOCINQ", __FUNCTION__,  port->number);
			return get_number_bytes_avail(mos7720_port, (unsigned int *) arg);
			break;

		case TIOCSERGETLSR:
			dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__,  port->number);
			return get_lsr_info(mos7720_port, (unsigned int *) arg);
			return 0;

		case TIOCMBIS:
		case TIOCMBIC:
		case TIOCMSET:
			dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,  port->number);
			return set_modem_info(mos7720_port, cmd, (unsigned int *) arg);

		case TIOCMGET:  
			dbg("%s (%d) TIOCMGET", __FUNCTION__,  port->number);
			return get_modem_info(mos7720_port, (unsigned int *) arg);

		case TIOCGSERIAL:
			dbg("%s (%d) TIOCGSERIAL", __FUNCTION__,  port->number);
			return get_serial_info(mos7720_port, (struct serial_struct *) arg);

		case TIOCSSERIAL:
			dbg("%s (%d) TIOCSSERIAL", __FUNCTION__,  port->number);
			break;

		case TIOCMIWAIT:
			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
			cprev = mos7720_port->icount;
			while (1) {
				//interruptible_sleep_on(&mos7720_port->delta_msr_wait);
				mos7720_port->delta_msr_cond=0;
		                wait_event_interruptible(mos7720_port->delta_msr_wait,(mos7720_port->delta_msr_cond==1));
				/* see if a signal did it */
				if (signal_pending(current))
					return -ERESTARTSYS;
				cnow = mos7720_port->icount;
				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
					return -EIO; /* no change => error */
				if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
				    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
				    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
				    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
					return 0;
				}
				cprev = cnow;
			}
			/* NOTREACHED */
			break;

		case TIOCGICOUNT:
			cnow = mos7720_port->icount;
			icount.cts = cnow.cts;
			icount.dsr = cnow.dsr;
			icount.rng = cnow.rng;
			icount.dcd = cnow.dcd;
			icount.rx = cnow.rx;
			icount.tx = cnow.tx;
			icount.frame = cnow.frame;
			icount.overrun = cnow.overrun;
			icount.parity = cnow.parity;
			icount.brk = cnow.brk;
			icount.buf_overrun = cnow.buf_overrun;

			dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,  port->number, icount.rx, icount.tx );
			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
				return -EFAULT;
			return 0;

		case TIOCEXBAUD:
			return 0;
	}

	return -ENOIOCTLCMD;
}


/*****************************************************************************
 * send_cmd_write_baud_rate
 *	this function sends the proper command to change the baud rate of the
 *	specified port.
 *****************************************************************************/

static int send_cmd_write_baud_rate (struct moschip_port *mos7720_port, int baudRate)
{
	int divisor;
	int status;
	unsigned char data;
	unsigned char number ;

	struct usb_serial_port *port;

	if (mos7720_port == NULL)
		return -1;

	port = (struct usb_serial_port*)mos7720_port->port;
	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return -1;
	}

	if(serial_paranoia_check(port->serial,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid Serial \n");
		return -1;
	}


//	DPRINTK("%s","Entering .......... \n");

	number = mos7720_port->port->number - mos7720_port->port->serial->minor;

	dbg("%s - port = %d, baud = %d", __FUNCTION__, mos7720_port->port->number, baudRate);

        /* Calculate the Divisor */
	status = calc_baud_rate_divisor (baudRate, &divisor);
	if (status) 
	{
		err("%s - bad baud rate", __FUNCTION__);
		DPRINTK("%s\n","bad baud rate");
		return status;
	}

        /* Enable access to divisor latch */
        data = mos7720_port->shadowLCR | LCR_DL_ENABLE;
        mos7720_port->shadowLCR  = data;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,LCR, &data);

	/* Write the divisor */
	data = LOW8 (divisor);
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,0x00, &data);

	data = HIGH8 (divisor);
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,0x01, &data);

        /* Disable access to divisor latch */
        data = mos7720_port->shadowLCR & ~LCR_DL_ENABLE;
        mos7720_port->shadowLCR = data;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,0x03, &data);

	return status;
}



/*****************************************************************************
 * calc_baud_rate_divisor
 *	this function calculates the proper baud rate divisor for the specified
 *	baud rate.
 *****************************************************************************/
static int calc_baud_rate_divisor (int baudrate, int *divisor)
{
	int i;
	__u16 custom;
	__u16 round1;
	__u16 round;


	dbg("%s - %d", __FUNCTION__, baudrate);

	for (i = 0; i < NUM_ENTRIES(divisor_table); i++) 
	{
		if ( divisor_table[i].BaudRate == baudrate ) 
		{
			*divisor = divisor_table[i].Divisor;
			return 0;
		}
	}

        /* After trying for all the standard baud rates    *
         * Try calculating the divisor for this baud rate  */

	if (baudrate > 75 &&  baudrate < 230400) 
	{
		/* get the divisor */
		custom = (__u16)(230400L  / baudrate);

		/* Check for round off */
		round1 = (__u16)(2304000L / baudrate);
		round = (__u16)(round1 - (custom * 10));
		if (round > 4) {
			custom++;
		}
		*divisor = custom;

		//DPRINTK(" Baud %d = %d\n",baudrate, custom);
		return 0;
	}

	//DPRINTK("%s\n"," Baud calculation Failed...");
	return -1;
}



/*****************************************************************************
 * change_port_settings
 *	This routine is called to set the UART on the device to match 
 *      the specified new settings.
 *****************************************************************************/

static void change_port_settings (struct moschip_port *mos7720_port, struct termios *old_termios)
{
	struct tty_struct *tty;
	int baud;
	unsigned cflag;
	unsigned iflag;
	__u8 mask = 0xff;
	__u8 lData;
	__u8 lParity;
	__u8 lStop;
	int status;
	char data;

	struct usb_serial_port *port;
	struct usb_serial *serial;

	if (mos7720_port == NULL)
		return ;

	port = (struct usb_serial_port *)mos7720_port->port;

	if(port_paranoia_check(port,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid port \n");
		return ;
	}

	if(serial_paranoia_check(port->serial,__FUNCTION__) )
	{
		DPRINTK("%s","Invalid Serial \n");
		return ;
	}

	serial = port->serial;

	dbg("%s - port %d", __FUNCTION__, mos7720_port->port->number);

	if ((!mos7720_port->open) && (!mos7720_port->openPending)) 
	{
		dbg("%s - port not opened", __FUNCTION__);
		return;
	}

	tty = mos7720_port->port->tty;
	
	if ((!tty) || (!tty->termios)) 
	{
		dbg("%s - no tty structures", __FUNCTION__);
		return;
	}

	DPRINTK("%s","Entering .......... \n");

	lData = LCR_BITS_8;
	lStop = LCR_STOP_1;         
	lParity = LCR_PAR_NONE;

	cflag = tty->termios->c_cflag;
	iflag = tty->termios->c_iflag;

	/* Change the number of bits */	
	switch (cflag & CSIZE) 
	{
		case CS5:	lData = LCR_BITS_5; 
				mask = 0x1f;    
			    	break;

		case CS6:   	lData = LCR_BITS_6; 
				mask = 0x3f;    
			    	break;

		case CS7:   	lData = LCR_BITS_7; 
				mask = 0x7f;    
			    	break;
		default:
		case CS8:   	lData = LCR_BITS_8;
                 	    	dbg("%s - data bits = 8", __FUNCTION__);   
			    	break;
	}

	/* Change the Parity bit */
	if (cflag & PARENB) 
	{
		if (cflag & PARODD) 
		{
			lParity = LCR_PAR_ODD;
			dbg("%s - parity = odd", __FUNCTION__);
		} 
		else 
		{
			lParity = LCR_PAR_EVEN;
			dbg("%s - parity = even", __FUNCTION__);
		}

	} 
	else 
	{
		dbg("%s - parity = none", __FUNCTION__);
	}
	
	if(cflag & CMSPAR)
	{
		lParity = lParity | 0x20;
	}

	/* Change the Stop bit */
	if (cflag & CSTOPB) 
	{
		lStop = LCR_STOP_2;
		dbg("%s - stop bits = 2", __FUNCTION__);
	} 
	else 
	{
		lStop = LCR_STOP_1;
		dbg("%s - stop bits = 1", __FUNCTION__);
	}

	/* Update the LCR with the correct value */
	mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
	mos7720_port->shadowLCR |= (lData | lParity | lStop);

	mos7720_port->validDataMask = mask;

	/* Disable Interrupts */
	data = 0x00;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,IER, &data);

	data = 0x00;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,FCR, &data);

	data = 0xcf;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,FCR, &data);

	/* Send the updated LCR value to the mos7720 */
	data = mos7720_port->shadowLCR;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,LCR, &data);

        data = 0x00b;
        mos7720_port->shadowMCR = data;
        SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);
        data = 0x00b;
        SendMosCmd(port->serial,MOS_WRITE,port->number - port->serial->minor,0x04, &data);

	/* set up the MCR register and send it to the mos7720 */
	
	mos7720_port->shadowMCR = MCR_MASTER_IE;
	if (cflag & CBAUD) 
	{
		mos7720_port->shadowMCR |= (MCR_DTR | MCR_RTS);
	}


	if (cflag & CRTSCTS) 
	{
		mos7720_port->shadowMCR |= (MCR_XON_ANY);

                /* To set hardware flow control to the specified *
                 * serial port, in SP1/2_CONTROL_REG             */

		if(port->number)
		{
		  data = 0x001;
		  SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x08, &data);
		}
		else
		{
		  data = 0x002;
		  SendMosCmd(port->serial,MOS_WRITE,MOS_MAX_PORT,0x08, &data);
		}
	}
	else
	{
		mos7720_port->shadowMCR &= ~(MCR_XON_ANY); 
	}


	data = mos7720_port->shadowMCR;
	SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,MCR, &data);
	


	/* Determine divisor based on baud rate */
	baud = tty_get_baud_rate(tty);

        if (!baud)
        {
                /* pick a default, any default... */
                DPRINTK("%s\n","Picked default baud...");
                baud = 9600;
        }


	if(baud >= 230400)
	{
		set_higher_rates(mos7720_port,&baud);
	        /* Enable Interrupts */
        	data = 0x0c;
        	SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,IER, &data);
		return;
	}  	


	dbg("%s - baud rate = %d", __FUNCTION__, baud);
	status = send_cmd_write_baud_rate (mos7720_port, baud);

	/* Enable Interrupts */
	data = 0x0c;
        SendMosCmd(mos7720_port->port->serial,MOS_WRITE,port->number - port->serial->minor,IER, &data);

	if(mos7720_port->read_urb->status!=-EINPROGRESS)
	{
		mos7720_port->read_urb->dev = serial->dev;
		
		status = usb_submit_urb(mos7720_port->read_urb, GFP_ATOMIC);
	
		if (status) 
		{
			DPRINTK(" usb_submit_urb(read bulk) failed, status = %d", status);
		}
	}
	wake_up(&mos7720_port->delta_msr_wait);
    mos7720_port->delta_msr_cond=1;
	return;
}

/****************************************************************************
 * mos7720_startup
 ****************************************************************************/

static int mos7720_startup (struct usb_serial *serial)
{
	struct moschip_serial *mos7720_serial;
	struct moschip_port *mos7720_port;
	struct usb_device *dev;
	static struct parport *pp;

	int i;

	/* parport */
        unsigned char data;
        struct parport_mos7715_private *priv;

	if(!serial)
	{
		DPRINTK("%s\n","Invalid Handler");
		return -1;
	}

	dev = serial->dev;
	
	DPRINTK("%s\n","Entering..\n.");

	/* create our private serial structure */
	mos7720_serial = kmalloc (sizeof(struct moschip_serial), GFP_KERNEL);
	if (mos7720_serial == NULL) 
	{
		err("%s - Out of memory", __FUNCTION__);
		return -ENOMEM;
	}

	/* resetting the private structure field values to zero */
	memset (mos7720_serial, 0, sizeof(struct moschip_serial));

	mos7720_serial->serial = serial;
	set_serial_private(serial,mos7720_serial);

	/* we set up the pointers to the endpoints in the mos7720_open *
	 * function, as the structures aren't created yet.             */

	/* set up port private structures */
	for (i = 0; i < serial->num_ports; ++i) 
	{
	        mos7720_port = kmalloc(sizeof(struct moschip_port), GFP_KERNEL);
		if (mos7720_port == NULL) 
		{
			err("%s - Out of memory", __FUNCTION__);
			set_serial_private(serial,NULL);
			kfree(mos7720_serial);
			return -ENOMEM;
		}
		memset (mos7720_port, 0, sizeof(struct moschip_port));


	/* Initialize all port interrupt end point to port 0 int endpoint *
	 * Our device has only one interrupt end point comman to all port */

		serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;

		mos7720_port->port = serial->port[i];
		set_port_private(serial->port[i],mos7720_port);

	DPRINTK("port number is %d \n",serial->port[i]->number);
	DPRINTK("port is %x \n",(unsigned int)serial->port[i]);
	DPRINTK("serial number is %d \n",serial->minor);

	}


	/* setting configuration feature to one */
	usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), (__u8)0x03, 0x00,0x01,0x00, 0x00, 0x00, 5*HZ);


	/* parport */
        if (!(priv = kmalloc(sizeof(struct parport_mos7715_private), GFP_KERNEL)))
                return -ENOMEM;

        if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE,&parport_mos7715_ops))) 
	{
                printk(KERN_WARNING "Could not register parport\n");
                goto probe_abort;
        }

        pp->private_data = priv;
        priv->usbdev = serial->dev;


        pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;

	mos7720_serial->parp=pp;	
	DPRINTK("parport is %x \n",(unsigned int)pp);

	/* Initialize the wait event for restore_state_thread */
	init_waitqueue_head(&restore_state_event);

	thread_pid = kernel_thread(restore_state_thread,pp,CLONE_KERNEL);
	if(thread_pid < 0) {
		printk("HCD thread creation failed \n");
		return -ENODEV;
	}

        DPRINTK("%s\n","Writing Registers Started\n");

        data = 0x30;
        SendMosCmd(serial,MOS_READ,MOS_MAX_PORT,0x04, &data);
        data = 0x80;
        SendMosCmd(serial,MOS_WRITE,MOS_MAX_PORT,0x04, &data);
        data = 0x00;
        SendMosCmd(serial,MOS_WRITE,MOS_MAX_PORT,0x04, &data);
      
        data = 0x0cc;
        SendMosCmd(pp,MOS_READ,0,0x02, &data); 
        data = 0x0cc;
        SendMosCmd(pp,MOS_WRITE,0,0x02, &data);
        priv->reg[1] = data; /* DCR */
        
        data = 0x045;
        SendMosCmd(pp,MOS_READ,0,0x0A, &data);
        data = 0x045;
        SendMosCmd(pp,MOS_WRITE,0,0x0A, &data);
        priv->reg[2] = data; /* ECR */

        DPRINTK("%s\n","Writing Registers Over\n");

        parport_announce_port(pp);

#ifdef ttttttttttt
                                                                                                                             
/* MATRIX */
/*      Loop Back For Port 2, Serial 1    */
                                                                                                                             
        data = 0xff;
        SendMosCmd(serial,MOS_READ,0x01,0x04, &data);   // Reading MCR For Port 2
        data |= 0x10;
        SendMosCmd(serial,MOS_WRITE,0x01,0x04, &data);  // Enabling Loop Back For Port 2
                                                                                                                             
        data = 0xff;
        SendMosCmd(serial,MOS_WRITE,0x01,0x00, &data);  // Writing 0xff To THR For Port 2
                                                                                                                             
        data = 0xcb;
        SendMosCmd(serial,MOS_WRITE,0x01,0x02, &data);  // Flushing THR and RHR For Port 2
                                                                                                                             
        data = 0xff;
        SendMosCmd(serial,MOS_READ,0x01,0x04, &data);   // Reading MCR For Port 2
        data &= 0xef;
        SendMosCmd(serial,MOS_WRITE,0x01,0x04, &data);  // Disabling Loop Back For Port 2
                                                                                                                             
        SendMosCmd(serial,MOS_READ,0x00,LSR, &data);  // LSR For Port 1
        DPRINTK("LSR:%x\n",data);
                                                                                                                             
        SendMosCmd(serial,MOS_READ,0x01,LSR, &data);  // LSR For Port 2
        DPRINTK("LSR:%x\n",data);
                                                                                                                             
#endif
/*      MATRIX  */

        DPRINTK("port is %x \n",(unsigned int)serial->port[0]);
        DPRINTK("port is %x \n",(unsigned int)serial->port[1]);


        DPRINTK("%s\n","Leaving : normal EXIT...\n");
	return 0;

probe_abort:
        kfree(priv);
        return -EPERM;

}


/****************************************************************************
 * mos7720_shutdown
 *	This function is called whenever the device is removed from the usb bus.
 ****************************************************************************/

static void mos7720_shutdown (struct usb_serial *serial)
{
	int i;
	struct parport_mos7715_private *priv;
	struct parport *pp;
	struct moschip_serial *ser;

	if(!serial)
	{
		DPRINTK("%s","Invalid Handler \n");
		return;
	}
	
	ser=get_serial_private(serial);
	pp=ser->parp;
	priv = pp->private_data;

	ThreadState = 1;
//	wake_up_interruptible(&restore_state_event);
	wake_up(&restore_state_event);
	thread_cond = 1;
	
	if (pp)
        {
                priv = pp->private_data;
                parport_remove_port(pp);
                priv->usbdev = NULL;
                parport_put_port(pp);
                kfree(priv);
                DPRINTK("%s\n","FREE, parallel private structure");
        }

	/* free private structure allocated for serial port  * 
	 * stop reads and writes on all ports   	     */

	DPRINTK("parport is %x \n",(unsigned int)pp);
	for (i=0; i < serial->num_ports; ++i) 
	{
		kfree(get_port_private(serial->port[i]));
		set_port_private(serial->port[i],NULL);
		DPRINTK("%s\n","FREE, port private structure");
	}

	/* free private structure allocated for serial device */

	kfree(get_serial_private(serial));
	set_serial_private(serial,NULL);
	DPRINTK("%s\n","FREE, serial private structure");

}




/* Inline functions to check the sanity of a pointer that is passed to us */
static int serial_paranoia_check (struct usb_serial *serial, const char *function)
{
        if (!serial) {
                dbg("%s - serial == NULL", function);
                return -1;
        }
//      if (serial->magic != USB_SERIAL_MAGIC) {
//              dbg("%s - bad magic number for serial", function);
//              return -1;
//      }
        if (!serial->type) {
                dbg("%s - serial->type == NULL!", function);
                return -1;
        }

        return 0;
}
static int port_paranoia_check (struct usb_serial_port *port, const char *function)
{
        if (!port) {
                dbg("%s - port == NULL", function);
                return -1;
        }
//      if (port->magic != USB_SERIAL_PORT_MAGIC) {
//              dbg("%s - bad magic number for port", function);
//              return -1;
//      }
        if (!port->serial) {
                dbg("%s - port->serial == NULL", function);
                return -1;
        }

        return 0;
}
static struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) {
        /* if no port was specified, or it fails a paranoia check */
        if (!port ||
                port_paranoia_check (port, function) ||
                serial_paranoia_check (port->serial, function)) {
                /* then say that we don't have a valid usb_serial thing, which will                  * end up genrating -ENODEV return values */
                return NULL;
        }

        return port->serial;
}


/****************************************************************************
 *	This is called by the module subsystem, or on startup to initialize us
 ****************************************************************************/

 int __init moschip7715_init(void)
{
	int retval;

	DPRINTK("%s \n"," mos7720_init :entering..........");

        /* Register with the usb serial */

	retval = usb_serial_register (&moschip7715_2port_device);

	if(retval)
		goto failed_port_device_register;

	DPRINTK("%s\n","Entring...");
	info(DRIVER_DESC " " DRIVER_VERSION);


 	/* Register with the usb */
	retval = usb_register(&io_driver);

	if (retval) 
		goto failed_usb_register;

	if(retval == 0) 
	{
		DPRINTK("%s\n","Leaving...");
		return 0;
	}


failed_usb_register:

	usb_serial_deregister(&moschip7715_2port_device);


failed_port_device_register:
	return retval;
}

/****************************************************************************
 * moschip7720_exit
 *	Called when the driver is about to be unloaded.
 ****************************************************************************/
void __exit moschip7715_exit (void)
{

	DPRINTK("%s \n"," mos7720_exit :entering..........");

	usb_deregister (&io_driver);

	usb_serial_deregister (&moschip7715_2port_device);

	DPRINTK("%s\n","Entring...");
}

module_init(moschip7715_init);
module_exit(moschip7715_exit);

/* Module information */
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");

MODULE_PARM_DESC(debug, "Debug enabled or not");

