/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Lennart Augustsson (lennart@augustsson.net).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *        This product includes software developed by the NetBSD
 *        Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 *
 * This is MOSCHIP SEMICONDUCTOR Ltd driver for MCS7840 an usb to 4 serial adapter
 * This code is based on uftdi.c and uplcom.c 
 * This code includes software developed by the NetBSD Foundation, Inc. and
 * its contributors.



 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/usb/moslcom.c,v 1.1 2007/05/05 MOSCHIP semiconductor $");

/*
 * MOSCHIP78xx serial adapter driver
 */

#include <sys/cdefs.h>

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/ioccom.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/file.h>

#if __FreeBSD_version >= 500014
#include <sys/selinfo.h>
#else
#include <sys/select.h>
#endif

#include <sys/sysctl.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#include <dev/usb/usbcdc.h>

#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include "usbdevs.h"

#include <dev/usb/ucomvar.h>

#include <dev/usb/uftdireg.h>

#include "mos7840.h"

#define MOS_RS485mode 1


#ifdef USB_DEBUG
static int umosdebug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, umos, CTLFLAG_RW, 0, "USB mos7840");
SYSCTL_INT(_hw_usb_umos, OID_AUTO, debug, CTLFLAG_RW,
	   &umosdebug, 0, "umos debug level");
#define DPRINTF(x)      do { \
				if (umosdebug) \
					logprintf x; \
			} while (0)

#define DPRINTFN(n, x)  do { \
				if (umosdebug > (n)) \
					logprintf x; \
			} while (0)

#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif

#define UMOS_CONFIG_INDEX	0
#define UMOS_IFACE_INDEX	0

#ifndef MOSLCOM_INTR_INTERVAL
#define MOSLCOM_INTR_INTERVAL		100	/* ms */
#endif





/*
 * These are the maximum number of bytes transferred per frame.
 * The output buffer size cannot be increased due to the size encoding.
 */
#define UMOSIBUFSIZE 64
#define UMOSOBUFSIZE 64

#define MOS_NO_OF_PORTS 16
#define MOSLCOM_MODVER                   1       /* module version */
#define USB_VENDOR_ID_MOSCHIP		0x9710
#define USB_PRODUCT_ID_MOSCHIP		0x7840
#define MCS_7840			0x4


#define MOSLCOM_CONFIG_INDEX             0
#define MOSLCOM_IFACE_INDEX              0
#define MOSLCOM_SECOND_IFACE_INDEX       1
#define MOSLCOMIBUFSIZE 		256
#define MOSLCOMOBUFSIZE 		256

#define MOSLCOMNUMPORTS			16


#define MCS_RD_RTYPE	0xC0
#define MCS_WR_RTYPE	0x40
#define MCS_RDREQ	0x0D
#define MCS_WRREQ	0x0E
#define MCS_CTRL_TIMEOUT	500
#define	MCS_READ_LENGTH		0x01

#define WAIT_FOR_EVER	0
#define MOS_TIMEOUT	(5)	


//#define MOS_DEBUG	0

#ifdef MOS_DEBUG
#define dprintf(fmt,args...)	printf("%s:"fmt,__FUNCTION__,##args)
#else
#define dprintf(fmt,args...)
#endif
#define DPRINTK dprintf
#define MOS_SIO_SET_DTR_MASK 0x1
#define MSO_SIO_SET_DTR_HIGH (1 | ( MOS_SIO_SET_DTR_MASK  << 8))
#define MOS_SIO_SET_DTR_LOW  (0 | ( MOS_SIO_SET_DTR_MASK  << 8))
#define MOS_SIO_SET_RTS_MASK 0x2
#define MOS_SIO_SET_RTS_HIGH (2 | ( MOS_SIO_SET_RTS_MASK << 8))
#define MOS_SIO_SET_RTS_LOW (0 | ( MOS_SIO_SET_RTS_MASK << 8))

#define MOS_SIO_RESET          0 /* Reset the port */
#define MOS_SIO_MODEM_CTRL     1 /* Set the modem control register */
#define MOS_SIO_SET_FLOW_CTRL  2 /* Set flow control register */
#define MOS_SIO_SET_BAUD_RATE  3 /* Set baud rate */
#define MOS_SIO_SET_DATA       4 /* Set the data characteristics of the port */
#define MOS_SIO_GET_STATUS     5 /* Retrieve current value of status reg */
#define MOS_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define MOS_SIO_SET_ERROR_CHAR 7 /* Set the error character */

#define MOS_PORT_MASK 0x0f
#define MOS_MSR_MASK 0xf0
#define MOS_GET_MSR(p) (((p)[0]) & MOS_MSR_MASK)
#define MOS_GET_LSR(p) ((p)[1])
#define MOS_LSR_MASK (~0x60) /* interesting bits */
#define MOS_OUT_TAG(len, port) (((len) << 2) | (port))


/* FTDI_SIO_RESET */
#define MOS_SIO_RESET_SIO 0
#define MOS_SIO_RESET_PURGE_RX 1
#define MOS_SIO_RESET_PURGE_TX 2

/* FTDI_SIO_MODEM_CTRL */
#define MOS_SIO_SET_DTR_MASK 0x1
#define MOS_SIO_SET_DTR_HIGH (1 | ( MOS_SIO_SET_DTR_MASK  << 8))
#define MOS_SIO_SET_DTR_LOW  (0 | ( MOS_SIO_SET_DTR_MASK  << 8))
#define MOS_SIO_SET_RTS_MASK 0x2
#define MOS_SIO_SET_RTS_HIGH (2 | ( MOS_SIO_SET_RTS_MASK << 8))
#define MOS_SIO_SET_RTS_LOW (0 | ( MOS_SIO_SET_RTS_MASK << 8))


