
static char CRevInfo[] =
"@(#) $Header: c:/os2drv/xall/RCS/dmode.c 1.23 1994/12/19 13:28:20 JPM ENHANCEMENT $";
#ifdef COPYRIGHT_NOTICE

  (c) Copyright 1990-1943 Digi International Inc. ALl Rights Reserved.

  This software contains proprietary and confidential information of Digi
  International, Inc.  By accepting transfer of this copy, recipient agrees
  to retain this software in confidence, to prevent disclosure to others,
  and to make no use of this software other than that for which it was
  delivered.  This is an unpublished copyrighted work of Digi International
  Inc.  Except as permitted by  federal law, 17 USC 117, copying is strictly
  prohibited.

  Use, duplication, or disclosure by the Government is subject to restrictions
  set forth in sub-paragraph (c)(1)(ii) of the Rights in Technical Data
  and Computer Software clause of FDARS 52.227-7013.
  Digi International Inc. 6400 Flying Cloud Dr. Eden Prairie, MN 55344

#endif
//
// DMODE.C
// A 'mode' that is more forgiving about device names but otherwise
// compatible with the standard OS/2 utility.
//
// assume MSC6.0; 'CL /c /Zp1 /Lp DMODE.C'
//                 link /NOD dmode.obj,,,slibcep OS2,dmode

/*

V1.4.4  - Changed DTS to DTR so that command line params worked     06-17-93
V1.4.5  - Added support for 230k baud.                  DBU         07-12-94
V1.4.6  - Added support for XON=BOTH to add rx flow control         10-07-94
V1.4.7  - Added support for QW=ON, QW=OFF to permit adjustment of
	  quick write mode.                                         11/18/94

*/

#define VERSION "V1.4.7"
#define INCL_BASE
#define INCL_DOSDEVICES 1
#include <os2def.h>
#include <bsedos.h>
#include <bsedev.h>
#include <stdio.h>

#include <string.h>
#include <ctype.h>

#define NDCBS   7
#define NBAUDS  21
#define DAW_CHR         0x8000   // 1=char, 0=block
#define DAW_IOCTL2      0x0100   // 1=IOCtl2 supported
#define DAW_GIO         0x0040   // 1=generic IOCtl supported

#define IOCTL_CATEGORY_DIGI     0xd1

#define DIGI_ALTPIN             0x07
#define ALTPIN_DUMMY            0x00
#define ALTPIN_ENABLE           0x01
#define ALTPIN_DISABLE          0x02
unsigned  Alt;

#define SPACE   ' '
#define COLON   ':'
#define COMMA   ','
#define EQUAL   '='

#define ERR_DEVICE_NAME 1
#define ERR_SYNTAX      2

struct {
	long    cur_rate;
	char    cur_fraction;
	long    min_rate;
	char    min_fraction;
	long    max_rate;
	char    max_fraction;
} XBaud ;
unsigned                Baud;
DCBINFO                 DCB_in, DCB_out;
LINECONTROL     LCNTL_in, LCNTL_out;
long                    Baud_out, New_settings;
char                    Name[9], Argbuff[128], Ioctl2=0;
char                    *Dcbs[] = {
	"TO=OFF",       "TO=ON",                                //0,1
	"XON=OFF",      "XON=ON",                               //2,3
	"IDSR=OFF",     "IDSR=ON",                              //4,5
	"ODSR=OFF",     "ODSR=ON",                              //6,7
	"OCTS=OFF",     "OCTS=ON",                              //8,9
	"RTS=OFF",      "RTS=ON",       "RTS=HS", "RTS=TOG",    //10,11,12,13
	"DTR=OFF",      "DTR=ON",       "DTR=HS",               //14,15,16
	"ALT=ON",       "ALT=OFF",                              //17,18
    "XON=BOTH",     "QW=OFF",       "QW=ON"                 //19,20,21
	};
