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

/************************************************************************************

Filename: mcs7780.c
Version: 0.1
Description: Irda Moschip Dongle
Status:

 *************************************************************************************/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/rtnetlink.h>
#include <linux/usb.h>
#include <linux/crc32.h>
#include <net/irda/irda.h>
#include <net/irda/irlap.h>
#include <net/irda/irda_device.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>


#include "mcs7780.h"
// Debugging prints

#define initial_prints 1
#define tx_prints 1
#define rx_prints 1
#ifdef initial_prints
#  define Dg_printk(fmt, args...) printk("%s: "fmt,__FUNCTION__,##args)
#else
#  define Dg_printk(fmt, args...)
#endif

#ifdef tx_prints
#  define Dtx_printk(fmt, args...) printk("%s: "fmt,__FUNCTION__,##args)
#else
#  define Dtx_printk(fmt, args...)
#endif

#ifdef rx_prints
#  define Drcv_printk(fmt, args...) printk("%s: "fmt,__FUNCTION__,##args)
#else
#  define Drcv_printk(fmt, args...)
#endif


#define MCS_VENDOR_ID 	0x9710	/* Vendor Id of Moschip MCS7780 */
#define MCS_PRODUCT_ID 	0x7780	/* Product Id  */
#define NIRDA_USB	4	/* Number of devices supported by the driver, This number is not constrained */

static struct usb_device_id mcs7780_table[] = {
	/* MosChip Corp.,  MCS7780 FIR-USB Adapter */
	{USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)},
	{},
};

MODULE_DEVICE_TABLE(usb, mcs7780_table);



int turboMode=0;		/* Minimum Turn around time flag */

module_param (turboMode,int, 0);
//MODULE_PARM (turboMode,int, 0);
MODULE_PARM_DESC(turboMode,"No Turn time");
MODULE_LICENSE("GPL");

/* Global Device structures It supports upto 4 devices */
static struct mcs7780_cb g_mcs7780_cb[NIRDA_USB];
/* Driver Starting and End points */
//static void *mcs7780_probe(struct usb_device *dev, unsigned int ifnum,const struct usb_device_id *id);
static int mcs7780_probe( struct usb_interface *intf,const struct usb_device_id *id );
//static void mcs7780_disconnect(struct usb_device *dev, void *ptr);
static void mcs7780_disconnect( struct usb_interface *intf );

/*Network related kernel handlers */
//static int mcs7780_net_init(struct net_device *dev);
static int mcs7780_net_open(struct net_device *netdev);
static int mcs7780_net_close(struct net_device *netdev);
static int mcs7780_hard_xmit(struct sk_buff *skb, struct net_device *netdev);
static int mcs7780_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
static struct net_device_stats *mcs7780_net_get_stats(struct net_device *netdev);
static void mcs7780_net_timeout(struct net_device *dev);

/* Driver internal functions */
//static inline int mcs7780_find_endpoints(struct mcs7780_cb *mcs, struct usb_endpoint_descriptor *ep, int epnum);
static int mcs7780_find_endpoints(struct mcs7780_cb *mcs, struct usb_host_endpoint *ep, int epnum);
static int mcs7780_irda_init_iobuf(iobuff_t *io, int size);

/* setting and get register values */
static int mcs7780_set_reg_sync(struct mcs7780_cb *mcs, __u16 reg, __u16 val);
static int mcs7780_get_reg_sync(struct mcs7780_cb *mcs, __u16 reg, __u16 * val);

/* speed change function */
static int mcs7780_speed_change_sync(struct mcs7780_cb *mcs,__u32 speed);
static void mcs7780_get_speed_bytes(int speed, __u16 *bytes);

/* Recieve function */
static void mcs7780_rx_submit(struct mcs7780_cb *mcs, struct urb *purb);
/* Recieve call back function */
static void mcs7780_receive(struct urb *purb, struct pt_regs *regs);
/* Sending recieved to upper layer(application) */
static void mcs7780_async_bump(struct net_device *dev, struct net_device_stats *stats, __u8 *buf, int len);

/* Transmit function */
static int mcs7780_tx_submit(struct mcs7780_cb *mcs,struct urb *purb,struct sk_buff *skb);
/* Transmit call back function */
static void mcs7780_write_bulk_callback(struct urb *purb, struct pt_regs *regs);

/* Compute checksum functions */
static __u16 ComputeFCS(__u8 *data, __u32 dataLen);
static unsigned int ComputeCrc32(unsigned char *Buffer,unsigned int Length);

/* Wrapping functions */
static inline int mcs7780_wrap_sir_skb(struct sk_buff *skb, unsigned char *buf);
static inline int mcs7780_wrap_mir_skb(struct sk_buff *skb, unsigned char *buf);
static inline int mcs7780_wrap_fir_skb(struct sk_buff *skb, unsigned char *buf);

/* Trans receiver functions */
static inline int mcs7780_setup_transciever_vishay_sync(struct mcs7780_cb *mcs);
static inline int mcs7780_setup_transciever_agilent_sync(struct mcs7780_cb *mcs);
static inline int mcs7780_setup_transciever_sharp_sync(struct mcs7780_cb *mcs);

/* Thread function */
static int speed_change_state_thread(void *);

/* USB structure for register device  */

struct usb_driver mcs_driver = {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
	.owner = THIS_MODULE,
#endif
	.name = "mcs7780",
	.probe = mcs7780_probe,
	.disconnect = mcs7780_disconnect,
	.id_table = mcs7780_table,
};

/*
Description: Pointer to the probe function in the USB driver. This function  is called by the USB core when it thinks it has a struct usb_interface that this driver can handle. 

Input Parameters:
Usb_device:  USB device structure.
Ifnum:	interface number.
Usb_device_id:  device number of the interface.

 */

//static void *mcs7780_probe(struct usb_device *dev, unsigned int ifnum,const struct usb_device_id *id)