/* FTDI_SIO_SET_DATA */
#define MOS_SIO_SET_DATA_BITS(n) (n)
#define MOS_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define MOS_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define MOS_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define MOS_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define MOS_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define MOS_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define MOS_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define MOS_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define MOS_SIO_SET_BREAK (0x1 << 14)

/* FTDI_SIO_SET_FLOW_CTRL */
#define MOS_SIO_DISABLE_FLOW_CTRL 0x0
#define MOS_SIO_RTS_CTS_HS 0x1
#define MOS_SIO_DTR_DSR_HS 0x2
#define MOS_SIO_XON_XOFF_HS 0x4

static int	moslcominterval = MOSLCOM_INTR_INTERVAL;

struct reg_set_offset{
	u_int			SpRegOffset;
	u_int			ControlRegOffset;
	u_int			DcrRegOffset;
	u_int			shadowLCR;
	u_int			shadowMCR;
	int 			port_open;
};


struct moslcom_softc {
	struct ucom_softc	sc_ucom[MOS_NO_OF_PORTS];
	struct reg_set_offset   sc_port_reg_offset[MOSLCOMNUMPORTS];
	 usbd_device_handle      sc_udev;        /* USB device */

	usbd_interface_handle	sc_iface;	/* interface */

	u_int			sc_hdrlen;

	u_char			sc_msr;
	u_char			sc_lsr;

	u_int			last_lcr;

	
	int			sc_no_ports;
	int			no_of_open_ports;

	usbd_interface_handle	sc_intr_iface;	/* interrupt interface */
	int			sc_intr_number;	/* interrupt number */	
	usbd_pipe_handle	sc_intr_pipe;	/* interrupt pipe */
	u_char			*sc_intr_buf;	/* interrupt buffer */
	int			sc_isize;
}__attribute__ ((packed));

Static void	moslcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
Static void	moslcom_set(void *, int, int, int);
Static int	moslcom_param(void *, int, struct termios *);
Static int	moslcom_open(void *sc, int portno);
Static void 	moslcom_close(void *, int);
//Static void	moslcom_read(void *sc, int portno, u_char **ptr,u_int32_t *count);
//Static void	moslcom_write(void *sc, int portno, u_char *to, u_char *from,u_int32_t *count);
//Static void	moslcom_break(void *sc, int portno, int onoff);

Static void moslcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status);

Static usbd_status moslcom_MCS7840_init(struct moslcom_softc *sc,int portno);

static int mos7840_get_reg_sync(struct moslcom_softc *sc,unsigned int reg,unsigned int *data);
static int mos7840_set_reg_sync(struct moslcom_softc *sc,unsigned int reg,unsigned int data);
static int mos7840_get_Uart_Reg(struct moslcom_softc *sc,int portno,unsigned int reg,unsigned int  *data);
static int mos7840_set_Uart_Reg(struct moslcom_softc *sc,int portno,unsigned int reg,unsigned int data);

static int mos7840_send_cmd_write_baud_rate (struct moslcom_softc *sc, int portno,int baudRate);
static int mos7840_calc_baud_rate_divisor (int baudRate, int *divisor,u_int16_t *clk_sel_val);

struct ucom_callback moslcom_callback = {
	moslcom_get_status,
	moslcom_set,
	moslcom_param,
	NULL,
	moslcom_open,
	moslcom_close,
	NULL,
	NULL,
};

USB_MATCH(moslcom)
{
	USB_MATCH_START(moslcom, uaa);

	if (uaa->iface != NULL) {
		
		return (UMATCH_NONE);
	}

	DPRINTFN(20,("moslcom: vendor=0x%x, product=0x%x\n",
		     uaa->vendor, uaa->product));

	if ((uaa->vendor == 0x9710) &&(uaa->product == 0x7840 || uaa->product == 0x7820))
	     return (UMATCH_VENDOR_PRODUCT);
	
	return (UMATCH_NONE);
}

