//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1993-1994
//
// File: port.c
//
// This files contains the dialog code for the Port Settings property page.
//
// History:
//  2-09-94 ScottH     Created
//
//---------------------------------------------------------------------------


/////////////////////////////////////////////////////  INCLUDES

#include "suiprv.h"         // common headers
#include "serialui.h"

#include "res.h"
#include "help.h"	/////BP trying this

// This is the structure that is used to fill the 
// max speed listbox
typedef struct _Bauds
    {
    DWORD   dwDTERate;
    int     ids;
    } Bauds;

static Bauds g_rgbauds[] = {
        { 110L,         IDS_BAUD_110     },
        { 300L,         IDS_BAUD_300     },
        { 1200L,        IDS_BAUD_1200    },
        { 2400L,        IDS_BAUD_2400    },
        { 4800L,        IDS_BAUD_4800    },
        { 9600L,        IDS_BAUD_9600    },
        { 19200,        IDS_BAUD_19200   },
        { 38400,        IDS_BAUD_38400   },
        { 57600,        IDS_BAUD_57600   },
        { 115200,       IDS_BAUD_115200  },
        { 230400,       IDS_BAUD_230400  },
        { 460800,       IDS_BAUD_460800  },
        { 921600,       IDS_BAUD_921600  },
        };

// Command IDs for the parity listbox
#define CMD_PARITY_EVEN         1
#define CMD_PARITY_ODD          2
#define CMD_PARITY_NONE         3
#define CMD_PARITY_MARK         4
#define CMD_PARITY_SPACE        5

// Command IDs for the flow control listbox
#define CMD_FLOWCTL_XONXOFF      1
#define CMD_FLOWCTL_HARDWARE     2
#define CMD_FLOWCTL_NONE         3

// This table is the generic port settings table
// that is used to fill the various listboxes
typedef struct _PortValues
    {
    union {
        BYTE bytesize;
        BYTE cmd;
        BYTE stopbits;
        };
    int ids;
    } PortValues, FAR * LPPORTVALUES;


#pragma data_seg(DATASEG_READONLY)

// This is the structure that is used to fill the data bits listbox
static PortValues s_rgbytesize[] = {
        { 4,  IDS_BYTESIZE_4  },
        { 5,  IDS_BYTESIZE_5  },
        { 6,  IDS_BYTESIZE_6  },
        { 7,  IDS_BYTESIZE_7  },
        { 8,  IDS_BYTESIZE_8  },
        };

// This is the structure that is used to fill the parity listbox
static PortValues s_rgparity[] = {
        { CMD_PARITY_EVEN,  IDS_PARITY_EVEN  },
        { CMD_PARITY_ODD,   IDS_PARITY_ODD   },
        { CMD_PARITY_NONE,  IDS_PARITY_NONE  },
        { CMD_PARITY_MARK,  IDS_PARITY_MARK  },
        { CMD_PARITY_SPACE, IDS_PARITY_SPACE },
        };

// This is the structure that is used to fill the stopbits listbox
static PortValues s_rgstopbits[] = {
        { ONESTOPBIT,   IDS_STOPBITS_1   },
        { ONE5STOPBITS, IDS_STOPBITS_1_5 },
        { TWOSTOPBITS,  IDS_STOPBITS_2   },
        };

// This is the structure that is used to fill the flow control listbox
static PortValues s_rgflowctl[] = {
        { CMD_FLOWCTL_XONXOFF,  IDS_FLOWCTL_XONXOFF  },
        { CMD_FLOWCTL_HARDWARE, IDS_FLOWCTL_HARDWARE },
        { CMD_FLOWCTL_NONE,     IDS_FLOWCTL_NONE     },
        };

#pragma data_seg()


typedef struct tagPORT
    {
    HWND hdlg;              // dialog handle
    HWND hwndBaudRate;
    HWND hwndDataBits;
    HWND hwndParity;
    HWND hwndStopBits;
    HWND hwndFlowCtl;

    LPPORTINFO pportinfo;   // pointer to shared working buffer
    
    } PORT, FAR * PPORT;

    
