diff mbox series

[SRU,B,1/4] UBUNTU: SAUCE: xr-usb-serial: Update driver for Exar USB serial ports

Message ID 20200219043805.11093-2-shrirang.bagul@canonical.com
State New
Headers show
Series UBUNTU: SAUCE: Updates to Exar USB serial driver | expand

Commit Message

Shrirang Bagul Feb. 19, 2020, 4:38 a.m. UTC
BugLink: http://bugs.launchpad.net/bugs/1863834

This patch adds the vendor release version on the Exar USB serial
device. Features include:
1. Fix for RX fail after wake-up from sleep (S3/S4)
2. Removes unnecessary debug messages

Changelog:

Version 1B, 11/6/2015
Fixed Bug: The conditional logic to support kernel 3.9 was
incorrect(line 396 in xr_usb_serial_common.c).

Version 1A, 1/9/2015
This driver will work with any USB UART function in these Exar devices:
	XR21V1410/1412/1414
	XR21B1411
	XR21B1420/1422/1424
	XR22801/802/804

Exar serial devices are typically enuremated as /dev/ttyXRUSB[0-3].

linux-oem buglink: http://bugs.launchpad.net/bugs/1685133

Signed-off-by: Shrirang Bagul <shrirang.bagul@canonical.com>
Acked-by: Colin Ian King <colin.king@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Timo Aaltonen <timo.aaltonen@canonical.com>
(cherry picked from commit db1290efc02fd20056795bc3c23df6f81e275a54)
(source tag: Ubuntu-oem-4.15.0-1073.83)
Signed-off-by: Shrirang Bagul <shrirang.bagul@canonical.com>
---
 ubuntu/xr-usb-serial/README.txt             |   3 +
 ubuntu/xr-usb-serial/xr_get_smbios.c        | 350 +++++++++++++++++
 ubuntu/xr-usb-serial/xr_get_smbios.h        | 237 ++++++++++++
 ubuntu/xr-usb-serial/xr_usb_serial_common.c | 392 +++++++++++++++-----
 ubuntu/xr-usb-serial/xr_usb_serial_common.h |  16 +-
 ubuntu/xr-usb-serial/xr_usb_serial_hal.c    | 244 ++++++++++--
 ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h  |   7 +
 7 files changed, 1119 insertions(+), 130 deletions(-)
 create mode 100644 ubuntu/xr-usb-serial/xr_get_smbios.c
 create mode 100644 ubuntu/xr-usb-serial/xr_get_smbios.h

Comments

Kleber Sacilotto de Souza Feb. 25, 2020, noon UTC | #1
On 19.02.20 05:38, Shrirang Bagul wrote:
> BugLink: http://bugs.launchpad.net/bugs/1863834