USB_ATTACH(moslcom)
{
	USB_ATTACH_START(moslcom, sc, uaa);
	usbd_device_handle dev = uaa->device;
	usbd_interface_handle iface;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	
	char *devinfo;
	//const char *devname;
	int endpoint=0,port_id=0;
	int unit,i;
	u_int data=0x0;
	usbd_status err;
	struct ucom_softc *ucom[MOSLCOMNUMPORTS];
	struct reg_set_offset *port_reg_offset[MOSLCOMNUMPORTS];
	dprintf("\n moslcom_attach: sc=%p softc is %p \n", sc,(struct moslcom_softc *)device_get_softc(self));
	
	devinfo = malloc(1024, M_USBDEV, M_WAITOK);
	unit=device_get_unit(self);
	
	usbd_devinfo(dev,0,devinfo);
	
	sc->sc_udev=dev;
	
	sc->sc_ucom[0].sc_udev = dev;
	
	if (uaa->iface == NULL) {
		/* Move the device into the configured state. */
		err = usbd_set_config_index(dev, UMOS_CONFIG_INDEX, 1);
		if (err) {
			printf("\n%s: failed to set configuration, err=%s\n",
			       __FUNCTION__, usbd_errstr(err));
			goto bad;
		}

		err = usbd_device2interface_handle(dev, UMOS_IFACE_INDEX, &iface);
		if (err) {
			printf("\n%s: failed to get interface, err=%s\n",
			       __FUNCTION__, usbd_errstr(err));
			goto bad;
		}
	} else {
		dprintf("\n%s: iface =uaa->iface \n",
			       __FUNCTION__);
		iface = uaa->iface;
	}
		
	
	
	
	
	
	data = 0x0;
	mos7840_get_reg_sync(sc,GPIO_REGISTER,&data);
	dprintf("1.Data is %x\n",data);
	if((data & 0x01)==0)
	{
		printf("Number of ports are two\n");	
		sc->sc_no_ports=2;
	}
	else
	{
		printf("Number of ports are four\n");	
		sc->sc_no_ports=4;
	}

	
	id = usbd_get_interface_descriptor(iface);
		
	dprintf("bNumEndpoints %d\n",id->bNumEndpoints);
	
	sc->sc_intr_number = -1;
	sc->sc_intr_pipe = NULL;
	for (i = 0; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(iface, i);
                if (ed == NULL) {
                        dprintf("%s: no endpoint descriptor for %d\n",
                                __FUNCTION__, i);
                        goto bad;
                }
                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
                        sc->sc_intr_number = ed->bEndpointAddress;
                        sc->sc_isize = UGETW(ed->wMaxPacketSize);
                }
        }
	/* keep interface for interrupt */
	sc->sc_intr_iface = iface;

	 if (sc->sc_intr_number == -1) {
                dprintf("%s: Could not find interrupt in\n",__FUNCTION__);

                goto bad;
        }
	

	for(port_id=0;port_id < sc->sc_no_ports;port_id++)
	{
	
			
		ucom[port_id]= &sc->sc_ucom[port_id];
	
		port_reg_offset[port_id]=&sc->sc_port_reg_offset[port_id];
	
		//ucom[0]->sc_dev = device_add_child(device_get_parent(self),"mos0",(unit+0));
		ucom[port_id]->sc_dev = device_add_child(self,NULL,(unit+port_id));
		if (!ucom[port_id]->sc_dev) {
                printf("1:Could not add USB device\n");
                goto bad;
        	}
		else 
		printf("created device  with port%d\n",port_id);
		
		device_set_softc(ucom[port_id]->sc_dev,sc);
		ucom[port_id]->sc_udev = dev;
		
		ucom[port_id]->sc_iface = iface;
		//devname = USBDEVNAME(ucom[port_id]->sc_dev);
		//printf("Devname: %s: %s\n",devname, devinfo);
		
		ucom[port_id]->sc_bulkin_no = ucom[port_id]->sc_bulkout_no = -1;
		ed = usbd_interface2endpoint_descriptor(ucom[port_id]->sc_iface,endpoint );
		
		if((sc->sc_no_ports==2) && (port_id==1))
		{
			ucom[port_id]->sc_bulkin_no = ed->bEndpointAddress+2;
		}
		else
		{
	        	ucom[port_id]->sc_bulkin_no = ed->bEndpointAddress;
		}
		
		//dprintf(" endpoint no:%d  bulkin:%x\n",endpoint,ucom[port_id]->sc_bulkin_no);
		endpoint ++;
       		ed = usbd_interface2endpoint_descriptor(ucom[port_id]->sc_iface,endpoint );
		if((sc->sc_no_ports==2) && (port_id==1))
		{
			ucom[port_id]->sc_bulkout_no = ed->bEndpointAddress+2;
		}
		else
		{
	        	ucom[port_id]->sc_bulkout_no = ed->bEndpointAddress;
		}
		//dprintf(" endpoint no:%d  bulkout:%x\n",endpoint,ucom[port_id]->sc_bulkout_no);
		
		endpoint ++;
	        ucom[port_id]->sc_parent = sc;
	        ucom[port_id]->sc_portno = port_id;
	        /* bulkin, bulkout set above */
	        ucom[port_id]->sc_ibufsize = MOSLCOMIBUFSIZE;
	        ucom[port_id]->sc_obufsize = MOSLCOMOBUFSIZE;
	        ucom[port_id]->sc_ibufsizepad = MOSLCOMIBUFSIZE;
	        ucom[port_id]->sc_opkthdrlen = 0;
 	        ucom[port_id]->sc_callback = &moslcom_callback;
		
        	//TASK_INIT(&sc->sc_task, 0, moslcom_notify, sc);
        	ucom_attach(&sc->sc_ucom[port_id]);
			
		
	}
	
	sc->no_of_open_ports =0;
	if(sc->sc_no_ports==4)
	{
	port_reg_offset[0]->SpRegOffset=0x0;		
	port_reg_offset[0]->ControlRegOffset=0x1;
	port_reg_offset[0]->DcrRegOffset=0x4;
	port_reg_offset[1]->SpRegOffset=0x8;		
	port_reg_offset[1]->ControlRegOffset=0x9;
	port_reg_offset[1]->DcrRegOffset=0x16;
	port_reg_offset[2]->SpRegOffset=0xa;		
	port_reg_offset[2]->ControlRegOffset=0xb;
	port_reg_offset[2]->DcrRegOffset=0x19;
	port_reg_offset[3]->SpRegOffset=0xc;		
	port_reg_offset[3]->ControlRegOffset=0xd;
	port_reg_offset[3]->DcrRegOffset=0x1c;
	}
	else if(sc->sc_no_ports ==2)
	{
	port_reg_offset[0]->SpRegOffset=0x0;		
	port_reg_offset[0]->ControlRegOffset=0x1;
	port_reg_offset[0]->DcrRegOffset=0x4;
	port_reg_offset[1]->SpRegOffset=0xa;		
	port_reg_offset[1]->ControlRegOffset=0xb;
	port_reg_offset[1]->DcrRegOffset=0x19;

	}