static int mcs7780_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct mcs7780_cb *mcs=NULL;
	//struct usb_interface_descriptor *interface;
	struct net_device *netdev;
	struct urb  *urb2;
	int i;
	int ret;
	int err;
	int num;
	Dg_printk("\n");

	for (i = 0; i < NIRDA_USB; i++) {
		struct mcs7780_cb *localmcs = &g_mcs7780_cb[i];
		if((localmcs->usbdev != NULL) &&
				(localmcs->present == 0) &&
				(localmcs->netopen == 0)) {
			printk("%s(), found a zombie instance !!!\n",
					__FUNCTION__);
			mcs7780_disconnect(intf);
		}
	}

	/* Find an free instance to handle this new device... */
	mcs = NULL;
	for (i = 0; i < NIRDA_USB; i++) {
		if(g_mcs7780_cb[i].usbdev == NULL) {
			mcs = &g_mcs7780_cb[i];
			break;
		}
	}
	if(mcs == NULL) {
		printk("Too many STIr IrDA devices !!! (max = %d)\n",
				NIRDA_USB);
		return -ENOMEM;
	}
	//mcs->usbdev=dev;
	mcs->usbdev=interface_to_usbdev(intf);
	mcs->present=1;		// device present flag
	mcs->netopen=0;		// device opened flag
	init_waitqueue_head(&mcs->restore_state_event);	
//	interface = &dev->actconfig->interface[ifnum].altsetting[0];
//	Dg_printk("endpoint: %d numberofendpoints: %d \n",(int)interface->endpoint->bEndpointAddress,(int) interface->bNumEndpoints);

	ret=mcs7780_find_endpoints(mcs,intf->cur_altsetting->endpoint,intf->cur_altsetting->desc.bNumEndpoints);	
	if(!ret)
		Dg_printk("Endpoint error\n");


	printk("after setting the configuration\n");
	for(num=0;num<MAX_TX_URBS;num++)
	{
		struct urb  *urb1 = usb_alloc_urb(0,GFP_KERNEL);
                if (urb1 == NULL) {
                        err("No free urbs available");
                        goto probe_error;
                }
                urb1->transfer_buffer = kmalloc (MAX_TX_BUFFER_SIZE, GFP_KERNEL);
                if (urb1->transfer_buffer == NULL) {
                        err("out of memory");
                        goto probe_error;
                }
                mcs->tx_urb[num] = urb1;

	}


	// initialise Rx urb and buffer
	for(num=0;num<MAX_RX_URBS;num++)
	{
		urb2 = usb_alloc_urb(0,GFP_KERNEL);
		if (urb2 == NULL) {
			printk("\nNo free RX urbs available\n");
			goto probe_error;
		}
		urb2->transfer_buffer = kmalloc (MAX_RX_BUFFER_SIZE, GFP_KERNEL);
		if (urb2->transfer_buffer == NULL) {
			err("out of memory");
			goto probe_error;
		}
		mcs->rx_urb[num] = urb2;
		

	}
	if(mcs->rx_buff.head == NULL)
	{
		if(mcs7780_irda_init_iobuf(&mcs->rx_buff,MAX_RX_BUFFER_SIZE))
		{
			printk(" Memory allocation error in Rx_buffer \n");
			goto probe_error;
		}
	}

	/* Initialize QoS for this device */
	/*
	   The purpose of irda_init_max_qos_capabilies function is for layers and drivers to be able to set the maximum QoS possible and then "and in" their own limitations. Initialise the   variables are window_size.bits, min_turn_time.bits, max_turn_time.bits, data_size.bits, link_disc_time.bits  and additional_bofs.bits.
	 */
	irda_init_max_qos_capabilies(&mcs->qos);
	mcs->qos.baud_rate.bits &= 0x01ff;	// it support upto 4mbps
	//        mcs->qos.baud_rate.bits &= 0x007f;	// it support upto 576000
	mcs->qos.min_turn_time.bits &= 0x07; //qos_mtt_bits; // 1 ms
//	mcs->qos.data_size.bits &= 0x07;	// 256 bytes
	mcs->qos.data_size.bits &= 0x3f;	// 2048 bytes
//	mcs->qos.window_size.value &=0x00;	// window size 1 frame
	mcs->qos.window_size.value &=0x03;	// window size 4 frame
	irda_qos_bits_to_value(&mcs->qos);

//	if (!(netdev = dev_alloc("irda%d", &err))) 
	if(!(netdev = alloc_irdadev(sizeof(* mcs))))
//	if(!(netdev = alloc_netdev(sizeof(struct mcs7780_cb),"irda%d",irda_device_setup)))
	{
		printk("%s(), dev_alloc() failed!\n", __FUNCTION__);
		Dg_printk("device allocation failed!\n");
		return -ENOMEM;
	}
	SET_MODULE_OWNER(netdev);
        SET_NETDEV_DEV(netdev, &intf->dev);

	mcs->netdev = netdev;
	netdev->priv = (void *) mcs;

	usb_set_intfdata(intf, mcs);
	/* Override the network functions we need to use */
//	netdev->init            = mcs7780_net_init;
	netdev->hard_start_xmit = mcs7780_hard_xmit;
	netdev->tx_timeout      = mcs7780_net_timeout;
	netdev->watchdog_timeo  = 250*HZ/1000;  /* 250 ms > USB timeout */
	netdev->open            = mcs7780_net_open;
	netdev->stop            = mcs7780_net_close;
	netdev->get_stats       = mcs7780_net_get_stats;
	netdev->do_ioctl        = mcs7780_net_ioctl;

	err= register_netdev(netdev);
	
	if(!err)
	{
		printk("******************Registered device with name:%s\n",netdev->name);
	}
	else
	{
		printk(" Registered device failed :%d\n",err);
	}

	return 0;
probe_error:
	printk("probe error\n");
	for (num = 0; num < MAX_TX_URBS; num++)
        {
                if (mcs->tx_urb[num])
                {
                        if (mcs->tx_urb[num]->transfer_buffer)
                                kfree (mcs->tx_urb[num]->transfer_buffer);
                        usb_free_urb (mcs->tx_urb[num]);
                }
        }
	for (num = 0; num < MAX_RX_URBS; num++)
	{
                if (mcs->rx_urb[num]) 
		{
                        if (mcs->rx_urb[num]->transfer_buffer)
                                kfree (mcs->rx_urb[num]->transfer_buffer);
                        usb_free_urb (mcs->rx_urb[num]);
                }
	}
	if (mcs->rx_buff.head)
		kfree(mcs->rx_buff.head);
	return -ENOMEM;

}

/*
Description: Pointer to the disconnect function in the USB driver. This function (described in the section probe and disconnect in Detail) is called by the USB core when the struct usb_interface has been removed from the system or when the driver is being unloaded from the USB core.
 */