The above link should use https. This can be fixed when
applying it (if ACK'ed).

> 
> This patch adds the vendor release version on the Exar USB serial
> device. Features include:
> 1. Fix for RX fail after wake-up from sleep (S3/S4)
> 2. Removes unnecessary debug messages
> 
> Changelog:
> 
> Version 1B, 11/6/2015
> Fixed Bug: The conditional logic to support kernel 3.9 was
> incorrect(line 396 in xr_usb_serial_common.c).
> 
> Version 1A, 1/9/2015
> This driver will work with any USB UART function in these Exar devices:
> 	XR21V1410/1412/1414
> 	XR21B1411
> 	XR21B1420/1422/1424
> 	XR22801/802/804
> 
> Exar serial devices are typically enuremated as /dev/ttyXRUSB[0-3].
> 
> linux-oem buglink: http://bugs.launchpad.net/bugs/1685133
> 
> Signed-off-by: Shrirang Bagul <shrirang.bagul@canonical.com>
> Acked-by: Colin Ian King <colin.king@canonical.com>
> Acked-by: Stefan Bader <stefan.bader@canonical.com>
> Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
> Signed-off-by: Timo Aaltonen <timo.aaltonen@canonical.com>
> (cherry picked from commit db1290efc02fd20056795bc3c23df6f81e275a54)
> (source tag: Ubuntu-oem-4.15.0-1073.83)
> Signed-off-by: Shrirang Bagul <shrirang.bagul@canonical.com>
> ---
>  ubuntu/xr-usb-serial/README.txt             |   3 +
>  ubuntu/xr-usb-serial/xr_get_smbios.c        | 350 +++++++++++++++++
>  ubuntu/xr-usb-serial/xr_get_smbios.h        | 237 ++++++++++++
>  ubuntu/xr-usb-serial/xr_usb_serial_common.c | 392 +++++++++++++++-----
>  ubuntu/xr-usb-serial/xr_usb_serial_common.h |  16 +-
>  ubuntu/xr-usb-serial/xr_usb_serial_hal.c    | 244 ++++++++++--
>  ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h  |   7 +
>  7 files changed, 1119 insertions(+), 130 deletions(-)
>  create mode 100644 ubuntu/xr-usb-serial/xr_get_smbios.c
>  create mode 100644 ubuntu/xr-usb-serial/xr_get_smbios.h
> 
> diff --git a/ubuntu/xr-usb-serial/README.txt b/ubuntu/xr-usb-serial/README.txt
> index eb88f40f2080..242c8f368039 100644
> --- a/ubuntu/xr-usb-serial/README.txt
> +++ b/ubuntu/xr-usb-serial/README.txt
> @@ -1,5 +1,8 @@
>  Exar USB Serial Driver
>  ======================
> +Version 1B, 11/6/2015
> +Fixed Bug: The conditional logic to support kernel 3.9 was incorrect(line 396 in xr_usb_serial_common.c). 
> +
>  Version 1A, 1/9/2015
>  
>  This driver will work with any USB UART function in these Exar devices:
> diff --git a/ubuntu/xr-usb-serial/xr_get_smbios.c b/ubuntu/xr-usb-serial/xr_get_smbios.c
> new file mode 100644
> index 000000000000..05a995f1a957
> --- /dev/null
> +++ b/ubuntu/xr-usb-serial/xr_get_smbios.c
> @@ -0,0 +1,350 @@
> +/*
> + * 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
> + */
> +
> +static void *smbios_base = 0;
> +/** SM-BIOS entry point structure */
> +struct smbios_entry_point_struct *smbios_entry_point = 0;
> +/** DMI-BIOS entry point structure */
> +struct dmibios_entry_point_struct *dmibios_entry_point = 0;
> +/** SM-BIOS, resp. DMI-BIOS structures base address; starting point */
> +void *smbios_structures_base = 0;
> +/** enumeration of SM-BIOS, resp. DMI-BIOS types that do have subtypes */
> +__u8 smbios_types_with_subtypes[] = { TYPES_WITH_SUBTYPES };
> +/** contains the SMBIOS Version, e.g. V2.31 */
> +char smbios_version_string[32];
> +/** \fn unsigned char smbios_check_entry_point (void * addr)
> + *  \brief checks the entry point structure for correct checksum
> + *  \param addr pointer to the entry point structure
> + *  \return the checksum of the entry point structure, should be '0'
> + *
> + *  This function checks the entry point structure for correct checksum.
> + *  The checksum is calculated with adding every byte of the structure
> + *  to the checksum byte. The entry point structure is considered correct
> + *  if the checksum byte is 0.
> + *
> + *  \author Markus Lyra
> + *  \author Thomas Bretthauer
> + *  \date October 2000
> + */
> +
> +unsigned char smbios_check_entry_point (void *addr)
> +{
> +    unsigned char *i;
> +    unsigned char checksum = 0;
> +    unsigned char length =((struct smbios_entry_point_struct *) addr)->entry_point_length;
> +    /* calculate checksum for entry point structure (should be 0) */
> +    for (i = (unsigned char *) addr; i < (unsigned char *) addr + length; i++)
> +        checksum += *i;
> +    return checksum;
> +}
> +
> +struct smbios_entry_point_struct * smbios_find_entry_point (void *base)
> +{
> +    struct smbios_entry_point_struct *entry_point = 0;	/** SM-BIOS entry point */
> +    unsigned int *temp;				        /** temp. pointer       */
> +
> +
> +    /* search for the magic dword - '_SM_� as DWORD formatted -  on paragraph boundaries */
> +    for (temp = base;
> +		 !entry_point && temp < (unsigned int *) base + BIOS_MAP_LENGTH;
> +	     temp += 4)
> +	{
> +        /* found the identifier ? */
> +        if (*temp == SMBIOS_MAGIC_DWORD)
> +        {
> +            /* check if entry point valid (build checksum) */
> +	        if (!(smbios_check_entry_point (temp)))
> +	        {
> +	            entry_point = (struct smbios_entry_point_struct *) temp;
> +				
> +				/* fix display of Bios version string */
> +			    /* SMBios version is known as 2.1, 2.2, 2.3 and 2.3.1, never as 2.01 (JB) */
> +	            SM_BIOS_DEBUG("SM-BIOS V%d.%d entry point found at 0x%x\n",
> +		        entry_point->major_version, entry_point->minor_version, (unsigned int) temp);
> +
> +                SM_BIOS_DEBUG("V%d.%d\n", entry_point->major_version, entry_point->minor_version);
> +	        }
> +        }
> +    }
> +    return entry_point;
> +}
> +struct dmibios_entry_point_struct *dmibios_find_entry_point (void *base)
> +{
> +    struct dmibios_entry_point_struct *entry_point = 0;	    /** DMI-BIOS entry point */
> +    unsigned char *temp = 0;			                /** temp. pointer        */
> +    unsigned char biossignature[] =		                /** '_DMI20_NT_'         */
> +                { 0x5f, 0x44, 0x4d, 0x49, 0x32, 0x30, 0x5f, 0x4e, 0x54, 0x5f };
> +
> +    /* search for the DMI-BIOS signature on character boundary (hm?) */
> +    for (temp = base;
> +	       !entry_point && 
> +				 temp < (__u8 *) base + BIOS_MAP_LENGTH - sizeof (biossignature) - 32;
> +	       temp++)
> +	{
> +        unsigned long *tempdword = (unsigned long *) temp;
> +
> +        /* found the identifier '_DMI' ?     (beginning of signature) */
> +        if (*tempdword == DMIBIOS_MAGIC_DWORD)
> +        {
> +	        entry_point = (struct dmibios_entry_point_struct *) temp;
> +	
> +	        SM_BIOS_DEBUG ("DMI-BIOS revision %d entry point at 0x%x\n",
> +		    entry_point->revision, (unsigned int) temp);
> +
> +            sprintf(smbios_version_string, "V%d\n", entry_point->revision);
> +
> +	        if (memcmp (temp, biossignature, sizeof (biossignature)) == 0)
> +	            SM_BIOS_DEBUG ("DMI BIOS successfully identified\n");
> +        }
> +    }
> +    return entry_point;
> +}
> +void dump_smbios_hex(unsigned char *p,int len)
> +{
> +   int i;
> +   SM_BIOS_DEBUG("dump_smbios_hex length:%d\n",len);
> +   for(i=0;i<len;i++)
> +   {
> +      if((p[i] == 0xc0)&&(p[i+1]==0x06))  
> +	  	SM_BIOS_DEBUG("Found 0xc0 at offset:%d 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n\t",i,p[i],p[i+1],p[i+2],p[i+3],p[i+4],p[i+5]);
> +   }
> +}
> +int smbios_type_has_subtype (unsigned char type)
> +{
> +    int i;
> +
> +
> +    for (i = 0; i < sizeof (smbios_types_with_subtypes); i++)
> +        if (type == smbios_types_with_subtypes[i])
> +	        return 1;
> +
> +    return 0;
> +}
> +
> +int smbios_get_struct_length (struct smbios_struct * struct_ptr)
> +{
> +    /* jump to string list */
> +    unsigned char *ptr = (unsigned char *) struct_ptr + struct_ptr->length;
> +
> +    /* search for the end of string list */
> +    while (ptr[0] != 0x00 || ptr[1] != 0x00)
> +        ptr++;
> +    ptr += 2;			/* terminating 0x0000 should be included */
> +
> +    return (int) ptr - (int) struct_ptr;
> +}
> +
> +unsigned int smbios_get_readable_name(char *name, struct smbios_struct *struct_ptr)
> +{
> +    switch(struct_ptr->type)
> +    {
> +        case 0: return sprintf (name, "%s", RD_BIOS);
> +        case 1: return sprintf (name, "%s", RD_SYSTEM);
> +		case 2: return sprintf (name, "%s", RD_BASEBOARD);
> +		case 3: return sprintf (name, "%s", RD_ENCLOSURE);
> +		case 4: return sprintf (name, "%s", RD_PROCESSOR);
> +		case 5: return sprintf (name, "%s", RD_MEMCTRL);
> +		case 6: return sprintf (name, "%s", RD_MEMMOD);
> +		case 7: return sprintf (name, "%s", RD_CACHE);
> +		case 8: return sprintf (name, "%s", RD_PORT);
> +		case 9: return sprintf (name, "%s", RD_SLOT);
> +		case 10: return sprintf (name, "%s", RD_ONBOARD);
> +		case 11: return sprintf (name, "%s", RD_OEMSTRINGS);
> +		case 12: return sprintf (name, "%s", RD_SYSTEMCONFIG);
> +		case 13: return sprintf (name, "%s", RD_BIOSLANG);
> +		case 14: return sprintf (name, "%s", RD_GROUPASSOC);
> +		case 15: return sprintf (name, "%s", RD_EVENTLOG);
> +		case 16: return sprintf (name, "%s", RD_MEMARRAY);
> +		case 17: return sprintf (name, "%s", RD_MEMDEV);
> +		case 18: return sprintf (name, "%s", RD_32MEMERR);
> +		case 19: return sprintf (name, "%s", RD_MEMMAPPEDADR);
> +		case 20: return sprintf (name, "%s", RD_MEMMAPPEDDEV);
> +		case 21: return sprintf (name, "%s", RD_POINTINGDEV);
> +		case 22: return sprintf (name, "%s", RD_BATTERY);
> +		case 23: return sprintf (name, "%s", RD_RESET);
> +		case 24: return sprintf (name, "%s", RD_SECURITY);
> +		case 25: return sprintf (name, "%s", RD_PWRCTRL);
> +		case 26: return sprintf (name, "%s", RD_VOLTAGE);
> +		case 27: return sprintf (name, "%s", RD_COOLINGDEV);
> +		case 28: return sprintf (name, "%s", RD_TEMP);
> +		case 29: return sprintf (name, "%s", RD_CURRENT);
> +		case 30: return sprintf (name, "%s", RD_RMTACCESS);
> +		case 31: return sprintf (name, "%s", RD_BIS);
> +		case 32: return sprintf (name, "%s", RD_BOOT_INFO);
> +		case 33: return sprintf (name, "%s", RD_64MEMERR);
> +		case 34: return sprintf (name, "%s", RD_MANAGDEV);
> +		case 35: return sprintf (name, "%s", RD_MANAGDEVCOMP);
> +		case 36: return sprintf (name, "%s", RD_MANAGDEVTHRESH);
> +		case 37: return sprintf (name, "%s", RD_MEMCHANNEL);
> +		case 38: return sprintf (name, "%s", RD_IPMI);
> +		case 39: return sprintf (name, "%s", RD_PWRSUP);
> +		case 126: return sprintf (name, "%s", RD_INACTIVE);
> +		case 127: return sprintf (name, "%s", RD_EOT);
> +		default: return sprintf (name, "%d", struct_ptr->type);
> +    }
> +}
> +unsigned int smbios_get_readable_name_ext(char *name, struct smbios_struct *struct_ptr)
> +{
> +    return sprintf (name, "%d-%d", struct_ptr->type, struct_ptr->subtype);
> +}
> +
> +int smbios_make_dir_entries (void)
> +{
> +    int i;
> +    unsigned int raw_name_length = 0;	
> +    char raw_name[12];                      /* e.g. 0.0 for structure type 0 , first instance */
> +    unsigned int readable_name_length = 0;	
> +    char readable_name[64];                 /* e.g. Bios.0 for structure type 0 , first instance */
> +    struct smbios_struct *struct_ptr = smbios_structures_base;
> +    /*
> +     *  for every SMBIOS structure do ...
> +     */
> +    for (i = 0; i < smbios_entry_point->no_of_structures; i++)
> +    {
> +        memset(raw_name,0,12);
> +		memset(readable_name,0,64);
> +        /*
> +         *  generate an unique name for the file:  "type[-subtype].count"
> +         */
> +        if (smbios_type_has_subtype (((struct smbios_struct *) struct_ptr)->type))
> +        {
> +      /* name will contain the raw file name, it equals the structure type (e.g. 1 for Type 1).
> +             * readable_name contains the interpreted file name (e.g. System for Type 1)
> +             */
> +	        raw_name_length = sprintf (raw_name, "%d-%d", struct_ptr->type, struct_ptr->subtype);
> +            readable_name_length = smbios_get_readable_name_ext(readable_name, struct_ptr);
> +			//printk(KERN_INFO "[%s] smbios_type_has_subtype[%d] length:%d\n",raw_name,struct_ptr->type,struct_ptr->length);
> +        }
> +        else
> +        {
> +	        raw_name_length = sprintf (raw_name, "%d", struct_ptr->type);
> +            readable_name_length = smbios_get_readable_name(readable_name, struct_ptr);
> +			//printk(KERN_INFO "[%s] smbios_type_has type:%d length:%d\n",readable_name,struct_ptr->type,struct_ptr->length);
> +        }
> +
> +    /*
> +         *  go to the next structure
> +         */
> +        struct_ptr =(struct smbios_struct *) ((unsigned char *) struct_ptr + smbios_get_struct_length(struct_ptr));
> +    }
> +
> +    return 0;
> +}
> +
> +int smbios_check_if_have_exar_config(unsigned char *config0,unsigned char *config1)
> +{
> +	int i;
> +	int result = -1;
> +	unsigned char *p;
> +	smbios_base = ioremap (BIOS_START_ADDRESS, BIOS_MAP_LENGTH);
> +	if(!smbios_base)
> +	{
> +        SM_BIOS_DEBUG ("ioremap() for entry point failed\n");
> +        result = -ENXIO;
> +        return result;
> +    }
> +	//printk(KERN_INFO "ioremap bios base at 0x%p\n", smbios_base);	
> +	if (!(smbios_entry_point = smbios_find_entry_point (smbios_base)))
> +	{
> +		SM_BIOS_DEBUG ("SM-BIOS entry point not found\n");
> +		iounmap (smbios_base);
> +		result = -ENXIO;
> +        return result;
> +		
> +	}
> +	 /*
> +	 *	for SM-BIOS:
> +	 *	check if Pointer to DMI structures exist.
> +	 *	intermediate_string (_DMI_) is not '\0' terminated,
> +	 *	so strncmp() with sizeof(DMI_STRING) - 1 is needed.
> +	 */
> +	if (smbios_entry_point)
> +	{
> +		if (strncmp((char *) &(smbios_entry_point->intermediate_string),
> +						DMI_STRING, sizeof (DMI_STRING) - 1))
> +		{
> +			SM_BIOS_DEBUG ("Pointer to DMI structures not found!\n");
> +		   
> +		}
> +	}
> +	
> +	/*
> +	 *	map the SM-BIOS structures physical address range.
> +	 *	the 'real' smbios_structures_base contains the starting
> +	 *	address, where the instances of dmi structures are located.
> +	 */
> +	if (smbios_entry_point)
> +	{
> +		if (!(smbios_structures_base =
> +			  ioremap (smbios_entry_point->struct_table_address,
> +				(unsigned long) smbios_entry_point->struct_table_length)))
> +		{
> +			SM_BIOS_DEBUG("ioremap() for structures table failed\n");
> +			iounmap (smbios_base);
> +		    result = -ENXIO;
> +            return result;
> +	  	}
> +	}
> +	SM_BIOS_DEBUG(KERN_INFO "smbios_structures_base to 0x%p length %d no_of_structures:%d\n", 
> +		 		  smbios_structures_base,
> +		   		  smbios_entry_point->struct_table_length,
> +		          smbios_entry_point->no_of_structures);	
> +	
> +   //dump_smbios_hex((unsigned char *)smbios_structures_base,smbios_entry_point->struct_table_length);
> +   p = (unsigned char *)smbios_structures_base;
> +   for(i=0;i<smbios_entry_point->struct_table_length;i++)
> +   {
> +      if((p[i] == 0xc0)&&(p[i+1]==0x06)) 
> +      {
> +	  	SM_BIOS_DEBUG("Found 0xc0 at offset:%d 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n\t",i,p[i],p[i+1],p[i+2],p[i+3],p[i+4],p[i+5]);
> +		*config0 = p[i+4];
> +		*config1 = p[i+5];
> +		result = 0;
> +		break;
> +      }
> +   }
> +    //smbios_make_dir_entries();
> +    iounmap (smbios_structures_base);
> +	iounmap (smbios_base);
> +    return result;
> +
> +}
> +/*
> +void dmi_dump_backup(void)
> +{
> +	const char *board_vendor, *board_name,*board_serial;
> +	const struct dmi_device *dmi;
> +	struct dmi_dev_onboard *donboard;
> +	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
> +	board_name = dmi_get_system_info(DMI_BOARD_NAME);
> +	board_serial =  dmi_get_system_info(DMI_BOARD_SERIAL);
> +	printk(KERN_INFO "DMI_BOARD_VENDOR:%s\n",board_vendor);
> +	printk(KERN_INFO "DMI_BOARD_NAME:%s\n",board_name);
> +	printk(KERN_INFO "DMI_BOARD_SERIAL:%s\n",board_serial);
> +	for(i=0;i<256;i++)
> +	{
> +		dmi = NULL;
> +		//printk(KERN_INFO "dmi_find_device<%d>\n",i);
> +		while ((dmi = dmi_find_device(i,NULL, dmi)) != NULL) 
> +		{
> +		  //donboard = dmi->device_data;
> +		  printk(KERN_INFO "<%d>Found name:%s   type:%d \n",i,dmi->name,dmi->type);
> +		}
> +	}			
> +
> +}
> +*/
> +
> diff --git a/ubuntu/xr-usb-serial/xr_get_smbios.h b/ubuntu/xr-usb-serial/xr_get_smbios.h
> new file mode 100644
> index 000000000000..f56b33084dab
> --- /dev/null
> +++ b/ubuntu/xr-usb-serial/xr_get_smbios.h
> @@ -0,0 +1,237 @@
> +/* Copyright (C) 2001-2001 Fujitsu Siemens Computers
> +   Joachim Braeuer
> +   This file is part of smbios
> +
> +   smbios 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.
> +
> +   smbios 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 smbios; see the file COPYING. If not, write to the
> +   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
> +   Boston, MA 02111-1307, USA.
> +*/
> +
> +/* $Id: bios.h,v 1.2 2002/09/03 10:33:12 bretthauert Exp $
> + *
> + * $Log: bios.h,v $
> + * Revision 1.2  2002/09/03 10:33:12  bretthauert
> + * fixed a bug with 2.4 kernels (changed kmalloc parameter from
> + * GFP_BUFFER to GFP_KERNEL
> + *
> + * Revision 1.1  2001/09/15 14:52:43  bretthauert
> + * initial release
> + *
> + */
> +
> +/** \file bios.h
> + *  declarations and prototypes of DMI-BIOS and SM-BIOS stuff
> + *
> + *  \author Markus Lyra
> + *  \author Thomas Bretthauer
> + *  \author Joachim Braeuer
> + *  \version 0.11
> + *  \date January 2001
> + */
> +     
> +#ifndef __SM_BIOS_H__
> +#define __SM_BIOS_H__
> +
> +#include <linux/types.h>
> +//#define _EN_DEBUG_ 1
> +#ifdef _EN_DEBUG_
> +#  define SM_BIOS_DEBUG(fmt, args...) printk( KERN_DEBUG "smbios: " fmt, ## args)
> +#else
> +#  define SM_BIOS_DEBUG(fmt, args...) /* not debugging: nothing */
> +#endif
> +/*
> + *   Magic numbers
> + */
> +
> +/** start address of BIOS segment to scanned for SM-BIOS and DMI-BIOS */
> +#define BIOS_START_ADDRESS      0xF0000
> +/** length of the scanned BIOS area for SM-BIOS and DMI-BIOS */
> +#define BIOS_MAP_LENGTH         0x10000
> +/** magic 4 bytes to identify SM-BIOS entry point, paragraph boundary */
> +#define SMBIOS_MAGIC_DWORD      0x5F4D535F /* anchor string "_SM_" */
> +/** magic 4 bytes to identify DMI-BIOS entry point, byte boundary */
> +#define DMIBIOS_MAGIC_DWORD     0x494d445f /* anchor string "_DMI" */
> +/** identifier for SM-BIOS structures within SM-BIOS entry point */
> +#define DMI_STRING              "_DMI_"
> +/** list of types which are known to have subtyes; expandable! */
> +#define TYPES_WITH_SUBTYPES     185, 187, 208, 209, 210, 211, 212, 254
> +/** maximum block size for proc read function */
> +#define PROC_BLOCK_SIZE         (3*1024)
> +
> +
> +/** mode raw/cooked */
> +#define FILE_MODE_RAW       0
> +#define FILE_MODE_COOKED    1
> +
> +/*
> + *   Structures
> + */
> +
> +/** SM-BIOS entry point structure 
> + * the SMBIOS Entry Point structure described below can be located by
> + * application software by searching for the anchor string on paragraph
> + * (16 byte) boundaries within the physical memory address range 000F0000h to
> + * 000FFFFFh. This entry point encapsulates an intermediate anchor string
> + * that is used by some existing DMI browsers.
> + *
> + * @note While the SMBIOS Major and Minor Versions (offsets 06h and 07h)
> + * currently duplicate the information present in the SMBIOS BCD Revision
> + * (offset 1Dh), they provide a path for future growth in this specification.
> + * The BCD Revision, for example, provides only a single digit for each of
> + * the major and minor version numbers.
> + */
> +struct smbios_entry_point_struct
> +{
> +	/** "_SM_", specified as four ASCII characters (5F 53 4D 5F) */
> +  __u32 anchor_string;
> +	/** checksum of the Entry Point Structure (EPS). This value, when added to 
> +	 * all other bytes in the EPS, will result in the value 00h (using 8 bit
> +	 * addition calculations). Values in the EPS are summed starting at offset
> +	 * 00h, for Entry Point Length bytes.*/
> +  __u8  entry_point_checksum;
> +	/** Length of the Entry Point Structure, starting with the Anchor String 
> +	 * field, in bytes, currently 1Fh. */
> +  __u8  entry_point_length;
> +	/** identifies the major version of this specification implemented in
> +	 * the table structures, e.g. the value will be 0Ah for revision 10.22
> +	 * and 02h for revision 2.1 */
> +  __u8  major_version;
> +	/** identifies the minor version of this specification implemented in
> +	 * the table structures, e.g. the value will be 16h for revision 10.22
> +	 * and 01h for revision 2.1 */
> +  __u8  minor_version;
> +	/** size of the largest SMBIOS structure, in bytes, and encompasses the
> +	 * structure's formatted area and text strings. This is the value returned
> +	 * as StructureSize from the Plug-n-Play 'Get SMBIOS Information' function */
> +	__u16 max_struct_size;
> +	/** identifies the EPS revision implemented in this structure and identifies
> +	 * the formatting of offsets 0Bh to 0Fh, one of:
> +	 * 00h     Entry Point based on SMBIOS 2.1 definition; formatted area is
> +	 *         reserved and set to all 00h.
> +	 * 01h-FFh reserved for assignment via this specification */
> +  __u8  revision;
> +	/** the value present in the Entry Point Revision field defines the
> +	 * interpretation to be placed upon these5 bytes. */
> +  __u8  formated_area[5];
> +	/** "_DMI_", specified as five ASCII characters (5F 44 4D 49 5F) */
> +  __u8  intermediate_string[5];
> +	/** checksum of the Intermediate Entry Point Structure (IEPS). This value,
> +	 * when added to all other bytes in the IEPS, will result in the value 00h
> +	 * (using 8 bit addition calculations). Values in the IEPS are summed
> +	 * starting at offset 10h, for 0Fh bytes */
> +  __u8  intermediate_checksum;
> +	/** the 32 bit physical starting address of the read-only SMBIOS Structure
> +	 * Table, that can start at any 32 bit address. This area contains all of the
> +	 * SMBIOS structures fully packed together. These structures can then be
> +	 * parsed to produce exactly the same format as that returned from a 'Get
> +	 * SMBIOS Structure' function call. */
> +  __u16 struct_table_length;
> +  __u32 struct_table_address;
> +  __u16 no_of_structures;
> +  __u8  bcd_revision;
> +}__attribute__ ((packed));
> +
> +/** SM-BIOS and DMI-BIOS structure header */
> +struct smbios_struct
> +{
> +  __u8  type ;
> +  __u8  length ;
> +  __u16 handle ;
> +  __u8  subtype;
> +        /* ... other fields are structure dependend ... */
> +} __attribute__ ((packed));
> +
> +/** DMI-BIOS structure header */
> +struct dmibios_table_entry_struct
> +{
> +  __u16 size;
> +  __u16 handle;
> +  __u32 procedure;
> +}__attribute__ ((packed));
> +
> +/** DMI-BIOS entry point structure */
> +struct dmibios_entry_point_struct
> +{
> +  __u8  signature[10];
> +  __u8  revision;
> +  struct dmibios_table_entry_struct entry[1];
> +}__attribute__ ((packed));
> +
> +/** readable names for smbios structures, they serve as filenames in the /proc file system */
> +#define RD_BIOS								"bios"
> +#define RD_SYSTEM							"system"
> +#define RD_BASEBOARD						"baseboard"
> +#define RD_ENCLOSURE						"enclosure"
> +#define RD_PROCESSOR						"processor"
> +#define RD_MEMCTRL							"memory_controller"
> +#define RD_MEMMOD							"memory_module"
> +#define RD_CACHE							"cache"
> +#define RD_PORT								"port_connector"
> +#define RD_SLOT								"system_slot"
> +#define RD_ONBOARD							"onboard_device"
> +#define RD_OEMSTRINGS						"oem_strings"
> +#define RD_SYSTEMCONFIG					    "system_configuration"
> +#define RD_BIOSLANG							"bios_language"
> +#define RD_GROUPASSOC						"group_association"
> +#define RD_EVENTLOG							"system_event_log"
> +#define RD_MEMARRAY							"physical_memory_array"
> +#define RD_MEMDEV							"physical_memory_device"
> +#define RD_32MEMERR							"32bit_memory_error_information"
> +#define RD_MEMMAPPEDADR					    "memory_array_mapped_address"
> +#define RD_MEMMAPPEDDEV					    "memory_device_mapped_address"
> +#define RD_POINTINGDEV					    "pointing_device"
> +#define RD_BATTERY							"portable_battery"
> +#define RD_RESET							"system_reset"
> +#define RD_SECURITY							"hardware_security"
> +#define RD_PWRCTRL							"system_power_controls"
> +#define RD_VOLTAGE							"voltage_probe"
> +#define RD_COOLINGDEV						"cooling_device"
> +#define RD_TEMP								"temperature_probe"
> +#define RD_CURRENT							"current_probe"
> +#define RD_RMTACCESS						"out_of_band_remote_access"
> +#define RD_BIS								"boot_integrity_services"
> +#define RD_BOOT_INFO						"system_boot_information"
> +#define RD_64MEMERR							"64bit_memory_error_information"
> +#define RD_MANAGDEV							"management_device"
> +#define RD_MANAGDEVCOMP					    "management_device_component"
> +#define RD_MANAGDEVTHRESH				    "management_device_thresholds"
> +#define RD_MEMCHANNEL						"memory_channel"
> +#define RD_IPMI								"ipmi_information"
> +#define RD_PWRSUP							"system_power_supply"
> +#define RD_INACTIVE							"inactive"
> +#define RD_EOT								"end_of_table"
> +
> +
> +//extern smbios_entry_point_struct * smbios_entry_point;      /* start of SMBIOS within the F-Segment */
> +//extern dmibios_entry_point_struct * dmibios_entry_point;    /* start of DMIBIOS within the F-Segment */
> +extern void * smbios_structures_base;                       /* base of SMBIOS raw structures */
> +extern unsigned char smbios_types_with_subtypes[];
> +extern char smbios_version_string[32];                      /* e.g. V2.31 */
> +/*
> + *   Functions
> + */
> +
> +/* for the description see the implementation file */
> +struct smbios_entry_point_struct * smbios_find_entry_point(void * base);
> +struct dmibios_entry_point_struct * dmibios_find_entry_point(void * base);
> +unsigned char smbios_check_entry_point(void * addr);
> +int smbios_type_has_subtype(unsigned char type);
> +int smbios_get_struct_length(struct smbios_struct * struct_ptr);
> +int dmibios_get_struct_length(struct smbios_struct * struct_ptr);
> +unsigned int smbios_get_readable_name_ext(char *readable_name, struct smbios_struct *struct_ptr);
> +unsigned int smbios_get_readable_name(char *readable_name, struct smbios_struct *struct_ptr);
> +int smbios_check_if_have_exar_config(unsigned char *config0,unsigned char *config1);
> +
> +
> +#endif /* __BIOS_H__ */
> diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_common.c b/ubuntu/xr-usb-serial/xr_usb_serial_common.c
> index d16f072613b1..5d049855fb1a 100644
> --- a/ubuntu/xr-usb-serial/xr_usb_serial_common.c
> +++ b/ubuntu/xr-usb-serial/xr_usb_serial_common.c
> @@ -28,12 +28,12 @@
>   * from www.exar.com that will work with kernel versions 2.6.18 to 3.4.x.
>   *
>   * ChangeLog:
> - *            Version 1A - Initial released version.
> + *            Version 1B - Initial released version.
>   */
>  
> -//#undef DEBUG
> +#undef DEBUG
>  #undef VERBOSE_DEBUG
> -
> +#include <linux/gpio.h>
>  #include <linux/kernel.h>
>  #include <linux/errno.h>
>  #include <linux/init.h>
> @@ -47,15 +47,20 @@
>  #include <linux/uaccess.h>
>  #include <linux/usb.h>
>  #include <linux/usb/cdc.h>
> +#include <linux/dmi.h>
>  #include <asm/byteorder.h>
>  #include <asm/unaligned.h>
>  #include <linux/list.h>
> +#include <linux/delay.h>
> +#include <asm/io.h>		    /* ioremap() */
>  #include "linux/version.h"
>  
> +#include "xr_get_smbios.h"
>  #include "xr_usb_serial_common.h"
>  #include "xr_usb_serial_ioctl.h"
>  
>  
> +
>  #define DRIVER_AUTHOR "<uarttechsupport@exar.com>"
>  #define DRIVER_DESC "Exar USB UART (serial port) driver"
>  
> @@ -65,6 +70,10 @@ static struct xr_usb_serial *xr_usb_serial_table[XR_USB_SERIAL_TTY_MINORS];
>  
>  static DEFINE_MUTEX(xr_usb_serial_table_lock);
>  
> +
> +
> +
> +
>  /*
>   * xr_usb_serial_table accessors
>   */
> @@ -137,6 +146,7 @@ static int xr_usb_serial_ctrl_msg(struct xr_usb_serial *xr_usb_serial, int reque
>  	return retval < 0 ? retval : 0;
>  }
>  
> +#include "xr_get_smbios.c"
>  #include "xr_usb_serial_hal.c"
>  
>  
> @@ -249,46 +259,6 @@ static ssize_t show_country_rel_date
>  }
>  
>  static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
> -
> -static ssize_t set_rs485_422_en(struct device *dev,
> -				struct device_attribute *attr, const char *buf,
> -				size_t count)
> -{
> -	struct usb_interface *intf = to_usb_interface(dev);
> -	struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf);
> -	int error, value = 0;
> -
> -	error = kstrtoint(buf, 0, &value);
> -	if (error)
> -		return error;
> -
> -	if (value == 0) {
> -		xr_usb_serial->rs485_422_en = false;
> -	} else if (value == 1) {
> -		// RS485,RS422 HD/FD mode
> -		xr_usb_serial->rs485_422_en = true;
> -	}
> -
> -	return count;
> -}
> -
> -static ssize_t show_rs485_422_en(struct device *dev,
> -				 struct device_attribute *attr, char *buf)
> -{
> -	struct usb_interface *intf = to_usb_interface(dev);
> -	struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf);
> -
> -	if (xr_usb_serial->rs485_422_en == false) {
> -		return sprintf(buf, "0");
> -	} else if (xr_usb_serial->rs485_422_en == true) {
> -		// RS485,RS422 HD/FD mode
> -		return sprintf(buf, "1");
> -	}
> -	return 0;
> -}
> -
> -static DEVICE_ATTR(bRS485_422_en, 0644, show_rs485_422_en, set_rs485_422_en);
> -
>  /*
>   * Interrupt handlers for various XR_USB_SERIAL device responses
>   */
> @@ -298,7 +268,10 @@ static void xr_usb_serial_ctrl_irq(struct urb *urb)
>  {
>  	struct xr_usb_serial *xr_usb_serial = urb->context;
>  	struct usb_cdc_notification *dr = urb->transfer_buffer;
> -	struct tty_struct *tty;
> +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
> +#else
> +   	struct tty_struct *tty;
> +#endif
>  	unsigned char *data;
>  	int newctrl;
>  	int retval;
> @@ -309,10 +282,11 @@ static void xr_usb_serial_ctrl_irq(struct urb *urb)
>  	switch (status) {
>  	case 0:
>  		p = (unsigned char *)(urb->transfer_buffer);
> +		/*
>  		for(i=0;i<urb->actual_length;i++)
>  	    {
>            dev_dbg(&xr_usb_serial->control->dev,"0x%02x\n",p[i]);
> -	    }
> +	    }*/
>  		/* success */
>  		break;
>  	case -ECONNRESET:
> @@ -362,7 +336,7 @@ static void xr_usb_serial_ctrl_irq(struct urb *urb)
>  		}
>  #endif
>  		xr_usb_serial->ctrlin = newctrl;
> -
> +        #if 0
>  		dev_dbg(&xr_usb_serial->control->dev,
>  			"%s - input control lines: dcd%c dsr%c break%c "
>  			"ring%c framing%c parity%c overrun%c\n",
> @@ -374,6 +348,7 @@ static void xr_usb_serial_ctrl_irq(struct urb *urb)
>  			xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_FRAMING ? '+' : '-',
>  			xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_PARITY ? '+' : '-',
>  			xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_OVERRUN ? '+' : '-');
> +		#endif
>  			break;
>  
>  	default:
> @@ -399,7 +374,7 @@ static int xr_usb_serial_submit_read_urb(struct xr_usb_serial *xr_usb_serial, in
>  	if (!test_and_clear_bit(index, &xr_usb_serial->read_urbs_free))
>  		return 0;
>  
> -	dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d\n", __func__, index);
> +	//dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d\n", __func__, index);
>  
>  	res = usb_submit_urb(xr_usb_serial->read_urbs[index], mem_flags);
>  	if (res) {
> @@ -430,10 +405,75 @@ static int xr_usb_serial_submit_read_urbs(struct xr_usb_serial *xr_usb_serial, g
>  }
>  static void xr_usb_serial_process_read_urb(struct xr_usb_serial *xr_usb_serial, struct urb *urb)
>  {
> -    struct tty_struct *tty;
> +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
> +#else
> +   	struct tty_struct *tty;
> +#endif
> +	int    preciseflags    = xr_usb_serial->preciseflags;
> +	int    have_extra_byte;
> +	int    length;
> +	
>  	if (!urb->actual_length)
>  		return;
> -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)    
> +		
> +	if (preciseflags)
> +    {
> +        char *dp = urb->transfer_buffer;
> +        int i, ch, ch_flags;
> +		
> +        length = urb->actual_length;
> +        length = length + (xr_usb_serial->have_extra_byte ? 1 : 0);
> +        have_extra_byte = (preciseflags && (length & 1));
> +        length      = (preciseflags) ? (length / 2) : length;
> +        for (i = 0; i < length; ++i)
> +		{
> +                char tty_flag;
> +                if (i == 0)
> +				{
> +                    if (xr_usb_serial->have_extra_byte)
> +					{
> +                            ch = xr_usb_serial->extra_byte;
> +                    } 
> +					else
> +					{
> +                            ch = *dp++;
> +                    }
> +                } 
> +				else 
> +				{
> +                   ch = *dp++;
> +                }
> +                ch_flags = *dp++;
> +                if (ch_flags & RAMCTL_BUFFER_PARITY)
> +                        tty_flag = TTY_PARITY;
> +                else if (ch_flags & RAMCTL_BUFFER_BREAK)
> +                        tty_flag = TTY_BREAK;
> +                else if (ch_flags & RAMCTL_BUFFER_FRAME)
> +                        tty_flag = TTY_FRAME;
> +                else if (ch_flags & RAMCTL_BUFFER_OVERRUN)
> +                        tty_flag = TTY_OVERRUN;
> +                else
> +                        tty_flag = TTY_NORMAL;
> +
> +                
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
> +                tty_insert_flip_char(&xr_usb_serial->port, ch, tty_flag);
> +				tty_flip_buffer_push(&xr_usb_serial->port);
> +#else
> +				tty = tty_port_tty_get(&xr_usb_serial->port);
> +				if (!tty)
> +				return;
> +				tty_insert_flip_char(&xr_usb_serial->port, ch, tty_flag);
> +				tty_flip_buffer_push(tty);
> +
> +				tty_kref_put(tty);
> +#endif
> +				
> +        }
> +    }
> +	else
> +	{
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
>  	tty_insert_flip_string(&xr_usb_serial->port, urb->transfer_buffer,
>  			urb->actual_length);
>  	tty_flip_buffer_push(&xr_usb_serial->port);
> @@ -446,6 +486,7 @@ static void xr_usb_serial_process_read_urb(struct xr_usb_serial *xr_usb_serial,
>  
>  	tty_kref_put(tty);
>  #endif
> +	}
>  }
>  
>  static void xr_usb_serial_read_bulk_callback(struct urb *urb)
> @@ -453,9 +494,10 @@ static void xr_usb_serial_read_bulk_callback(struct urb *urb)
>  	struct xr_usb_serial_rb *rb = urb->context;
>  	struct xr_usb_serial *xr_usb_serial = rb->instance;
>  	unsigned long flags;
> -
> +    /*
>  	dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d, len %d\n", __func__,
> -					rb->index, urb->actual_length);
> +					rb->index, urb->actual_length);*/
> +	
>  	set_bit(rb->index, &xr_usb_serial->read_urbs_free);
>  
>  	if (!xr_usb_serial->dev) {
> @@ -467,7 +509,7 @@ static void xr_usb_serial_read_bulk_callback(struct urb *urb)
>  	if (urb->status) {
>  		dev_dbg(&xr_usb_serial->data->dev, "%s - non-zero urb status: %d\n",
>  							__func__, urb->status);
> -		return;
> +		//return;
>  	}
>  	xr_usb_serial_process_read_urb(xr_usb_serial, urb);
>  
> @@ -505,9 +547,13 @@ static void xr_usb_serial_write_bulk(struct urb *urb)
>  static void xr_usb_serial_softint(struct work_struct *work)
>  {
>  	struct xr_usb_serial *xr_usb_serial = container_of(work, struct xr_usb_serial, work);
> -    struct tty_struct *tty;
> +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
> +#else
> +		struct tty_struct *tty;
> +#endif
> +
>  	
> -	dev_vdbg(&xr_usb_serial->data->dev, "%s\n", __func__);
> +	//dev_vdbg(&xr_usb_serial->data->dev, "%s\n", __func__);
>  #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)
>  	tty_port_tty_wakeup(&xr_usb_serial->port);
>  #else	
> @@ -528,7 +574,7 @@ static int xr_usb_serial_tty_install(struct tty_driver *driver, struct tty_struc
>  	struct xr_usb_serial *xr_usb_serial;
>  	int retval;
>  
> -	dev_dbg(tty->dev, "%s\n", __func__);
> +	//dev_dbg(tty->dev, "%s\n", __func__);
>  
>  	xr_usb_serial = xr_usb_serial_get_by_index(tty->index);
>  	if (!xr_usb_serial)
> @@ -550,9 +596,10 @@ static int xr_usb_serial_tty_install(struct tty_driver *driver, struct tty_struc
>  static int xr_usb_serial_tty_open(struct tty_struct *tty, struct file *filp)
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
> -
> -	dev_dbg(tty->dev, "%s\n", __func__);
> -
> +	int result;
> +    result = xr_usb_serial_fifo_reset(xr_usb_serial);
> +	//dev_dbg(tty->dev, "%s\n", __func__);
> +    
>  	return tty_port_open(&xr_usb_serial->port, tty, filp);
>  }
>  
> @@ -561,7 +608,7 @@ static int xr_usb_serial_port_activate(struct tty_port *port, struct tty_struct
>  	struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port);
>  	int retval = -ENODEV;
>  
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>  
>  	mutex_lock(&xr_usb_serial->mutex);
>  	if (xr_usb_serial->disconnected)
> @@ -624,14 +671,18 @@ static void xr_usb_serial_port_destruct(struct tty_port *port)
>  {
>  	struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port);
>  
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>      #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
>  	tty_unregister_device(xr_usb_serial_tty_driver, xr_usb_serial->minor);
>  	#endif
> +#ifdef CONFIG_GPIOLIB	
> +	gpiochip_remove(&xr_usb_serial->xr_usb_gpio); 
> +#endif
>  	xr_usb_serial_release_minor(xr_usb_serial);
>  	usb_put_intf(xr_usb_serial->control);
>  	kfree(xr_usb_serial->country_codes);
>  	kfree(xr_usb_serial);
> +	
>  }
>  
>  static void xr_usb_serial_port_shutdown(struct tty_port *port)
> @@ -639,7 +690,7 @@ static void xr_usb_serial_port_shutdown(struct tty_port *port)
>  	struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port);
>  	int i;
>  
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>  
>  	mutex_lock(&xr_usb_serial->mutex);
>  	if (!xr_usb_serial->disconnected) {
> @@ -659,21 +710,21 @@ static void xr_usb_serial_port_shutdown(struct tty_port *port)
>  static void xr_usb_serial_tty_cleanup(struct tty_struct *tty)
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>  	tty_port_put(&xr_usb_serial->port);
>  }
>  
>  static void xr_usb_serial_tty_hangup(struct tty_struct *tty)
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>  	tty_port_hangup(&xr_usb_serial->port);
>  }
>  
>  static void xr_usb_serial_tty_close(struct tty_struct *tty, struct file *filp)
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>  	tty_port_close(&xr_usb_serial->port, tty, filp);
>  }
>  
> @@ -689,7 +740,7 @@ static int xr_usb_serial_tty_write(struct tty_struct *tty,
>  	if (!count)
>  		return 0;
>  
> -	dev_vdbg(&xr_usb_serial->data->dev, "%s - count %d\n", __func__, count);
> +	//dev_vdbg(&xr_usb_serial->data->dev, "%s - count %d\n", __func__, count);
>  
>  	spin_lock_irqsave(&xr_usb_serial->write_lock, flags);
>  	wbn = xr_usb_serial_wb_alloc(xr_usb_serial);
> @@ -706,7 +757,7 @@ static int xr_usb_serial_tty_write(struct tty_struct *tty,
>  	}
>  
>  	count = (count > xr_usb_serial->writesize) ? xr_usb_serial->writesize : count;
> -	dev_vdbg(&xr_usb_serial->data->dev, "%s - write %d\n", __func__, count);
> +	//dev_vdbg(&xr_usb_serial->data->dev, "%s - write %d\n", __func__, count);
>  	memcpy(wb->buf, buf, count);
>  	wb->len = count;
>  
> @@ -785,7 +836,7 @@ static int xr_usb_serial_tty_break_ctl(struct tty_struct *tty, int state)
>  
>  	retval = xr_usb_serial_send_break(xr_usb_serial, state ? 0xffff : 0);
>  	if (retval < 0)
> -		dev_dbg(&xr_usb_serial->control->dev, "%s - send break failed\n",
> +		dev_err(&xr_usb_serial->control->dev, "%s - send break failed\n",
>  								__func__);
>  	return retval;
>  }
> @@ -793,7 +844,7 @@ static int xr_usb_serial_tty_break_ctl(struct tty_struct *tty, int state)
>  static int xr_usb_serial_tty_tiocmget(struct tty_struct *tty)
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
> -	dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmget\n");
> +	//dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmget\n");
>      return xr_usb_serial_tiocmget(xr_usb_serial);
>  
>  }
> @@ -802,7 +853,7 @@ static int xr_usb_serial_tty_tiocmset(struct tty_struct *tty,
>  			    unsigned int set, unsigned int clear)
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
> -	dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmset set=0x%x clear=0x%x\n",set,clear);
> +	//dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmset set=0x%x clear=0x%x\n",set,clear);
>      return xr_usb_serial_tiocmset(xr_usb_serial,set,clear);
>  
>  }
> @@ -865,8 +916,9 @@ static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
>  {
>  	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
>  	int rv = -ENOIOCTLCMD;
> -    unsigned int  channel, reg, val;
> -
> +    unsigned int  channel, reg, val,preciseflags;
> +    int           baud_rate = 0;
> +	struct usb_cdc_line_coding newline;
>      short	*data;
>  	switch (cmd) {
>  	case TIOCGSERIAL: /* gets serial port data */
> @@ -895,7 +947,8 @@ static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
>  				{
>  			  	  rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,reg, data);
>  				}
> -                if (rv != 1) {
> +                if (rv < 0)
> +                {
>                          dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d)\n", rv);
>                          kfree(data);
>                          return -EFAULT;
> @@ -941,6 +994,93 @@ static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
>                 return -EFAULT;
>  			 rv = 0;
>  		     break;
> +	 case XR_USB_SERIAL_SET_GPIO_MODE_REG:
> +		xr_usb_serial_disable(xr_usb_serial);
> +		if (get_user(channel, (int __user *)arg))
> +		    return -EFAULT;
> +		if (get_user(val, (int __user *)(arg + sizeof(int))))
> +		    return -EFAULT;
> +	   	if (channel == -1)
> +		{
> +			//block = portdata->block;
> +		    rv = xr_usb_serial_set_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, val);
> +		}
> +		else
> +		{
> +		    rv = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr, val);
> +		}
> +		
> +		dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_SET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,val);
> +		xr_usb_serial_enable(xr_usb_serial);
> +		if (rv < 0)
> +		        return -EFAULT;
> +		break;
> +	case XR_USB_SERIAL_GET_GPIO_MODE_REG:
> +		xr_usb_serial_disable(xr_usb_serial);
> +		if (get_user(channel, (int __user *)arg))
> +                        return -EFAULT;
> +       
> +        data = kmalloc(2, GFP_KERNEL);
> +        if (data == NULL) {
> +                dev_err(&xr_usb_serial->control->dev, "%s - Cannot allocate USB buffer.\n", __func__);
> +                return -ENOMEM;
> +		}
> +
> +		if (channel == -1)
> +		{
> +		     rv = xr_usb_serial_get_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, data);
> +		}
> +		else
> +		{
> +		    rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr,data);
> +		}
> +		
> +		xr_usb_serial_enable(xr_usb_serial);
> +		
> +		dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_GET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,*data);
> +		
> +        if (rv < 0 ) {
> +                dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d) channel=%d \n", rv,channel);
> +                kfree(data);
> +                return -EFAULT;
> +        }
> +				
> +        if (put_user(data[0], (int __user *)(arg + sizeof(int)))) {
> +                dev_err(&xr_usb_serial->control->dev, "Cannot put user result\n");
> +                kfree(data);
> +                return -EFAULT;
> +        }
> +
> +        kfree(data);
> +		break;
> +	case XRIOC_SET_ANY_BAUD_RATE:
> +		
> +		 if (get_user(baud_rate, (int __user *)arg)) {
> +		 	   dev_dbg(&xr_usb_serial->control->dev, "get_user errot \n");
> +               return -EFAULT;
> +		 }
> +		 xr_usb_serial->line.dwDTERate = baud_rate; 
> +		 memcpy(&newline,&(xr_usb_serial->line),sizeof(struct usb_cdc_line_coding));
> +		 xr_usb_serial_disable(xr_usb_serial);
> +		 rv = xr_usb_serial_set_line(xr_usb_serial,&newline);
> +		 xr_usb_serial_enable(xr_usb_serial);
> +		 dev_dbg(&xr_usb_serial->control->dev, "XRIOC_SET_ANY_BAUD_RATE set baud_rate:%d ret=%d\n", baud_rate,rv);
> +		 break;	
> +	case XRIOC_SET_PRECISE_FLAGS:
> +		 preciseflags = arg;
> +		 dev_dbg(&xr_usb_serial->control->dev, "%s VIOC_SET_PRECISE_FLAGS %d\n", __func__, preciseflags);
> +		 xr_usb_serial_disable(xr_usb_serial);
> +		 if (preciseflags) 
> +		 {
> +		        xr_usb_serial->preciseflags = 1;
> +		 } 
> +		 else 
> +		 {
> +		        xr_usb_serial->preciseflags = 0;
> +		 }
> +		 xr_usb_serial_set_wide_mode(xr_usb_serial,xr_usb_serial->preciseflags);
> +		 xr_usb_serial_enable(xr_usb_serial);
> +		 break;	 
>  		
>  	}
>  
> @@ -965,9 +1105,11 @@ static void xr_usb_serial_tty_set_termios(struct tty_struct *tty,
>  	newline.bParityType = termios->c_cflag & PARENB ?
>  				(termios->c_cflag & PARODD ? 1 : 2) +
>  				(termios->c_cflag & CMSPAR ? 2 : 0) : 0;
> +	xr_usb_serial->trans9 = 0;
>  	switch (termios->c_cflag & CSIZE) {
>  	case CS5:/*using CS5 replace of the 9 bit data mode*/
>  		newline.bDataBits = 9;
> +		xr_usb_serial->trans9 =1;
>  		break;
>  	case CS6:
>  		newline.bDataBits = 6;
> @@ -993,15 +1135,27 @@ static void xr_usb_serial_tty_set_termios(struct tty_struct *tty,
>  		xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout = newctrl);
>  	
>      xr_usb_serial_set_flow_mode(xr_usb_serial,tty,cflag);/*set the serial flow mode*/
> -	 	
> +    if (xr_usb_serial->trans9) 
> +	{
> +       /* Turn on wide mode if we're 9-bit transparent. */
> +       	xr_usb_serial_set_wide_mode(xr_usb_serial,1);
> +    } 
> +	else if (!xr_usb_serial->preciseflags) 
> +	{
> +        xr_usb_serial_set_wide_mode(xr_usb_serial,0);
> +    }
> +
> +		
>  	if (memcmp(&xr_usb_serial->line, &newline, sizeof newline))
>  	{
>  		memcpy(&xr_usb_serial->line, &newline, sizeof newline);
> +		/*
>  		dev_dbg(&xr_usb_serial->control->dev, "%s - set line: %d %d %d %d\n",
>  			__func__,
>  			le32_to_cpu(newline.dwDTERate),
>  			newline.bCharFormat, newline.bParityType,
> -			newline.bDataBits);
> +			newline.bDataBits);*/
> +		
>  		xr_usb_serial_set_line(xr_usb_serial, &xr_usb_serial->line);
>  	}
>  	xr_usb_serial_enable(xr_usb_serial);
> @@ -1060,6 +1214,36 @@ static int xr_usb_serial_write_buffers_alloc(struct xr_usb_serial *xr_usb_serial
>  	return 0;
>  }
>  
> +#ifdef CONFIG_GPIOLIB
> +static int xr_usb_gpio_get(struct gpio_chip *chip, unsigned offset)
> +{
> +    struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
> +	dev_dbg(chip->dev, "xr_usb_gpio_get offset = %d channel = %d\n",offset,xr_usb_serial->channel);
> +	return 0;
> +}
> +
> +static void xr_usb_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
> +{
> +   struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
> +   dev_dbg(chip->dev, "xr_usb_gpio_set offset =%d val=%d channel = %d\n",offset,val,xr_usb_serial->channel);
> +}
> +
> +static int xr_usb_gpio_direction_input(struct gpio_chip *chip,unsigned offset)
> +{
> +	struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
> +    dev_dbg(chip->dev, "xr_usb_gpio_direction_input offset =%d channel = %d\n",offset,xr_usb_serial->channel);
> +	return 0;
> +}
> +
> +static int xr_usb_gpio_direction_output(struct gpio_chip *chip,
> +					   unsigned offset, int val)
> +{
> +    struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
> +	dev_dbg(chip->dev, "xr_usb_gpio_direction_output offset =%d val=%d channel:%d\n",offset,val,xr_usb_serial->channel);
> +	return 0;
> +}
> +#endif
> +
>  static int xr_usb_serial_probe(struct usb_interface *intf,
>  		     const struct usb_device_id *id)
>  {
> @@ -1096,7 +1280,7 @@ static int xr_usb_serial_probe(struct usb_interface *intf,
>  
>  	num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : XR_USB_SERIAL_NR;
>  	
> -    dev_dbg(&intf->dev, "USB_device_id idVendor:%04x, idProduct %04x\n",id->idVendor,id->idProduct);
> +    //dev_dbg(&intf->dev, "USB_device_id idVendor:%04x, idProduct %04x\n",id->idVendor,id->idProduct);
>  	
>  	/* handle quirks deadly to normal probing*/
>  	if (quirks == NO_UNION_NORMAL) {
> @@ -1337,7 +1521,7 @@ static int xr_usb_serial_probe(struct usb_interface *intf,
>  	}
>  	#else
>  	xr_usb_serial->channel = epwrite->bEndpointAddress;
> -	dev_dbg(&intf->dev, "epwrite->bEndpointAddress =%d\n",epwrite->bEndpointAddress);
> +	//dev_dbg(&intf->dev, "epwrite->bEndpointAddress =%d\n",epwrite->bEndpointAddress);
>  	#endif
>  	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &xr_usb_serial->ctrl_dma);
>  	if (!buf) {
> @@ -1424,14 +1608,9 @@ static int xr_usb_serial_probe(struct usb_interface *intf,
>  
>  	usb_set_intfdata(intf, xr_usb_serial);
>  
> -	xr_usb_serial->rs485_422_en = false;	//default enable rs232
> -	i = device_create_file(&intf->dev, &dev_attr_bRS485_422_en);
> -	if (i < 0)
> -		goto alloc_fail7;
> -
>  	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
>  	if (i < 0)
> -		goto alloc_fail8;
> +		goto alloc_fail7;
>  
>  	if (cfd) { /* export the country data */
>  		xr_usb_serial->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
> @@ -1470,7 +1649,7 @@ static int xr_usb_serial_probe(struct usb_interface *intf,
>  	xr_usb_serial->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
>  	xr_usb_serial->ctrlurb->transfer_dma = xr_usb_serial->ctrl_dma;
>  
> -	dev_info(&intf->dev, "ttyXR_USB_SERIAL%d: USB XR_USB_SERIAL device\n", minor);
> +	//dev_info(&intf->dev, "ttyXR_USB_SERIAL%d: USB XR_USB_SERIAL device channel:%d\n", minor,xr_usb_serial->channel);
>  	
>      xr_usb_serial_pre_setup(xr_usb_serial);
>  	
> @@ -1491,12 +1670,26 @@ static int xr_usb_serial_probe(struct usb_interface *intf,
>  			&control_interface->dev);
>  	if (IS_ERR(tty_dev)) {
>  		rv = PTR_ERR(tty_dev);
> -		goto alloc_fail9;
> +		goto alloc_fail8;
>  	}
>  #endif	
> -
> +#ifdef CONFIG_GPIOLIB	
> +   	/* Setup GPIO cotroller */
> +	xr_usb_serial->xr_usb_gpio.owner		 = THIS_MODULE;
> +	xr_usb_serial->xr_usb_gpio.dev		 = &control_interface->dev;
> +	xr_usb_serial->xr_usb_gpio.label		 = dev_name(&control_interface->dev);
> +	xr_usb_serial->xr_usb_gpio.direction_input	 = xr_usb_gpio_direction_input;
> +	xr_usb_serial->xr_usb_gpio.get		 = xr_usb_gpio_get;
> +	xr_usb_serial->xr_usb_gpio.direction_output = xr_usb_gpio_direction_output;
> +	xr_usb_serial->xr_usb_gpio.set		 = xr_usb_gpio_set;
> +	xr_usb_serial->xr_usb_gpio.base		 = 100 + xr_usb_serial->channel*10;
> +	xr_usb_serial->xr_usb_gpio.ngpio		 = 4;
> +	xr_usb_serial->xr_usb_gpio.can_sleep	 = 1;
> +	rv = gpiochip_add(&xr_usb_serial->xr_usb_gpio);
> +	dev_dbg(&xr_usb_serial->control->dev, "gpiochip_add %d\n",rv);
> +#endif		
>  	return 0;
> -alloc_fail9:
> +alloc_fail8:
>  	if (xr_usb_serial->country_codes) {
>  		device_remove_file(&xr_usb_serial->control->dev,
>  				&dev_attr_wCountryCodes);
> @@ -1504,8 +1697,6 @@ static int xr_usb_serial_probe(struct usb_interface *intf,
>  				&dev_attr_iCountryCodeRelDate);
>  	}
>  	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bmCapabilities);
> -alloc_fail8:
> -	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bRS485_422_en);
>  alloc_fail7:
>  	usb_set_intfdata(intf, NULL);
>  	for (i = 0; i < XR_USB_SERIAL_NW; i++)
> @@ -1530,7 +1721,7 @@ static void stop_data_traffic(struct xr_usb_serial *xr_usb_serial)
>  {
>  	int i;
>  
> -	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
> +	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
>  
>  	usb_kill_urb(xr_usb_serial->ctrlurb);
>  	for (i = 0; i < XR_USB_SERIAL_NW; i++)
> @@ -1548,7 +1739,7 @@ static void xr_usb_serial_disconnect(struct usb_interface *intf)
>  	struct tty_struct *tty;
>  	int i;
>  
> -	dev_dbg(&intf->dev, "%s\n", __func__);
> +	//dev_dbg(&intf->dev, "%s\n", __func__);
>  
>  	/* sibling interface is already cleaning up */
>  	if (!xr_usb_serial)
> @@ -1563,7 +1754,6 @@ static void xr_usb_serial_disconnect(struct usb_interface *intf)
>  				&dev_attr_iCountryCodeRelDate);
>  	}
>  	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bmCapabilities);
> -	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bRS485_422_en);
>  	usb_set_intfdata(xr_usb_serial->control, NULL);
>  	usb_set_intfdata(xr_usb_serial->data, NULL);
>  	mutex_unlock(&xr_usb_serial->mutex);
> @@ -1631,7 +1821,9 @@ static int xr_usb_serial_resume(struct usb_interface *intf)
>  	struct xr_usb_serial_wb *wb;
>  	int rv = 0;
>  	int cnt;
> -
> +	     
> +	xr_usb_serial_pre_setup(xr_usb_serial);
> +	
>  	spin_lock_irq(&xr_usb_serial->read_lock);
>  	xr_usb_serial->susp_count -= 1;
>  	cnt = xr_usb_serial->susp_count;
> @@ -1670,7 +1862,10 @@ static int xr_usb_serial_resume(struct usb_interface *intf)
>  static int xr_usb_serial_reset_resume(struct usb_interface *intf)
>  {
>  	struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf);
> -    struct tty_struct *tty;
> +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
> +#else
> +   	struct tty_struct *tty;
> +#endif
>  	if (test_bit(ASYNCB_INITIALIZED, &xr_usb_serial->port.flags)){
>  #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
>  	tty_port_tty_hangup(&xr_usb_serial->port, false);
> @@ -1745,14 +1940,11 @@ static const struct tty_operations xr_usb_serial_ops = {
>  	.tiocmget =		xr_usb_serial_tty_tiocmget,
>  	.tiocmset =		xr_usb_serial_tty_tiocmset,
>  };
> -
> -/*
> - * Init / exit.
> - */
> -
>  static int __init xr_usb_serial_init(void)
>  {
>  	int retval;
> +	int i;
> +	
>  	xr_usb_serial_tty_driver = alloc_tty_driver(XR_USB_SERIAL_TTY_MINORS);
>  	if (!xr_usb_serial_tty_driver)
>  		return -ENOMEM;
> @@ -1780,17 +1972,17 @@ static int __init xr_usb_serial_init(void)
>  		put_tty_driver(xr_usb_serial_tty_driver);
>  		return retval;
>  	}
> -
> +  
>  	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
>  
>  	return 0;
>  }
> -
>  static void __exit xr_usb_serial_exit(void)
>  {
>  	usb_deregister(&xr_usb_serial_driver);
>  	tty_unregister_driver(xr_usb_serial_tty_driver);
>  	put_tty_driver(xr_usb_serial_tty_driver);
> +	
>  }
>  
>  module_init(xr_usb_serial_init);
> diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_common.h b/ubuntu/xr-usb-serial/xr_usb_serial_common.h
> index fe3460c57adf..97e902425794 100644
> --- a/ubuntu/xr-usb-serial/xr_usb_serial_common.h
> +++ b/ubuntu/xr-usb-serial/xr_usb_serial_common.h
> @@ -70,6 +70,11 @@
>  #define XR_USB_SERIAL_NW  16
>  #define XR_USB_SERIAL_NR  16
>  
> +#define RAMCTL_BUFFER_PARITY                               0x1
> +#define RAMCTL_BUFFER_BREAK                                0x2
> +#define RAMCTL_BUFFER_FRAME                                0x4
> +#define RAMCTL_BUFFER_OVERRUN                              0x8
> +
>  struct xr_usb_serial_wb {
>  	unsigned char *buf;
>  	dma_addr_t dmah;
> @@ -144,10 +149,19 @@ struct xr_usb_serial {
>  	u8 bInterval;
>  	struct xr_usb_serial_wb *delayed_wb;			/* write queued for a device about to be woken */
>  	unsigned int channel;
> +	int           preciseflags; /* USB: wide mode, TTY: flags per character */
> +    int           trans9;   /* USB: wide mode, serial 9N1 */
> +	int           have_extra_byte;
> +    int           extra_byte;
> +	
>  	unsigned short DeviceVendor;
>  	unsigned short DeviceProduct;
> +#ifdef CONFIG_GPIOLIB	
> +	struct gpio_chip   xr_usb_gpio;
> +#endif
>  	struct reg_addr_map reg_map;
> -	bool rs485_422_en;
> +    int found_smbios_exar_config;
> +	unsigned char channel_config;
>  };
>  
>  #define CDC_DATA_INTERFACE_TYPE	0x0a
> diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_hal.c b/ubuntu/xr-usb-serial/xr_usb_serial_hal.c
> index f44970995368..bf9d2bf136ac 100644
> --- a/ubuntu/xr-usb-serial/xr_usb_serial_hal.c
> +++ b/ubuntu/xr-usb-serial/xr_usb_serial_hal.c
> @@ -31,7 +31,7 @@ int xr_usb_serial_set_reg(struct xr_usb_serial *xr_usb_serial,int regnum, int va
>  {
>  	int result;
>  	int channel = 0;
> -	dev_dbg(&xr_usb_serial->control->dev, "%s Channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
> +	//dev_info(&xr_usb_serial->control->dev, "%s Channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
>  	if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1400)
>  	{
>  	    int XR2280xaddr = XR2280x_FUNC_MGR_OFFSET + regnum; 
> @@ -97,7 +97,7 @@ int xr_usb_serial_set_reg(struct xr_usb_serial *xr_usb_serial,int regnum, int va
>  	    result = -1;
>  	}
>  	if(result < 0)
> -		dev_dbg(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
> +		dev_err(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
>      return result;
>  	
>         
> @@ -106,7 +106,7 @@ int xr_usb_serial_set_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
>  {
>  	int result;
>  	int XR2280xaddr = XR2280x_FUNC_MGR_OFFSET + regnum; 
> -	dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
> +	//dev_info(&xr_usb_serial->control->dev, "%s channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
>  	if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1400)
>  	{
>  		result = usb_control_msg(xr_usb_serial->dev,                     /* usb device */
> @@ -165,7 +165,7 @@ int xr_usb_serial_set_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
>  	    result = -1;
>  	}
>  	if(result < 0)
> -		dev_dbg(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
> +		dev_err(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
>      return result;
>  	
>         
> @@ -242,9 +242,9 @@ int xr_usb_serial_get_reg(struct xr_usb_serial *xr_usb_serial,int regnum, short
>  	}
>  	
>  	if(result < 0)
> -		dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d Reg 0x%x Error:%d\n", __func__,channel,regnum,result);
> -	else
> -	    dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
> +		dev_err(&xr_usb_serial->control->dev, "%s channel:%d Reg 0x%x Error:%d\n", __func__,channel,regnum,result);
> +	//else
> +	    //dev_info(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
>  	
>  	return result;
>  
> @@ -285,7 +285,7 @@ int xr_usb_serial_get_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
>                                   &reg_value,                           /* data */
>                                   1,                               /* size */
>                                   5000);                           /* timeout */
> -	   dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_get_reg_ext reg:%x\n",reg_value);
> +	   //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_get_reg_ext reg:%x\n",reg_value);
>  	   *value = reg_value; 
>  	}
>  	else if(xr_usb_serial->DeviceProduct == 0x1411) 
> @@ -320,9 +320,9 @@ int xr_usb_serial_get_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
>  	}
>  	
>  	if(result < 0)
> -		dev_dbg(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
> -	else
> -	    dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
> +		dev_err(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
> +	//else
> +	    //dev_info(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
>  	
>  	return result;
>  
> @@ -384,7 +384,7 @@ static int xr21v141x_set_baud_rate(struct xr_usb_serial *xr_usb_serial, unsigned
>  	unsigned int 	tx_mask = xr21v141x_baud_rates[i].tx;
>  	unsigned int 	rx_mask = (divisor & 1) ? xr21v141x_baud_rates[i].rx1 : xr21v141x_baud_rates[i].rx0;
>  
> -	dev_dbg(&xr_usb_serial->control->dev, "Setting baud rate to %d: i=%u div=%u tx=%03x rx=%03x\n", rate, i, divisor, tx_mask, rx_mask);
> +	//dev_info(&xr_usb_serial->control->dev, "Setting baud rate to %d: i=%u div=%u tx=%03x rx=%03x\n", rate, i, divisor, tx_mask, rx_mask);
>  
>  	xr_usb_serial_set_reg(xr_usb_serial,UART_CLOCK_DIVISOR_0, (divisor >>  0) & 0xff);
>  	xr_usb_serial_set_reg(xr_usb_serial,UART_CLOCK_DIVISOR_1, (divisor >>  8) & 0xff);
> @@ -458,7 +458,7 @@ int xr_usb_serial_set_line(struct xr_usb_serial *xr_usb_serial, struct usb_cdc_l
>  	
>  	if (cflag & CRTSCTS)
>  	{
> -	    dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:hardware\n");
> +	    //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:hardware\n");
>  	    flow      = UART_FLOW_MODE_HW;
>  	    gpio_mode = UART_GPIO_MODE_SEL_RTS_CTS;
>  	} 
> @@ -466,7 +466,7 @@ int xr_usb_serial_set_line(struct xr_usb_serial *xr_usb_serial, struct usb_cdc_l
>  	{
>  	    unsigned char   start_char = START_CHAR(tty);
>  	    unsigned char   stop_char  = STOP_CHAR(tty);
> -        dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:software\n");
> +        //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:software\n");
>  	    flow      = UART_FLOW_MODE_SW;
>  	    gpio_mode = UART_GPIO_MODE_SEL_GPIO;
>  
> @@ -475,23 +475,47 @@ int xr_usb_serial_set_line(struct xr_usb_serial *xr_usb_serial, struct usb_cdc_l
>  	}
>  	else
>  	{
> -	    dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:none\n");
> +	    //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:none\n");
>  	    flow      = UART_FLOW_MODE_NONE;
>  	    gpio_mode = UART_GPIO_MODE_SEL_GPIO;
>  	}
> -	// rs485,rs422 FD/HD mode
> -	if (xr_usb_serial->rs485_422_en) {
> -		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);
> -		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0B);
> -	} else {
> -		//rs232, default mode
> -		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, flow);
> -		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, gpio_mode);
> +	
> +    if((xr_usb_serial->DeviceProduct == 0x1420)||
> +	   (xr_usb_serial->DeviceProduct == 0x1422)||
> +	   (xr_usb_serial->DeviceProduct == 0x1424))
> +    {//Add support for the TXT and RXT function for 0x1420, 0x1422, 0x1424, by setting GPIO_MODE [9:8] = '11'
> +        gpio_mode |= 0x300;
> +    }
> +	
> +    if((xr_usb_serial->DeviceProduct == 0x1412)||
> +	  (xr_usb_serial->DeviceProduct == 0x1414))
> +    {
> +      if(xr_usb_serial->found_smbios_exar_config)
> +	  	{
> +	  	   if((xr_usb_serial->channel_config == 2)
> +		   	 ||(xr_usb_serial->channel_config == 3))
> +	  	   //if find the exar channel config in the smbios, the value can not be changed  by the application
> +	  	   //dev_info(&xr_usb_serial->control->dev, "Sorry, Application can not change the channel gpio&flow mode,because there are config at SMBIOS\n");
> +	  	   return 0;
> +		}
> +    }
> +		
> +    xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, flow);
> +	
> +	if((xr_usb_serial->found_smbios_exar_config == 1)&&(xr_usb_serial->channel_config == 1))
> +	{
> +       //dev_info(&xr_usb_serial->control->dev, "Sorry, Application can not change the channel gpio mode,because there are config at SMBIOS\n");
>  	}
> +	else
> +	   xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, gpio_mode);
> +	
>  	return 0;
>  	 
>  
>   }
> +
> +
> +
>   
>  int xr_usb_serial_send_break(struct xr_usb_serial *xr_usb_serial, int state)
>  {
> @@ -516,11 +540,17 @@ int xr_usb_serial_send_break(struct xr_usb_serial *xr_usb_serial, int state)
>  #define URM_ENABLE_BASE        0x010
>  #define URM_ENABLE_0_TX        0x001
>  #define URM_ENABLE_0_RX        0x002
> +#define URM_RESET_RX_FIFO_BASE        0x018
> +#define URM_RESET_TX_FIFO_BASE        0x01C
> +
> +
>  
>  int xr_usb_serial_enable(struct xr_usb_serial *xr_usb_serial)
>  {
>  	int ret = 0;
>  	int channel = xr_usb_serial->channel;
> +	//dev_info(&xr_usb_serial->control->dev, "xr_usb_serial_enable channel=%d\n",channel);
> +	if(channel) channel--;
>  	if((xr_usb_serial->DeviceProduct == 0x1410)||
>  	   (xr_usb_serial->DeviceProduct == 0x1412)||
>  	   (xr_usb_serial->DeviceProduct == 0x1414))
> @@ -536,10 +566,31 @@ int xr_usb_serial_enable(struct xr_usb_serial *xr_usb_serial)
>  	
>  	return ret;
>  }
> +int xr_usb_serial_fifo_reset(struct xr_usb_serial *xr_usb_serial)
> +{
> +	    int ret = 0;
> +		int channel = xr_usb_serial->channel;
> +		
> +		if(channel) channel--;
> +		if((xr_usb_serial->DeviceProduct == 0x1410)||
> +		   (xr_usb_serial->DeviceProduct == 0x1412)||
> +		   (xr_usb_serial->DeviceProduct == 0x1414))
> +		{
> +		   
> +		  ret = xr_usb_serial_set_reg_ext(xr_usb_serial,URM_REG_BLOCK,URM_RESET_RX_FIFO_BASE + channel,0xff);
> +		  ret |= xr_usb_serial_set_reg_ext(xr_usb_serial,URM_REG_BLOCK,URM_RESET_TX_FIFO_BASE + channel,0xff);
> +		   
> +		}
> +		return ret;
> +}
> +
> +
>  int xr_usb_serial_disable(struct xr_usb_serial *xr_usb_serial)
>  {
>  	int ret = 0;
>  	int channel = xr_usb_serial->channel;
> +	//dev_info(&xr_usb_serial->control->dev, "xr_usb_serial_disable channel=%d\n",channel);
> +	if(channel) channel--;
>  	ret = xr_usb_serial_set_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_enable_addr,0);
>  	if((xr_usb_serial->DeviceProduct == 0x1410)||
>  	   (xr_usb_serial->DeviceProduct == 0x1412)||
> @@ -554,12 +605,81 @@ int xr_usb_serial_set_loopback(struct xr_usb_serial *xr_usb_serial, int channel)
>  {
>  	int ret = 0;
>  	xr_usb_serial_disable(xr_usb_serial);
> -	ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
> +	
> +	if((xr_usb_serial->DeviceProduct == 0x1410) ||
> +		    (xr_usb_serial->DeviceProduct == 0x1412) ||
> +		    (xr_usb_serial->DeviceProduct == 0x1414))
> +	{
> +		switch (channel)
> +		{
> +			case 0:
> +				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
> +		                            xr_usb_serial->reg_map.uart_loopback_addr,0x40);
> +			break;
> +			case 1:
> +				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
> +		                            xr_usb_serial->reg_map.uart_loopback_addr,0x41);
> +			break;
> +			case 2:
> +				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
> +		                            xr_usb_serial->reg_map.uart_loopback_addr,0x42);
> +			break;
> +			case 3:
> +				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
> +		                            xr_usb_serial->reg_map.uart_loopback_addr,0x43);
> +			break;
> +			default:
> +				
> +			break;
> +		}
> +	}
> +	else if((xr_usb_serial->DeviceProduct == 0x1420)||
> +		    (xr_usb_serial->DeviceProduct == 0x1422)||
> +		    (xr_usb_serial->DeviceProduct == 0x1424))
> +	{
> +	  ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
>  		                            xr_usb_serial->reg_map.uart_loopback_addr,0x07);
> +	}
>  	xr_usb_serial_enable(xr_usb_serial);
>  	return ret;
>  }
>  
> +#define XR21V1414_WIDE_MODE_OFFSET         3
> +#define XR21B142X_WIDE_MODE_TX_OFFSET     0x42
> +#define XR21B142X_WIDE_MODE_RX_OFFSET     0x45
> +int xr_usb_serial_set_wide_mode(struct xr_usb_serial *xr_usb_serial, int preciseflags)
> +{
> +    int ret = 0;
> +	int channel = xr_usb_serial->channel;  
> +	xr_usb_serial_disable(xr_usb_serial);
> +    if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1400)
> +	{
> +		
> +	}
> +	else if((xr_usb_serial->DeviceProduct == 0x1410)||
> +		   (xr_usb_serial->DeviceProduct == 0x1412)||
> +		   (xr_usb_serial->DeviceProduct == 0x1414))
> +	{
> +	 
> +	  if(channel)  channel--;
> +	  xr_usb_serial_set_reg_ext(xr_usb_serial, 0x66, channel*8 + XR21V1414_WIDE_MODE_OFFSET, preciseflags);
> +		
> +	}
> +	else if(xr_usb_serial->DeviceProduct == 0x1411)
> +	{
> +	  xr_usb_serial_set_reg(xr_usb_serial,0xd02, preciseflags);
> +	}
> +	else if((xr_usb_serial->DeviceProduct == 0x1420)||
> +		   (xr_usb_serial->DeviceProduct == 0x1422)||
> +		   (xr_usb_serial->DeviceProduct == 0x1424))
> +	{
> +	  xr_usb_serial_set_reg(xr_usb_serial, XR21B142X_WIDE_MODE_TX_OFFSET, preciseflags); 
> +	  xr_usb_serial_set_reg(xr_usb_serial, XR21B142X_WIDE_MODE_RX_OFFSET, preciseflags); 
> +	}
> +	xr_usb_serial_enable(xr_usb_serial);  
> +	return ret;
> +}
> +
>  
>  static int xr_usb_serial_tiocmget(struct xr_usb_serial *xr_usb_serial)
>  
> @@ -567,7 +687,7 @@ static int xr_usb_serial_tiocmget(struct xr_usb_serial *xr_usb_serial)
>          short data;
>  		int result;
>  		result = xr_usb_serial_get_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_status_addr, &data);
> -		dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tiocmget uart_gpio_status_addr:0x%04x\n",data);
> +		//dev_info(&xr_usb_serial->control->dev, "xr_usb_serial_tiocmget uart_gpio_status_addr:0x%04x\n",data);
>  		if (result)
>  			return ((data & 0x8) ? 0: TIOCM_DTR) | ((data & 0x20) ? 0:TIOCM_RTS ) | ((data & 0x4) ? 0:TIOCM_DSR) | ((data & 0x1) ? 0 : TIOCM_RI) | ((data & 0x2) ? 0:TIOCM_CD) | ((data & 0x10) ? 0 : TIOCM_CTS); 
>  		else
> @@ -675,11 +795,12 @@ static void init_xr21b142x_reg_map(void)
>  	xr21b140x_reg_map.uart_custom_driver = 0x60;
>  	xr21b140x_reg_map.uart_low_latency = 0x46;
>  }
> -
> +int smbios_check_if_have_exar_config(unsigned char *config0,unsigned char *config1);
>  int xr_usb_serial_pre_setup(struct xr_usb_serial *xr_usb_serial)
>  {
>  	int ret = 0;
> -	
> +	unsigned char channel1_config = 255;
> +	unsigned char channel2_config = 255;
>  	init_xr21b140x_reg_map();
>  	init_xr21b1411_reg_map();
>  	init_xr21v141x_reg_map();
> @@ -716,9 +837,74 @@ int xr_usb_serial_pre_setup(struct xr_usb_serial *xr_usb_serial)
>  	xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_dir_addr, 0x28);  
>      xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_set_addr, UART_GPIO_SET_DTR | UART_GPIO_SET_RTS); 
>  	
> +	if((xr_usb_serial->DeviceProduct == 0x1412)||
> +	  (xr_usb_serial->DeviceProduct == 0x1414))
> +	{
> +	  xr_usb_serial->found_smbios_exar_config = 0;
> +	  if(smbios_check_if_have_exar_config(&channel1_config,&channel2_config) == 0)
> +	  {
> +	     
> +		 if(xr_usb_serial->channel == 1)
> +		 {
> +		    xr_usb_serial->found_smbios_exar_config = 1;
> +			xr_usb_serial->channel_config = channel1_config;
> +			switch (channel1_config)
> +		    {
> +				case 1://for RS232 Mode
> +				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS232\n");
> +				    xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0); 
> +					
> +				break;
> +				case 2://RS-485 HALF DUPLEX
> +				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485 HALF DUPLEX\n");
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b); 
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
> +				break;
> +				case 3://RS-485/422 FULL DUPLEX 
> +				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485/422 FULL DUPLEX\n");
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b);
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
> +				break;
> +				default:
> +					xr_usb_serial->found_smbios_exar_config = 0;
> +				break;
> +		     }
> +			
> +		 }
> +		 else if(xr_usb_serial->channel == 2)
> +		 {
> +		    xr_usb_serial->found_smbios_exar_config = 1;
> +			xr_usb_serial->channel_config = channel2_config;
> +			switch (channel2_config)
> +		    {
> +				case 1://for RS232 Mode
> +				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS232\n");
> +				    xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0); 
> +					
> +				break;
> +				case 2://RS-485 HALF DUPLEX
> +				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485 HALF DUPLEX\n");
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b); 
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
> +				break;
> +				case 3://RS-485/422 FULL DUPLEX 
> +				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485/422 FULL DUPLEX\n");
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b);
> +					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
> +				break;
> +				default:
> +				   xr_usb_serial->found_smbios_exar_config = 0;
> +				break;
> +		     }
> +		 }
> +		 else
> +		 {
> +		   //Nothing to do
> +		 }
> +	  }
> +	  
> +	}
>      return ret;
>     
>  }
>  
> -	
> -
> diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h b/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h
> index c28b6bdc0b16..81394aac3290 100644
> --- a/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h
> +++ b/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h
> @@ -24,6 +24,13 @@
>  #define XR_USB_SERIAL_SET_PRECISE_FLAGS     	_IO(XR_USB_SERIAL_IOC_MAGIC, 4)
>  #define XR_USB_SERIAL_TEST_MODE         	_IO(XR_USB_SERIAL_IOC_MAGIC, 5)
>  #define XR_USB_SERIAL_LOOPBACK          	_IO(XR_USB_SERIAL_IOC_MAGIC, 6)
> +#define XR_USB_SERIAL_SET_GPIO_MODE_REG    _IO(XR_USB_SERIAL_IOC_MAGIC, 9) 
> +#define	XR_USB_SERIAL_GET_GPIO_MODE_REG    _IO(XR_USB_SERIAL_IOC_MAGIC, 10) 
> +#define XRIOC_SET_ANY_BAUD_RATE           _IO(XR_USB_SERIAL_IOC_MAGIC, 11)
> +#define XRIOC_SET_PRECISE_FLAGS     	   _IO(XR_USB_SERIAL_IOC_MAGIC, 12)
> +
> +
> +
>  
>  #define VZ_ADDRESS_UNICAST_S        	0
>  #define VZ_ADDRESS_BROADCAST_S      	8
>
diff mbox series