/*
	for(port_id=0;port_id < sc->sc_no_ports;port_id++)
	{
		dprintf("moslcom: in = 0x%x, out = 0x%x, intr = 0x%x\n",         		ucom[port_id]->sc_bulkin_no,ucom[port_id]->sc_bulkout_no,sc->sc_intr_number);
		dprintf("%s UNIT NUMBER IS %d sc_parent%p\n",__FUNCTION__,device_get_unit(ucom[port_id]->sc_dev),ucom[port_id]->sc_parent);
		printf("port %d: SpRegOffset %x ControlRegOffset %x DcrRegOffset %x \n",port_id,port_reg_offset[port_id]->SpRegOffset,port_reg_offset[port_id]->ControlRegOffset,port_reg_offset[port_id]->DcrRegOffset);
		printf("port %d: SpRegOffset %x ControlRegOffset %x DcrRegOffset %x \n",port_id,sc->sc_port_reg_offset[port_id].SpRegOffset,sc->sc_port_reg_offset[port_id].ControlRegOffset,sc->sc_port_reg_offset[port_id].DcrRegOffset);
	}
*/
        free(devinfo, M_USBDEV);
	USB_ATTACH_SUCCESS_RETURN;
	
bad:
	DPRINTF(("moslcom_attach: ATTACH ERROR\n"));
	//ucom->sc_dying = 1;
	free(devinfo, M_USBDEV);

	USB_ATTACH_ERROR_RETURN;
	

}



USB_DETACH(moslcom)
{
	
	USB_DETACH_START(moslcom, sc);
	
	int rv = 0;
	int port_id;
	for(port_id=0;port_id < sc->sc_no_ports;port_id++)
	{
        	sc->sc_ucom[port_id].sc_dying = 1;
	        rv = ucom_detach(&sc->sc_ucom[port_id]);
		device_delete_child(self,sc->sc_ucom[port_id].sc_dev);
	}


	return rv;
}


static int mos7840_get_reg_sync(struct moslcom_softc *sc,unsigned int reg,unsigned int *data)
{
	usb_device_request_t req;
	usbd_status err;
	req.bmRequestType = MCS_RD_RTYPE;
	req.bRequest = MCS_RDREQ;
	USETW(req.wValue, 0);
	USETW(req.wIndex, reg);
	USETW(req.wLength, MCS_READ_LENGTH);
	dprintf("%s offset %x \n",__FUNCTION__,reg);
	
	err = usbd_do_request(sc->sc_udev, &req,(void *)data);
	
	if (err) {
		dprintf("%s: usbd_do_request failed: %s\n",
				__FUNCTION__, usbd_errstr(err));
		
		return (EIO);
	}
	
	*data = (*data) & 0x00ff;
	return (0);
}

static int mos7840_set_reg_sync(struct moslcom_softc *sc,unsigned int reg,unsigned int data)
{
	usb_device_request_t req;
	usbd_status err;
	
	data = data & 0x00ff;
	req.bmRequestType = MCS_WR_RTYPE;
	req.bRequest = MCS_WRREQ;
	USETW(req.wValue, data);
	USETW(req.wIndex, reg);
	USETW(req.wLength, 0);
	dprintf("%s offset %x data:%x\n",__FUNCTION__,reg,data);
	
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err) {
		dprintf("%s: usbd_do_request failed: %s\n",
				__FUNCTION__, usbd_errstr(err));
		return (EIO);
	}
	
	
	return (0);
}

static int mos7840_get_Uart_Reg(struct moslcom_softc *sc,int portno,unsigned int reg,unsigned int  *data)
{
	usb_device_request_t req;
	unsigned int Wval=0x0;
	usbd_status err;
	
	if((sc->sc_no_ports==2) && (portno==1))
	{
		Wval |= (portno+2)<<8;
	}
	else 
	{
		Wval=(portno+1)<<8;
	}
	req.bmRequestType = MCS_RD_RTYPE;
	req.bRequest = MCS_RDREQ;
	USETW(req.wValue, Wval);
	USETW(req.wIndex, reg);
	USETW(req.wLength, MCS_READ_LENGTH);
	dprintf("%s offset %x data:%x\n",__FUNCTION__,reg,Wval);
	//printf("%s offset %x data:%x portno %d\n",__FUNCTION__,reg,Wval,portno);
	err = usbd_do_request(sc->sc_udev, &req,(void *)data);
	if (err) {
		printf("%s: usbd_do_request failed: %s\n",
				__FUNCTION__, usbd_errstr(err));
		
		return (EIO);
	}
	
	*data = (*data) & 0x00ff;
	
	return (0);
}
static int mos7840_set_Uart_Reg(struct moslcom_softc *sc,int portno,unsigned int reg,unsigned int data)
{
	usb_device_request_t req;
	unsigned int Wval=0x0;
	usbd_status err;
	Wval=(unsigned int)data;
	Wval = Wval & 0x00ff;
	
	if((sc->sc_no_ports==2) && (portno==1))
	{
		Wval |= (portno+2)<<8;
	}
	else 
	{
		Wval |= (portno+1)<<8;
	}
	
	req.bmRequestType = MCS_WR_RTYPE;
	req.bRequest = MCS_WRREQ;
	USETW(req.wValue, Wval);
	USETW(req.wIndex, reg);
	USETW(req.wLength,0);
	dprintf("%s offset %x data:%x\n",__FUNCTION__,reg,Wval);
	
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err) {
		printf("%s: usbd_do_request failed: %s\n",
				__FUNCTION__, usbd_errstr(err));
		
		return (EIO);
	}
	

	return (0);
}

Static usbd_status
moslcom_MCS7840_init(struct moslcom_softc *sc,int portno)
{
	int status;
	unsigned int Data=0x0;

/////////////////////////////////////////////////////////////////////////////////////	
	status=0;
	Data=0x0;
	status=mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,&Data);
	if(status<0){
		dprintf("Reading Spreg failed\n");
		return -1;
	}
	
	Data |= 0x80;
	status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,Data);
	if(status<0){
		dprintf("writing Spreg failed\n");
		return -1;
	}
	
	Data &= ~0x80;
	status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,Data);
	if(status<0){
		dprintf("writing Spreg failed\n");
		return -1;
	}
