2 * PROJECT: ReactOS system libraries
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dlls\win32\msports\classinst.c
5 * PURPOSE: Ports class installer
6 * PROGRAMMERS: Copyright 2011 Eric Kohl
13 #define NTOS_MODE_USER
14 #include <ndk/cmtypes.h>
16 typedef enum _PORT_TYPE
23 LPWSTR pszCom
= L
"COM";
24 LPWSTR pszLpt
= L
"LPT";
28 GetBootResourceList(HDEVINFO DeviceInfoSet
,
29 PSP_DEVINFO_DATA DeviceInfoData
,
30 PCM_RESOURCE_LIST
*ppResourceList
)
32 WCHAR DeviceInstanceIdBuffer
[128];
34 HKEY hDeviceKey
= NULL
;
35 HKEY hConfigKey
= NULL
;
36 LPBYTE lpBuffer
= NULL
;
41 FIXME("GetBootResourceList()\n");
43 *ppResourceList
= NULL
;
45 if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet
,
47 DeviceInstanceIdBuffer
,
48 ARRAYSIZE(DeviceInstanceIdBuffer
),
51 ERR("SetupDiGetDeviceInstanceIdW() failed\n");
55 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
56 L
"SYSTEM\\CurrentControlSet\\Enum",
60 if (lError
!= ERROR_SUCCESS
)
62 ERR("RegOpenKeyExW() failed (Error %lu)\n", lError
);
66 lError
= RegOpenKeyExW(hEnumKey
,
67 DeviceInstanceIdBuffer
,
71 if (lError
!= ERROR_SUCCESS
)
73 ERR("RegOpenKeyExW() failed (Error %lu)\n", lError
);
77 lError
= RegOpenKeyExW(hDeviceKey
,
82 if (lError
!= ERROR_SUCCESS
)
84 ERR("RegOpenKeyExW() failed (Error %lu)\n", lError
);
88 /* Get the configuration data size */
89 lError
= RegQueryValueExW(hConfigKey
,
95 if (lError
!= ERROR_SUCCESS
)
97 ERR("RegQueryValueExW() failed (Error %lu)\n", lError
);
101 /* Allocate the buffer */
102 lpBuffer
= HeapAlloc(GetProcessHeap(), 0, dwDataSize
);
103 if (lpBuffer
== NULL
)
105 ERR("Failed to allocate the resource list buffer\n");
109 /* Retrieve the configuration data */
110 lError
= RegQueryValueExW(hConfigKey
,
116 if (lError
== ERROR_SUCCESS
)
118 ERR("RegQueryValueExW() failed (Error %lu)\n", lError
);
123 if (ret
== FALSE
&& lpBuffer
!= NULL
)
124 HeapFree(GetProcessHeap(), 0, lpBuffer
);
127 RegCloseKey(hConfigKey
);
130 RegCloseKey(hDeviceKey
);
133 RegCloseKey(hEnumKey
);
136 *ppResourceList
= (PCM_RESOURCE_LIST
)lpBuffer
;
143 GetSerialPortNumber(IN HDEVINFO DeviceInfoSet
,
144 IN PSP_DEVINFO_DATA DeviceInfoData
)
146 PCM_RESOURCE_LIST lpResourceList
= NULL
;
147 PCM_PARTIAL_RESOURCE_DESCRIPTOR lpResDes
;
149 DWORD dwBaseAddress
= 0;
150 DWORD dwPortNumber
= 0;
152 TRACE("GetSerialPortNumber(%p, %p)\n",
153 DeviceInfoSet
, DeviceInfoData
);
155 if (GetBootResourceList(DeviceInfoSet
,
159 TRACE("Full resource descriptors: %ul\n", lpResourceList
->Count
);
160 if (lpResourceList
->Count
> 0)
162 TRACE("Partial resource descriptors: %ul\n", lpResourceList
->List
[0].PartialResourceList
.Count
);
164 for (i
= 0; i
< lpResourceList
->List
[0].PartialResourceList
.Count
; i
++)
166 lpResDes
= &lpResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
167 TRACE("Type: %u\n", lpResDes
->Type
);
169 switch (lpResDes
->Type
)
171 case CmResourceTypePort
:
172 TRACE("Port: Start: %I64x Length: %lu\n",
173 lpResDes
->u
.Port
.Start
.QuadPart
,
174 lpResDes
->u
.Port
.Length
);
175 if ((lpResDes
->u
.Port
.Start
.HighPart
== 0) && (dwBaseAddress
== 0))
176 dwBaseAddress
= (DWORD
)lpResDes
->u
.Port
.Start
.LowPart
;
179 case CmResourceTypeInterrupt
:
180 TRACE("Interrupt: Level: %lu Vector: %lu\n",
181 lpResDes
->u
.Interrupt
.Level
,
182 lpResDes
->u
.Interrupt
.Vector
);
188 HeapFree(GetProcessHeap(), 0, lpResourceList
);
191 switch (dwBaseAddress
)
215 GetParallelPortNumber(IN HDEVINFO DeviceInfoSet
,
216 IN PSP_DEVINFO_DATA DeviceInfoData
)
218 PCM_RESOURCE_LIST lpResourceList
= NULL
;
219 PCM_PARTIAL_RESOURCE_DESCRIPTOR lpResDes
;
221 DWORD dwBaseAddress
= 0;
222 DWORD dwPortNumber
= 0;
224 TRACE("GetParallelPortNumber(%p, %p)\n",
225 DeviceInfoSet
, DeviceInfoData
);
227 if (GetBootResourceList(DeviceInfoSet
,
231 TRACE("Full resource descriptors: %ul\n", lpResourceList
->Count
);
232 if (lpResourceList
->Count
> 0)
234 TRACE("Partial resource descriptors: %ul\n", lpResourceList
->List
[0].PartialResourceList
.Count
);
236 for (i
= 0; i
< lpResourceList
->List
[0].PartialResourceList
.Count
; i
++)
238 lpResDes
= &lpResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
239 TRACE("Type: %u\n", lpResDes
->Type
);
241 switch (lpResDes
->Type
)
243 case CmResourceTypePort
:
244 TRACE("Port: Start: %I64x Length: %lu\n",
245 lpResDes
->u
.Port
.Start
.QuadPart
,
246 lpResDes
->u
.Port
.Length
);
247 if ((lpResDes
->u
.Port
.Start
.HighPart
== 0) && (dwBaseAddress
== 0))
248 dwBaseAddress
= (DWORD
)lpResDes
->u
.Port
.Start
.LowPart
;
251 case CmResourceTypeInterrupt
:
252 TRACE("Interrupt: Level: %lu Vector: %lu\n",
253 lpResDes
->u
.Interrupt
.Level
,
254 lpResDes
->u
.Interrupt
.Vector
);
262 HeapFree(GetProcessHeap(), 0, lpResourceList
);
265 switch (dwBaseAddress
)
281 InstallSerialPort(IN HDEVINFO DeviceInfoSet
,
282 IN PSP_DEVINFO_DATA DeviceInfoData
)
284 WCHAR szDeviceDescription
[256];
285 WCHAR szFriendlyName
[256];
287 DWORD dwPortNumber
= 0;
289 HCOMDB hComDB
= HCOMDB_INVALID_HANDLE_VALUE
;
293 TRACE("InstallSerialPort(%p, %p)\n",
294 DeviceInfoSet
, DeviceInfoData
);
296 /* Open the com port database */
299 /* Try to read the 'PortName' value and determine the port number */
300 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
307 if (hKey
!= INVALID_HANDLE_VALUE
)
309 dwSize
= sizeof(szPortName
);
310 lError
= RegQueryValueEx(hKey
,
316 if (lError
== ERROR_SUCCESS
)
318 if (_wcsnicmp(szPortName
, pszCom
, wcslen(pszCom
)) == 0)
320 dwPortNumber
= _wtoi(szPortName
+ wcslen(pszCom
));
321 TRACE("COM port number found: %lu\n", dwPortNumber
);
328 /* Determine the port number from its resources ... */
329 if (dwPortNumber
== 0)
330 dwPortNumber
= GetSerialPortNumber(DeviceInfoSet
,
333 if (dwPortNumber
!= 0)
335 /* ... and claim the port number in the database */
336 ComDBClaimPort(hComDB
,
343 /* ... or claim the next free port number */
344 ComDBClaimNextFreePort(hComDB
,
348 /* Build the name of the port device */
349 swprintf(szPortName
, L
"%s%u", pszCom
, dwPortNumber
);
351 /* Close the com port database */
352 if (hComDB
!= HCOMDB_INVALID_HANDLE_VALUE
)
355 /* Set the 'PortName' value */
356 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
363 if (hKey
!= INVALID_HANDLE_VALUE
)
370 (wcslen(szPortName
) + 1) * sizeof(WCHAR
));
375 /* Install the device */
376 if (!SetupDiInstallDevice(DeviceInfoSet
,
379 return GetLastError();
382 /* Get the device description... */
383 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet
,
387 (LPBYTE
)szDeviceDescription
,
391 /* ... and use it to build a new friendly name */
392 swprintf(szFriendlyName
,
399 /* ... or build a generic friendly name */
400 swprintf(szFriendlyName
,
405 /* Set the friendly name for the device */
406 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet
,
409 (LPBYTE
)szFriendlyName
,
410 (wcslen(szFriendlyName
) + 1) * sizeof(WCHAR
));
412 return ERROR_SUCCESS
;
417 InstallParallelPort(IN HDEVINFO DeviceInfoSet
,
418 IN PSP_DEVINFO_DATA DeviceInfoData
)
420 WCHAR szDeviceDescription
[256];
421 WCHAR szFriendlyName
[256];
423 DWORD dwPortNumber
= 0;
429 TRACE("InstallParallelPort(%p, %p)\n",
430 DeviceInfoSet
, DeviceInfoData
);
432 /* Try to read the 'PortName' value and determine the port number */
433 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
440 if (hKey
!= INVALID_HANDLE_VALUE
)
442 dwSize
= sizeof(szPortName
);
443 lError
= RegQueryValueEx(hKey
,
449 if (lError
== ERROR_SUCCESS
)
451 if (_wcsnicmp(szPortName
, pszLpt
, wcslen(pszLpt
)) == 0)
453 dwPortNumber
= _wtoi(szPortName
+ wcslen(pszLpt
));
454 TRACE("LPT port number found: %lu\n", dwPortNumber
);
461 /* ... try to determine the port number from its resources */
462 if (dwPortNumber
== 0)
464 dwPortNumber
= GetParallelPortNumber(DeviceInfoSet
,
466 TRACE("GetParallelPortNumber() returned port number: %lu\n", dwPortNumber
);
469 if (dwPortNumber
== 0)
472 FIXME("Got no valid port numer!\n");
475 if (dwPortNumber
!= 0)
477 swprintf(szPortName
, L
"%s%u", pszLpt
, dwPortNumber
);
481 wcscpy(szPortName
, L
"LPTx");
484 if (dwPortNumber
!= 0)
486 /* Set the 'PortName' value */
487 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
494 if (hKey
!= INVALID_HANDLE_VALUE
)
501 (wcslen(szPortName
) + 1) * sizeof(WCHAR
));
505 * This is to get the w2k3 parport.sys to work until we have our own.
506 * This setting makes the driver accept resources with an IRQ instead
507 * of only resources without an IRQ.
509 * We should probably also fix IO manager to actually give devices a
510 * chance to register without an IRQ. CORE-9645
514 L
"FilterResourceMethod",
524 /* Install the device */
525 if (!SetupDiInstallDevice(DeviceInfoSet
,
528 return GetLastError();
531 /* Get the device description... */
532 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet
,
536 (LPBYTE
)szDeviceDescription
,
540 /* ... and use it to build a new friendly name */
541 swprintf(szFriendlyName
,
548 /* ... or build a generic friendly name */
549 swprintf(szFriendlyName
,
550 L
"Parallel Port (%s)",
554 TRACE("Friendly name: %S\n", szFriendlyName
);
556 /* Set the friendly name for the device */
557 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet
,
560 (LPBYTE
)szFriendlyName
,
561 (wcslen(szFriendlyName
) + 1) * sizeof(WCHAR
));
563 return ERROR_SUCCESS
;
568 InstallDeviceData(IN HDEVINFO DeviceInfoSet
,
569 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
572 HINF hInf
= INVALID_HANDLE_VALUE
;
573 SP_DRVINFO_DATA DriverInfoData
;
574 PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData
;
575 WCHAR InfSectionWithExt
[256];
579 TRACE("InstallDeviceData()\n");
581 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
591 DriverInfoData
.cbSize
= sizeof(SP_DRVINFO_DATA
);
592 if (!SetupDiGetSelectedDriverW(DeviceInfoSet
,
599 DriverInfoDetailData
= (PSP_DRVINFO_DETAIL_DATA
)buffer
;
600 DriverInfoDetailData
->cbSize
= sizeof(SP_DRVINFO_DETAIL_DATA
);
601 if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet
,
604 DriverInfoDetailData
,
608 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
612 TRACE("Inf file name: %S\n", DriverInfoDetailData
->InfFileName
);
614 hInf
= SetupOpenInfFileW(DriverInfoDetailData
->InfFileName
,
618 if (hInf
== INVALID_HANDLE_VALUE
)
621 TRACE("Section name: %S\n", DriverInfoDetailData
->SectionName
);
623 if (!SetupDiGetActualSectionToInstallW(hInf
,
624 DriverInfoDetailData
->SectionName
,
631 TRACE("InfSectionWithExt: %S\n", InfSectionWithExt
);
633 SetupInstallFromInfSectionW(NULL
,
651 if (hInf
!= INVALID_HANDLE_VALUE
)
652 SetupCloseInfFile(hInf
);
658 GetPortType(IN HDEVINFO DeviceInfoSet
,
659 IN PSP_DEVINFO_DATA DeviceInfoData
)
665 PORT_TYPE PortType
= UnknownPort
;
668 TRACE("GetPortType()\n");
670 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
682 dwSize
= sizeof(BYTE
);
683 lError
= RegQueryValueExW(hKey
,
690 TRACE("lError: %ld\n", lError
);
691 TRACE("dwSize: %lu\n", dwSize
);
692 TRACE("dwType: %lu\n", dwType
);
694 if (lError
== ERROR_SUCCESS
&&
695 dwSize
== sizeof(BYTE
) &&
696 dwType
== REG_BINARY
)
699 PortType
= ParallelPort
;
701 PortType
= SerialPort
;
708 TRACE("GetPortType() returns %u \n", PortType
);
715 InstallPort(IN HDEVINFO DeviceInfoSet
,
716 IN PSP_DEVINFO_DATA DeviceInfoData
)
720 InstallDeviceData(DeviceInfoSet
, DeviceInfoData
);
722 PortType
= GetPortType(DeviceInfoSet
, DeviceInfoData
);
726 return InstallParallelPort(DeviceInfoSet
, DeviceInfoData
);
729 return InstallSerialPort(DeviceInfoSet
, DeviceInfoData
);
732 return ERROR_DI_DO_DEFAULT
;
738 RemovePort(IN HDEVINFO DeviceInfoSet
,
739 IN PSP_DEVINFO_DATA DeviceInfoData
)
742 HCOMDB hComDB
= HCOMDB_INVALID_HANDLE_VALUE
;
746 DWORD dwPortNameSize
;
749 /* If we are removing a serial port ... */
750 PortType
= GetPortType(DeviceInfoSet
, DeviceInfoData
);
751 if (PortType
== SerialPort
)
753 /* Open the port database */
754 if (ComDBOpen(&hComDB
) == ERROR_SUCCESS
)
756 /* Open the device key */
757 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
,
763 if (hKey
!= INVALID_HANDLE_VALUE
)
765 /* Query the port name */
766 dwPortNameSize
= sizeof(szPortName
);
767 lError
= RegQueryValueEx(hKey
,
774 /* Close the device key */
777 /* If we got a valid port name ...*/
778 if (lError
== ERROR_SUCCESS
)
780 /* Get the port number */
781 dwPortNumber
= _wtoi(szPortName
+ wcslen(pszCom
));
783 /* Release the port */
784 ComDBReleasePort(hComDB
, dwPortNumber
);
788 /* Close the port database */
793 /* Remove the device */
794 if (!SetupDiRemoveDevice(DeviceInfoSet
, DeviceInfoData
))
795 return GetLastError();
797 return ERROR_SUCCESS
;
803 PortsClassInstaller(IN DI_FUNCTION InstallFunction
,
804 IN HDEVINFO DeviceInfoSet
,
805 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
807 TRACE("PortsClassInstaller(%lu, %p, %p)\n",
808 InstallFunction
, DeviceInfoSet
, DeviceInfoData
);
810 switch (InstallFunction
)
812 case DIF_INSTALLDEVICE
:
813 return InstallPort(DeviceInfoSet
, DeviceInfoData
);
816 return RemovePort(DeviceInfoSet
, DeviceInfoData
);
819 TRACE("Install function %u ignored\n", InstallFunction
);
820 return ERROR_DI_DO_DEFAULT
;