//static void mcs7780_disconnect(struct usb_device *dev, void *ptr)
static void mcs7780_disconnect( struct usb_interface *intf )
{
	struct mcs7780_cb *mcs = usb_get_intfdata( intf );
	int num;
	mcs->present=0;
	Dg_printk("%s: start\n",__FUNCTION__);
	if((mcs->netopen)||(mcs->irlap))
	{
		netif_stop_queue(mcs->netdev);
		mcs->ThreadState=1;
		wake_up(&mcs->restore_state_event);
		mcs->thread_cond = 1;
		for (num =  MAX_TX_URBS-1; num >= 0;num--)
		{
			if (mcs->tx_urb[num])
			{
			#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
				mcs->tx_urb[num]->transfer_flags &= ~URB_ASYNC_UNLINK;
			#endif
			
			#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
				usb_kill_urb(mcs->tx_urb[num]);
			#endif
			
			#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
        			usb_unlink_urb(mcs->tx_urb[num]);
        		#endif
			}
		}
		for (num =  MAX_RX_URBS-1; num >= 0;num--)
		{
			if (mcs->rx_urb[num])
			{
			#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
				mcs->rx_urb[num]->transfer_flags &= ~URB_ASYNC_UNLINK;
			#endif

			#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
				usb_kill_urb(mcs->rx_urb[num]);
			#endif
			#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
                                usb_unlink_urb(mcs->rx_urb[num]);
                        #endif
			}
		}
	}
	for (num =  MAX_TX_URBS-1; num >= 0;num--)
	{
		if (mcs->tx_urb[num])
		{
			if (mcs->tx_urb[num]->transfer_buffer)
				kfree (mcs->tx_urb[num]->transfer_buffer);
			usb_free_urb (mcs->tx_urb[num]);
		}
	}
	for (num =  MAX_RX_URBS-1; num >= 0;num--)
	{
		if (mcs->rx_urb[num])
		{
			if (mcs->rx_urb[num]->transfer_buffer)
				kfree (mcs->rx_urb[num]->transfer_buffer);
			usb_free_urb (mcs->rx_urb[num]);
		}
	}
	if (mcs->rx_buff.head)
		kfree(mcs->rx_buff.head);
	if (mcs->netdev) {
		unregister_netdev(mcs->netdev);
		mcs->netdev = NULL;
	}

	mcs->usbdev=NULL;
	Dg_printk("%s:end\n",__FUNCTION__);
}

/*
Description:- This function is used to find endpoints which are available on the interface.

Input Parameters: 
mcs7780_cb:  is private Data Structure.
Usb_host_endpoint: Host endpoint
Epnum: Number of endpoints.
 */

//static inline int mcs7780_find_endpoints(struct mcs7780_cb *mcs, struct usb_endpoint_descriptor *ep, int epnum)
static int mcs7780_find_endpoints(struct mcs7780_cb *mcs, struct usb_host_endpoint *ep, int epnum)
{
	int i=0;
	int ret=0;
	Dg_printk("\n");
	for (i = 0; i < epnum; i++) {
		if (ep[i].desc.bEndpointAddress & USB_DIR_IN)
		{
			mcs-> bulk_in_ep = ep[i].desc.bEndpointAddress;

		}
		else
		{
			mcs-> bulk_out_ep = ep[i].desc.bEndpointAddress;
		}

		/* MosChip says that the chip has only two bulk
		 * endpoints. Find one for each direction and move on.
		 */
		Dg_printk(" mcs->bulk_in_ep :%d mcs->bulk_out_ep:%d\n",mcs->bulk_in_ep, mcs->bulk_out_ep);
		if ((mcs->bulk_in_ep != 0) && (mcs->bulk_out_ep != 0)) {
			ret = 1;
			break;
		}
	}

	return ret;
}

static int mcs7780_irda_init_iobuf(iobuff_t *io, int size)
{
	io->head = kmalloc(size, GFP_KERNEL);
	if (io->head != NULL) {
		io->truesize = size;
		io->in_frame = FALSE;
		io->state    = OUTSIDE_FRAME;
		io->data     = io->head;
	}
	return io->head ? 0 : -ENOMEM;
}

/* Network related user handlers  */

/*
Description: When the ioctl system call is invoked on a socket, the command number is one of the symbols defined in <linux/sockios.h>, and the sock_ioctl function directly invokes a protocol-specific function.  Any ioctl command that is not recognized by the protocol layer is passed to the device layer. These device-related ioctl commands accept a third argument from user space, a struct ifreq* . This structure is defined in <linux/if.h>.
IOCTL’s used:
SIOCSBANDWIDTH:  Seting the bandwidth of the device.
SIOCSMEDIABUSY:  Checking the device is busy or not

Input Parameters:
Net_device:  Network device structure.
Ifreq: pointer points to a kernel-space address that holds a copy of the structure passed by the user. After mcs7780_net_ioctl returns, the structure is copied back to user space; Therefore, the driver can use the private commands to both receive and return data.
Cmd: Command number

 */

static int mcs7780_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
	struct if_irda_req *irq = (struct if_irda_req *) rq;
	struct mcs7780_cb *mcs;
	int ret=0;
	mcs=netdev->priv;
	Dg_printk(" baudrate:%x\n",(int)irq->ifr_baudrate);
	switch (cmd) {
		case SIOCSBANDWIDTH: /* Set bandwidth */
			Dg_printk("in SIOCBANDWIDTH\n");
			if (!capable(CAP_NET_ADMIN))
				return -EPERM;
			/* Protect us from USB callbacks, net watchdog and else. */
			/* Check if the device is still there */
			//        if(irq->ifr_baudrate!=9600) 
			mcs->new_speed = irq->ifr_baudrate;
			if((mcs->new_speed != mcs->speed) && (mcs->new_speed != -1))
			{
				/* Set the desired speed */
				mcs->speed=mcs->new_speed;
				mcs->new_speed=-1;
				wake_up(&mcs->restore_state_event);
				mcs->thread_cond = 1;

			}
			break;
		case SIOCGRECEIVING: /* Check if we are receiving right now */
			irq->ifr_receiving = 0;
			break;
		default:
			ret = -EOPNOTSUPP;
			break;

	}

	return ret;
}