// This structure contains the default settings for the dialog
static struct _DefPortSettings
    {
    int  iSelBaud;
    int  iSelDataBits;
    int  iSelParity;
    int  iSelStopBits;
    int  iSelFlowCtl;
    } s_defportsettings;

// These are default settings
#define DEFAULT_BAUDRATE            9600L
#define DEFAULT_BYTESIZE            8
#define DEFAULT_PARITY              CMD_PARITY_NONE
#define DEFAULT_STOPBITS            ONESTOPBIT
#define DEFAULT_FLOWCTL             CMD_FLOWCTL_XONXOFF


#define Port_GetPtr(hwnd)           (PPORT)GetWindowLong(hwnd, DWL_USER)
#define Port_SetPtr(hwnd, lp)       (PPORT)SetWindowLong(hwnd, DWL_USER, (LONG)(lp))

UINT WINAPI FeFiFoFum(HWND hwndOwner, LPCSTR pszPortName);


/*----------------------------------------------------------
Purpose: Fills the baud rate combobox with the possible baud
         rates that Windows supports.
Returns: --
Cond:    --
*/
void PRIVATE Port_FillBaud(
    PPORT this)
    {
    HWND hwndCB = this->hwndBaudRate;
    WIN32DCB FAR * pdcb = &this->pportinfo->dcb;
    int i;
    int n;
    int iMatch = -1;
    int iDef = -1;
    int iSel;
    char sz[MAXMEDLEN];

    // Fill the listbox
    for (i = 0; i < ARRAYSIZE(g_rgbauds); i++)
        {
        n = ComboBox_AddString(hwndCB, SzFromIDS(g_rgbauds[i].ids, sz, sizeof(sz)));
        ComboBox_SetItemData(hwndCB, n, g_rgbauds[i].dwDTERate);

        // Keep our eyes peeled for important values
        if (DEFAULT_BAUDRATE == g_rgbauds[i].dwDTERate)
            {
            iDef = n;
            }
        if (pdcb->BaudRate == g_rgbauds[i].dwDTERate)
            {
            iMatch = n;
            }
        }

    ASSERT(-1 != iDef);
    s_defportsettings.iSelBaud = iDef;

    // Does the DCB baudrate exist in our list of baud rates?
    if (-1 == iMatch)
        {
        // No; choose the default
        iSel = iDef;
        }
    else 
        {
        // Yes; choose the matched value
        ASSERT(-1 != iMatch);
        iSel = iMatch;
        }
    ComboBox_SetCurSel(hwndCB, iSel);
    }


/*----------------------------------------------------------
Purpose: Fills the bytesize combobox with the possible byte sizes.
Returns: --
Cond:    --
*/
void PRIVATE Port_FillDataBits(
    PPORT this)
    {
    HWND hwndCB = this->hwndDataBits;
    WIN32DCB FAR * pdcb = &this->pportinfo->dcb;
    int i;
    int iSel;
    int n;
    int iMatch = -1;
    int iDef = -1;
    char sz[MAXMEDLEN];

    // Fill the listbox
    for (i = 0; i < ARRAYSIZE(s_rgbytesize); i++)
        {
        n = ComboBox_AddString(hwndCB, SzFromIDS(s_rgbytesize[i].ids, sz, sizeof(sz)));
        ComboBox_SetItemData(hwndCB, n, s_rgbytesize[i].bytesize);

        // Keep our eyes peeled for important values
        if (DEFAULT_BYTESIZE == s_rgbytesize[i].bytesize)
            {
            iDef = n;
            }
        if (pdcb->ByteSize == s_rgbytesize[i].bytesize)
            {
            iMatch = n;
            }
        }

    ASSERT(-1 != iDef);
    s_defportsettings.iSelDataBits = iDef;

    // Does the DCB value exist in our list?
    if (-1 == iMatch)
        {
        // No; choose the default
        iSel = iDef;
        }
    else 
        {
        // Yes; choose the matched value
        ASSERT(-1 != iMatch);
        iSel = iMatch;
        }
    ComboBox_SetCurSel(hwndCB, iSel);
    }


