/*++ Copyright (c) 1998 Microsoft Corporation Module Name: pcihal.c Abstract: Routines for the Pci Hal property page. Author: Santosh Jodh 10-July-1998 --*/ #include "setupp.h" #pragma hdrstop #include #include #define MSG_SIZE 2048 #define Allocate(n) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, n) #define Release(p) HeapFree(GetProcessHeap(), 0, (LPVOID)p) typedef struct _PciHalPropData PCIHALPROPDATA, *PPCIHALPROPDATA; struct _PciHalPropData { HKEY LocalMachine; BOOLEAN CloseKey; DWORD Options; HDEVINFO DeviceInfoSet; PSP_DEVINFO_DATA DeviceInfoData; }; const DWORD gPciPropHelpIds[] = { IDC_PCIHAL_ICON, (DWORD)-1, // Icon IDC_PCIHAL_DEVDESC, (DWORD)-1, // Name of PC IDC_PCIHAL_ENABLE, IDH_IRQ_ENABLE, // Enable IRQ Routing IDC_PCIHAL_MSSPEC, IDH_IRQ_MSSPEC, // Use $PIR table IDC_PCIHAL_REALMODE, IDH_IRQ_REALMODE, // Use table from Real-mode BIOS call IDC_PCIHAL_SETDEFAULTS, IDH_IRQ_SETDEFAULTS, // Set defaults for options IDC_PCIHAL_RESULTS, IDH_IRQ_RESULTS, // Status information 0,0 }; // // Table used to translate status codes into string ids. // UINT gStatus[PIR_STATUS_MAX + 1] = { IDS_PCIHAL_ERROR, IDS_PCIHAL_ENABLED, IDS_PCIHAL_DISABLED, IDS_PCIHAL_NOSTATUS }; UINT gTableStatus[PIR_STATUS_TABLE_MAX] = { IDS_PCIHAL_TABLE_REGISTRY, IDS_PCIHAL_TABLE_MSSPEC, IDS_PCIHAL_TABLE_REALMODE, IDS_PCIHAL_TABLE_NONE, IDS_PCIHAL_TABLE_ERROR, IDS_PCIHAL_TABLE_BAD, IDS_PCIHAL_TABLE_SUCCESS }; UINT gMiniportStatus[PIR_STATUS_MINIPORT_MAX] = { IDS_PCIHAL_MINIPORT_NORMAL, IDS_PCIHAL_MINIPORT_COMPATIBLE, IDS_PCIHAL_MINIPORT_OVERRIDE, IDS_PCIHAL_MINIPORT_NONE, IDS_PCIHAL_MINIPORT_ERROR, IDS_PCIHAL_MINIPORT_NOKEY, IDS_PCIHAL_MINIPORT_SUCCESS, IDS_PCIHAL_MINIPORT_INVALID }; PCIHALPROPDATA gPciHalPropData = {0}; VOID PciHalSetControls ( IN HWND Dialog, IN DWORD Options, IN DWORD Attributes ) /*++ Routine Description: This routine sets the controls on the Irq Routing page to the specified options. Input Parameters: Dialog - Window handle for the property sheet page. Options - Pci Irq Routing options to be displayed. Return Value: None. --*/ { BOOL enabled = FALSE; // // Enable the buttons depending on the options. // if (Options & PIR_OPTION_ENABLED) { enabled = TRUE; CheckDlgButton(Dialog, IDC_PCIHAL_ENABLE, 1); } CheckDlgButton(Dialog, IDC_PCIHAL_MSSPEC, Options & PIR_OPTION_MSSPEC); CheckDlgButton(Dialog, IDC_PCIHAL_REALMODE, Options & PIR_OPTION_REALMODE); // // Gray the windows not meaningful. // EnableWindow(GetDlgItem(Dialog, IDC_PCIHAL_ENABLE), !(Attributes & PIR_OPTION_ENABLED) ); EnableWindow(GetDlgItem(Dialog, IDC_PCIHAL_SETDEFAULTS), !(Attributes & PIR_OPTION_ENABLED) ); EnableWindow(GetDlgItem(Dialog, IDC_PCIHAL_MSSPEC), enabled && !(Attributes & PIR_OPTION_MSSPEC) ); EnableWindow(GetDlgItem(Dialog, IDC_PCIHAL_REALMODE), enabled && !(Attributes & PIR_OPTION_REALMODE) ); } LPTSTR PciHalGetDescription ( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData ) /*++ Routine Description: This routine allocates memory and returns the device description for the specified device. Input Parameters: DeviceInfoSet - For the device. DeviceInfoData - For the device. Return Value: Pointer to the description iff successful. Else NULL. --*/ { LPTSTR desc; DWORD size; desc = NULL; // // Get the size of the description for this device. // size = 0; SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DEVICEDESC, NULL, NULL, 0, &size ); if (size != 0) { // // Account for the terminating NULL character. // size++; // // Allocate memory for the device description. // desc = Allocate(size * sizeof(TCHAR)); if (desc != NULL) { // // Get the device description. // if (SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)desc, size * sizeof(TCHAR), &size) == FALSE) { Release(desc); desc = NULL; } } } return desc; } LPTSTR PciHalGetStatus ( IN DWORD Status, IN DWORD TableStatus, IN DWORD MiniportStatus ) /*++ Routine Description: This routine converts the different status codes into a status string and returns the pointer to the string. The caller should free the memory when done using this string. Input Parameters: Status - Pci Irq Routing status. TableStatus - Pci Irq Routing Table status. Lower WORD indicates the source of the table. The upper WORD indicates the table processing status. MiniportStatus - Pci Irq Routing Miniport status. Lower WORD indicates the source of the miniport. The upper WORD indicates the miniport processing status. Return Value: Pointer to the status string iff successful. Else NULL. --*/ { LPTSTR status; TCHAR temp[128]; DWORD statusLength; statusLength = MSG_SIZE; status = Allocate(statusLength * sizeof(TCHAR)); if (status) { // // Get the status about Pci Irq Routing. // status[0] = TEXT('\0'); LoadString(MyModuleHandle, gStatus[Status], status, MSG_SIZE); // // Get the status about the source of Pci Irq Routing Table. // if ((TableStatus & 0xFFFF) < PIR_STATUS_TABLE_MAX) { StringCchCat(status, statusLength, L"\r\n\r\n"); temp[0] = TEXT('\0'); LoadString(MyModuleHandle, gTableStatus[TableStatus & 0xFFFF], temp, ARRAYSIZE(temp) ); StringCchCat(status, statusLength, temp); } // // Get the status about the Pci Irq Routing table. // TableStatus >>= 16; if (TableStatus < PIR_STATUS_TABLE_MAX) { StringCchCat(status, statusLength, L"\r\n\r\n"); temp[0] = TEXT('\0'); LoadString(MyModuleHandle, gTableStatus[TableStatus], temp, ARRAYSIZE(temp)); StringCchCat(status, statusLength, temp); } // // Get the status about the source of the miniport. // if ((MiniportStatus & 0xFFFF) < PIR_STATUS_MINIPORT_MAX) { StringCchCat(status, statusLength, L"\r\n\r\n"); temp[0] = TEXT('\0'); LoadString(MyModuleHandle, gMiniportStatus[MiniportStatus & 0xFFFF], temp, ARRAYSIZE(temp) ); StringCchCat(status, statusLength, temp); } // // Get the status about the miniport status. // MiniportStatus >>= 16; if (MiniportStatus < PIR_STATUS_MINIPORT_MAX) { StringCchCat(status, statusLength, L"\r\n\r\n"); temp[0] = TEXT('\0'); LoadString(MyModuleHandle, gMiniportStatus[MiniportStatus], temp, ARRAYSIZE(temp) ); StringCchCat(status, statusLength, temp); } } return status; } BOOL PciHalOnInitDialog ( IN HWND Dialog, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: This routine initializes the property sheet page on creation. Input Paramters: Dialog - Window handle for the property sheet page. wParam - wParam of the WM_INITDIALOG message. lParam - Pointer to the property sheet page. Return Value: TRUE. --*/ { PPCIHALPROPDATA pciHalPropData; HKEY hKey; DWORD size; DWORD status; DWORD tableStatus; DWORD miniportStatus; DWORD attributes; HICON hIconOld; HICON hIconNew; INT iconIndex; LPTSTR desc; SP_DEVINFO_LIST_DETAIL_DATA details; pciHalPropData = (PPCIHALPROPDATA)((LPPROPSHEETPAGE)lParam)->lParam; // // Read the Pci Irq Routing options and status from the registry. // pciHalPropData->Options = 0; status = PIR_STATUS_MAX; tableStatus = PIR_STATUS_TABLE_MAX | (PIR_STATUS_TABLE_MAX << 16); miniportStatus = PIR_STATUS_MINIPORT_MAX | (PIR_STATUS_MINIPORT_MAX << 16); details.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA); attributes = PIR_OPTION_ENABLED | PIR_OPTION_MSSPEC | PIR_OPTION_REALMODE; if (SetupDiGetDeviceInfoListDetail(pciHalPropData->DeviceInfoSet, &details)) { if (RegConnectRegistry( (details.RemoteMachineName[0] == TEXT('\0'))? NULL : details.RemoteMachineName, HKEY_LOCAL_MACHINE, &pciHalPropData->LocalMachine) == ERROR_SUCCESS) { pciHalPropData->CloseKey = TRUE; if (RegOpenKeyEx(pciHalPropData->LocalMachine, REGSTR_PATH_PCIIR, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { size = sizeof(pciHalPropData->Options); RegQueryValueEx(hKey, REGSTR_VAL_OPTIONS, NULL, NULL, (LPBYTE)&pciHalPropData->Options, &size ); size = sizeof(status); RegQueryValueEx(hKey, REGSTR_VAL_STAT, NULL, NULL, (LPBYTE)&status, &size); size = sizeof(tableStatus); RegQueryValueEx(hKey, REGSTR_VAL_TABLE_STAT, NULL, NULL, (LPBYTE)&tableStatus, &size ); size = sizeof(miniportStatus); RegQueryValueEx(hKey, REGSTR_VAL_MINIPORT_STAT, NULL, NULL, (LPBYTE)&miniportStatus, &size ); RegCloseKey(hKey); } // // Gray out the controls if the user does not have READ+WRITE access to the REGSTR_PATH_PCIIR. // if (RegOpenKeyEx(pciHalPropData->LocalMachine, REGSTR_PATH_PCIIR, 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) { RegCloseKey(hKey); attributes = 0; if (RegOpenKeyEx(pciHalPropData->LocalMachine, REGSTR_PATH_BIOSINFO L"\\PciIrqRouting", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { size = sizeof(attributes); RegQueryValueEx(hKey, L"Attributes", NULL, NULL, (LPBYTE)&attributes, &size ); RegCloseKey(hKey); } } } } // // Set the class icon. // if (SetupDiLoadClassIcon( &pciHalPropData->DeviceInfoData->ClassGuid, &hIconNew, &iconIndex) == TRUE) { hIconOld = (HICON)SendDlgItemMessage(Dialog, IDC_PCIHAL_ICON, STM_SETICON, (WPARAM)hIconNew, 0 ); if (hIconOld) { DestroyIcon(hIconOld); } } // // Set the device description. // desc = PciHalGetDescription(pciHalPropData->DeviceInfoSet, pciHalPropData->DeviceInfoData ); if (desc) { SetDlgItemText(Dialog, IDC_PCIHAL_DEVDESC, desc); Release(desc); } // // Set the initial state of the controls. // PciHalSetControls(Dialog, pciHalPropData->Options, attributes); // // Display status. // desc = PciHalGetStatus(status, tableStatus, miniportStatus); if (desc) { SetDlgItemText(Dialog, IDC_PCIHAL_RESULTS, desc); Release(desc); } // // Let the system set the focus. // return TRUE; } BOOL PciHalOnCommand ( IN HWND Dialog, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: This routine handles the message when the user modifies something on the property sheet page. Input Parameters: Dialog - Window handle for the property sheet page. wParam - wParam of the WM_COMMAND message. lParam - lParam of the WM_COMMAND message. Return Value: TRUE if this function handles the message. Else FALSE. --*/ { BOOL status; BOOL enabled; status = FALSE; switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_PCIHAL_SETDEFAULTS: // // Set the controls to the default value. // status = TRUE; PciHalSetControls(Dialog, PIR_OPTION_DEFAULT, 0); break; case IDC_PCIHAL_ENABLE: // // Gray out the sub-options if Irq Routing is being disabled. // status = TRUE; enabled = IsDlgButtonChecked(Dialog, IDC_PCIHAL_ENABLE); EnableWindow(GetDlgItem(Dialog, IDC_PCIHAL_MSSPEC), enabled); EnableWindow(GetDlgItem(Dialog, IDC_PCIHAL_REALMODE), enabled); break; default: break; } return status; } BOOL PciHalOnNotify( IN HWND Dialog, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: This routine handles the WM_NOTIFY message for the Pci Irq Routing property sheet page. Input Parameters: Dialog - Window handle for the property sheet page. wParam - wParam of the WM_NOTIFY message. lParam - lParam of the WM_NOTIFY message. Return Value: TRUE if this function handles the message. Else FALSE. --*/ { BOOL status = FALSE; HKEY hKey; DWORD options; switch (((LPNMHDR)lParam)->code) { case PSN_RESET: // // User hit cancel. // status = TRUE; if (RegOpenKey(gPciHalPropData.LocalMachine, REGSTR_PATH_PCIIR, &hKey) == ERROR_SUCCESS) { RegSetValueEx(hKey, REGSTR_VAL_OPTIONS, 0, REG_DWORD, (CONST BYTE *)&gPciHalPropData.Options, sizeof(gPciHalPropData.Options) ); RegCloseKey(hKey); } break; case PSN_APPLY: // // User hit Apply or Ok. // status = TRUE; // // Read the different control status and write it to the registry. // options = gPciHalPropData.Options; if (IsDlgButtonChecked(Dialog, IDC_PCIHAL_ENABLE) == BST_CHECKED) { options |= PIR_OPTION_ENABLED; } else { options &= ~PIR_OPTION_ENABLED; } if (IsDlgButtonChecked(Dialog, IDC_PCIHAL_MSSPEC)) { options |= PIR_OPTION_MSSPEC; } else { options &= ~PIR_OPTION_MSSPEC; } if (IsDlgButtonChecked(Dialog, IDC_PCIHAL_REALMODE)) { options |= PIR_OPTION_REALMODE; } else { options &= ~PIR_OPTION_REALMODE; } if (RegOpenKey(gPciHalPropData.LocalMachine, REGSTR_PATH_PCIIR, &hKey) == ERROR_SUCCESS) { RegSetValueEx( hKey, REGSTR_VAL_OPTIONS, 0, REG_DWORD, (CONST BYTE *)&options, sizeof(options)); RegCloseKey(hKey); } // // Reboot if any of the options changed. // if (options != gPciHalPropData.Options) { SP_DEVINSTALL_PARAMS deviceInstallParams; ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams)); deviceInstallParams.cbSize = sizeof(deviceInstallParams); if (SetupDiGetDeviceInstallParams(gPciHalPropData.DeviceInfoSet, gPciHalPropData.DeviceInfoData, &deviceInstallParams)) { deviceInstallParams.Flags |= DI_NEEDREBOOT; SetupDiSetDeviceInstallParams(gPciHalPropData.DeviceInfoSet, gPciHalPropData.DeviceInfoData, &deviceInstallParams ); } } break; default: break; } return status; } INT_PTR CALLBACK PciHalDialogProc( IN HWND Dialog, IN UINT Message, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: This is the DlgProc for the Pci Irq Routing property sheet page. Input Parameters: Standard DlgProc parameters. Return Value: TRUE if it handles the message. Else FALSE. --*/ { BOOL status = FALSE; PCWSTR szHelpFile = L"devmgr.hlp"; HICON hIconOld; switch (Message) { case WM_INITDIALOG: status = PciHalOnInitDialog(Dialog, wParam, lParam); break; case WM_COMMAND: status = PciHalOnCommand(Dialog, wParam, lParam); break; case WM_NOTIFY: status = PciHalOnNotify(Dialog, wParam, lParam); break; case WM_HELP: WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, szHelpFile, HELP_WM_HELP, (ULONG_PTR)gPciPropHelpIds ); status = TRUE; break; case WM_CONTEXTMENU: WinHelp((HWND)wParam, szHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)gPciPropHelpIds ); status = TRUE; break; case WM_DESTROY: if (gPciHalPropData.CloseKey) { RegCloseKey(gPciHalPropData.LocalMachine); gPciHalPropData.CloseKey = FALSE; } hIconOld = (HICON)SendDlgItemMessage(Dialog, IDC_PCIHAL_ICON, STM_GETICON, (WPARAM)0, 0 ); if (hIconOld) { DestroyIcon(hIconOld); } default: break; } return status; } DWORD PciHalCoInstaller( IN DI_FUNCTION InstallFunction, IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, IN OUT PCOINSTALLER_CONTEXT_DATA Context ) { BOOL status; HPROPSHEETPAGE pageHandle; PROPSHEETPAGE page; SP_DEVINFO_LIST_DETAIL_DATA details; SP_ADDPROPERTYPAGE_DATA addPropertyPageData; switch (InstallFunction) { case DIF_ADDPROPERTYPAGE_ADVANCED: case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED: details.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA); if (SetupDiGetDeviceInfoListDetail(DeviceInfoSet, &details)) { if (RegConnectRegistry( (details.RemoteMachineName[0] == TEXT('\0'))? NULL : details.RemoteMachineName, HKEY_LOCAL_MACHINE, &gPciHalPropData.LocalMachine) == ERROR_SUCCESS) { RegCloseKey(gPciHalPropData.LocalMachine); status = TRUE; break; } } default: status = FALSE; break; } if (status) { ZeroMemory(&addPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA)); addPropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); if (SetupDiGetClassInstallParams( DeviceInfoSet, DeviceInfoData, (PSP_CLASSINSTALL_HEADER)&addPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA), NULL )) { if (addPropertyPageData.NumDynamicPages < MAX_INSTALLWIZARD_DYNAPAGES) { // // Initialize our globals here. // gPciHalPropData.DeviceInfoSet = DeviceInfoSet; gPciHalPropData.DeviceInfoData = DeviceInfoData; // // Initialize our property page here. // ZeroMemory(&page, sizeof(PROPSHEETPAGE)); page.dwSize = sizeof(PROPSHEETPAGE); page.hInstance = MyModuleHandle; page.pszTemplate = MAKEINTRESOURCE(IDD_PCIHAL_PROPPAGE); page.pfnDlgProc = PciHalDialogProc; page.lParam = (LPARAM)&gPciHalPropData; pageHandle = CreatePropertySheetPage(&page); if (pageHandle != NULL) { addPropertyPageData.DynamicPages[addPropertyPageData.NumDynamicPages++] = pageHandle; SetupDiSetClassInstallParams( DeviceInfoSet, DeviceInfoData, (PSP_CLASSINSTALL_HEADER)&addPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA) ); return NO_ERROR; } } } } return NO_ERROR; }