/*
Description: This is a pointer to a function, which stop the interface. This function is called whenever ifconfig deactivates the device (for example “ifconfig irda0 down”). The stop method releases all the resources acquired by mcs7780_net_open function. This function will call netif_stop_queue(dev)  and also it will kill the urb which are initiliased in the mcs7780_net_open function. Last it will call irlap_close(irlap), This function will disconnect the link and unregister the irda device.

Input Parameter:
Net_device: Network device structure.
 */

static int mcs7780_net_close(struct net_device *netdev)
{
	struct mcs7780_cb *mcs=NULL;
	//int num;
	Dg_printk("%s start \n",__FUNCTION__);
	//	ASSERT(netdev != NULL, return -1;);
	mcs = (struct mcs7780_cb *)netdev->priv;
	//      ASSERT(mcs != NULL, return -1;);
	if(mcs->present)
	{
		mcs->netopen = 0;
		mcs->transciever_type=MCS_TSC_VISHAY;
		mcs->receive_mode = 1;
		netif_stop_queue(mcs->netdev);
	//	mcs->ThreadState=1;
	//	wake_up(&mcs->restore_state_event);
	//	mcs->thread_cond = 1;
	/*	for (num = 0; num < MAX_TX_URBS; num++)
		{
			if (mcs->tx_urb[num])
			{
				mcs->tx_urb[num]->transfer_flags &= ~URB_ASYNC_UNLINK;
				usb_kill_urb(mcs->tx_urb[num]);
			}
		}
		for (num = 0; num < MAX_RX_URBS; num++)
		{
			if (mcs->rx_urb[num])
			{		
				mcs->rx_urb[num]->transfer_flags &= ~URB_ASYNC_UNLINK;
				usb_kill_urb(mcs->rx_urb[num]);
			}
		}*/
	}
	if(mcs->irlap)
	{
		irlap_close(mcs->irlap);
		mcs->irlap=NULL;
	}
	Dg_printk("%s end\n",__FUNCTION__);
	return 0;
}

/*
Description: This is a pointer to a function, which opens the device. This function is called whenever ifconfig activates the device (for example “ifconfig irda0 up”).   It will call function irlap_open(). This kernel function initialise irlap_cb(IrLap) structure by assigning device name, qos,  transmit queues and source address. It will call kernel function irlmp_register_link().This function register IrLAP layer with IrLMP. There is possible to have multiple instances of the IrLAP layer, each connected to different IrDA ports. This irlap_open function will return initilased structure irlap_cb.
Allow IrLAP to send data to driver by calling the function netif_start_queue(dev). 
 */

static int mcs7780_net_open(struct net_device *netdev)
{
	struct mcs7780_cb *mcs;
	char hwname[16];
	int ret=0;
	__u16 rval=0;
	mcs = (struct mcs7780_cb *) netdev->priv;
	if(!mcs->present)
	{
		printk("device not present returning\n");	
		return -1;
	}
	mcs->close_flag=0;
	mcs->new_speed = -1;
	mcs->netopen = 1;
	mcs->receive_mode = 1;
	sprintf(hwname, "usb#%d", mcs->usbdev->devnum);
	mcs->speed=9600;
	mcs->sir_tweak=1;
	mcs->transciever_type=MCS_TSC_VISHAY;
	ret = mcs7780_get_reg_sync(mcs, MCS_MODE_REG, &rval);
	rval |= MCS_DRIVER;	// enabling the driver done bit
	ret = mcs7780_set_reg_sync(mcs, MCS_MODE_REG, rval);
	ret=mcs7780_speed_change_sync(mcs,mcs->speed);
	mcs->ThreadState=0;
	mcs->thread_pid = kernel_thread(speed_change_state_thread,mcs,CLONE_KERNEL);

	/* Description: opening the irda devices by passing network device structure and hadware name as a parameter. */

	mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);
	netif_start_queue(netdev);
	mcs->idle_rx_urb= mcs->rx_urb[1];
	mcs->idle_rx_urb->context=NULL;
	mcs7780_rx_submit(mcs,mcs->rx_urb[0]);	
	return 0;
}


static int speed_change_state_thread(void *ptr)
{
	int ret=1;
	__u16 rval=0;
	int DebugCount=0;
	struct mcs7780_cb *mcs;
	mcs=ptr;
	//daemonize();
	while(1)
	{
		mcs->thread_cond = 0;
		wait_event_interruptible(mcs->restore_state_event,(mcs->thread_cond==1));

		if(mcs->ThreadState)
                {
                        Dg_printk("thread exiting \n");
                        break;
                }

		netif_stop_queue(mcs->netdev);	
		while(1)
		{	
			ret = mcs7780_get_reg_sync(mcs, MCS_RESV_REG, &rval);
			++DebugCount;
			if((rval & 0x1) == 0)
			{
				// Sometimes the last OUT has not yet been started,
				// and the TX status is read as OFF
				// To take care of this situation, remain in the loop
				// for at least 3 iterations
				if(DebugCount < 3)
				{
					continue;
				}
				else
					break;
			}


			if(DebugCount > 3000)  //100
			{
				Dg_printk(" ** ERROR ** : Timeout in SetSpeed \n");
				return 0;
			}

		}
		ret=mcs7780_speed_change_sync(mcs,mcs->speed);
		Dg_printk(" return value of speed change:%d\n",ret);
		/* Restart the transmission of data from the application.*/
		netif_wake_queue(mcs->netdev);

	}
	return 0;


}

static struct net_device_stats *mcs7780_net_get_stats(struct net_device *netdev)
{
	struct mcs7780_cb *mcs;