Patch

diff --git a/ubuntu/xr-usb-serial/README.txt b/ubuntu/xr-usb-serial/README.txt
index eb88f40f2080..242c8f368039 100644
--- a/ubuntu/xr-usb-serial/README.txt
+++ b/ubuntu/xr-usb-serial/README.txt
@@ -1,5 +1,8 @@ 
 Exar USB Serial Driver
 ======================
+Version 1B, 11/6/2015
+Fixed Bug: The conditional logic to support kernel 3.9 was incorrect(line 396 in xr_usb_serial_common.c). 
+
 Version 1A, 1/9/2015
 
 This driver will work with any USB UART function in these Exar devices:
diff --git a/ubuntu/xr-usb-serial/xr_get_smbios.c b/ubuntu/xr-usb-serial/xr_get_smbios.c
new file mode 100644
index 000000000000..05a995f1a957
--- /dev/null
+++ b/ubuntu/xr-usb-serial/xr_get_smbios.c
@@ -0,0 +1,350 @@ 
+/*
+ * 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
+ */
+
+static void *smbios_base = 0;
+/** SM-BIOS entry point structure */
+struct smbios_entry_point_struct *smbios_entry_point = 0;
+/** DMI-BIOS entry point structure */
+struct dmibios_entry_point_struct *dmibios_entry_point = 0;
+/** SM-BIOS, resp. DMI-BIOS structures base address; starting point */
+void *smbios_structures_base = 0;
+/** enumeration of SM-BIOS, resp. DMI-BIOS types that do have subtypes */
+__u8 smbios_types_with_subtypes[] = { TYPES_WITH_SUBTYPES };
+/** contains the SMBIOS Version, e.g. V2.31 */
+char smbios_version_string[32];
+/** \fn unsigned char smbios_check_entry_point (void * addr)
+ *  \brief checks the entry point structure for correct checksum
+ *  \param addr pointer to the entry point structure
+ *  \return the checksum of the entry point structure, should be '0'
+ *
+ *  This function checks the entry point structure for correct checksum.
+ *  The checksum is calculated with adding every byte of the structure
+ *  to the checksum byte. The entry point structure is considered correct
+ *  if the checksum byte is 0.
+ *
+ *  \author Markus Lyra
+ *  \author Thomas Bretthauer
+ *  \date October 2000
+ */
+
+unsigned char smbios_check_entry_point (void *addr)
+{
+    unsigned char *i;
+    unsigned char checksum = 0;
+    unsigned char length =((struct smbios_entry_point_struct *) addr)->entry_point_length;
+    /* calculate checksum for entry point structure (should be 0) */
+    for (i = (unsigned char *) addr; i < (unsigned char *) addr + length; i++)
+        checksum += *i;
+    return checksum;
+}
+
+struct smbios_entry_point_struct * smbios_find_entry_point (void *base)
+{
+    struct smbios_entry_point_struct *entry_point = 0;	/** SM-BIOS entry point */
+    unsigned int *temp;				        /** temp. pointer       */
+
+
+    /* search for the magic dword - '_SM_� as DWORD formatted -  on paragraph boundaries */
+    for (temp = base;
+		 !entry_point && temp < (unsigned int *) base + BIOS_MAP_LENGTH;
+	     temp += 4)
+	{
+        /* found the identifier ? */
+        if (*temp == SMBIOS_MAGIC_DWORD)
+        {
+            /* check if entry point valid (build checksum) */
+	        if (!(smbios_check_entry_point (temp)))
+	        {
+	            entry_point = (struct smbios_entry_point_struct *) temp;
+				
+				/* fix display of Bios version string */
+			    /* SMBios version is known as 2.1, 2.2, 2.3 and 2.3.1, never as 2.01 (JB) */
+	            SM_BIOS_DEBUG("SM-BIOS V%d.%d entry point found at 0x%x\n",
+		        entry_point->major_version, entry_point->minor_version, (unsigned int) temp);
+
+                SM_BIOS_DEBUG("V%d.%d\n", entry_point->major_version, entry_point->minor_version);
+	        }
+        }
+    }
+    return entry_point;
+}
+struct dmibios_entry_point_struct *dmibios_find_entry_point (void *base)
+{
+    struct dmibios_entry_point_struct *entry_point = 0;	    /** DMI-BIOS entry point */
+    unsigned char *temp = 0;			                /** temp. pointer        */
+    unsigned char biossignature[] =		                /** '_DMI20_NT_'         */
+                { 0x5f, 0x44, 0x4d, 0x49, 0x32, 0x30, 0x5f, 0x4e, 0x54, 0x5f };
+
+    /* search for the DMI-BIOS signature on character boundary (hm?) */
+    for (temp = base;
+	       !entry_point && 
+				 temp < (__u8 *) base + BIOS_MAP_LENGTH - sizeof (biossignature) - 32;
+	       temp++)
+	{
+        unsigned long *tempdword = (unsigned long *) temp;
+
+        /* found the identifier '_DMI' ?     (beginning of signature) */
+        if (*tempdword == DMIBIOS_MAGIC_DWORD)
+        {
+	        entry_point = (struct dmibios_entry_point_struct *) temp;
+	
+	        SM_BIOS_DEBUG ("DMI-BIOS revision %d entry point at 0x%x\n",
+		    entry_point->revision, (unsigned int) temp);
+
+            sprintf(smbios_version_string, "V%d\n", entry_point->revision);
+
+	        if (memcmp (temp, biossignature, sizeof (biossignature)) == 0)
+	            SM_BIOS_DEBUG ("DMI BIOS successfully identified\n");
+        }
+    }
+    return entry_point;
+}
+void dump_smbios_hex(unsigned char *p,int len)
+{
+   int i;
+   SM_BIOS_DEBUG("dump_smbios_hex length:%d\n",len);
+   for(i=0;i<len;i++)
+   {
+      if((p[i] == 0xc0)&&(p[i+1]==0x06))  
+	  	SM_BIOS_DEBUG("Found 0xc0 at offset:%d 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n\t",i,p[i],p[i+1],p[i+2],p[i+3],p[i+4],p[i+5]);
+   }
+}
+int smbios_type_has_subtype (unsigned char type)
+{
+    int i;
+
+
+    for (i = 0; i < sizeof (smbios_types_with_subtypes); i++)
+        if (type == smbios_types_with_subtypes[i])
+	        return 1;
+
+    return 0;
+}
+
+int smbios_get_struct_length (struct smbios_struct * struct_ptr)
+{
+    /* jump to string list */
+    unsigned char *ptr = (unsigned char *) struct_ptr + struct_ptr->length;
+
+    /* search for the end of string list */
+    while (ptr[0] != 0x00 || ptr[1] != 0x00)
+        ptr++;
+    ptr += 2;			/* terminating 0x0000 should be included */
+
+    return (int) ptr - (int) struct_ptr;
+}
+
+unsigned int smbios_get_readable_name(char *name, struct smbios_struct *struct_ptr)
+{
+    switch(struct_ptr->type)
+    {
+        case 0: return sprintf (name, "%s", RD_BIOS);
+        case 1: return sprintf (name, "%s", RD_SYSTEM);
+		case 2: return sprintf (name, "%s", RD_BASEBOARD);
+		case 3: return sprintf (name, "%s", RD_ENCLOSURE);
+		case 4: return sprintf (name, "%s", RD_PROCESSOR);
+		case 5: return sprintf (name, "%s", RD_MEMCTRL);
+		case 6: return sprintf (name, "%s", RD_MEMMOD);
+		case 7: return sprintf (name, "%s", RD_CACHE);
+		case 8: return sprintf (name, "%s", RD_PORT);
+		case 9: return sprintf (name, "%s", RD_SLOT);
+		case 10: return sprintf (name, "%s", RD_ONBOARD);
+		case 11: return sprintf (name, "%s", RD_OEMSTRINGS);
+		case 12: return sprintf (name, "%s", RD_SYSTEMCONFIG);
+		case 13: return sprintf (name, "%s", RD_BIOSLANG);
+		case 14: return sprintf (name, "%s", RD_GROUPASSOC);
+		case 15: return sprintf (name, "%s", RD_EVENTLOG);
+		case 16: return sprintf (name, "%s", RD_MEMARRAY);
+		case 17: return sprintf (name, "%s", RD_MEMDEV);
+		case 18: return sprintf (name, "%s", RD_32MEMERR);
+		case 19: return sprintf (name, "%s", RD_MEMMAPPEDADR);
+		case 20: return sprintf (name, "%s", RD_MEMMAPPEDDEV);
+		case 21: return sprintf (name, "%s", RD_POINTINGDEV);
+		case 22: return sprintf (name, "%s", RD_BATTERY);
+		case 23: return sprintf (name, "%s", RD_RESET);
+		case 24: return sprintf (name, "%s", RD_SECURITY);
+		case 25: return sprintf (name, "%s", RD_PWRCTRL);
+		case 26: return sprintf (name, "%s", RD_VOLTAGE);
+		case 27: return sprintf (name, "%s", RD_COOLINGDEV);
+		case 28: return sprintf (name, "%s", RD_TEMP);
+		case 29: return sprintf (name, "%s", RD_CURRENT);
+		case 30: return sprintf (name, "%s", RD_RMTACCESS);
+		case 31: return sprintf (name, "%s", RD_BIS);
+		case 32: return sprintf (name, "%s", RD_BOOT_INFO);
+		case 33: return sprintf (name, "%s", RD_64MEMERR);
+		case 34: return sprintf (name, "%s", RD_MANAGDEV);
+		case 35: return sprintf (name, "%s", RD_MANAGDEVCOMP);
+		case 36: return sprintf (name, "%s", RD_MANAGDEVTHRESH);
+		case 37: return sprintf (name, "%s", RD_MEMCHANNEL);
+		case 38: return sprintf (name, "%s", RD_IPMI);
+		case 39: return sprintf (name, "%s", RD_PWRSUP);
+		case 126: return sprintf (name, "%s", RD_INACTIVE);
+		case 127: return sprintf (name, "%s", RD_EOT);
+		default: return sprintf (name, "%d", struct_ptr->type);
+    }
+}
+unsigned int smbios_get_readable_name_ext(char *name, struct smbios_struct *struct_ptr)
+{
+    return sprintf (name, "%d-%d", struct_ptr->type, struct_ptr->subtype);
+}
+
+int smbios_make_dir_entries (void)
+{
+    int i;
+    unsigned int raw_name_length = 0;	
+    char raw_name[12];                      /* e.g. 0.0 for structure type 0 , first instance */
+    unsigned int readable_name_length = 0;	
+    char readable_name[64];                 /* e.g. Bios.0 for structure type 0 , first instance */
+    struct smbios_struct *struct_ptr = smbios_structures_base;
+    /*
+     *  for every SMBIOS structure do ...
+     */
+    for (i = 0; i < smbios_entry_point->no_of_structures; i++)
+    {
+        memset(raw_name,0,12);
+		memset(readable_name,0,64);
+        /*
+         *  generate an unique name for the file:  "type[-subtype].count"
+         */
+        if (smbios_type_has_subtype (((struct smbios_struct *) struct_ptr)->type))
+        {
+      /* name will contain the raw file name, it equals the structure type (e.g. 1 for Type 1).
+             * readable_name contains the interpreted file name (e.g. System for Type 1)
+             */
+	        raw_name_length = sprintf (raw_name, "%d-%d", struct_ptr->type, struct_ptr->subtype);
+            readable_name_length = smbios_get_readable_name_ext(readable_name, struct_ptr);
+			//printk(KERN_INFO "[%s] smbios_type_has_subtype[%d] length:%d\n",raw_name,struct_ptr->type,struct_ptr->length);
+        }
+        else
+        {
+	        raw_name_length = sprintf (raw_name, "%d", struct_ptr->type);
+            readable_name_length = smbios_get_readable_name(readable_name, struct_ptr);
+			//printk(KERN_INFO "[%s] smbios_type_has type:%d length:%d\n",readable_name,struct_ptr->type,struct_ptr->length);
+        }
+
+    /*
+         *  go to the next structure
+         */
+        struct_ptr =(struct smbios_struct *) ((unsigned char *) struct_ptr + smbios_get_struct_length(struct_ptr));
+    }
+
+    return 0;
+}
+
+int smbios_check_if_have_exar_config(unsigned char *config0,unsigned char *config1)
+{
+	int i;
+	int result = -1;
+	unsigned char *p;
+	smbios_base = ioremap (BIOS_START_ADDRESS, BIOS_MAP_LENGTH);
+	if(!smbios_base)
+	{
+        SM_BIOS_DEBUG ("ioremap() for entry point failed\n");
+        result = -ENXIO;
+        return result;
+    }
+	//printk(KERN_INFO "ioremap bios base at 0x%p\n", smbios_base);	
+	if (!(smbios_entry_point = smbios_find_entry_point (smbios_base)))
+	{
+		SM_BIOS_DEBUG ("SM-BIOS entry point not found\n");
+		iounmap (smbios_base);
+		result = -ENXIO;
+        return result;
+		
+	}
+	 /*
+	 *	for SM-BIOS:
+	 *	check if Pointer to DMI structures exist.
+	 *	intermediate_string (_DMI_) is not '\0' terminated,
+	 *	so strncmp() with sizeof(DMI_STRING) - 1 is needed.
+	 */
+	if (smbios_entry_point)
+	{
+		if (strncmp((char *) &(smbios_entry_point->intermediate_string),
+						DMI_STRING, sizeof (DMI_STRING) - 1))
+		{
+			SM_BIOS_DEBUG ("Pointer to DMI structures not found!\n");
+		   
+		}
+	}
+	
+	/*
+	 *	map the SM-BIOS structures physical address range.
+	 *	the 'real' smbios_structures_base contains the starting
+	 *	address, where the instances of dmi structures are located.
+	 */
+	if (smbios_entry_point)
+	{
+		if (!(smbios_structures_base =
+			  ioremap (smbios_entry_point->struct_table_address,
+				(unsigned long) smbios_entry_point->struct_table_length)))
+		{
+			SM_BIOS_DEBUG("ioremap() for structures table failed\n");
+			iounmap (smbios_base);
+		    result = -ENXIO;
+            return result;
+	  	}
+	}
+	SM_BIOS_DEBUG(KERN_INFO "smbios_structures_base to 0x%p length %d no_of_structures:%d\n", 
+		 		  smbios_structures_base,
+		   		  smbios_entry_point->struct_table_length,
+		          smbios_entry_point->no_of_structures);	
+	
+   //dump_smbios_hex((unsigned char *)smbios_structures_base,smbios_entry_point->struct_table_length);
+   p = (unsigned char *)smbios_structures_base;
+   for(i=0;i<smbios_entry_point->struct_table_length;i++)
+   {
+      if((p[i] == 0xc0)&&(p[i+1]==0x06)) 
+      {
+	  	SM_BIOS_DEBUG("Found 0xc0 at offset:%d 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n\t",i,p[i],p[i+1],p[i+2],p[i+3],p[i+4],p[i+5]);
+		*config0 = p[i+4];
+		*config1 = p[i+5];
+		result = 0;
+		break;
+      }
+   }
+    //smbios_make_dir_entries();
+    iounmap (smbios_structures_base);
+	iounmap (smbios_base);
+    return result;
+
+}
+/*
+void dmi_dump_backup(void)
+{
+	const char *board_vendor, *board_name,*board_serial;
+	const struct dmi_device *dmi;
+	struct dmi_dev_onboard *donboard;
+	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+	board_name = dmi_get_system_info(DMI_BOARD_NAME);
+	board_serial =  dmi_get_system_info(DMI_BOARD_SERIAL);
+	printk(KERN_INFO "DMI_BOARD_VENDOR:%s\n",board_vendor);
+	printk(KERN_INFO "DMI_BOARD_NAME:%s\n",board_name);
+	printk(KERN_INFO "DMI_BOARD_SERIAL:%s\n",board_serial);
+	for(i=0;i<256;i++)
+	{
+		dmi = NULL;
+		//printk(KERN_INFO "dmi_find_device<%d>\n",i);
+		while ((dmi = dmi_find_device(i,NULL, dmi)) != NULL) 
+		{
+		  //donboard = dmi->device_data;
+		  printk(KERN_INFO "<%d>Found name:%s   type:%d \n",i,dmi->name,dmi->type);
+		}
+	}			
+
+}
+*/
+
diff --git a/ubuntu/xr-usb-serial/xr_get_smbios.h b/ubuntu/xr-usb-serial/xr_get_smbios.h
new file mode 100644
index 000000000000..f56b33084dab
--- /dev/null
+++ b/ubuntu/xr-usb-serial/xr_get_smbios.h
@@ -0,0 +1,237 @@ 
+/* Copyright (C) 2001-2001 Fujitsu Siemens Computers
+   Joachim Braeuer
+   This file is part of smbios
+
+   smbios 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.
+
+   smbios 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 smbios; see the file COPYING. If not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
+
+/* $Id: bios.h,v 1.2 2002/09/03 10:33:12 bretthauert Exp $
+ *
+ * $Log: bios.h,v $
+ * Revision 1.2  2002/09/03 10:33:12  bretthauert
+ * fixed a bug with 2.4 kernels (changed kmalloc parameter from
+ * GFP_BUFFER to GFP_KERNEL
+ *
+ * Revision 1.1  2001/09/15 14:52:43  bretthauert
+ * initial release
+ *
+ */
+
+/** \file bios.h
+ *  declarations and prototypes of DMI-BIOS and SM-BIOS stuff
+ *
+ *  \author Markus Lyra
+ *  \author Thomas Bretthauer
+ *  \author Joachim Braeuer
+ *  \version 0.11
+ *  \date January 2001
+ */
+     
+#ifndef __SM_BIOS_H__
+#define __SM_BIOS_H__
+
+#include <linux/types.h>
+//#define _EN_DEBUG_ 1
+#ifdef _EN_DEBUG_
+#  define SM_BIOS_DEBUG(fmt, args...) printk( KERN_DEBUG "smbios: " fmt, ## args)
+#else
+#  define SM_BIOS_DEBUG(fmt, args...) /* not debugging: nothing */
+#endif
+/*
+ *   Magic numbers
+ */
+
+/** start address of BIOS segment to scanned for SM-BIOS and DMI-BIOS */
+#define BIOS_START_ADDRESS      0xF0000
+/** length of the scanned BIOS area for SM-BIOS and DMI-BIOS */
+#define BIOS_MAP_LENGTH         0x10000
+/** magic 4 bytes to identify SM-BIOS entry point, paragraph boundary */
+#define SMBIOS_MAGIC_DWORD      0x5F4D535F /* anchor string "_SM_" */
+/** magic 4 bytes to identify DMI-BIOS entry point, byte boundary */
+#define DMIBIOS_MAGIC_DWORD     0x494d445f /* anchor string "_DMI" */
+/** identifier for SM-BIOS structures within SM-BIOS entry point */
+#define DMI_STRING              "_DMI_"
+/** list of types which are known to have subtyes; expandable! */
+#define TYPES_WITH_SUBTYPES     185, 187, 208, 209, 210, 211, 212, 254
+/** maximum block size for proc read function */
+#define PROC_BLOCK_SIZE         (3*1024)
+
+
+/** mode raw/cooked */
+#define FILE_MODE_RAW       0
+#define FILE_MODE_COOKED    1
+
+/*
+ *   Structures
+ */
+
+/** SM-BIOS entry point structure 
+ * the SMBIOS Entry Point structure described below can be located by
+ * application software by searching for the anchor string on paragraph
+ * (16 byte) boundaries within the physical memory address range 000F0000h to
+ * 000FFFFFh. This entry point encapsulates an intermediate anchor string
+ * that is used by some existing DMI browsers.
+ *
+ * @note While the SMBIOS Major and Minor Versions (offsets 06h and 07h)
+ * currently duplicate the information present in the SMBIOS BCD Revision
+ * (offset 1Dh), they provide a path for future growth in this specification.
+ * The BCD Revision, for example, provides only a single digit for each of
+ * the major and minor version numbers.
+ */
+struct smbios_entry_point_struct
+{
+	/** "_SM_", specified as four ASCII characters (5F 53 4D 5F) */
+  __u32 anchor_string;
+	/** checksum of the Entry Point Structure (EPS). This value, when added to 
+	 * all other bytes in the EPS, will result in the value 00h (using 8 bit
+	 * addition calculations). Values in the EPS are summed starting at offset
+	 * 00h, for Entry Point Length bytes.*/
+  __u8  entry_point_checksum;
+	/** Length of the Entry Point Structure, starting with the Anchor String 
+	 * field, in bytes, currently 1Fh. */
+  __u8  entry_point_length;
+	/** identifies the major version of this specification implemented in
+	 * the table structures, e.g. the value will be 0Ah for revision 10.22
+	 * and 02h for revision 2.1 */
+  __u8  major_version;
+	/** identifies the minor version of this specification implemented in
+	 * the table structures, e.g. the value will be 16h for revision 10.22
+	 * and 01h for revision 2.1 */
+  __u8  minor_version;
+	/** size of the largest SMBIOS structure, in bytes, and encompasses the
+	 * structure's formatted area and text strings. This is the value returned
+	 * as StructureSize from the Plug-n-Play 'Get SMBIOS Information' function */
+	__u16 max_struct_size;
+	/** identifies the EPS revision implemented in this structure and identifies
+	 * the formatting of offsets 0Bh to 0Fh, one of:
+	 * 00h     Entry Point based on SMBIOS 2.1 definition; formatted area is
+	 *         reserved and set to all 00h.
+	 * 01h-FFh reserved for assignment via this specification */
+  __u8  revision;
+	/** the value present in the Entry Point Revision field defines the
+	 * interpretation to be placed upon these5 bytes. */
+  __u8  formated_area[5];
+	/** "_DMI_", specified as five ASCII characters (5F 44 4D 49 5F) */
+  __u8  intermediate_string[5];
+	/** checksum of the Intermediate Entry Point Structure (IEPS). This value,
+	 * when added to all other bytes in the IEPS, will result in the value 00h
+	 * (using 8 bit addition calculations). Values in the IEPS are summed
+	 * starting at offset 10h, for 0Fh bytes */
+  __u8  intermediate_checksum;
+	/** the 32 bit physical starting address of the read-only SMBIOS Structure
+	 * Table, that can start at any 32 bit address. This area contains all of the
+	 * SMBIOS structures fully packed together. These structures can then be
+	 * parsed to produce exactly the same format as that returned from a 'Get
+	 * SMBIOS Structure' function call. */
+  __u16 struct_table_length;
+  __u32 struct_table_address;
+  __u16 no_of_structures;
+  __u8  bcd_revision;
+}__attribute__ ((packed));
+
+/** SM-BIOS and DMI-BIOS structure header */
+struct smbios_struct
+{
+  __u8  type ;
+  __u8  length ;
+  __u16 handle ;
+  __u8  subtype;
+        /* ... other fields are structure dependend ... */
+} __attribute__ ((packed));
+
+/** DMI-BIOS structure header */
+struct dmibios_table_entry_struct
+{
+  __u16 size;
+  __u16 handle;
+  __u32 procedure;
+}__attribute__ ((packed));
+
+/** DMI-BIOS entry point structure */
+struct dmibios_entry_point_struct
+{
+  __u8  signature[10];
+  __u8  revision;
+  struct dmibios_table_entry_struct entry[1];
+}__attribute__ ((packed));
+
+/** readable names for smbios structures, they serve as filenames in the /proc file system */
+#define RD_BIOS								"bios"
+#define RD_SYSTEM							"system"
+#define RD_BASEBOARD						"baseboard"
+#define RD_ENCLOSURE						"enclosure"
+#define RD_PROCESSOR						"processor"
+#define RD_MEMCTRL							"memory_controller"
+#define RD_MEMMOD							"memory_module"
+#define RD_CACHE							"cache"
+#define RD_PORT								"port_connector"
+#define RD_SLOT								"system_slot"
+#define RD_ONBOARD							"onboard_device"
+#define RD_OEMSTRINGS						"oem_strings"
+#define RD_SYSTEMCONFIG					    "system_configuration"
+#define RD_BIOSLANG							"bios_language"
+#define RD_GROUPASSOC						"group_association"
+#define RD_EVENTLOG							"system_event_log"
+#define RD_MEMARRAY							"physical_memory_array"
+#define RD_MEMDEV							"physical_memory_device"
+#define RD_32MEMERR							"32bit_memory_error_information"
+#define RD_MEMMAPPEDADR					    "memory_array_mapped_address"
+#define RD_MEMMAPPEDDEV					    "memory_device_mapped_address"
+#define RD_POINTINGDEV					    "pointing_device"
+#define RD_BATTERY							"portable_battery"
+#define RD_RESET							"system_reset"
+#define RD_SECURITY							"hardware_security"
+#define RD_PWRCTRL							"system_power_controls"
+#define RD_VOLTAGE							"voltage_probe"
+#define RD_COOLINGDEV						"cooling_device"
+#define RD_TEMP								"temperature_probe"
+#define RD_CURRENT							"current_probe"
+#define RD_RMTACCESS						"out_of_band_remote_access"
+#define RD_BIS								"boot_integrity_services"
+#define RD_BOOT_INFO						"system_boot_information"
+#define RD_64MEMERR							"64bit_memory_error_information"
+#define RD_MANAGDEV							"management_device"
+#define RD_MANAGDEVCOMP					    "management_device_component"
+#define RD_MANAGDEVTHRESH				    "management_device_thresholds"
+#define RD_MEMCHANNEL						"memory_channel"
+#define RD_IPMI								"ipmi_information"
+#define RD_PWRSUP							"system_power_supply"
+#define RD_INACTIVE							"inactive"
+#define RD_EOT								"end_of_table"
+
+
+//extern smbios_entry_point_struct * smbios_entry_point;      /* start of SMBIOS within the F-Segment */
+//extern dmibios_entry_point_struct * dmibios_entry_point;    /* start of DMIBIOS within the F-Segment */
+extern void * smbios_structures_base;                       /* base of SMBIOS raw structures */
+extern unsigned char smbios_types_with_subtypes[];
+extern char smbios_version_string[32];                      /* e.g. V2.31 */
+/*
+ *   Functions
+ */
+
+/* for the description see the implementation file */
+struct smbios_entry_point_struct * smbios_find_entry_point(void * base);
+struct dmibios_entry_point_struct * dmibios_find_entry_point(void * base);
+unsigned char smbios_check_entry_point(void * addr);
+int smbios_type_has_subtype(unsigned char type);
+int smbios_get_struct_length(struct smbios_struct * struct_ptr);
+int dmibios_get_struct_length(struct smbios_struct * struct_ptr);
+unsigned int smbios_get_readable_name_ext(char *readable_name, struct smbios_struct *struct_ptr);
+unsigned int smbios_get_readable_name(char *readable_name, struct smbios_struct *struct_ptr);
+int smbios_check_if_have_exar_config(unsigned char *config0,unsigned char *config1);
+
+
+#endif /* __BIOS_H__ */
diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_common.c b/ubuntu/xr-usb-serial/xr_usb_serial_common.c
index d16f072613b1..5d049855fb1a 100644
--- a/ubuntu/xr-usb-serial/xr_usb_serial_common.c
+++ b/ubuntu/xr-usb-serial/xr_usb_serial_common.c
@@ -28,12 +28,12 @@ 
  * from www.exar.com that will work with kernel versions 2.6.18 to 3.4.x.
  *
  * ChangeLog:
- *            Version 1A - Initial released version.
+ *            Version 1B - Initial released version.
  */
 
-//#undef DEBUG
+#undef DEBUG
 #undef VERBOSE_DEBUG
-
+#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -47,15 +47,20 @@ 
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
+#include <linux/dmi.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <linux/list.h>
+#include <linux/delay.h>
+#include <asm/io.h>		    /* ioremap() */
 #include "linux/version.h"
 
+#include "xr_get_smbios.h"
 #include "xr_usb_serial_common.h"
 #include "xr_usb_serial_ioctl.h"
 
 
+
 #define DRIVER_AUTHOR "<uarttechsupport@exar.com>"
 #define DRIVER_DESC "Exar USB UART (serial port) driver"
 
@@ -65,6 +70,10 @@  static struct xr_usb_serial *xr_usb_serial_table[XR_USB_SERIAL_TTY_MINORS];
 
 static DEFINE_MUTEX(xr_usb_serial_table_lock);
 
+
+
+
+
 /*
  * xr_usb_serial_table accessors
  */
@@ -137,6 +146,7 @@  static int xr_usb_serial_ctrl_msg(struct xr_usb_serial *xr_usb_serial, int reque
 	return retval < 0 ? retval : 0;
 }
 
+#include "xr_get_smbios.c"
 #include "xr_usb_serial_hal.c"
 
 