/*----------------------------------------------------------
Purpose: Fills the parity combobox with the possible settings.
Returns: --
Cond:    --
*/
void PRIVATE Port_FillParity(
    PPORT this)
    {
    HWND hwndCB = this->hwndParity;
    WIN32DCB FAR * pdcb = &this->pportinfo->dcb;
    int i;
    int iSel;
    int n;
    int iMatch = -1;
    int iDef = -1;
    char sz[MAXMEDLEN];

    // Fill the listbox
    for (i = 0; i < ARRAYSIZE(s_rgparity); i++)
        {
        n = ComboBox_AddString(hwndCB, SzFromIDS(s_rgparity[i].ids, sz, sizeof(sz)));
        ComboBox_SetItemData(hwndCB, n, s_rgparity[i].cmd);

        // Keep our eyes peeled for important values
        if (DEFAULT_PARITY == s_rgparity[i].cmd)
            {
            iDef = n;
            }
        switch (s_rgparity[i].cmd)
            {
        case CMD_PARITY_EVEN:
            if (TRUE == pdcb->fParity && EVENPARITY == pdcb->Parity)
                iMatch = n;
            break;

        case CMD_PARITY_ODD:
            if (TRUE == pdcb->fParity && ODDPARITY == pdcb->Parity)
                iMatch = n;
            break;

        case CMD_PARITY_NONE:
            if (FALSE == pdcb->fParity && NOPARITY == pdcb->Parity)
                iMatch = n;
            break;

        case CMD_PARITY_MARK:
            if (TRUE == pdcb->fParity && MARKPARITY == pdcb->Parity)
                iMatch = n;
            break;

        case CMD_PARITY_SPACE:
            if (TRUE == pdcb->fParity && SPACEPARITY == pdcb->Parity)
                iMatch = n;
            break;

        default:
            ASSERT(0);
            break;
            }
        }

    ASSERT(-1 != iDef);
    s_defportsettings.iSelParity = iDef;

    // Does the DCB value exist in our list?
    if (-1 == iMatch)
        {
        // No; choose the default
        iSel = iDef;
        }
    else 
        {
        // Yes; choose the matched value
        ASSERT(-1 != iMatch);
        iSel = iMatch;
        }
    ComboBox_SetCurSel(hwndCB, iSel);
    }


/*----------------------------------------------------------
Purpose: Fills the stopbits combobox with the possible settings.
Returns: --
Cond:    --
*/
void PRIVATE Port_FillStopBits(
    PPORT this)
    {
    HWND hwndCB = this->hwndStopBits;
    WIN32DCB FAR * pdcb = &this->pportinfo->dcb;
    int i;
    int iSel;
    int n;
    int iMatch = -1;
    int iDef = -1;
    char sz[MAXMEDLEN];

    // Fill the listbox
    for (i = 0; i < ARRAYSIZE(s_rgstopbits); i++)
        {
        n = ComboBox_AddString(hwndCB, SzFromIDS(s_rgstopbits[i].ids, sz, sizeof(sz)));
        ComboBox_SetItemData(hwndCB, n, s_rgstopbits[i].stopbits);

        // Keep our eyes peeled for important values
        if (DEFAULT_STOPBITS == s_rgstopbits[i].stopbits)
            {
            iDef = n;
            }
        if (pdcb->StopBits == s_rgstopbits[i].stopbits)
            {
            iMatch = n;
            }
        }

    ASSERT(-1 != iDef);
    s_defportsettings.iSelStopBits = iDef;

    // Does the DCB value exist in our list?
    if (-1 == iMatch)
        {
        // No; choose the default
        iSel = iDef;
        }
    else 
        {
        // Yes; choose the matched value
        ASSERT(-1 != iMatch);
        iSel = iMatch;
        }
    ComboBox_SetCurSel(hwndCB, iSel);
    }