	Dg_printk("\n");
	mcs= (struct mcs7780_cb *)netdev->priv;
	return &mcs->stats;
}
static int mcs7780_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
{
	struct mcs7780_cb *mcs = (struct mcs7780_cb *) netdev->priv;
	__u32 speed=0;	
	struct urb *purb=NULL;
	int i=0;

	Dtx_printk("skb->len:%d\n",skb->len);
	if(skb == NULL || netdev == NULL)
		return -EINVAL;

	/* Stop the transmission data from the application by calling */

	netif_stop_queue(netdev);

	if((!mcs) || (!mcs->present))
	{
		Dtx_printk(" Device not existing\n");
	}

	/* Check if we need to change the speed */
	speed = irda_get_next_speed(skb);

	if ((speed != mcs->speed) && (speed != -1)) {
		//printk(" new_speed:%d speed:%d\n",speed,mcs->speed);

		if(skb->len==0)
		{
			mcs->speed=speed;
			wake_up(&mcs->restore_state_event);
			mcs->thread_cond = 1;

			Dtx_printk("speed change sucessfully and skb->len is zero\n");
			dev_kfree_skb(skb);
			netdev->trans_start = jiffies;
			return 0;
		}
		else
		{
			mcs->new_speed = speed;
			Dtx_printk("speed change will occur in callback function\n");
		}
	}
	for (i = 0; i < MAX_TX_URBS; i++)
        {
                if (mcs->tx_urb[i]->status != -EINPROGRESS)
                {
		//	printk("i:%d\n",i);
                        purb = mcs->tx_urb[i];
                        break;
                }
        }

	mcs7780_tx_submit(mcs,purb,skb);
	//netif_wake_queue(mcs->netdev);
	//mcs7780_tx_submit(mcs,skb);
	return 0;
}
/*
static int mcs7780_net_init(struct net_device *dev)
{
	Dg_printk("\n");
	irda_device_setup(dev);
	return 0;
}
*/

static int mcs7780_speed_change_sync(struct mcs7780_cb *mcs,__u32 speed)
{
	__u16 rval=0;
	__u16 speedval=0;
	int ret=0;

	ret = mcs7780_get_reg_sync(mcs, MCS_MODE_REG, &rval);
	Dg_printk("mode_reg ret:0x%x\n",rval);
	rval &= ~(MCS_SPEED_MASK | MCS_FIR);
	if (mcs->sir_tweak)
		rval |= MCS_SIR16US;    /*1.6us pulse width */
	else
		rval &= ~MCS_SIR16US;   /*1.6us pulse width */
	rval &= ~MCS_SIPEN;
	rval &= ~MCS_PLLPWDN;   /*turn the power on */
	mcs7780_get_speed_bytes(speed,&speedval);	
	Dg_printk("speed :%d speedbits:%x\n",speed,speedval);
	rval |= speedval;
	ret = mcs7780_set_reg_sync(mcs, MCS_MODE_REG, rval);
	Dg_printk("after setting speed ret:%d\n",ret);
	//	mcs->speed = speed;

	/* MINRXPW values recomended by MosChip */

	if (mcs->speed <= 115200) {

		ret=mcs7780_set_reg_sync(mcs, MCS_MINRXPW_REG, 0);
		Dg_printk("setting 0 to minrxpwreg ret:%d\n",ret);

	} else if ((mcs->speed > 115200)  && (mcs->speed <= 1152000)) {

		Dg_printk("setting 1 to minrxpwreg\n");
		mcs7780_set_reg_sync(mcs, MCS_MINRXPW_REG,1);

	} else {

		Dg_printk("setting 5 to minrxpwreg\n");
		rval |= MCS_FIR;
		mcs7780_set_reg_sync(mcs, MCS_MINRXPW_REG, 5);

	}
	Dg_printk("setting transciever\n");
	switch (mcs->transciever_type) {
		case MCS_TSC_VISHAY:
			ret = mcs7780_setup_transciever_vishay_sync(mcs);
			break;

		case MCS_TSC_SHARP:
			ret = mcs7780_setup_transciever_sharp_sync(mcs);
			break;

		case MCS_TSC_AGILENT:
			ret = mcs7780_setup_transciever_agilent_sync(mcs);
			break;

		default:
			Dg_printk("Unknown tranciever type: %d", mcs->transciever_type);
			break;
	}

	Dg_printk("after setting transciever:%d ret:%d\n",MCS_TSC_VISHAY,ret);
	ret=mcs7780_get_reg_sync(mcs, MCS_MODE_REG, &rval);	
	Dg_printk("issue software reset with value:0x%x\n",rval);
	rval &= ~MCS_RESET;
	ret = mcs7780_set_reg_sync(mcs, MCS_MODE_REG, rval);
	Dg_printk("after issue reset :%d\n",ret);
	return ret;

}

/*
Description:- To set the Control register by calling usb_fill_control_urb function by passing usb_rcvctrlpipe function as parameter.

Input Parameters: 
mcs7780_cb:  is private Data Structure.
Reg: Register Address
Val:  Value to receive from the Register.
 */

static int mcs7780_get_reg_sync(struct mcs7780_cb *mcs, __u16 reg, __u16 * val)
{
	struct usb_device *dev = mcs->usbdev;
	int ret=0;

	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
			MCS_RD_RTYPE, 0, reg, val, 2,
			msecs_to_jiffies(MCS_CTRL_TIMEOUT));
	return ret;
}

/* 
Description:- To set the Control register by calling usb_fill_control_urb function by passing usb_sndctrlpipe function as parameter.

Input Parameters: 
mcs7780_cb:  is private Data Structure.
Reg: Register Address
Val:  Value to set in the Register.
 */

static int mcs7780_set_reg_sync(struct mcs7780_cb *mcs, __u16 reg, __u16  val)
{
	struct usb_device *dev = mcs->usbdev;

	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
			MCS_WR_RTYPE, val, reg, NULL, 0,
			msecs_to_jiffies(MCS_CTRL_TIMEOUT));
}

/*
Description:- To set the Vishay Transciever Control register by passing mcs7780 private data as parameter.

Input Parameters: 
mcs7780_cb:  is private Data Structure.
 */


static inline int mcs7780_setup_transciever_vishay_sync(struct mcs7780_cb *mcs)
{
	int ret = 0;
	__u16 rval=0;
	/* mcs_get_reg should read exactly two bytes from the dongle */
	ret = mcs7780_get_reg_sync(mcs, MCS_XCVR_REG, &rval);
	if (unlikely(ret != 2)) {
		ret = -EIO;
		goto error;
	}

	rval |= (MCS_MODE0 | MCS_XCVR_CONF);
	rval &= ~(MCS_STFIR);
	rval &= ~MCS_MODE1;

	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if (unlikely(ret))
		goto error;

	rval &= ~MCS_MODE0;

	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if (unlikely(ret))
		goto error;

	rval &= ~MCS_XCVR_CONF;

	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if (unlikely(ret))
		goto error;
	if(mcs->receive_mode)
	{
		rval |= MCS_RXFAST ;	
	}
	else
	{
		rval &= ~MCS_RXFAST ;
	}	
	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if(unlikely(ret))
		goto error;

	ret = 0;
	return ret;
error:
	Dg_printk("error with return value:%d\n",ret);
	return ret;
}