@@ -249,46 +259,6 @@  static ssize_t show_country_rel_date
 }
 
 static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
-
-static ssize_t set_rs485_422_en(struct device *dev,
-				struct device_attribute *attr, const char *buf,
-				size_t count)
-{
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf);
-	int error, value = 0;
-
-	error = kstrtoint(buf, 0, &value);
-	if (error)
-		return error;
-
-	if (value == 0) {
-		xr_usb_serial->rs485_422_en = false;
-	} else if (value == 1) {
-		// RS485,RS422 HD/FD mode
-		xr_usb_serial->rs485_422_en = true;
-	}
-
-	return count;
-}
-
-static ssize_t show_rs485_422_en(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf);
-
-	if (xr_usb_serial->rs485_422_en == false) {
-		return sprintf(buf, "0");
-	} else if (xr_usb_serial->rs485_422_en == true) {
-		// RS485,RS422 HD/FD mode
-		return sprintf(buf, "1");
-	}
-	return 0;
-}
-
-static DEVICE_ATTR(bRS485_422_en, 0644, show_rs485_422_en, set_rs485_422_en);
-
 /*
  * Interrupt handlers for various XR_USB_SERIAL device responses
  */
@@ -298,7 +268,10 @@  static void xr_usb_serial_ctrl_irq(struct urb *urb)
 {
 	struct xr_usb_serial *xr_usb_serial = urb->context;
 	struct usb_cdc_notification *dr = urb->transfer_buffer;
-	struct tty_struct *tty;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
+#else
+   	struct tty_struct *tty;
+#endif
 	unsigned char *data;
 	int newctrl;
 	int retval;
@@ -309,10 +282,11 @@  static void xr_usb_serial_ctrl_irq(struct urb *urb)
 	switch (status) {
 	case 0:
 		p = (unsigned char *)(urb->transfer_buffer);
+		/*
 		for(i=0;i<urb->actual_length;i++)
 	    {
           dev_dbg(&xr_usb_serial->control->dev,"0x%02x\n",p[i]);
-	    }
+	    }*/
 		/* success */
 		break;
 	case -ECONNRESET:
@@ -362,7 +336,7 @@  static void xr_usb_serial_ctrl_irq(struct urb *urb)
 		}
 #endif
 		xr_usb_serial->ctrlin = newctrl;
-
+        #if 0
 		dev_dbg(&xr_usb_serial->control->dev,
 			"%s - input control lines: dcd%c dsr%c break%c "
 			"ring%c framing%c parity%c overrun%c\n",
@@ -374,6 +348,7 @@  static void xr_usb_serial_ctrl_irq(struct urb *urb)
 			xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_FRAMING ? '+' : '-',
 			xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_PARITY ? '+' : '-',
 			xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_OVERRUN ? '+' : '-');
+		#endif
 			break;
 
 	default:
@@ -399,7 +374,7 @@  static int xr_usb_serial_submit_read_urb(struct xr_usb_serial *xr_usb_serial, in
 	if (!test_and_clear_bit(index, &xr_usb_serial->read_urbs_free))
 		return 0;
 
-	dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d\n", __func__, index);
+	//dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d\n", __func__, index);
 
 	res = usb_submit_urb(xr_usb_serial->read_urbs[index], mem_flags);
 	if (res) {
@@ -430,10 +405,75 @@  static int xr_usb_serial_submit_read_urbs(struct xr_usb_serial *xr_usb_serial, g
 }
 static void xr_usb_serial_process_read_urb(struct xr_usb_serial *xr_usb_serial, struct urb *urb)
 {
-    struct tty_struct *tty;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
+#else
+   	struct tty_struct *tty;
+#endif
+	int    preciseflags    = xr_usb_serial->preciseflags;
+	int    have_extra_byte;
+	int    length;
+	
 	if (!urb->actual_length)
 		return;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)    
+		
+	if (preciseflags)
+    {
+        char *dp = urb->transfer_buffer;
+        int i, ch, ch_flags;
+		
+        length = urb->actual_length;
+        length = length + (xr_usb_serial->have_extra_byte ? 1 : 0);
+        have_extra_byte = (preciseflags && (length & 1));
+        length      = (preciseflags) ? (length / 2) : length;
+        for (i = 0; i < length; ++i)
+		{
+                char tty_flag;
+                if (i == 0)
+				{
+                    if (xr_usb_serial->have_extra_byte)
+					{
+                            ch = xr_usb_serial->extra_byte;
+                    } 
+					else
+					{
+                            ch = *dp++;
+                    }
+                } 
+				else 
+				{
+                   ch = *dp++;
+                }
+                ch_flags = *dp++;
+                if (ch_flags & RAMCTL_BUFFER_PARITY)
+                        tty_flag = TTY_PARITY;
+                else if (ch_flags & RAMCTL_BUFFER_BREAK)
+                        tty_flag = TTY_BREAK;
+                else if (ch_flags & RAMCTL_BUFFER_FRAME)
+                        tty_flag = TTY_FRAME;
+                else if (ch_flags & RAMCTL_BUFFER_OVERRUN)
+                        tty_flag = TTY_OVERRUN;
+                else
+                        tty_flag = TTY_NORMAL;
+
+                
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+                tty_insert_flip_char(&xr_usb_serial->port, ch, tty_flag);
+				tty_flip_buffer_push(&xr_usb_serial->port);
+#else
+				tty = tty_port_tty_get(&xr_usb_serial->port);
+				if (!tty)
+				return;
+				tty_insert_flip_char(&xr_usb_serial->port, ch, tty_flag);
+				tty_flip_buffer_push(tty);
+
+				tty_kref_put(tty);
+#endif
+				
+        }
+    }
+	else
+	{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
 	tty_insert_flip_string(&xr_usb_serial->port, urb->transfer_buffer,
 			urb->actual_length);
 	tty_flip_buffer_push(&xr_usb_serial->port);
@@ -446,6 +486,7 @@  static void xr_usb_serial_process_read_urb(struct xr_usb_serial *xr_usb_serial,
 
 	tty_kref_put(tty);
 #endif
+	}
 }
 
 static void xr_usb_serial_read_bulk_callback(struct urb *urb)
@@ -453,9 +494,10 @@  static void xr_usb_serial_read_bulk_callback(struct urb *urb)
 	struct xr_usb_serial_rb *rb = urb->context;
 	struct xr_usb_serial *xr_usb_serial = rb->instance;
 	unsigned long flags;
-
+    /*
 	dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d, len %d\n", __func__,
-					rb->index, urb->actual_length);
+					rb->index, urb->actual_length);*/
+	
 	set_bit(rb->index, &xr_usb_serial->read_urbs_free);
 
 	if (!xr_usb_serial->dev) {
@@ -467,7 +509,7 @@  static void xr_usb_serial_read_bulk_callback(struct urb *urb)
 	if (urb->status) {
 		dev_dbg(&xr_usb_serial->data->dev, "%s - non-zero urb status: %d\n",
 							__func__, urb->status);
-		return;
+		//return;
 	}
 	xr_usb_serial_process_read_urb(xr_usb_serial, urb);
 
@@ -505,9 +547,13 @@  static void xr_usb_serial_write_bulk(struct urb *urb)
 static void xr_usb_serial_softint(struct work_struct *work)
 {
 	struct xr_usb_serial *xr_usb_serial = container_of(work, struct xr_usb_serial, work);
-    struct tty_struct *tty;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
+#else
+		struct tty_struct *tty;
+#endif
+
 	
-	dev_vdbg(&xr_usb_serial->data->dev, "%s\n", __func__);
+	//dev_vdbg(&xr_usb_serial->data->dev, "%s\n", __func__);
 #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)
 	tty_port_tty_wakeup(&xr_usb_serial->port);
 #else	
@@ -528,7 +574,7 @@  static int xr_usb_serial_tty_install(struct tty_driver *driver, struct tty_struc
 	struct xr_usb_serial *xr_usb_serial;
 	int retval;
 
-	dev_dbg(tty->dev, "%s\n", __func__);
+	//dev_dbg(tty->dev, "%s\n", __func__);
 
 	xr_usb_serial = xr_usb_serial_get_by_index(tty->index);
 	if (!xr_usb_serial)
@@ -550,9 +596,10 @@  static int xr_usb_serial_tty_install(struct tty_driver *driver, struct tty_struc
 static int xr_usb_serial_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
-
-	dev_dbg(tty->dev, "%s\n", __func__);
-
+	int result;
+    result = xr_usb_serial_fifo_reset(xr_usb_serial);
+	//dev_dbg(tty->dev, "%s\n", __func__);
+    
 	return tty_port_open(&xr_usb_serial->port, tty, filp);
 }
 
@@ -561,7 +608,7 @@  static int xr_usb_serial_port_activate(struct tty_port *port, struct tty_struct
 	struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port);
 	int retval = -ENODEV;
 
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
 
 	mutex_lock(&xr_usb_serial->mutex);
 	if (xr_usb_serial->disconnected)
@@ -624,14 +671,18 @@  static void xr_usb_serial_port_destruct(struct tty_port *port)
 {
 	struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port);
 
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
     #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
 	tty_unregister_device(xr_usb_serial_tty_driver, xr_usb_serial->minor);
 	#endif
+#ifdef CONFIG_GPIOLIB	
+	gpiochip_remove(&xr_usb_serial->xr_usb_gpio); 
+#endif
 	xr_usb_serial_release_minor(xr_usb_serial);
 	usb_put_intf(xr_usb_serial->control);
 	kfree(xr_usb_serial->country_codes);
 	kfree(xr_usb_serial);
+	
 }
 
 static void xr_usb_serial_port_shutdown(struct tty_port *port)
@@ -639,7 +690,7 @@  static void xr_usb_serial_port_shutdown(struct tty_port *port)
 	struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port);
 	int i;
 
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
 
 	mutex_lock(&xr_usb_serial->mutex);
 	if (!xr_usb_serial->disconnected) {
@@ -659,21 +710,21 @@  static void xr_usb_serial_port_shutdown(struct tty_port *port)
 static void xr_usb_serial_tty_cleanup(struct tty_struct *tty)
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
 	tty_port_put(&xr_usb_serial->port);
 }
 
 static void xr_usb_serial_tty_hangup(struct tty_struct *tty)
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
 	tty_port_hangup(&xr_usb_serial->port);
 }
 
 static void xr_usb_serial_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
 	tty_port_close(&xr_usb_serial->port, tty, filp);
 }
 
@@ -689,7 +740,7 @@  static int xr_usb_serial_tty_write(struct tty_struct *tty,
 	if (!count)
 		return 0;
 
-	dev_vdbg(&xr_usb_serial->data->dev, "%s - count %d\n", __func__, count);
+	//dev_vdbg(&xr_usb_serial->data->dev, "%s - count %d\n", __func__, count);
 
 	spin_lock_irqsave(&xr_usb_serial->write_lock, flags);
 	wbn = xr_usb_serial_wb_alloc(xr_usb_serial);
@@ -706,7 +757,7 @@  static int xr_usb_serial_tty_write(struct tty_struct *tty,
 	}
 
 	count = (count > xr_usb_serial->writesize) ? xr_usb_serial->writesize : count;
-	dev_vdbg(&xr_usb_serial->data->dev, "%s - write %d\n", __func__, count);
+	//dev_vdbg(&xr_usb_serial->data->dev, "%s - write %d\n", __func__, count);
 	memcpy(wb->buf, buf, count);
 	wb->len = count;
 
@@ -785,7 +836,7 @@  static int xr_usb_serial_tty_break_ctl(struct tty_struct *tty, int state)
 
 	retval = xr_usb_serial_send_break(xr_usb_serial, state ? 0xffff : 0);
 	if (retval < 0)
-		dev_dbg(&xr_usb_serial->control->dev, "%s - send break failed\n",
+		dev_err(&xr_usb_serial->control->dev, "%s - send break failed\n",
 								__func__);
 	return retval;
 }
@@ -793,7 +844,7 @@  static int xr_usb_serial_tty_break_ctl(struct tty_struct *tty, int state)
 static int xr_usb_serial_tty_tiocmget(struct tty_struct *tty)
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
-	dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmget\n");
+	//dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmget\n");
     return xr_usb_serial_tiocmget(xr_usb_serial);
 
 }
@@ -802,7 +853,7 @@  static int xr_usb_serial_tty_tiocmset(struct tty_struct *tty,
 			    unsigned int set, unsigned int clear)
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
-	dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmset set=0x%x clear=0x%x\n",set,clear);
+	//dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmset set=0x%x clear=0x%x\n",set,clear);
     return xr_usb_serial_tiocmset(xr_usb_serial,set,clear);
 
 }
@@ -865,8 +916,9 @@  static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
 {
 	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
 	int rv = -ENOIOCTLCMD;
-    unsigned int  channel, reg, val;
-
+    unsigned int  channel, reg, val,preciseflags;
+    int           baud_rate = 0;
+	struct usb_cdc_line_coding newline;
     short	*data;
 	switch (cmd) {
 	case TIOCGSERIAL: /* gets serial port data */
@@ -895,7 +947,8 @@  static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
 				{
 			  	  rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,reg, data);
 				}
-                if (rv != 1) {
+                if (rv < 0)
+                {
                         dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d)\n", rv);
                         kfree(data);
                         return -EFAULT;
@@ -941,6 +994,93 @@  static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
                return -EFAULT;
 			 rv = 0;
 		     break;
+	 case XR_USB_SERIAL_SET_GPIO_MODE_REG:
+		xr_usb_serial_disable(xr_usb_serial);
+		if (get_user(channel, (int __user *)arg))
+		    return -EFAULT;
+		if (get_user(val, (int __user *)(arg + sizeof(int))))
+		    return -EFAULT;
+	   	if (channel == -1)
+		{
+			//block = portdata->block;
+		    rv = xr_usb_serial_set_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, val);
+		}
+		else
+		{
+		    rv = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr, val);
+		}
+		
+		dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_SET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,val);
+		xr_usb_serial_enable(xr_usb_serial);
+		if (rv < 0)
+		        return -EFAULT;
+		break;
+	case XR_USB_SERIAL_GET_GPIO_MODE_REG:
+		xr_usb_serial_disable(xr_usb_serial);
+		if (get_user(channel, (int __user *)arg))
+                        return -EFAULT;
+       
+        data = kmalloc(2, GFP_KERNEL);
+        if (data == NULL) {
+                dev_err(&xr_usb_serial->control->dev, "%s - Cannot allocate USB buffer.\n", __func__);
+                return -ENOMEM;
+		}
+
+		if (channel == -1)
+		{
+		     rv = xr_usb_serial_get_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, data);
+		}
+		else
+		{
+		    rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr,data);
+		}
+		
+		xr_usb_serial_enable(xr_usb_serial);
+		
+		dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_GET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,*data);
+		
+        if (rv < 0 ) {
+                dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d) channel=%d \n", rv,channel);
+                kfree(data);
+                return -EFAULT;
+        }
+				
+        if (put_user(data[0], (int __user *)(arg + sizeof(int)))) {
+                dev_err(&xr_usb_serial->control->dev, "Cannot put user result\n");
+                kfree(data);
+                return -EFAULT;
+        }
+
+        kfree(data);
+		break;
+	case XRIOC_SET_ANY_BAUD_RATE:
+		
+		 if (get_user(baud_rate, (int __user *)arg)) {
+		 	   dev_dbg(&xr_usb_serial->control->dev, "get_user errot \n");
+               return -EFAULT;
+		 }
+		 xr_usb_serial->line.dwDTERate = baud_rate; 
+		 memcpy(&newline,&(xr_usb_serial->line),sizeof(struct usb_cdc_line_coding));
+		 xr_usb_serial_disable(xr_usb_serial);
+		 rv = xr_usb_serial_set_line(xr_usb_serial,&newline);
+		 xr_usb_serial_enable(xr_usb_serial);
+		 dev_dbg(&xr_usb_serial->control->dev, "XRIOC_SET_ANY_BAUD_RATE set baud_rate:%d ret=%d\n", baud_rate,rv);
+		 break;	
+	case XRIOC_SET_PRECISE_FLAGS:
+		 preciseflags = arg;
+		 dev_dbg(&xr_usb_serial->control->dev, "%s VIOC_SET_PRECISE_FLAGS %d\n", __func__, preciseflags);
+		 xr_usb_serial_disable(xr_usb_serial);
+		 if (preciseflags) 
+		 {
+		        xr_usb_serial->preciseflags = 1;
+		 } 
+		 else 
+		 {
+		        xr_usb_serial->preciseflags = 0;
+		 }
+		 xr_usb_serial_set_wide_mode(xr_usb_serial,xr_usb_serial->preciseflags);
+		 xr_usb_serial_enable(xr_usb_serial);
+		 break;	 
 		
 	}
 