/*----------------------------------------------------------
Purpose: Fills the flow control combobox with the possible settings.
Returns: --
Cond:    --
*/
void PRIVATE Port_FillFlowCtl(
    PPORT this)
    {
    HWND hwndCB = this->hwndFlowCtl;
    WIN32DCB FAR * pdcb = &this->pportinfo->dcb;
    int i;
    int iSel;
    int n;
    int iMatch = -1;
    int iDef = -1;
    char sz[MAXMEDLEN];

    // Fill the listbox
    for (i = 0; i < ARRAYSIZE(s_rgflowctl); i++)
        {
        n = ComboBox_AddString(hwndCB, SzFromIDS(s_rgflowctl[i].ids, sz, sizeof(sz)));
        ComboBox_SetItemData(hwndCB, n, s_rgflowctl[i].cmd);

        // Keep our eyes peeled for important values
        if (DEFAULT_FLOWCTL == s_rgflowctl[i].cmd)
            {
            iDef = n;
            }
        switch (s_rgflowctl[i].cmd)
            {
        case CMD_FLOWCTL_XONXOFF:
            if (TRUE == pdcb->fOutX && FALSE == pdcb->fOutxCtsFlow)
                iMatch = n;
            break;

        case CMD_FLOWCTL_HARDWARE:
            if (FALSE == pdcb->fOutX && TRUE == pdcb->fOutxCtsFlow)
                iMatch = n;
            break;

        case CMD_FLOWCTL_NONE:
            if (FALSE == pdcb->fOutX && FALSE == pdcb->fOutxCtsFlow)
                iMatch = n;
            break;

        default:
            ASSERT(0);
            break;
            }
        }

    ASSERT(-1 != iDef);
    s_defportsettings.iSelFlowCtl = iDef;

    // Does the DCB value exist in our list?
    if (-1 == iMatch)
        {
        // No; choose the default
        iSel = iDef;
        }
    else 
        {
        // Yes; choose the matched value
        ASSERT(-1 != iMatch);
        iSel = iMatch;
        }
    ComboBox_SetCurSel(hwndCB, iSel);
    }


/*----------------------------------------------------------
Purpose: WM_INITDIALOG Handler
Returns: FALSE when we assign the control focus
Cond:    --
*/
BOOL PRIVATE Port_OnInitDialog(
    PPORT this,
    HWND hwndFocus,
    LPARAM lParam)              // expected to be PROPSHEETINFO 
    {
    LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
    HWND hwnd = this->hdlg;

    ASSERT((LPSTR)lppsp->lParam);

    this->pportinfo = (LPPORTINFO)lppsp->lParam;

    // Save away the window handles
    this->hwndBaudRate = GetDlgItem(hwnd, IDC_PS_BAUDRATE);
    this->hwndDataBits = GetDlgItem(hwnd, IDC_PS_DATABITS);
    this->hwndParity = GetDlgItem(hwnd, IDC_PS_PARITY);
    this->hwndStopBits = GetDlgItem(hwnd, IDC_PS_STOPBITS);
    this->hwndFlowCtl = GetDlgItem(hwnd, IDC_PS_FLOWCTL);

    Port_FillBaud(this);
    Port_FillDataBits(this);
    Port_FillParity(this);
    Port_FillStopBits(this);
    Port_FillFlowCtl(this);

    return TRUE;   // allow USER to set the initial focus
    }

/*----------------------------------------------------------
Purpose: WM_COMMAND Handler
Returns: --
Cond:    --
*/
void PRIVATE Port_OnCommand(
    PPORT this,
    int id,
    HWND hwndCtl,
    UINT uNotifyCode)
    {
    HWND hwnd = this->hdlg;
    
    switch (id)
        {
    case IDC_PS_PB_RESTORE:
        // Set the values to the default settings
        ComboBox_SetCurSel(this->hwndBaudRate, s_defportsettings.iSelBaud);
        ComboBox_SetCurSel(this->hwndDataBits, s_defportsettings.iSelDataBits);
        ComboBox_SetCurSel(this->hwndParity, s_defportsettings.iSelParity);
        ComboBox_SetCurSel(this->hwndStopBits, s_defportsettings.iSelStopBits);
        ComboBox_SetCurSel(this->hwndFlowCtl, s_defportsettings.iSelFlowCtl);
        break;

    case IDC_PS_ADVANCED:
        FeFiFoFum(this->hdlg, this->pportinfo->szFriendlyName);
        break;

    default:
        break;
        }
    }