/*
Description:- To set the Agilent Transciever Control register by passing mcs7780 private data as parameter.

Input Parameters: 
mcs7780_cb:  is private Data Structure.

 */
static inline int mcs7780_setup_transciever_agilent_sync(struct mcs7780_cb *mcs)
{
	int ret = 0;
	__u16 rval;
	Dg_printk("\n");
	ret = mcs7780_get_reg_sync(mcs, MCS_XCVR_REG, &rval);
	rval &= ~MCS_MODE0;
	rval &= ~MCS_STFIR;
	rval &= ~MCS_MODE1;
	rval |= MCS_SMODE0;
	rval &= ~MCS_SMODE0;
	rval &= ~MCS_INVTX; 
	rval |= MCS_INVTX;
	if(mcs->receive_mode)
	{
		rval |= MCS_RXFAST ;	
	}
	else
	{
		rval &= ~MCS_RXFAST ;
	}	
	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if(unlikely(ret))
		Dg_printk(" error while write value to register\n");
	return 0;
}

/*
Description:- To set the Sharp Transciever Control register by passing mcs7780 private data as parameter.

Input Parameters: 
mcs7780_cb:  is private Data Structure.
 */

static inline int mcs7780_setup_transciever_sharp_sync(struct mcs7780_cb *mcs)
{
	int ret = 0;
	__u16 rval;

	/* mcs_get_reg should read exactly two bytes from the dongle */
	ret = mcs7780_get_reg_sync(mcs, MCS_XCVR_REG, &rval);
	if (unlikely(ret != 2)) {
		ret = -EIO;
		goto error;
	}

	rval |= (MCS_MODE0 | MCS_XCVR_CONF | MCS_STFIR);
	rval &= ~MCS_MODE1;
	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if (unlikely(ret))
		goto error;

	rval &= ~MCS_MODE0;
	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if (unlikely(ret))
		goto error;

	rval &= ~MCS_XCVR_CONF;
	ret = mcs7780_set_reg_sync(mcs, MCS_XCVR_REG, rval);
	if (unlikely(ret))
		goto error;

	rval = 0x4D;
	ret = mcs7780_set_reg_sync(mcs, MCS_TXPW_REG, rval);
	if (unlikely(ret))
		goto error;
	ret = 0;
error:
	return ret;
}

/*
Description:- This Function called to wrap the skb packet with the EOF,BOF and CRC by calling function async_wrap_skb function and copy it to the Tx buffer (buf).

Input Parameters: 
skb:  Socket buffer contains packet header, tail, length, data etc.,
buf: Transmit buffer
 */

static inline int mcs7780_wrap_sir_skb(struct sk_buff *skb, unsigned char *buf)
{
	int wraplen;

	Dtx_printk("\n");

	/* 2: full frame length, including "the length" */
	wraplen = async_wrap_skb(skb, buf + 2, 4094);

	wraplen += 2;
	buf[0] = wraplen & 0xff;
	buf[1] = (wraplen >> 8) & 0xff;

	return wraplen;


}

/*
Description:- This function called to wrap the skb packet with the 7E and CRC and copy it to the Tx buffer (buf).

Input Parameters: 
skb:  Socket buffer contains packet header, tail, length, data etc.,
buf: Transmit buffer
 */

static inline int mcs7780_wrap_mir_skb(struct sk_buff *skb, unsigned char *buf)
{
	__u16 fcs=0xffff;
	__u16 wraplen;

	memcpy(buf+2,skb->data,skb->len);
	fcs = ComputeFCS(skb->data,skb->len);
	Dg_printk(" fcs:%x \n",fcs);
	buf[skb->len+2+0]=(fcs & 0xff);
	buf[skb->len+2+1]=((fcs >> 8) & 0xff);

	wraplen = skb->len + 2 + 2;// each 2 are number of bytes of length and checksum
	/* Fill in header length */

	buf[0] = wraplen & 0xff;
	buf[1] = (wraplen >> 8) & 0xff;
	return wraplen;
}

/*
Description:- This function called to wrap the skb packet with the 7E and CRC and copy it to the Tx buffer (buf).

Input Parameters: 
skb:  Socket buffer contains packet header, tail, length, data etc.,
buf: Transmit buffer
 */

static inline int mcs7780_wrap_fir_skb(struct sk_buff *skb, unsigned char  *buf)
{	
	__u16 wraplen;
	__u32 fcs = ComputeCrc32(skb->data, skb->len);

	memcpy(buf+2,skb->data,skb->len);
	buf[skb->len + 2] = (fcs & 0xff);
	buf[skb->len + 2 + 1] = ((fcs >> 8) & 0xff);
	buf[skb->len + 2 + 2] = ((fcs >> 16) & 0xff);
	buf[skb->len + 2 + 3] = ((fcs >> 24) & 0xff);

	wraplen = skb->len + 2 + 4;// each 2 are number of bytes of length and checksum
	/* Fill in header length */
	buf[0] = wraplen & 0xff;
	buf[1] = (wraplen >> 8) & 0xff;
	return wraplen;
}

/* mcs7780_net_timeout(netdev) is called after every 250 msec if the driver does not give confirmation about the packet being sent . Timeout is set by driver. Timer function to be called is given during initialization. When the driver calls netif_wake_queue() it means that the current packet has been transmitted and the application should send the next packet.*/

static void mcs7780_net_timeout(struct net_device *dev)
{
	struct mcs7780_cb *mcs=dev->priv;
	int num;
        for (num = 0; num < MAX_TX_URBS; num++)
        {
//	printk("%s mcs->tx_urb[%d]->status:%d\n",__FUNCTION__,num,mcs->tx_urb[num]->status);
	if(mcs->tx_urb[num]->status != 0) {
		mcs->stats.tx_errors++;
		switch (mcs->tx_urb[num]->status) {
			case -EINPROGRESS: 		/* -115 */
				break;
			case -ECONNABORTED:             /* -103 */
			case -ECONNRESET:               /* -104 */
			case -ETIMEDOUT:                /* -110 */
			case -ENOENT:                   /* -2 (urb killed by us)  */
			default:                        /* ??? - Play safe */
				mcs->tx_urb[num]->status = 0;
				/* Restart the transmission of data from the application. */
				netif_wake_queue(mcs->netdev);
				break;
		}
	}
	}
}