@@ -965,9 +1105,11 @@  static void xr_usb_serial_tty_set_termios(struct tty_struct *tty,
 	newline.bParityType = termios->c_cflag & PARENB ?
 				(termios->c_cflag & PARODD ? 1 : 2) +
 				(termios->c_cflag & CMSPAR ? 2 : 0) : 0;
+	xr_usb_serial->trans9 = 0;
 	switch (termios->c_cflag & CSIZE) {
 	case CS5:/*using CS5 replace of the 9 bit data mode*/
 		newline.bDataBits = 9;
+		xr_usb_serial->trans9 =1;
 		break;
 	case CS6:
 		newline.bDataBits = 6;
@@ -993,15 +1135,27 @@  static void xr_usb_serial_tty_set_termios(struct tty_struct *tty,
 		xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout = newctrl);
 	
     xr_usb_serial_set_flow_mode(xr_usb_serial,tty,cflag);/*set the serial flow mode*/
-	 	
+    if (xr_usb_serial->trans9) 
+	{
+       /* Turn on wide mode if we're 9-bit transparent. */
+       	xr_usb_serial_set_wide_mode(xr_usb_serial,1);
+    } 
+	else if (!xr_usb_serial->preciseflags) 
+	{
+        xr_usb_serial_set_wide_mode(xr_usb_serial,0);
+    }
+
+		
 	if (memcmp(&xr_usb_serial->line, &newline, sizeof newline))
 	{
 		memcpy(&xr_usb_serial->line, &newline, sizeof newline);
+		/*
 		dev_dbg(&xr_usb_serial->control->dev, "%s - set line: %d %d %d %d\n",
 			__func__,
 			le32_to_cpu(newline.dwDTERate),
 			newline.bCharFormat, newline.bParityType,
-			newline.bDataBits);
+			newline.bDataBits);*/
+		
 		xr_usb_serial_set_line(xr_usb_serial, &xr_usb_serial->line);
 	}
 	xr_usb_serial_enable(xr_usb_serial);
@@ -1060,6 +1214,36 @@  static int xr_usb_serial_write_buffers_alloc(struct xr_usb_serial *xr_usb_serial
 	return 0;
 }
 
+#ifdef CONFIG_GPIOLIB
+static int xr_usb_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+    struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
+	dev_dbg(chip->dev, "xr_usb_gpio_get offset = %d channel = %d\n",offset,xr_usb_serial->channel);
+	return 0;
+}
+
+static void xr_usb_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+   struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
+   dev_dbg(chip->dev, "xr_usb_gpio_set offset =%d val=%d channel = %d\n",offset,val,xr_usb_serial->channel);
+}
+
+static int xr_usb_gpio_direction_input(struct gpio_chip *chip,unsigned offset)
+{
+	struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
+    dev_dbg(chip->dev, "xr_usb_gpio_direction_input offset =%d channel = %d\n",offset,xr_usb_serial->channel);
+	return 0;
+}
+
+static int xr_usb_gpio_direction_output(struct gpio_chip *chip,
+					   unsigned offset, int val)
+{
+    struct xr_usb_serial *xr_usb_serial = container_of(chip, struct xr_usb_serial, xr_usb_gpio);
+	dev_dbg(chip->dev, "xr_usb_gpio_direction_output offset =%d val=%d channel:%d\n",offset,val,xr_usb_serial->channel);
+	return 0;
+}
+#endif
+
 static int xr_usb_serial_probe(struct usb_interface *intf,
 		     const struct usb_device_id *id)
 {
@@ -1096,7 +1280,7 @@  static int xr_usb_serial_probe(struct usb_interface *intf,
 
 	num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : XR_USB_SERIAL_NR;
 	
-    dev_dbg(&intf->dev, "USB_device_id idVendor:%04x, idProduct %04x\n",id->idVendor,id->idProduct);
+    //dev_dbg(&intf->dev, "USB_device_id idVendor:%04x, idProduct %04x\n",id->idVendor,id->idProduct);
 	
 	/* handle quirks deadly to normal probing*/
 	if (quirks == NO_UNION_NORMAL) {
@@ -1337,7 +1521,7 @@  static int xr_usb_serial_probe(struct usb_interface *intf,
 	}
 	#else
 	xr_usb_serial->channel = epwrite->bEndpointAddress;
-	dev_dbg(&intf->dev, "epwrite->bEndpointAddress =%d\n",epwrite->bEndpointAddress);
+	//dev_dbg(&intf->dev, "epwrite->bEndpointAddress =%d\n",epwrite->bEndpointAddress);
 	#endif
 	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &xr_usb_serial->ctrl_dma);
 	if (!buf) {
@@ -1424,14 +1608,9 @@  static int xr_usb_serial_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, xr_usb_serial);
 
-	xr_usb_serial->rs485_422_en = false;	//default enable rs232
-	i = device_create_file(&intf->dev, &dev_attr_bRS485_422_en);
-	if (i < 0)
-		goto alloc_fail7;
-
 	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
 	if (i < 0)
-		goto alloc_fail8;
+		goto alloc_fail7;
 
 	if (cfd) { /* export the country data */
 		xr_usb_serial->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
@@ -1470,7 +1649,7 @@  static int xr_usb_serial_probe(struct usb_interface *intf,
 	xr_usb_serial->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	xr_usb_serial->ctrlurb->transfer_dma = xr_usb_serial->ctrl_dma;
 
-	dev_info(&intf->dev, "ttyXR_USB_SERIAL%d: USB XR_USB_SERIAL device\n", minor);
+	//dev_info(&intf->dev, "ttyXR_USB_SERIAL%d: USB XR_USB_SERIAL device channel:%d\n", minor,xr_usb_serial->channel);
 	
     xr_usb_serial_pre_setup(xr_usb_serial);
 	
@@ -1491,12 +1670,26 @@  static int xr_usb_serial_probe(struct usb_interface *intf,
 			&control_interface->dev);
 	if (IS_ERR(tty_dev)) {
 		rv = PTR_ERR(tty_dev);
-		goto alloc_fail9;
+		goto alloc_fail8;
 	}
 #endif	
-
+#ifdef CONFIG_GPIOLIB	
+   	/* Setup GPIO cotroller */
+	xr_usb_serial->xr_usb_gpio.owner		 = THIS_MODULE;
+	xr_usb_serial->xr_usb_gpio.dev		 = &control_interface->dev;
+	xr_usb_serial->xr_usb_gpio.label		 = dev_name(&control_interface->dev);
+	xr_usb_serial->xr_usb_gpio.direction_input	 = xr_usb_gpio_direction_input;
+	xr_usb_serial->xr_usb_gpio.get		 = xr_usb_gpio_get;
+	xr_usb_serial->xr_usb_gpio.direction_output = xr_usb_gpio_direction_output;
+	xr_usb_serial->xr_usb_gpio.set		 = xr_usb_gpio_set;
+	xr_usb_serial->xr_usb_gpio.base		 = 100 + xr_usb_serial->channel*10;
+	xr_usb_serial->xr_usb_gpio.ngpio		 = 4;
+	xr_usb_serial->xr_usb_gpio.can_sleep	 = 1;
+	rv = gpiochip_add(&xr_usb_serial->xr_usb_gpio);
+	dev_dbg(&xr_usb_serial->control->dev, "gpiochip_add %d\n",rv);
+#endif		
 	return 0;
-alloc_fail9:
+alloc_fail8:
 	if (xr_usb_serial->country_codes) {
 		device_remove_file(&xr_usb_serial->control->dev,
 				&dev_attr_wCountryCodes);
@@ -1504,8 +1697,6 @@  static int xr_usb_serial_probe(struct usb_interface *intf,
 				&dev_attr_iCountryCodeRelDate);
 	}
 	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bmCapabilities);
-alloc_fail8:
-	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bRS485_422_en);
 alloc_fail7:
 	usb_set_intfdata(intf, NULL);
 	for (i = 0; i < XR_USB_SERIAL_NW; i++)
@@ -1530,7 +1721,7 @@  static void stop_data_traffic(struct xr_usb_serial *xr_usb_serial)
 {
 	int i;
 
-	dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
+	//dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__);
 
 	usb_kill_urb(xr_usb_serial->ctrlurb);
 	for (i = 0; i < XR_USB_SERIAL_NW; i++)
@@ -1548,7 +1739,7 @@  static void xr_usb_serial_disconnect(struct usb_interface *intf)
 	struct tty_struct *tty;
 	int i;
 
-	dev_dbg(&intf->dev, "%s\n", __func__);
+	//dev_dbg(&intf->dev, "%s\n", __func__);
 
 	/* sibling interface is already cleaning up */
 	if (!xr_usb_serial)
@@ -1563,7 +1754,6 @@  static void xr_usb_serial_disconnect(struct usb_interface *intf)
 				&dev_attr_iCountryCodeRelDate);
 	}
 	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bmCapabilities);