/*----------------------------------------------------------
Purpose: PSN_APPLY handler
Returns: --
Cond:    --
*/
void PRIVATE Port_OnApply(
    PPORT this)
    {
    int iSel;
    BYTE cmd;
    WIN32DCB FAR * pdcb = &this->pportinfo->dcb;

    // Determine new speed settings
    iSel = ComboBox_GetCurSel(this->hwndBaudRate);
    pdcb->BaudRate = ComboBox_GetItemData(this->hwndBaudRate, iSel);


    // Determine new byte size
    iSel = ComboBox_GetCurSel(this->hwndDataBits);
    pdcb->ByteSize = (BYTE)ComboBox_GetItemData(this->hwndDataBits, iSel);


    // Determine new parity settings
    iSel = ComboBox_GetCurSel(this->hwndParity);
    cmd = (BYTE)ComboBox_GetItemData(this->hwndParity, iSel);
    switch (cmd)
        {
    case CMD_PARITY_EVEN:
        pdcb->fParity = TRUE;
        pdcb->Parity = EVENPARITY;
        break;

    case CMD_PARITY_ODD:
        pdcb->fParity = TRUE;
        pdcb->Parity = ODDPARITY;
        break;

    case CMD_PARITY_NONE:
        pdcb->fParity = FALSE;
        pdcb->Parity = NOPARITY;
        break;

    case CMD_PARITY_MARK:
        pdcb->fParity = TRUE;
        pdcb->Parity = MARKPARITY;
        break;

    case CMD_PARITY_SPACE:
        pdcb->fParity = TRUE;
        pdcb->Parity = SPACEPARITY;
        break;

    default:
        ASSERT(0);
        break;
        }

    // Determine new stopbits setting
    iSel = ComboBox_GetCurSel(this->hwndStopBits);
    pdcb->StopBits = (BYTE)ComboBox_GetItemData(this->hwndStopBits, iSel);


    // Determine new flow control settings
    iSel = ComboBox_GetCurSel(this->hwndFlowCtl);
    cmd = (BYTE)ComboBox_GetItemData(this->hwndFlowCtl, iSel);
    switch (cmd)
        {
    case CMD_FLOWCTL_XONXOFF:
        pdcb->fOutX = TRUE;
        pdcb->fInX = TRUE;
        pdcb->fOutxCtsFlow = FALSE;
        pdcb->fRtsControl = RTS_CONTROL_DISABLE;
        break;

    case CMD_FLOWCTL_HARDWARE:
        pdcb->fOutX = FALSE;
        pdcb->fInX = FALSE;
        pdcb->fOutxCtsFlow = TRUE;
        pdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
        break;

    case CMD_FLOWCTL_NONE:
        pdcb->fOutX = FALSE;
        pdcb->fInX = FALSE;
        pdcb->fOutxCtsFlow = FALSE;
        pdcb->fRtsControl = RTS_CONTROL_DISABLE;
        break;

    default:
        ASSERT(0);      // should never be here
        break;
        }

    this->pportinfo->idRet = IDOK;
    }


/*----------------------------------------------------------
Purpose: WM_NOTIFY handler
Returns: varies
Cond:    --
*/
LRESULT PRIVATE Port_OnNotify(
    PPORT this,
    int idFrom,
    NMHDR FAR * lpnmhdr)
    {
    LRESULT lRet = 0;
    
    switch (lpnmhdr->code)
        {
    case PSN_SETACTIVE:
        break;

    case PSN_KILLACTIVE:
        // N.b. This message is not sent if user clicks Cancel!
        // N.b. This message is sent prior to PSN_APPLY
        //
        break;

    case PSN_APPLY:
        Port_OnApply(this);
        break;

    default:
        break;
        }

    return lRet;
    }


/////////////////////////////////////////////////////  EXPORTED FUNCTIONS

static BOOL s_bPortRecurse = FALSE;

LRESULT INLINE Port_DefProc(
    HWND hDlg, 
    UINT msg,
    WPARAM wParam,
    LPARAM lParam) 
    {
    ENTEREXCLUSIVE()
        {
        s_bPortRecurse = TRUE;
        }
    LEAVEEXCLUSIVE()

    return DefDlgProc(hDlg, msg, wParam, lParam); 
    }