/////////////////////////////////////////////////////////////////////////////////////
//#ifdef RS485	
	
	if(MOS_RS485mode==1)
                       Data = 0xC0;
	       else
                        Data = 0x00;
	
 		
                status=0;
                status=mos7840_set_Uart_Reg(sc,portno,SCRATCH_PAD_REGISTER,Data);
                if(status<0) {
                        dprintf("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
                        return -1;
                }
                else dprintf("SCRATCH_PAD_REGISTER Writing success status%d\n",status);
	
//#endif
/////////////////////////////////////////////////////////////////////////////////////

	status=0;
	Data=0x0;
	status=mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,&Data);
	if(status<0){
		dprintf("Reading Controlreg failed\n");
		return -1;
	}
	Data |= 0x08;//Driver done bit
	/*
	status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,Data);
	if(status<0){
		dprintf("writing Controlreg failed\n");
		return -1;
	}
	*/
	Data |= 0x20;//rx_disable
	status=0;
	status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,Data);
	if(status<0){
		dprintf("writing Controlreg failed\n");
		return -1;
	}
/*test reg writing*/
#ifdef TEST_VENDOR_COMMANDS
	dprintf("SRI: 1 writing 0X%x to ControlRegOffset\n",Data);
	status=0;
	Data=0x28;
	status=mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,Data);
	if(status<0){
		dprintf("writing Controlreg failed\n");
		return -1;
	}
	status=0;
	Data=0x0;
	status=mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,&Data);
	if(status<0){
		dprintf("Reading Controlreg failed\n");
		return -1;
	}
	dprintf("SRI: 1 READ 0X%x from ControlRegOffset\n",Data);


	Data = 0x10;
	dprintf("2.SRI:mos7840_set_Uart_Reg writing 0x%x\n",Data);
	status = 0;
	status = mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
	sc->sc_port_reg_offset[portno].shadowLCR=Data;

	Data = 0x00;
	status=0;
	status = mos7840_get_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,&Data);
	dprintf("2.SRI:mos7840_get_Uart_Reg returns 0x%x\n",Data);

#endif
/*test end*/
/////////////////////////////////////////////////////////////////////////////////////	

	Data = 0x00;
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,INTERRUPT_ENABLE_REGISTER,Data);
	if(status<0){
		dprintf("disableing interrupts failed\n");
		return -1;
	}
	 // Set FIFO_CONTROL_REGISTER to the default value 
	Data = 0x00;
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,FIFO_CONTROL_REGISTER,Data);
	if(status<0){
		dprintf("Writing FIFO_CONTROL_REGISTER  failed\n");
		return -1;
	}

	Data = 0xcf;  //chk
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,FIFO_CONTROL_REGISTER,Data);
	if(status<0){
		dprintf("Writing FIFO_CONTROL_REGISTER  failed\n");
		return -1;
	}

	Data = 0x03; //LCR_BITS_8
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
	sc->sc_port_reg_offset[portno].shadowLCR=Data;

	Data = 0x0b; // MCR_DTR|MCR_RTS|MCR_MASTER_IE
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,Data);
	sc->sc_port_reg_offset[portno].shadowMCR=Data;
/////////////////////////////////////////////////////////////////////////////////////	
#ifdef SET_BAUD_9600
	Data = 0x00;
	status=0;
	status = mos7840_get_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,&Data);
	sc->sc_port_reg_offset[portno].shadowLCR=Data;

	Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
	status = 0;
	status = mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
	
	Data = 0x0c;
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,DIVISOR_LATCH_LSB,Data);
	
	Data = 0x0;
	status=0;
	status = mos7840_set_Uart_Reg(sc,portno,DIVISOR_LATCH_MSB,Data);

	Data = 0x00;
	status=0;
	status = mos7840_get_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,&Data);

//	Data = mos7840_port->shadowLCR; //data latch disable
	Data = Data & ~SERIAL_LCR_DLAB;
	status = 0;
	status = mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
	sc->sc_port_reg_offset[portno].shadowLCR=Data;
#endif
/////////////////////////////////////////////////////////////////////////////////////	
	//clearing Bulkin and Bulkout Fifo
	Data = 0x0;
	status = 0;
	status = mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,&Data);
	
	Data = Data | 0x0c;
	status = 0;
        status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,Data);
	  
	Data = Data & ~0x0c;
	status = 0;
        status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,Data);
	//Finally enable all interrupts

	Data = 0x00;
	status=0;
	status = mos7840_get_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,&Data);
	
	Data = 0x0;
	Data = 0x0c;
	status = 0;
        status = mos7840_set_Uart_Reg(sc,portno,INTERRUPT_ENABLE_REGISTER,Data);

	//clearing rx_disable
	Data = 0x0;
	status = 0;
        status = mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,&Data);
	Data = Data & ~0x20;
	status = 0;
        status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,Data);

	// rx_negate
	Data = 0x0;
	status = 0;
        status = mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,&Data);
	Data = Data |0x10;
	status = 0;
        status = mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].ControlRegOffset,Data);


}




Static int
moslcom_open(void *vsc, int portno)
{
	struct moslcom_softc *sc=vsc;
	usbd_status err;
	dprintf("%s portno:%d\n",__FUNCTION__,portno);

	moslcom_MCS7840_init(sc,portno);
	
	
	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
		
		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
		err = usbd_open_pipe_intr(sc->sc_intr_iface,
					  sc->sc_intr_number,
					  USBD_SHORT_XFER_OK,
					  &sc->sc_intr_pipe,
					  sc,
					  sc->sc_intr_buf,
					  sc->sc_isize,
					  moslcom_intr,
					  moslcominterval);
		if (err) {
			dprintf("%s: cannot open interrupt pipe (addr %d)\n",
			       USBDEVNAME(sc->sc_ucom[portno].sc_dev),
			       sc->sc_intr_number);
			return (EIO);
		}
	}

	sc->no_of_open_ports++;
	sc->sc_port_reg_offset[portno].port_open=1;
	return 0;
}