-	device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bRS485_422_en);
 	usb_set_intfdata(xr_usb_serial->control, NULL);
 	usb_set_intfdata(xr_usb_serial->data, NULL);
 	mutex_unlock(&xr_usb_serial->mutex);
@@ -1631,7 +1821,9 @@  static int xr_usb_serial_resume(struct usb_interface *intf)
 	struct xr_usb_serial_wb *wb;
 	int rv = 0;
 	int cnt;
-
+	     
+	xr_usb_serial_pre_setup(xr_usb_serial);
+	
 	spin_lock_irq(&xr_usb_serial->read_lock);
 	xr_usb_serial->susp_count -= 1;
 	cnt = xr_usb_serial->susp_count;
@@ -1670,7 +1862,10 @@  static int xr_usb_serial_resume(struct usb_interface *intf)
 static int xr_usb_serial_reset_resume(struct usb_interface *intf)
 {
 	struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf);
-    struct tty_struct *tty;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
+#else
+   	struct tty_struct *tty;
+#endif
 	if (test_bit(ASYNCB_INITIALIZED, &xr_usb_serial->port.flags)){
 #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0)	
 	tty_port_tty_hangup(&xr_usb_serial->port, false);
@@ -1745,14 +1940,11 @@  static const struct tty_operations xr_usb_serial_ops = {
 	.tiocmget =		xr_usb_serial_tty_tiocmget,
 	.tiocmset =		xr_usb_serial_tty_tiocmset,
 };
-
-/*
- * Init / exit.
- */
-
 static int __init xr_usb_serial_init(void)
 {
 	int retval;
+	int i;
+	
 	xr_usb_serial_tty_driver = alloc_tty_driver(XR_USB_SERIAL_TTY_MINORS);
 	if (!xr_usb_serial_tty_driver)
 		return -ENOMEM;
@@ -1780,17 +1972,17 @@  static int __init xr_usb_serial_init(void)
 		put_tty_driver(xr_usb_serial_tty_driver);
 		return retval;
 	}
-
+  
 	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
 
 	return 0;
 }