/*----------------------------------------------------------
Purpose: Real dialog proc
Returns: varies
Cond:    --
*/
LRESULT Port_DlgProc(
    PPORT this,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
    {
#pragma data_seg(DATASEG_READONLY)
    const static DWORD rgHelpIDs[] = {
        IDC_PS_LBL_BAUDRATE,    IDH_PORT_BAUD,
        IDC_PS_BAUDRATE,        IDH_PORT_BAUD,
        IDC_PS_LBL_DATABITS,    IDH_PORT_DATA,
        IDC_PS_DATABITS,        IDH_PORT_DATA,
        IDC_PS_LBL_PARITY,      IDH_PORT_PARITY,
        IDC_PS_PARITY,          IDH_PORT_PARITY,
        IDC_PS_LBL_STOPBITS,    IDH_PORT_STOPBITS,
        IDC_PS_STOPBITS,        IDH_PORT_STOPBITS,
        IDC_PS_LBL_FLOWCTL,     IDH_PORT_FLOW,
        IDC_PS_FLOWCTL,         IDH_PORT_FLOW,
        IDC_PS_PB_RESTORE,      IDH_PORT_RESTORE,
        0, 0 };
#pragma data_seg()

    switch (message)
        {
        HANDLE_MSG(this, WM_INITDIALOG, Port_OnInitDialog);
        HANDLE_MSG(this, WM_COMMAND, Port_OnCommand);
        HANDLE_MSG(this, WM_NOTIFY, Port_OnNotify);

    case WM_HELP:
        WinHelp(((LPHELPINFO)lParam)->hItemHandle, c_szWinHelpFile, HELP_WM_HELP, (DWORD)(LPVOID)rgHelpIDs);
        return 0;

    case WM_CONTEXTMENU:
        WinHelp((HWND)wParam, c_szWinHelpFile, HELP_CONTEXTMENU, (DWORD)(LPVOID)rgHelpIDs);
        return 0;

        default:
            return Port_DefProc(this->hdlg, message, wParam, lParam);
        }
    }


/*----------------------------------------------------------
Purpose: Dialog Wrapper
Returns: varies
Cond:    --
*/
BOOL CALLBACK Port_WrapperProc(
    HWND hDlg,          // std params
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
    {
    PPORT this;

    // Cool windowsx.h dialog technique.  For full explanation, see
    //  WINDOWSX.TXT.  This supports multiple-instancing of dialogs.
    //
    ENTEREXCLUSIVE()
        {
        if (s_bPortRecurse)
            {
            s_bPortRecurse = FALSE;
            LEAVEEXCLUSIVE()
            return FALSE;
            }
        }
    LEAVEEXCLUSIVE()

    this = Port_GetPtr(hDlg);
    if (this == NULL)
        {
        if (message == WM_INITDIALOG)
            {
            this = (PPORT)LocalAlloc(LPTR, sizeof(PORT));
            if (!this)
                {
                MsgBox_Err(hDlg, IDS_OOM_PORT, IDS_CAP_PORT);
                EndDialog(hDlg, IDCANCEL);
                return (BOOL)Port_DefProc(hDlg, message, wParam, lParam);
                }
            this->hdlg = hDlg;
            Port_SetPtr(hDlg, this);
            }
        else
            {
            return (BOOL)Port_DefProc(hDlg, message, wParam, lParam);
            }
        }

    if (message == WM_DESTROY)
        {
        Port_DlgProc(this, message, wParam, lParam);
        LocalFree((HLOCAL)OFFSETOF(this));
        Port_SetPtr(hDlg, NULL);
        return 0;
        }

    return SetDlgMsgResult(hDlg, message, Port_DlgProc(this, message, wParam, lParam));
    }


//
// Advanced Port Settings
//

#pragma data_seg(DATASEG_READONLY)

// Fifo related strings

char const FAR c_szSettings[] = "Settings";
char const FAR c_szComxFifo[] = "Fifo";
char const FAR c_szEnh[] = "386Enh";
char const FAR c_szSystem[] = "system.ini";

#pragma data_seg()


/*----------------------------------------------------------
Purpose: Set the dialog controls

Returns: --
Cond:    --
*/
void DisplayAdvSettings(
    HWND hDlg,
    BYTE RxTrigger,
    BYTE TxTrigger,
    BOOL bUseFifo)
    {
    SendDlgItemMessage(hDlg, IDC_RXFIFO_USAGE, TBM_SETRANGE, 0, 0x30000);
    SendDlgItemMessage(hDlg, IDC_TXFIFO_USAGE, TBM_SETRANGE, 0, 0x30000);

    // Use FIFO?
    if ( !bUseFifo ) 
        {
        // No
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO_LO), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO_HI), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_RXFIFO_USAGE), FALSE);

        EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO_LO), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO_HI), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_TXFIFO_USAGE), FALSE);
        CheckDlgButton(hDlg, IDC_FIFO_USAGE, FALSE);
        } 
    else 
        {
        CheckDlgButton(hDlg, IDC_FIFO_USAGE, TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO_LO), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO_HI), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_RXFIFO_USAGE), TRUE);

        EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO_LO), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO_HI), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_TXFIFO_USAGE), TRUE);
        SendDlgItemMessage(hDlg, IDC_RXFIFO_USAGE, TBM_SETPOS,
            TRUE, RxTrigger);
        SendDlgItemMessage(hDlg, IDC_TXFIFO_USAGE, TBM_SETPOS,
            TRUE, TxTrigger/4);
        }
    }