Static void moslcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
	struct moslcom_softc *sc = priv;
	u_char *buf = sc->sc_intr_buf;
	u_char sp[5];
	int portno;


	if (status != USBD_NORMAL_COMPLETION) {
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			return;

		DPRINTF(("%s: uplcom_intr: abnormal status: %s\n",
			USBDEVNAME(sc->sc_ucom.sc_dev),
			usbd_errstr(status)));
		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
		return;
	}
	dprintf("interrupt buffer size is %d\n",sizeof(sc->sc_intr_buf));
		
	if(sc->sc_no_ports == 4)
	{
	sp[0]=(u_char)buf[0];	
	sp[1]=(u_char)buf[1];	
	sp[2]=(u_char)buf[2];	
	sp[3]=(u_char)buf[3];	
	
	}
	else
	{
	sp[0]=(u_char)buf[0];	
	sp[1]=(u_char)buf[2];	
	//sp[2]=(u_char)buf[2];	
	//sp[3]=(u_char)buf[3];	
	
	}


	//	printk("%s data is sp1:%x sp2:%x sp3:%x sp4:%x status:%x\n",__FUNCTION__,sp1,sp2,sp3,sp4,st);

	for(portno=0;portno<sc->sc_no_ports;portno++)
	{	
	if(sc->sc_port_reg_offset[portno].port_open != 0)
	{	
		
		
		if(sp[portno] & 0x01)
		{
			DPRINTK("SP%d No Interrupt !!!\n",portno);
		}
		else
		{
			switch(sp[portno] & 0x0f)
			{
			case SERIAL_IIR_RLS: 
			    DPRINTK("Serial Port %d: Receiver status error or ",portno);
			    DPRINTK("address bit detected in 9-bit mode\n");
			     //mos7840_port->MsrLsr=1;
			     //mos7840_get_reg(mos7840_port,wval,LINE_STATUS_REGISTER,&Data);
			     break;
            		case SERIAL_IIR_MS:
			     DPRINTK("Serial Port %d: Modem status change\n",portno);
			     //mos7840_port->MsrLsr=0;	
			     //mos7840_get_reg(mos7840_port,wval, MODEM_STATUS_REGISTER, &Data);	
			     break;
			}
		}
	}
	
	}





	/*
		//pstatus = buf[8];
	if (ISSET(pstatus, RSAQ_STATUS_CTS))
		sc->sc_msr |= SER_CTS;
	else
		sc->sc_msr &= ~SER_CTS;
	if (ISSET(pstatus, RSAQ_STATUS_DSR))
		sc->sc_msr |= SER_DSR;
	else
		sc->sc_msr &= ~SER_DSR;
	if (ISSET(pstatus, RSAQ_STATUS_DCD))
		sc->sc_msr |= SER_DCD;
	else
		sc->sc_msr &= ~SER_DCD;
	*/
	/* Deferred notifying to the ucom layer */
//	taskqueue_enqueue(taskqueue_swi_giant, &sc->sc_task);
}




Static  void moslcom_close(void *vsc, int portno)
{
	
	struct moslcom_softc *sc = vsc;
	int err;

	if (sc->sc_ucom[portno].sc_dying)
		return;
	dprintf("%s portno:%d\n",__FUNCTION__,portno);
	
	sc->no_of_open_ports--;
	if(sc->no_of_open_ports ==0)
	{
		if (sc->sc_intr_pipe != NULL) {
			err = usbd_abort_pipe(sc->sc_intr_pipe);
			if (err)
				dprintf("%s: abort interrupt pipe failed: %s\n",
			       	USBDEVNAME(sc->sc_ucom[portno].sc_dev),
			       	usbd_errstr(err));
			err = usbd_close_pipe(sc->sc_intr_pipe);
			if (err)
				dprintf("%s: close interrupt pipe failed: %s\n",
			       	USBDEVNAME(sc->sc_ucom[portno].sc_dev),
			       	usbd_errstr(err));
			free(sc->sc_intr_buf, M_USBDEV);
			sc->sc_intr_pipe = NULL;
		}
	}
	sc->sc_port_reg_offset[portno].port_open=0;
}
	
Static void
moslcom_set(void *vsc, int portno, int reg, int onoff)
{
	struct moslcom_softc *sc=vsc;
	unsigned int mcr;
	int status;
	dprintf("%s portno:%d\n",__FUNCTION__,portno);

	mcr = sc->sc_port_reg_offset[portno].shadowMCR;
	switch (reg) {
	case UCOM_SET_RTS:
		if(onoff==1) mcr &= ~MCR_RTS;
		else mcr |= MCR_RTS;
		break;
	case UCOM_SET_DTR:
		if(onoff==1) mcr &= ~MCR_DTR;
		else mcr |= MCR_DTR;
		break;
	#ifdef KnowWhatIsBreak
	case UCOM_SET_BREAK:
	
		break;
	#endif
	default:
		break;
	}

	sc->sc_port_reg_offset[portno].shadowMCR = mcr;

	status=0;
        status = mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,mcr);
        if(status <0)
        {
                dprintf("setting MODEM_CONTROL_REGISTER Failed\n");
               // return -1;
        }



}