-
 static void __exit xr_usb_serial_exit(void)
 {
 	usb_deregister(&xr_usb_serial_driver);
 	tty_unregister_driver(xr_usb_serial_tty_driver);
 	put_tty_driver(xr_usb_serial_tty_driver);
+	
 }
 
 module_init(xr_usb_serial_init);
diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_common.h b/ubuntu/xr-usb-serial/xr_usb_serial_common.h
index fe3460c57adf..97e902425794 100644
--- a/ubuntu/xr-usb-serial/xr_usb_serial_common.h
+++ b/ubuntu/xr-usb-serial/xr_usb_serial_common.h
@@ -70,6 +70,11 @@ 
 #define XR_USB_SERIAL_NW  16
 #define XR_USB_SERIAL_NR  16
 
+#define RAMCTL_BUFFER_PARITY                               0x1
+#define RAMCTL_BUFFER_BREAK                                0x2
+#define RAMCTL_BUFFER_FRAME                                0x4
+#define RAMCTL_BUFFER_OVERRUN                              0x8
+
 struct xr_usb_serial_wb {
 	unsigned char *buf;
 	dma_addr_t dmah;
@@ -144,10 +149,19 @@  struct xr_usb_serial {
 	u8 bInterval;
 	struct xr_usb_serial_wb *delayed_wb;			/* write queued for a device about to be woken */
 	unsigned int channel;
+	int           preciseflags; /* USB: wide mode, TTY: flags per character */
+    int           trans9;   /* USB: wide mode, serial 9N1 */
+	int           have_extra_byte;
+    int           extra_byte;
+	
 	unsigned short DeviceVendor;
 	unsigned short DeviceProduct;
+#ifdef CONFIG_GPIOLIB	
+	struct gpio_chip   xr_usb_gpio;
+#endif
 	struct reg_addr_map reg_map;
-	bool rs485_422_en;
+    int found_smbios_exar_config;
+	unsigned char channel_config;
 };
 
 #define CDC_DATA_INTERFACE_TYPE	0x0a
diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_hal.c b/ubuntu/xr-usb-serial/xr_usb_serial_hal.c
index f44970995368..bf9d2bf136ac 100644
--- a/ubuntu/xr-usb-serial/xr_usb_serial_hal.c
+++ b/ubuntu/xr-usb-serial/xr_usb_serial_hal.c
@@ -31,7 +31,7 @@  int xr_usb_serial_set_reg(struct xr_usb_serial *xr_usb_serial,int regnum, int va
 {
 	int result;
 	int channel = 0;
-	dev_dbg(&xr_usb_serial->control->dev, "%s Channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
+	//dev_info(&xr_usb_serial->control->dev, "%s Channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
 	if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1400)
 	{
 	    int XR2280xaddr = XR2280x_FUNC_MGR_OFFSET + regnum; 
@@ -97,7 +97,7 @@  int xr_usb_serial_set_reg(struct xr_usb_serial *xr_usb_serial,int regnum, int va
 	    result = -1;
 	}
 	if(result < 0)
-		dev_dbg(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
+		dev_err(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
     return result;
 	
        
@@ -106,7 +106,7 @@  int xr_usb_serial_set_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
 {
 	int result;
 	int XR2280xaddr = XR2280x_FUNC_MGR_OFFSET + regnum; 
-	dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
+	//dev_info(&xr_usb_serial->control->dev, "%s channel:%d 0x%02x = 0x%02x\n", __func__,channel,regnum, value);
 	if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1400)
 	{
 		result = usb_control_msg(xr_usb_serial->dev,                     /* usb device */
@@ -165,7 +165,7 @@  int xr_usb_serial_set_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
 	    result = -1;
 	}
 	if(result < 0)
-		dev_dbg(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
+		dev_err(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
     return result;
 	
        
@@ -242,9 +242,9 @@  int xr_usb_serial_get_reg(struct xr_usb_serial *xr_usb_serial,int regnum, short
 	}
 	
 	if(result < 0)
-		dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d Reg 0x%x Error:%d\n", __func__,channel,regnum,result);
-	else
-	    dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
+		dev_err(&xr_usb_serial->control->dev, "%s channel:%d Reg 0x%x Error:%d\n", __func__,channel,regnum,result);
+	//else
+	    //dev_info(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
 	
 	return result;
 
@@ -285,7 +285,7 @@  int xr_usb_serial_get_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
                                  &reg_value,                           /* data */
                                  1,                               /* size */
                                  5000);                           /* timeout */
-	   dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_get_reg_ext reg:%x\n",reg_value);
+	   //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_get_reg_ext reg:%x\n",reg_value);
 	   *value = reg_value; 
 	}
 	else if(xr_usb_serial->DeviceProduct == 0x1411) 
@@ -320,9 +320,9 @@  int xr_usb_serial_get_reg_ext(struct xr_usb_serial *xr_usb_serial,int channel,in
 	}
 	
 	if(result < 0)
-		dev_dbg(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
-	else
-	    dev_dbg(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
+		dev_err(&xr_usb_serial->control->dev, "%s Error:%d\n", __func__,result);
+	//else
+	    //dev_info(&xr_usb_serial->control->dev, "%s channel:%d 0x%x = 0x%04x\n", __func__,channel,regnum, *value);
 	
 	return result;
 
@@ -384,7 +384,7 @@  static int xr21v141x_set_baud_rate(struct xr_usb_serial *xr_usb_serial, unsigned
 	unsigned int 	tx_mask = xr21v141x_baud_rates[i].tx;
 	unsigned int 	rx_mask = (divisor & 1) ? xr21v141x_baud_rates[i].rx1 : xr21v141x_baud_rates[i].rx0;
 
-	dev_dbg(&xr_usb_serial->control->dev, "Setting baud rate to %d: i=%u div=%u tx=%03x rx=%03x\n", rate, i, divisor, tx_mask, rx_mask);
+	//dev_info(&xr_usb_serial->control->dev, "Setting baud rate to %d: i=%u div=%u tx=%03x rx=%03x\n", rate, i, divisor, tx_mask, rx_mask);
 
 	xr_usb_serial_set_reg(xr_usb_serial,UART_CLOCK_DIVISOR_0, (divisor >>  0) & 0xff);
 	xr_usb_serial_set_reg(xr_usb_serial,UART_CLOCK_DIVISOR_1, (divisor >>  8) & 0xff);
@@ -458,7 +458,7 @@  int xr_usb_serial_set_line(struct xr_usb_serial *xr_usb_serial, struct usb_cdc_l
 	
 	if (cflag & CRTSCTS)
 	{
-	    dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:hardware\n");
+	    //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:hardware\n");
 	    flow      = UART_FLOW_MODE_HW;
 	    gpio_mode = UART_GPIO_MODE_SEL_RTS_CTS;
 	} 
@@ -466,7 +466,7 @@  int xr_usb_serial_set_line(struct xr_usb_serial *xr_usb_serial, struct usb_cdc_l
 	{
 	    unsigned char   start_char = START_CHAR(tty);
 	    unsigned char   stop_char  = STOP_CHAR(tty);
-        dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:software\n");
+        //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:software\n");
 	    flow      = UART_FLOW_MODE_SW;
 	    gpio_mode = UART_GPIO_MODE_SEL_GPIO;
 
@@ -475,23 +475,47 @@  int xr_usb_serial_set_line(struct xr_usb_serial *xr_usb_serial, struct usb_cdc_l
 	}
 	else
 	{
-	    dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:none\n");
+	    //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_set_flow_mode:none\n");
 	    flow      = UART_FLOW_MODE_NONE;
 	    gpio_mode = UART_GPIO_MODE_SEL_GPIO;
 	}
-	// rs485,rs422 FD/HD mode
-	if (xr_usb_serial->rs485_422_en) {
-		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);
-		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0B);
-	} else {
-		//rs232, default mode
-		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, flow);
-		xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, gpio_mode);
+	
+    if((xr_usb_serial->DeviceProduct == 0x1420)||
+	   (xr_usb_serial->DeviceProduct == 0x1422)||
+	   (xr_usb_serial->DeviceProduct == 0x1424))
+    {//Add support for the TXT and RXT function for 0x1420, 0x1422, 0x1424, by setting GPIO_MODE [9:8] = '11'
+        gpio_mode |= 0x300;
+    }
+	
+    if((xr_usb_serial->DeviceProduct == 0x1412)||
+	  (xr_usb_serial->DeviceProduct == 0x1414))
+    {
+      if(xr_usb_serial->found_smbios_exar_config)
+	  	{
+	  	   if((xr_usb_serial->channel_config == 2)
+		   	 ||(xr_usb_serial->channel_config == 3))
+	  	   //if find the exar channel config in the smbios, the value can not be changed  by the application
+	  	   //dev_info(&xr_usb_serial->control->dev, "Sorry, Application can not change the channel gpio&flow mode,because there are config at SMBIOS\n");
+	  	   return 0;
+		}
+    }
+		
+    xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, flow);
+	
+	if((xr_usb_serial->found_smbios_exar_config == 1)&&(xr_usb_serial->channel_config == 1))
+	{
+       //dev_info(&xr_usb_serial->control->dev, "Sorry, Application can not change the channel gpio mode,because there are config at SMBIOS\n");
 	}
+	else
+	   xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, gpio_mode);
+	
 	return 0;
 	 
 
  }
+
+
+
  
 int xr_usb_serial_send_break(struct xr_usb_serial *xr_usb_serial, int state)
 {
@@ -516,11 +540,17 @@  int xr_usb_serial_send_break(struct xr_usb_serial *xr_usb_serial, int state)
 #define URM_ENABLE_BASE        0x010
 #define URM_ENABLE_0_TX        0x001
 #define URM_ENABLE_0_RX        0x002
+#define URM_RESET_RX_FIFO_BASE        0x018
+#define URM_RESET_TX_FIFO_BASE        0x01C
+
+
 
 int xr_usb_serial_enable(struct xr_usb_serial *xr_usb_serial)
 {
 	int ret = 0;
 	int channel = xr_usb_serial->channel;
+	//dev_info(&xr_usb_serial->control->dev, "xr_usb_serial_enable channel=%d\n",channel);
+	if(channel) channel--;
 	if((xr_usb_serial->DeviceProduct == 0x1410)||
 	   (xr_usb_serial->DeviceProduct == 0x1412)||
 	   (xr_usb_serial->DeviceProduct == 0x1414))
@@ -536,10 +566,31 @@  int xr_usb_serial_enable(struct xr_usb_serial *xr_usb_serial)
 	
 	return ret;
 }
+int xr_usb_serial_fifo_reset(struct xr_usb_serial *xr_usb_serial)
+{
+	    int ret = 0;
+		int channel = xr_usb_serial->channel;
+		
+		if(channel) channel--;
+		if((xr_usb_serial->DeviceProduct == 0x1410)||
+		   (xr_usb_serial->DeviceProduct == 0x1412)||
+		   (xr_usb_serial->DeviceProduct == 0x1414))
+		{
+		   
+		  ret = xr_usb_serial_set_reg_ext(xr_usb_serial,URM_REG_BLOCK,URM_RESET_RX_FIFO_BASE + channel,0xff);
+		  ret |= xr_usb_serial_set_reg_ext(xr_usb_serial,URM_REG_BLOCK,URM_RESET_TX_FIFO_BASE + channel,0xff);
+		   
+		}
+		return ret;
+}
+
+
 int xr_usb_serial_disable(struct xr_usb_serial *xr_usb_serial)
 {
 	int ret = 0;
 	int channel = xr_usb_serial->channel;
+	//dev_info(&xr_usb_serial->control->dev, "xr_usb_serial_disable channel=%d\n",channel);
+	if(channel) channel--;
 	ret = xr_usb_serial_set_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_enable_addr,0);
 	if((xr_usb_serial->DeviceProduct == 0x1410)||
 	   (xr_usb_serial->DeviceProduct == 0x1412)||
@@ -554,12 +605,81 @@  int xr_usb_serial_set_loopback(struct xr_usb_serial *xr_usb_serial, int channel)
 {
 	int ret = 0;
 	xr_usb_serial_disable(xr_usb_serial);
-	ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
+	
+	if((xr_usb_serial->DeviceProduct == 0x1410) ||
+		    (xr_usb_serial->DeviceProduct == 0x1412) ||
+		    (xr_usb_serial->DeviceProduct == 0x1414))
+	{
+		switch (channel)
+		{
+			case 0:
+				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
+		                            xr_usb_serial->reg_map.uart_loopback_addr,0x40);
+			break;
+			case 1:
+				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
+		                            xr_usb_serial->reg_map.uart_loopback_addr,0x41);
+			break;
+			case 2:
+				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
+		                            xr_usb_serial->reg_map.uart_loopback_addr,0x42);
+			break;
+			case 3:
+				 ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
+		                            xr_usb_serial->reg_map.uart_loopback_addr,0x43);
+			break;
+			default:
+				
+			break;
+		}
+	}
+	else if((xr_usb_serial->DeviceProduct == 0x1420)||
+		    (xr_usb_serial->DeviceProduct == 0x1422)||
+		    (xr_usb_serial->DeviceProduct == 0x1424))
+	{
+	  ret = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,
 		                            xr_usb_serial->reg_map.uart_loopback_addr,0x07);
+	}
 	xr_usb_serial_enable(xr_usb_serial);
 	return ret;
 }
 
+#define XR21V1414_WIDE_MODE_OFFSET         3
+#define XR21B142X_WIDE_MODE_TX_OFFSET     0x42
+#define XR21B142X_WIDE_MODE_RX_OFFSET     0x45
+int xr_usb_serial_set_wide_mode(struct xr_usb_serial *xr_usb_serial, int preciseflags)
+{
+    int ret = 0;
+	int channel = xr_usb_serial->channel;  
+	xr_usb_serial_disable(xr_usb_serial);
+    if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1400)
+	{
+		
+	}
+	else if((xr_usb_serial->DeviceProduct == 0x1410)||
+		   (xr_usb_serial->DeviceProduct == 0x1412)||
+		   (xr_usb_serial->DeviceProduct == 0x1414))
+	{
+	 
+	  if(channel)  channel--;
+	  xr_usb_serial_set_reg_ext(xr_usb_serial, 0x66, channel*8 + XR21V1414_WIDE_MODE_OFFSET, preciseflags);
+		
+	}
+	else if(xr_usb_serial->DeviceProduct == 0x1411)
+	{
+	  xr_usb_serial_set_reg(xr_usb_serial,0xd02, preciseflags);
+	}
+	else if((xr_usb_serial->DeviceProduct == 0x1420)||
+		   (xr_usb_serial->DeviceProduct == 0x1422)||
+		   (xr_usb_serial->DeviceProduct == 0x1424))
+	{
+	  xr_usb_serial_set_reg(xr_usb_serial, XR21B142X_WIDE_MODE_TX_OFFSET, preciseflags); 
+	  xr_usb_serial_set_reg(xr_usb_serial, XR21B142X_WIDE_MODE_RX_OFFSET, preciseflags); 
+	}
+	xr_usb_serial_enable(xr_usb_serial);  
+	return ret;
+}
+
 
 static int xr_usb_serial_tiocmget(struct xr_usb_serial *xr_usb_serial)
 
@@ -567,7 +687,7 @@  static int xr_usb_serial_tiocmget(struct xr_usb_serial *xr_usb_serial)
         short data;
 		int result;
 		result = xr_usb_serial_get_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_status_addr, &data);
-		dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tiocmget uart_gpio_status_addr:0x%04x\n",data);
+		//dev_info(&xr_usb_serial->control->dev, "xr_usb_serial_tiocmget uart_gpio_status_addr:0x%04x\n",data);
 		if (result)
 			return ((data & 0x8) ? 0: TIOCM_DTR) | ((data & 0x20) ? 0:TIOCM_RTS ) | ((data & 0x4) ? 0:TIOCM_DSR) | ((data & 0x1) ? 0 : TIOCM_RI) | ((data & 0x2) ? 0:TIOCM_CD) | ((data & 0x10) ? 0 : TIOCM_CTS); 
 		else
@@ -675,11 +795,12 @@  static void init_xr21b142x_reg_map(void)
 	xr21b140x_reg_map.uart_custom_driver = 0x60;
 	xr21b140x_reg_map.uart_low_latency = 0x46;
 }
-
+int smbios_check_if_have_exar_config(unsigned char *config0,unsigned char *config1);
 int xr_usb_serial_pre_setup(struct xr_usb_serial *xr_usb_serial)
 {
 	int ret = 0;
-	
+	unsigned char channel1_config = 255;
+	unsigned char channel2_config = 255;
 	init_xr21b140x_reg_map();
 	init_xr21b1411_reg_map();
 	init_xr21v141x_reg_map();
@@ -716,9 +837,74 @@  int xr_usb_serial_pre_setup(struct xr_usb_serial *xr_usb_serial)
 	xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_dir_addr, 0x28);  
     xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_set_addr, UART_GPIO_SET_DTR | UART_GPIO_SET_RTS); 
 	
+	if((xr_usb_serial->DeviceProduct == 0x1412)||
+	  (xr_usb_serial->DeviceProduct == 0x1414))
+	{
+	  xr_usb_serial->found_smbios_exar_config = 0;
+	  if(smbios_check_if_have_exar_config(&channel1_config,&channel2_config) == 0)
+	  {
+	     
+		 if(xr_usb_serial->channel == 1)
+		 {
+		    xr_usb_serial->found_smbios_exar_config = 1;
+			xr_usb_serial->channel_config = channel1_config;
+			switch (channel1_config)
+		    {
+				case 1://for RS232 Mode
+				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS232\n");
+				    xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0); 
+					
+				break;
+				case 2://RS-485 HALF DUPLEX
+				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485 HALF DUPLEX\n");
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b); 
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
+				break;
+				case 3://RS-485/422 FULL DUPLEX 
+				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485/422 FULL DUPLEX\n");
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b);
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
+				break;
+				default:
+					xr_usb_serial->found_smbios_exar_config = 0;
+				break;
+		     }
+			
+		 }
+		 else if(xr_usb_serial->channel == 2)
+		 {
+		    xr_usb_serial->found_smbios_exar_config = 1;
+			xr_usb_serial->channel_config = channel2_config;
+			switch (channel2_config)
+		    {
+				case 1://for RS232 Mode
+				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS232\n");
+				    xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0); 
+					
+				break;
+				case 2://RS-485 HALF DUPLEX
+				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485 HALF DUPLEX\n");
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b); 
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
+				break;
+				case 3://RS-485/422 FULL DUPLEX 
+				    //dev_info(&xr_usb_serial->control->dev, "SMBIOS Set Channel Mode to RS-485/422 FULL DUPLEX\n");
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_gpio_mode_addr, 0x0b);
+					xr_usb_serial_set_reg(xr_usb_serial, xr_usb_serial->reg_map.uart_flow_addr, 0x00);  
+				break;
+				default:
+				   xr_usb_serial->found_smbios_exar_config = 0;
+				break;
+		     }
+		 }
+		 else
+		 {
+		   //Nothing to do
+		 }
+	  }
+	  
+	}
     return ret;
    
 }
 
-	
-
diff --git a/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h b/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h
index c28b6bdc0b16..81394aac3290 100644
--- a/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h
+++ b/ubuntu/xr-usb-serial/xr_usb_serial_ioctl.h
@@ -24,6 +24,13 @@ 
 #define XR_USB_SERIAL_SET_PRECISE_FLAGS     	_IO(XR_USB_SERIAL_IOC_MAGIC, 4)
 #define XR_USB_SERIAL_TEST_MODE         	_IO(XR_USB_SERIAL_IOC_MAGIC, 5)
 #define XR_USB_SERIAL_LOOPBACK          	_IO(XR_USB_SERIAL_IOC_MAGIC, 6)
+#define XR_USB_SERIAL_SET_GPIO_MODE_REG    _IO(XR_USB_SERIAL_IOC_MAGIC, 9) 
+#define	XR_USB_SERIAL_GET_GPIO_MODE_REG    _IO(XR_USB_SERIAL_IOC_MAGIC, 10) 
+#define XRIOC_SET_ANY_BAUD_RATE           _IO(XR_USB_SERIAL_IOC_MAGIC, 11)
+#define XRIOC_SET_PRECISE_FLAGS     	   _IO(XR_USB_SERIAL_IOC_MAGIC, 12)
+
+
+
 
 #define VZ_ADDRESS_UNICAST_S        	0
 #define VZ_ADDRESS_BROADCAST_S      	8