typedef struct tagSETTINGS 
    {
    BYTE fifoon;
    BYTE txfifosize;
    BYTE dsron;
    BYTE rxtriggersize;
    } SETTINGS;

typedef enum 
    {
    ACT_GET,
    ACT_SET
    } ACTION;

BYTE RxTriggerValues[4]={0,0x40,0x80,0xC0};


/*----------------------------------------------------------
Purpose: Gets or sets the advanced settings of the port

Returns: --
Cond:    --
*/
void GetSetAdvSettings(
    LPCSTR pszPortName,
    BYTE FAR *RxTrigger,
    BYTE FAR *TxTrigger,
    BOOL FAR * pbUseFifo,
    ACTION action)
    {
    HKEY hkeyDevice, hkeyDriver;
    DWORD cbData;
    SETTINGS settings;
    char szFifo[256];
    char OnStr[2] = "0";

    ASSERT(pszPortName);

    if (FindDevice(c_szPortClass, pszPortName, &hkeyDevice, &hkeyDriver) ||
        FindDeviceByString(c_szPortClass, c_szPortName, pszPortName, &hkeyDevice, &hkeyDriver) ||
        FindDeviceByString(c_szModemClass, c_szPortName, pszPortName, &hkeyDevice, &hkeyDriver)) 
        {
        switch (action)
            {
        case ACT_GET:
            ASSERT(4 == sizeof(SETTINGS));

            cbData = sizeof(SETTINGS);
            if (ERROR_SUCCESS != RegQueryValueEx(hkeyDevice, c_szSettings, NULL,
                NULL, (LPSTR)&settings, &cbData)) 
                {
                // Default settings if not in registry
                settings.fifoon = 0x02;
                settings.dsron = 0;
                settings.txfifosize = 16;
                settings.rxtriggersize = 0x80;
                }
            if (!settings.fifoon)
                *pbUseFifo = FALSE;
            else
                *pbUseFifo = TRUE;
            settings.rxtriggersize = settings.rxtriggersize % 0xC1;
            *RxTrigger = settings.rxtriggersize/0x40;
            *TxTrigger = settings.txfifosize % 17;
            break;

        case ACT_SET:
            if (FALSE == *pbUseFifo)
                settings.fifoon = 0;
            else
                settings.fifoon = 2;

            settings.rxtriggersize = RxTriggerValues[*RxTrigger];
            settings.dsron = 0;
            settings.txfifosize = (*TxTrigger)*5+1;
            RegSetValueEx(hkeyDevice, c_szSettings, NULL, REG_BINARY,
                (LPSTR)&settings, sizeof(SETTINGS));
            break;

        default:
            ASSERT(0);
            break;
            }

        cbData = 250;       // leave room for "fifo" on the end
        RegQueryValueEx(hkeyDevice, c_szPortName, NULL, NULL, szFifo,
            &cbData);
        RegCloseKey(hkeyDevice);
        RegCloseKey(hkeyDriver);
        lstrcat(szFifo, c_szComxFifo);
        if (*pbUseFifo)
            WritePrivateProfileString(c_szEnh, szFifo, NULL, c_szSystem);
        else
            WritePrivateProfileString(c_szEnh, szFifo, OnStr, c_szSystem);
        }
    }