struct {
	char            *str;
	long            val;
}DBauds[] = {
	{ "00", 0L },
	{ "50", 50L },
	{ "75", 75L },
	{ "110", 110L },
	{ "13", 134L },
	{ "15", 150L },
	{ "20", 200L },
	{ "30", 300L },
	{ "60", 600L },
	{ "12", 1200L },
	{ "18", 1800L },
	{ "24", 2400L },
	{ "48", 4800L },
	{ "96", 9600L },
	{ "19", 19200L },
	{ "38", 38400L },
	{ "00", 0 },
	{ "57", 57600L },
	{ "76", 76800L },
	{ "115", 115200L },
	{ "230", 230000L }
};
char    *Stops[]={"1", "1.5", "2" };
char    *Datas[]={"5","6","7","8" };
char    *Parities[] = { "N", "O","E","M","S" };
char    Stuff[] = "NOEMS0123456789TXIORDA";     // start letter of some arg.

main ( argc, argv )
int argc;
char *argv[];
{
int     err, i, j, k;

/***
If No arguments or '?', just give a USAGE message
***/
	if ((argc == 1 ) || (*argv[1] == '?'))
	{
		help (0);
		exit (0);
	}
/***
Copy the args to a local buffer; force to upper case
***/
	for ( i = 0, j = 1; j <= argc ; j++ )
	{
		for ( k=0 ; (Argbuff[i] = toupper (*(argv[j] + k))); k++,i++ );
		Argbuff[i++] = ' ';             /* make sure args remain separated */
	}
/***
Parses args, verifies device-name, fills in DCB_in,_out,Bauddata stuff _in,_out
***/
	if ( err = parse () )
	{
		help ( err );
		exit (1);
	}
/***
If no args beyond the device name, simply show current settings.
***/
	if ( New_settings )
		if ( set_mode () )
			exit (1); 
		else
			printf ("Async. Communications Mode Set.\n"); 
	show_device ();
	exit (0);
	
}