/* 
   For receive we use single URB. In the open function URB is sent down, After data received, In the completion routine of the same urb is sent down by calling the mcs7780_rx_submit function with urb as parameter.
   The Receive is started from Open function (mcs7780_net_open).*/




#define RXPACK_LEN	4096
static void mcs7780_rx_submit(struct mcs7780_cb *mcs, struct urb *purb)
{
	int ret=0;
	Drcv_printk("starting\n");

	if(!purb)
	{
		Drcv_printk(" urb is NULL\n");
		return;
	}

	/* Prepare the urb for the submission by calling usb_fill_bulk_urb()*/
	/* usb_fill_bulk_urb() set mcs7780_recieve() as callback function */


	usb_fill_bulk_urb(purb,mcs->usbdev,usb_rcvbulkpipe(mcs->usbdev,mcs->bulk_in_ep),purb->transfer_buffer,RXPACK_LEN,mcs7780_receive,mcs);
	purb->transfer_buffer_length = RXPACK_LEN;

	/*set the URB transfer flag and status */
	//purb->transfer_flags= USB_QUEUE_BULK;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
	purb->transfer_flags =  URB_ASYNC_UNLINK;
#endif
	purb->status=0;

	/* make the next in the urb is NULL */

//	purb->next=NULL;

	/* submit the the rx urb */

	ret = usb_submit_urb(purb, GFP_ATOMIC);
	Drcv_printk(" return value of usb_submit:%d\n",ret);
}

/*
   void async_unwrap_char(struct net_device *dev, struct net_device_stats *stats,iobuff_t *rx_buff, __u8 byte)
Description: This function will de-stuff BOF and EOF and CRC from received packet. 

Input Parameter:
Net_device: Network device structure.
Rx_buff: Recieve buffer.
Byte: Size of the Received buffer.

 */


static void mcs7780_receive(struct urb *purb ,struct pt_regs *regs)
{
	struct mcs7780_cb *mcs= purb->context;
	__u16 fcs = 0xffff;
	__u16 recieved_fcs = 0;
	__u32 fcs32 = 0xffffffff;
	__u32 recieved_fcs32 = 0;
	int i;
	if ((!mcs->netopen) || (!mcs->present)) {
		IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__);
		/* Don't re-submit the URB : will stall the Rx path */
		return;
	}
	// submitting the idle urb 
	mcs7780_rx_submit(mcs,mcs->idle_rx_urb);

	/* check the urb status */

	if(purb->status != 0)
	{
		switch(purb->status)
		{
			case -ECONNRESET:
				Drcv_printk("connection reset\n");
				break;
			default:
				Drcv_printk(" default value\n");
				break;
		}
		purb->actual_length=0;
	}
	if(purb->actual_length <= 0)
	{
		Drcv_printk(" start recieve timer and delay for 1ms\n");
	}

	/* check the speed data is received */

	Drcv_printk(" Actual length received:%d\n",purb->actual_length);
	if(purb->actual_length)
	{
		if(mcs->speed <= 115200)
		{
			Drcv_printk(" Extract data SIR packet\n");
			async_unwrap_char(mcs->netdev, &mcs->stats,&mcs->rx_buff, 0xc0);
			for (i = 0; i < purb->actual_length; i++) 
			{
				async_unwrap_char(mcs->netdev, &mcs->stats,&mcs->rx_buff,((unsigned char *)purb->transfer_buffer)[i]);
			}
			async_unwrap_char(mcs->netdev, &mcs->stats,&mcs->rx_buff, 0xc1);
		}
		else if(mcs->speed >= 576000 && mcs->speed <= 1152000)
		{
			Drcv_printk(" Extract data MIR packet\n");
				fcs = ComputeFCS((unsigned char *)purb->transfer_buffer,purb->actual_length - 2);
			memcpy(&recieved_fcs,&(((unsigned char *)purb->transfer_buffer)[purb->actual_length - 2]),2);
			if(fcs!=recieved_fcs)
			{
				printk("MIRcalculated fcs:0x%x\n",fcs);
				printk("MIRrecieved fcs:0x%x\n",recieved_fcs);
			}
			mcs7780_async_bump(mcs->netdev,&mcs->stats,(unsigned char *)purb->transfer_buffer,purb->actual_length);
		}
		else
		{
			Drcv_printk(" Extract data FIR packet\n");
			fcs32 = ComputeCrc32((unsigned char *)purb->transfer_buffer,purb->actual_length - 4);
			memcpy(&recieved_fcs32,&(((unsigned char *)purb->transfer_buffer)[purb->actual_length - 4]),4);
			if(fcs32!=recieved_fcs32)
			{
				printk("FIRcalculated fcs:0x%x\n",fcs32);
				printk("FIRrecieved fcs:0x%x\n",recieved_fcs32);
			}
			mcs7780_async_bump(mcs->netdev,&mcs->stats,(unsigned char *)purb->transfer_buffer,purb->actual_length-2);
		}
	}
	purb->context=NULL;
	mcs->idle_rx_urb = purb;
}


static void mcs7780_async_bump(struct net_device *dev, struct net_device_stats *stats, __u8 *buf, int len)
{
	struct sk_buff *skb;

	skb = dev_alloc_skb(len+1);
	if (!skb)  {
		stats->rx_dropped++;
		return;
	}

	/* Align IP header to 20 bytes */
	skb_reserve(skb, 1);

	/* Copy data without CRC */
	memcpy(skb_put(skb, len-2), buf, len-2);

	/* Feed it to IrLAP layer */
	skb->dev = dev;
	skb->mac.raw  = skb->data;
	skb->protocol = htons(ETH_P_IRDA);

	netif_rx(skb);
	stats->rx_packets++;
	stats->rx_bytes += len;
}



#define bulk_tx_timeout 2000