/*----------------------------------------------------------
Purpose: Dialog proc for advanced port settings

Returns: standard
Cond:    --
*/
BOOL CALLBACK AdvPort_DlgProc(
    HWND hDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
    {
    BOOL bRet = FALSE;
    BYTE rxtrigger, txtrigger;
    BOOL bUseFifo;
    LPCSTR pszPortName;

    switch (uMsg) 
        {
    case WM_INITDIALOG:
        pszPortName = (LPCSTR)lParam;
        SetWindowLong(hDlg, DWL_USER, (LONG)pszPortName);

        GetSetAdvSettings(pszPortName, &rxtrigger, &txtrigger, &bUseFifo, ACT_GET);
        DisplayAdvSettings(hDlg, rxtrigger, txtrigger, bUseFifo);
        break;

    case WM_COMMAND:
        pszPortName = (LPCSTR)GetWindowLong(hDlg, DWL_USER);
        if (!pszPortName)
            {
            ASSERT(0);
            break;
            }

        switch (wParam) 
            {
        case IDOK:
            if (IsDlgButtonChecked(hDlg, IDC_FIFO_USAGE))
                bUseFifo = TRUE;
            else
                bUseFifo = FALSE;

            rxtrigger = (BYTE)SendDlgItemMessage(hDlg,
                IDC_RXFIFO_USAGE, TBM_GETPOS, 0, 0);
            txtrigger = (BYTE)SendDlgItemMessage(hDlg,
                IDC_TXFIFO_USAGE, TBM_GETPOS, 0, 0);

            GetSetAdvSettings(pszPortName, &rxtrigger, &txtrigger, &bUseFifo, ACT_SET);

            // Fall thru
            //  |    |
            //  v    v

        case IDCANCEL:
            EndDialog(hDlg, IDOK == wParam);
            break;

        case IDC_FIFO_USAGE:
            if (!IsDlgButtonChecked(hDlg, IDC_FIFO_USAGE))
                DisplayAdvSettings(hDlg, 0, 0, FALSE);
            else 
                {
                EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO), TRUE);
                EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO_LO), TRUE);
                EnableWindow(GetDlgItem(hDlg, IDC_LBL_RXFIFO_HI), TRUE);
                EnableWindow(GetDlgItem(hDlg, IDC_RXFIFO_USAGE), TRUE);

                EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO), TRUE);
                EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO_LO), TRUE);
                EnableWindow(GetDlgItem(hDlg, IDC_LBL_TXFIFO_HI), TRUE);
                EnableWindow(GetDlgItem(hDlg, IDC_TXFIFO_USAGE), TRUE);
                }
            break;

        case IDC_DEFAULTS:
            DisplayAdvSettings(hDlg, 2, 12, TRUE);
            break;
            }
        break;

    default:
        break;
        }
    return bRet;
    }


/*----------------------------------------------------------
Purpose: Private entry point to show the Advanced Fifo dialog

Returns: IDOK or IDCANCEL

Cond:    --
*/
UINT WINAPI FeFiFoFum(
    HWND hwndOwner,
    LPCSTR pszPortName)
    {
    UINT uRet = (UINT)-1;

    // Invoke the advanced dialog
    if (pszPortName)
        {
        uRet = DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_ADV_PORT), 
                hwndOwner, AdvPort_DlgProc, (LPARAM)pszPortName);
        }
    return uRet;
    }