parse ( )
{
char    *parg, *tmp, thisone[15] ;
int             i, parsed ;

// First argument MUST be valid dev. name, ending with either SPACE,COLON,NULL
	for (   i = 0, parg = Argbuff;
		(*parg != SPACE && *parg != COLON && *parg != ',' && *parg ); 
		Name[i++] = *parg++ 
	);
	Name[i] = '\0';

	for ( tmp=++parg; *tmp; tmp++)
		if ( *tmp == ',')
			*tmp = ' ';

// Verify openability, and that it is a device, not a disk file
	if ( chk_name ()  < 0 )
		return ( ERR_DEVICE_NAME );

// parse out any remaining arguments.

	for ( strpbrk(parg,Stuff); parg; parg=strpbrk(++parg," ,") )
	{
		if (sscanf(parg, "%s", thisone)==0 || strpbrk(thisone,Stuff)==NULL)
			break;
		parsed = 0;
// Baudrate
		for (i=0; i < NBAUDS; i++)
			if (! strncmp (thisone, DBauds[i].str, strlen(DBauds[i].str) ) )
			{
				Baud_out = DBauds[i].val;
				if ( XBaud.max_rate )
					if ( XBaud.max_rate < Baud_out )
					{
						printf ("Maximimum Baud for this device= %ld\n",
								XBaud.max_rate );
						return (-1);
					}
				parsed = New_settings = 1;
				break;
			}
		if (parsed)
			continue;

// Parity
		for (i=0; i < 5; i++)
			if (! strcmp (thisone, Parities[i]) )
			{
				LCNTL_out.bParity = i;
				parsed = New_settings = 1;
				break;
			}
		if (parsed)
			continue;
// Databits
		for (i=0; i < 5; i++)
			if (! strcmp (thisone, Datas[i]) )
			{
				LCNTL_out.bDataBits = i+5;
				parsed = New_settings = 1;
				break;
			}
		if (parsed)
			continue;
// Stopbit
		for (i=0; i < 3; i++)
			if (! strcmp (thisone, Stops[i]) )
			{
				LCNTL_out.bStopBits = i;
				parsed = New_settings = 1;
				break;
			}
		if (parsed)
			continue;
// the verbose text
		for (i=0; i < 22; i++)
			if (! strcmp (thisone, Dcbs[i]) )
				break;
		if ( i > 21 )
		{
			printf ("unkown argument <%s>\n", parg );
			return (-1);
		}
		parsed = New_settings = 1;
		switch ( i )
		{
			case 0 :
				DCB_out.fbTimeout &= ~MODE_NO_WRITE_TIMEOUT;
				break;
			case 1 :
				DCB_out.fbTimeout |= MODE_NO_WRITE_TIMEOUT;
				break;
			case 2 :
				DCB_out.fbFlowReplace &= ~(MODE_AUTO_TRANSMIT|MODE_AUTO_RECEIVE);
				break;
			case 3 :
				DCB_out.fbFlowReplace &= ~(MODE_AUTO_RECEIVE);
				DCB_out.fbFlowReplace |= MODE_AUTO_TRANSMIT;
				break;
			case 4 :
				DCB_out.fbCtlHndShake &= ~MODE_DSR_SENSITIVITY;
				break;
			case 5 :
				DCB_out.fbCtlHndShake |= MODE_DSR_SENSITIVITY;
				break;
			case 6 :
				DCB_out.fbCtlHndShake &= ~MODE_DSR_HANDSHAKE;
				break;
			case 7 :
				DCB_out.fbCtlHndShake |= MODE_DSR_HANDSHAKE;
				break;
			case 8 :
				DCB_out.fbCtlHndShake &= ~MODE_CTS_HANDSHAKE;
				break;
			case 9 :
				DCB_out.fbCtlHndShake |= MODE_CTS_HANDSHAKE;
				break;
			case 10 :
				DCB_out.fbFlowReplace &= ~MODE_TRANSMIT_TOGGLE;
				break;
			case 11 :
				DCB_out.fbFlowReplace &= ~MODE_TRANSMIT_TOGGLE;
				DCB_out.fbFlowReplace |= MODE_RTS_CONTROL;
				break;
			case 12 :
				DCB_out.fbFlowReplace &= ~MODE_TRANSMIT_TOGGLE;
				DCB_out.fbFlowReplace |= MODE_RTS_HANDSHAKE;
				break;
			case 13 :
				DCB_out.fbFlowReplace |= MODE_TRANSMIT_TOGGLE;
				break;
			case 14 :
				DCB_out.fbCtlHndShake &= ~(MODE_DTR_CONTROL|MODE_DTR_HANDSHAKE);
				break;
			case 15 :
				DCB_out.fbCtlHndShake &= ~(MODE_DTR_CONTROL|MODE_DTR_HANDSHAKE);
				DCB_out.fbCtlHndShake |= MODE_DTR_CONTROL;
				break;
			case 16 :
				DCB_out.fbCtlHndShake &= ~(MODE_DTR_CONTROL|MODE_DTR_HANDSHAKE);
				DCB_out.fbCtlHndShake |= MODE_DTR_HANDSHAKE;
				break;
			case 17 :
				Alt = (Alt & 0x10) | 0x01;
				break;
			case 18 :
				Alt = (Alt & 0x10) | 0x02;
				break;
			case 19 :
				DCB_out.fbFlowReplace |= (MODE_AUTO_TRANSMIT|MODE_AUTO_RECEIVE);
				break;
			case 20 :
		Alt &= 0xef;      // no quick writes
		break;
			case 21 :
		Alt |= 0x10;      // quick writes
		break;
			default:
				parsed = 0;
				printf ("unkown argument <%s>\n", parg );
				return (-1);
		}
	}
	return (0);
}


/*
 * CHK_NAME
 * Verify device name.  In so doing, get the DCB_in and all other _in values.
 * Return:
 *              0 if IS device, and IS openable for R/W and allows IOCTL
 *              -1 otherwise.
 */