Static int
moslcom_param(void *vsc, int portno, struct termios *t)
{
	
	struct moslcom_softc *sc = vsc;
	unsigned int Data=0x0;
	u_int8_t lData=0x0;
	u_int8_t lParity=0x0;
	u_int8_t lStop=0x0;
	int status=0;
	usb_cdc_line_state_t ls;
	dprintf("%s portno:%d\n",__FUNCTION__,portno);

	USETDW(ls.dwDTERate, t->c_ospeed);
	if (ISSET(t->c_cflag, CSTOPB))
	{
		ls.bCharFormat = UCDC_STOP_BIT_2;
		lStop = LCR_STOP_2;//UCDC_STOP_BIT_2;
	}
	else
	{	
		ls.bCharFormat = UCDC_STOP_BIT_1;
		lStop = LCR_STOP_1;//UCDC_STOP_BIT_1;
	}
	if (ISSET(t->c_cflag, PARENB)) {
		if (ISSET(t->c_cflag, PARODD))
		{
			ls.bParityType = UCDC_PARITY_ODD;
			lParity= LCR_PAR_ODD;//UCDC_PARITY_ODD;
		}
		else
		{
			ls.bParityType = UCDC_PARITY_EVEN;
			lParity = LCR_PAR_EVEN;//UCDC_PARITY_EVEN;
		}
	} else
		ls.bParityType = LCR_PAR_NONE;//UCDC_PARITY_NONE;

	switch (ISSET(t->c_cflag, CSIZE)) {
	case CS5:
		ls.bDataBits = 5;
		lData =LCR_BITS_5;// 5;
		break;
	case CS6:
		ls.bDataBits = 6;
		lData =LCR_BITS_6;// 6;
		break;
	case CS7:
		ls.bDataBits = 7;
		lData = LCR_BITS_7;//7;
		break;
	case CS8:
		ls.bDataBits = 8;
		lData = LCR_BITS_8;//8;
		break;
	}
		Data=0x0;
		mos7840_get_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,&Data);
		sc->sc_port_reg_offset[portno].shadowLCR =Data;
	/* Update the LCR with the correct value */
	sc->sc_port_reg_offset[portno].shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
	sc->sc_port_reg_offset[portno].shadowLCR |= (lData | lParity | lStop);
	dprintf("uplcom_set_line_coding: rate = %d, fmt = %d, parity = %d bits = %d\n",UGETDW(ls.dwDTERate), ls.bCharFormat,ls.bParityType, ls.bDataBits);
	dprintf("uplcom_set_line_coding: lData %d lParity %d lStop %d\n",lData,lParity,lStop );
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	dprintf("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n",sc->sc_port_reg_offset[portno].shadowLCR);
	/* Disable Interrupts */
	Data = 0x00;
	mos7840_set_Uart_Reg(sc,portno,INTERRUPT_ENABLE_REGISTER,Data);
	

	Data = 0x00;
	mos7840_set_Uart_Reg(sc,portno,FIFO_CONTROL_REGISTER,Data);

	Data = 0xcf;
	mos7840_set_Uart_Reg(sc,portno,FIFO_CONTROL_REGISTER,Data);

	/* Send the updated LCR value to the mos7840 */
	Data = sc->sc_port_reg_offset[portno].shadowLCR;

	mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
//#ifdef CAUSE_FAILURE

        Data = 0x00b;
        sc->sc_port_reg_offset[portno].shadowMCR = Data;
	mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,Data);
        Data = 0x00b;
	mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,Data);

	/* set up the MCR register and send it to the mos7840 */
	
	sc->sc_port_reg_offset[portno].shadowMCR = MCR_MASTER_IE;
	// NEED to CHECK
	#ifdef CHECK
	if (ISSET(t->c_cflag, CBAUD)) 
	{
		sc->sc_port_reg_offset[portno].shadowMCR |= (MCR_DTR | MCR_RTS);
	}
	#endif
	// END of CHECK
	 
	if (ISSET(t->c_cflag, CRTSCTS)) 
	{
		sc->sc_port_reg_offset[portno].shadowMCR |= (MCR_XON_ANY);

		
	}
	else
	{
		sc->sc_port_reg_offset[portno].shadowMCR &= ~(MCR_XON_ANY); 
	}


	Data = sc->sc_port_reg_offset[portno].shadowMCR;
	mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,Data);
#ifdef CAUSE_FAILURE	
#endif
	dprintf("%s - baud rate = %d", __FUNCTION__,UGETDW(ls.dwDTERate) );
	status = mos7840_send_cmd_write_baud_rate (sc,portno,UGETDW(ls.dwDTERate));

	/* Enable Interrupts */
	Data = 0x0c;
	mos7840_set_Uart_Reg(sc,portno,INTERRUPT_ENABLE_REGISTER,Data);



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////


	dprintf("moslcom_set_line_coding: rate = %d, fmt = %d, parity = %d bits = %d\n",UGETDW(ls.dwDTERate),ls.bCharFormat,ls.bParityType, ls.bDataBits);
	dprintf("moslcom_set_line_coding: rate = %d, fmt = %d, parity = %d bits = %d\n",UGETDW(ls.dwDTERate),lStop,lParity, lData);	

	return (0);
}
/*****************************************************************************
 * mos7840_send_cmd_write_baud_rate
 *	this function sends the proper command to change the baud rate of the
 *	specified port.
 *****************************************************************************/