static int mcs7780_tx_submit(struct mcs7780_cb *mcs,struct urb *purb,struct sk_buff *skb)
{
//	struct urb *purb=&mcs->tx_urb;
	int txlen=0;
	int turnaround_time=0;
	int res;
	Dtx_printk("\n");

	if (purb->status != 0) {
		printk("%s(), URB still in use!\n", __FUNCTION__);
		Dg_printk("tx urb is null\n");
		return 1;
	}

	//	printk(" skb->len:%d txlen:%d\n",skb->len,txlen);

	if(mcs->speed <= 115200)
	{
		Dtx_printk("speed :%d \n",mcs->speed);
		txlen=mcs7780_wrap_sir_skb(skb,purb->transfer_buffer);
	}
	else if((mcs->speed > 115200) && (mcs->speed <= 1152000))
	{
		Dtx_printk("speed :%d \n",mcs->speed);
		txlen=mcs7780_wrap_mir_skb(skb,purb->transfer_buffer);
	}
	else
	{
		Dtx_printk("speed :%d \n",mcs->speed);
		txlen=mcs7780_wrap_fir_skb(skb,purb->transfer_buffer);

	}

	/* Prepare the URB for submission by calling usb_fill_bulk_urb( ). (Parameters for this call are urb, usbdev, pipe, txdata, tx_length,callbackfunction, private data structure mcs7780)(usb_fill_bulk_urb() sets mcs7780_write_bulk_callback() as callback function). */

	netif_wake_queue(mcs->netdev);
	usb_fill_bulk_urb(purb,mcs->usbdev,usb_sndbulkpipe(mcs->usbdev,mcs->bulk_out_ep),purb->transfer_buffer,txlen,mcs7780_write_bulk_callback,mcs);

	purb->transfer_buffer_length = txlen;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
	purb->transfer_flags = URB_ASYNC_UNLINK ;
	//	purb->transfer_flags = USB_QUEUE_BULK;
#endif

	//purb->timeout = MSECS_TO_JIFFIES(bulk_tx_timeout);
	purb->context = mcs;

	/*Utility function for getting the minimum turnaround time out of the skb. */
	turnaround_time=irda_get_mtt(skb);
	
	if(turnaround_time)
	{
		//printk(" turnaround time: %d \n",turnaround_time);
		if(mcs->speed > 115200)
		{
			if(!turboMode) 
			udelay(turnaround_time);
		}
		else
			udelay(turnaround_time);
		
	}
	if((res = usb_submit_urb(purb, GFP_ATOMIC)))
	{	
		Dtx_printk("Warning failed Tx_urb\n");
	}	
	else
	{
		mcs->stats.tx_packets++;
		mcs->stats.tx_bytes += skb->len;	
	}
	dev_kfree_skb(skb);
	return 0;
}

static void mcs7780_write_bulk_callback(struct urb *purb,struct pt_regs *regs)
{
	struct mcs7780_cb *mcs = purb->context;
	if(purb->status != 0) {
		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
		Dtx_printk("URB complete status %d, transfer_flags 0x%04X\n",purb->status, purb->transfer_flags);
		return;
	}
	if(mcs->new_speed != -1)
	{
		mcs->speed=mcs->new_speed;
		mcs->new_speed=-1;
		wake_up(&mcs->restore_state_event);
		mcs->thread_cond = 1;

	}
	/* Restart the transmission of data from the application. */
//	netif_wake_queue(mcs->netdev);
	return;
}


static __u16 ComputeFCS(__u8 *data, __u32 dataLen)
{
	__u16 fcs = 0xffff;
	__u32 i;

	for (i = 0; i < dataLen; i++){
		fcs = (fcs >> 8) ^ fcsTable[(fcs ^ *data++) & 0xff];
	}

	fcs = ~fcs;

	return fcs;
}


static unsigned int ComputeCrc32(unsigned char *Buffer,unsigned int Length)
{
	unsigned long Crc, Carry, CrcToReturn = 0;
	unsigned int i, j;
	unsigned char CurByte;

	Crc = 0xffffffff;

	for (i = 0; i < Length; i++) {

		CurByte = Buffer[i];

		for (j = 0; j < 8; j++) {

			Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);

			Crc <<= 1;

			CurByte >>= 1;

			if (Carry) {

				Crc = (Crc ^ 0x04c11db6) | Carry;

			}
		}

	}

	// First invert it
	Crc = ~Crc;

	// Now (bitwise) reverse it
	Carry = 0x1;
	for(i = 0; i < 32; i ++)
	{
		if(Crc & Carry)
		{
			CrcToReturn |= 0x1;
		}
		Carry <<= 1;
		if(i == 31)
			break;
		CrcToReturn <<= 1;
	}

	return CrcToReturn;
}

static void mcs7780_get_speed_bytes(int speed, __u16 *bytes)
{
	switch (speed) {
		case 2400:
			*bytes =MCS_SPEED_2400;
			break;
		default:
		case 9600:
			*bytes = MCS_SPEED_9600;
			break;
		case 19200:
			*bytes = (MCS_SPEED_19200);
			break;
		case 38400:
			*bytes = (MCS_SPEED_38400);
			break;
		case 57600:
			*bytes = (MCS_SPEED_57600);
			break;
		case 115200:
			*bytes = (MCS_SPEED_115200);
			break;
		case 576000:
			*bytes = (MCS_SPEED_576000);
			break;
		case 1152000:
			*bytes = (MCS_SPEED_1152000);
			break;
		case 4000000:
			*bytes = (MCS_FIR);
			break;
	}
}


static int __init mcs7780_init(void)
{
	memset(&g_mcs7780_cb, 0, sizeof(g_mcs7780_cb));

	if (usb_register(&mcs_driver) < 0)
		return -1;
	printk("USB IrDA support registered\n");
	return 0;
}

static void __exit mcs7780_cleanup(void)
{
	struct mcs7780_cb *mcs;
	int i;
	//int num;
	Dg_printk("%s start\n",__FUNCTION__);
	for (i = 0; i < NIRDA_USB; i++) 
	{
		mcs = &g_mcs7780_cb[i];
		/* If the Device is zombie */
		if((mcs->usbdev != NULL) && (mcs->present == 0)) {
			IRDA_DEBUG(0, "%s(), disconnect zombie now !\n",
					__FUNCTION__);
			printk("%s(), disconnect zombie now !\n",
					__FUNCTION__);
			//mcs7780_disconnect(mcs->usbdev, (void *) mcs);
		}
	}
	usb_deregister(&mcs_driver);
	Dg_printk("%s end\n",__FUNCTION__);
}


module_init(mcs7780_init);
module_exit(mcs7780_cleanup);