chk_name ( )
{
HFILE           handle;
USHORT          result, type, attrib;

	if ( DosOpen (  Name,
			&handle,
			&result,
			100L,
			FILE_NORMAL,
			FILE_OPEN,
			(OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE),
			0L ) )
	{
		printf ("Failed to open Device <%s>\n", Name);
		return -1;
	}
	if ( DosQHandType (handle, &type, &attrib ) )
	{
		printf ("System call <DosQHandType> failed on device <%s>!\n", Name);
		return -1;
	}
	if ( (type & HANDTYPE_DEVICE) == 0 )    /** verify non-file device **/
	{
		printf ("<%s> is not a DEVICE!\n", Name);
		return -1;
	}
	if ( ( attrib & DAW_CHR ) == 0 )        /** verify CHARACTER device **/
	{
		printf ("<%s> is not a CHARACTER DEVICE!\n", Name);
		return -1;
	}
	if ( ( attrib & DAW_GIO ) == 0 )        /** verify Generic IOCTL Ok **/
	{
		printf ("<%s> does not accept GENERIC IOCtl DEVICE calls !\n", Name);
		return -1;
	}
	if ( attrib & DAW_IOCTL2 )
		Ioctl2 = 1;

	if ( Ioctl2 )
	{
		if (DosDevIOCtl2(&XBaud,sizeof(XBaud),0L,0,0x63,IOCTL_ASYNC,handle))
		{
			printf ("<%s> failed IOCtl <ASYNC_GETXBAUDRATE>\n", Name);
			return -1;
		}
		Baud_out = XBaud.cur_rate;
	printf ("Maximimum Baud for this device= %ld\n", XBaud.max_rate );
	}
	else
	{
		if ( DosDevIOCtl (&Baud,0L,ASYNC_GETBAUDRATE,IOCTL_ASYNC,handle ) )
		{
			printf ("<%s> failed IOCtl <ASYNC_GETBAUDRATE>\n", Name);
			return -1;
		}
		Baud_out = Baud;
	}


	if ( DosDevIOCtl (&DCB_in,0L,ASYNC_GETDCBINFO,IOCTL_ASYNC,handle ) )
	{
		printf ("<%s> failed IOCtl <ASYNC_GETDCBINFO>\n", Name);
		return -1;
	}
	DCB_out = DCB_in;
	if ( DosDevIOCtl (&LCNTL_in,0L,ASYNC_GETLINECTRL,IOCTL_ASYNC,handle ) )
	{
		printf ("<%s> failed IOCtl <ASYNC_GETLINECTRL>\n", Name);
		return -1;
	}
	LCNTL_out = LCNTL_in;

	Alt = 0;                    // causes return of current alt-pin setting
	if  (DosDevIOCtl(&Alt,&Alt,DIGI_ALTPIN,IOCTL_CATEGORY_DIGI,handle))
		Alt = 0;

	DosClose ( handle );

	return 0;
}

help (flag)
{
	printf (
"DMODE %s.  DigiBoard OS/2 asynchronous serial device configuration utility.\n\n",
	VERSION);
	printf ("Usage:\n\
DMODE devname[:]baud[,parity,databits,stopbits][,TO=state][,XON=state]\n\
	 [,IDSR=state][,ODSR=state][,OCTS=state][,DTR=dtrstate][,RTS=rtsstate]\
	 \n");
	printf ("Aditional DigiCHANNEL options: ..[,ALT=state][,QW=state]\n\n");
}