static int mos7840_send_cmd_write_baud_rate (struct moslcom_softc *sc, int portno,int baudRate)
{
	int divisor = 0;
	int status;
	u_int16_t clk_sel_val;
	//unsigned char number ;
	unsigned int Data;
	

	

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

	
	dprintf("%s - port = %d, baud = %d", __FUNCTION__, portno, baudRate);
	//reset clk_uart_sel in spregOffset
	if(baudRate >115200)
	{
		#ifdef HW_flow_control
		//NOTE: need to see the pther register to modify
		//setting h/w flow control bit to 1;
		status=0;
		//Data = mos7840_port->shadowMCR ;
		Data = 0x2b;
		sc->sc_port_reg_offset[portno].shadowMCR=Data;
		status=mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,Data);
		if(status<0)
		{		
			DPRINTK("Writing spreg failed in set_serial_baud\n");
			return -1;
		}
		#endif

	}
	else
	{
		#ifdef HW_flow_control
		//setting h/w flow control bit to 0;
		status=0;
		//Data = mos7840_port->shadowMCR ;
		Data = 0xb;
		sc->sc_port_reg_offset[portno].shadowMCR=Data;
		status=mos7840_set_Uart_Reg(sc,portno,MODEM_CONTROL_REGISTER,Data);
		if(status<0)
		{		
			DPRINTK("Writing spreg failed in set_serial_baud\n");
			return -1;
		}
	
		#endif

	
	}

	
	if(1)//baudRate <= 115200)
	{
		clk_sel_val=0x0;
		Data=0x0;
		mos7840_get_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,&Data);
		sc->sc_port_reg_offset[portno].shadowLCR =Data;
		Data=0x0;
		status=0;
		status = mos7840_calc_baud_rate_divisor (baudRate, &divisor,&clk_sel_val);
		status= mos7840_get_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,&Data);
		if(status<0)
		{		
			DPRINTK("reading spreg failed in set_serial_baud\n");
			return -1;
		}
		Data = (Data & 0x8f)|clk_sel_val;
		status=0;
		status= mos7840_set_reg_sync(sc,sc->sc_port_reg_offset[portno].SpRegOffset,Data);
		if(status<0)
		{		
			DPRINTK("Writing spreg failed in set_serial_baud\n");
			return -1;
		}
       		 /* Calculate the Divisor */
		
	
		if (status) 
		{
			dprintf("%s - bad baud rate", __FUNCTION__);
			DPRINTK("%s\n","bad baud rate");
			return status;
		}
	        /* Enable access to divisor latch */
	        Data = sc->sc_port_reg_offset[portno].shadowLCR | SERIAL_LCR_DLAB;
	        sc->sc_port_reg_offset[portno].shadowLCR  = Data;
		mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
	
		/* Write the divisor */
		Data = LOW8 (divisor);//MOSCHIP:  commented to test
		DPRINTK("set_serial_baud Value to write DLL is %x\n",Data);
		mos7840_set_Uart_Reg(sc,portno,DIVISOR_LATCH_LSB,Data);
	
		Data = HIGH8 (divisor); //MOSCHIP:  commented to test
		DPRINTK("set_serial_baud Value to write DLM is %x\n",Data);
		mos7840_set_Uart_Reg(sc,portno,DIVISOR_LATCH_MSB,Data);
	
	        /* Disable access to divisor latch */
	        Data = sc->sc_port_reg_offset[portno].shadowLCR & ~SERIAL_LCR_DLAB;
	        sc->sc_port_reg_offset[portno].shadowLCR = Data;
		mos7840_set_Uart_Reg(sc,portno,LINE_CONTROL_REGISTER,Data);
	
	}
		
	return status;
}



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

	dprintf("%s - %d", __FUNCTION__, baudRate);

		if(baudRate <=115200)
		{
			*divisor = 115200/baudRate;
			*clk_sel_val = 0x0;
		}
	 	if((baudRate > 115200) && (baudRate <= 230400))
		{
			*divisor = 230400/baudRate;	
			*clk_sel_val=0x10;
		}
	 	else if((baudRate > 230400) && (baudRate <= 403200))
		{
			*divisor = 403200/baudRate;	
			*clk_sel_val=0x20;
		}
	 	else if((baudRate > 403200) && (baudRate <= 460800))
		{
			*divisor = 460800/baudRate;	
			*clk_sel_val=0x30;
		}
	 	else if((baudRate > 460800) && (baudRate <= 806400))
		{
			*divisor = 806400/baudRate;	
			*clk_sel_val=0x40;
		}
	 	else if((baudRate >806400) && (baudRate <= 921600))
		{
			*divisor = 921600/baudRate;	
			*clk_sel_val=0x50;
		}
	 	else if((baudRate > 921600) && (baudRate <= 1572864))
		{
			*divisor = 1572864/baudRate;	
			*clk_sel_val=0x60;
		}
	 	else if((baudRate > 1572864) && (baudRate <= 3145728))
		{
			*divisor = 3145728/baudRate;	
			*clk_sel_val=0x70;
		}
	return 0;	
}





void
moslcom_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
{
	dprintf("%s\n",__FUNCTION__);
}
/*
Static void
moslcom_read(void *vsc, int portno, u_char **ptr, u_int32_t *count)
{
	dprintf("%s\n",__FUNCTION__);
}	
Static void
moslcom_write(void *vsc, int portno, u_char *to, u_char *from, u_int32_t *count)
{
	dprintf("%s portno:%d\n",__FUNCTION__,portno);
}	
void
moslcom_break(void *vsc, int portno, int onoff)
{
	dprintf("%s\n",__FUNCTION__);
}
*/



Static device_method_t moslcom_methods[] = {
	/* Device interface */
	DEVMETHOD(device_probe, moslcom_match),
	DEVMETHOD(device_attach, moslcom_attach),
	DEVMETHOD(device_detach, moslcom_detach),

	{ 0, 0 }
};


Static driver_t moslcom_driver = {
	"ucom",
	moslcom_methods,
	sizeof (struct moslcom_softc)
};

DRIVER_MODULE(moslcom, uhub, moslcom_driver, ucom_devclass, usbd_driver_load, 0);
MODULE_DEPEND(moslcom, usb, 1, 1, 1);
MODULE_DEPEND(moslcom, ucom,UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