show_device()
{
char    string[128];

	sprintf ( string, "%s %ld %s,%d,%s ", Name, Baud_out,
		Parities [LCNTL_out.bParity],
		LCNTL_out.bDataBits, 
		Stops[LCNTL_out.bStopBits] );

	if ( DCB_out.fbTimeout & MODE_NO_WRITE_TIMEOUT )
		strcat (string, "TO=ON," );
	else
		strcat (string, "TO=OFF," );

	if ( DCB_out.fbFlowReplace & MODE_AUTO_TRANSMIT )
	if ( DCB_out.fbFlowReplace & MODE_AUTO_RECEIVE )
		strcat (string, "XON=BOTH," );
	else
		strcat (string, "XON=ON," );
	else
		strcat (string, "XON=OFF," );


    #if 0
	if ( DCB_out.fbFlowReplace & MODE_AUTO_TRANSMIT )
		strcat (string, "XON=ON," );
	else
		strcat (string, "XON=OFF," );
    #endif


	if ( DCB_out.fbCtlHndShake & MODE_DSR_SENSITIVITY )
		strcat (string, "IDSR=ON," );
	else
		strcat (string, "IDSR=OFF," );

	if ( DCB_out.fbCtlHndShake & MODE_DSR_HANDSHAKE )
		strcat (string, "ODSR=ON," );
	else
		strcat (string, "ODSR=OFF," );

	if ( DCB_out.fbCtlHndShake & MODE_CTS_HANDSHAKE )
		strcat (string, "OCTS=ON," );
	else
		strcat (string, "OCTS=OFF," );

	if ((DCB_out.fbFlowReplace & MODE_TRANSMIT_TOGGLE) == MODE_TRANSMIT_TOGGLE)
		strcat (string, "RTS=TOG," );
	else if ((DCB_out.fbFlowReplace&MODE_TRANSMIT_TOGGLE) == MODE_RTS_HANDSHAKE)
		strcat (string, "RTS=HS," );
	else if ((DCB_out.fbFlowReplace&MODE_TRANSMIT_TOGGLE) == MODE_RTS_CONTROL)
		strcat (string, "RTS=ON," );
	else
		strcat (string, "RTS=OFF," );

	if ( DCB_out.fbCtlHndShake & MODE_DTR_CONTROL )
		strcat (string, "DTR=ON" );
	else if ( DCB_out.fbCtlHndShake & MODE_DTR_HANDSHAKE )
		strcat (string, "DTR=HS" );
	else
		strcat (string, "DTR=OFF" );

	if ( Alt )
    {
		if ( Alt & 0x1 )
			strcat (string, ", ALT=ON" );
		else
			strcat (string, ", ALT=OFF" );

		if ( Alt & 0x10 )
			strcat (string, ", QW=ON" );
		else
			strcat (string, ", QW=OFF" );

    }

	printf ("%s\n", string);
	return 0;

}


set_mode ()
{
HFILE   handle;
USHORT  result, type, attrib;

	if ( DosOpen (  Name,
			&handle,
			&result,
			100L,
			FILE_NORMAL,
			FILE_OPEN,
			(OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE),
			0L ) )
		return -1;

	if ( Ioctl2 )
	{
		if (DosDevIOCtl2(0L,0,&Baud_out,4,0x43,IOCTL_ASYNC,handle))
		{
			printf ("Failed to <ASYNC_SETXBAUDRATE>\n");
			return -1;
		}
	}
	else
	{
		if ( DosDevIOCtl (0L,&Baud_out,ASYNC_SETBAUDRATE,IOCTL_ASYNC,handle ) )
		{
			printf ("Failed to <ASYNC_SETBAUDRATE>\n");
			return -1;
		}
	}
	if ( DosDevIOCtl (0L,&LCNTL_out,ASYNC_SETLINECTRL,IOCTL_ASYNC,handle ) )
	{
		printf ("Failed to <ASYNC_SETLINECTRL>\n");
		return -1;
	}
	if ( DosDevIOCtl (0L,&DCB_out,ASYNC_SETDCBINFO,IOCTL_ASYNC,handle ) )
	{
		printf ("Failed to <ASYNC_SETDCBINFO>\n");
		return -1;
	}
	if ( Alt )
		if  (DosDevIOCtl(&Alt,&Alt,DIGI_ALTPIN,IOCTL_CATEGORY_DIGI,handle))
	{
		printf ("Failed to <DIGI_ALTPIN>\n");
		return -1;
	}

	DosClose ( handle );

	return 0;
}
