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 HKEY hDeviceKey
= NULL
;
33 HKEY hConfigKey
= NULL
;
34 LPBYTE lpBuffer
= NULL
;
39 *ppResourceList
= NULL
;
41 hDeviceKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
51 lError
= RegOpenKeyExW(hDeviceKey
,
56 if (lError
!= ERROR_SUCCESS
)
59 /* Get the configuration data size */
60 lError
= RegQueryValueExW(hConfigKey
,
66 if (lError
!= ERROR_SUCCESS
)
69 /* Allocate the buffer */
70 lpBuffer
= HeapAlloc(GetProcessHeap(), 0, dwDataSize
);
74 /* Retrieve the configuration data */
75 lError
= RegQueryValueExW(hConfigKey
,
81 if (lError
== ERROR_SUCCESS
)
85 if (ret
== FALSE
&& lpBuffer
!= NULL
)
86 HeapFree(GetProcessHeap(), 0, lpBuffer
);
89 RegCloseKey(hConfigKey
);
92 RegCloseKey(hDeviceKey
);
95 *ppResourceList
= (PCM_RESOURCE_LIST
)lpBuffer
;
102 GetSerialPortNumber(IN HDEVINFO DeviceInfoSet
,
103 IN PSP_DEVINFO_DATA DeviceInfoData
)
105 PCM_RESOURCE_LIST lpResourceList
= NULL
;
106 PCM_PARTIAL_RESOURCE_DESCRIPTOR lpResDes
;
108 DWORD dwBaseAddress
= 0;
109 DWORD dwPortNumber
= 0;
111 TRACE("GetSerialPortNumber(%p, %p)\n",
112 DeviceInfoSet
, DeviceInfoData
);
114 if (GetBootResourceList(DeviceInfoSet
,
118 TRACE("Full resource descriptors: %ul\n", lpResourceList
->Count
);
119 if (lpResourceList
->Count
> 0)
121 TRACE("Partial resource descriptors: %ul\n", lpResourceList
->List
[0].PartialResourceList
.Count
);
123 for (i
= 0; i
< lpResourceList
->List
[0].PartialResourceList
.Count
; i
++)
125 lpResDes
= &lpResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
126 TRACE("Type: %u\n", lpResDes
->Type
);
128 switch (lpResDes
->Type
)
130 case CmResourceTypePort
:
131 TRACE("Port: Start: %I64x Length: %lu\n",
132 lpResDes
->u
.Port
.Start
.QuadPart
,
133 lpResDes
->u
.Port
.Length
);
134 if ((lpResDes
->u
.Port
.Start
.HighPart
== 0) && (dwBaseAddress
== 0))
135 dwBaseAddress
= (DWORD
)lpResDes
->u
.Port
.Start
.LowPart
;
138 case CmResourceTypeInterrupt
:
139 TRACE("Interrupt: Level: %lu Vector: %lu\n",
140 lpResDes
->u
.Interrupt
.Level
,
141 lpResDes
->u
.Interrupt
.Vector
);
147 HeapFree(GetProcessHeap(), 0, lpResourceList
);
150 switch (dwBaseAddress
)
174 GetParallelPortNumber(IN HDEVINFO DeviceInfoSet
,
175 IN PSP_DEVINFO_DATA DeviceInfoData
)
177 PCM_RESOURCE_LIST lpResourceList
= NULL
;
178 PCM_PARTIAL_RESOURCE_DESCRIPTOR lpResDes
;
180 DWORD dwBaseAddress
= 0;
181 DWORD dwPortNumber
= 0;
183 TRACE("GetParallelPortNumber(%p, %p)\n",
184 DeviceInfoSet
, DeviceInfoData
);
186 if (GetBootResourceList(DeviceInfoSet
,
190 TRACE("Full resource descriptors: %ul\n", lpResourceList
->Count
);
191 if (lpResourceList
->Count
> 0)
193 TRACE("Partial resource descriptors: %ul\n", lpResourceList
->List
[0].PartialResourceList
.Count
);
195 for (i
= 0; i
< lpResourceList
->List
[0].PartialResourceList
.Count
; i
++)
197 lpResDes
= &lpResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
198 TRACE("Type: %u\n", lpResDes
->Type
);
200 switch (lpResDes
->Type
)
202 case CmResourceTypePort
:
203 TRACE("Port: Start: %I64x Length: %lu\n",
204 lpResDes
->u
.Port
.Start
.QuadPart
,
205 lpResDes
->u
.Port
.Length
);
206 if ((lpResDes
->u
.Port
.Start
.HighPart
== 0) && (dwBaseAddress
== 0))
207 dwBaseAddress
= (DWORD
)lpResDes
->u
.Port
.Start
.LowPart
;
210 case CmResourceTypeInterrupt
:
211 TRACE("Interrupt: Level: %lu Vector: %lu\n",
212 lpResDes
->u
.Interrupt
.Level
,
213 lpResDes
->u
.Interrupt
.Vector
);
221 HeapFree(GetProcessHeap(), 0, lpResourceList
);
224 switch (dwBaseAddress
)
240 InstallSerialPort(IN HDEVINFO DeviceInfoSet
,
241 IN PSP_DEVINFO_DATA DeviceInfoData
)
243 WCHAR szDeviceDescription
[256];
244 WCHAR szFriendlyName
[256];
246 DWORD dwPortNumber
= 0;
248 HCOMDB hComDB
= HCOMDB_INVALID_HANDLE_VALUE
;
252 TRACE("InstallSerialPort(%p, %p)\n",
253 DeviceInfoSet
, DeviceInfoData
);
255 /* Open the com port database */
258 /* Try to read the 'PortName' value and determine the port number */
259 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
266 if (hKey
!= INVALID_HANDLE_VALUE
)
268 dwSize
= sizeof(szPortName
);
269 lError
= RegQueryValueEx(hKey
,
275 if (lError
== ERROR_SUCCESS
)
277 if (_wcsnicmp(szPortName
, pszCom
, wcslen(pszCom
)) == 0)
279 dwPortNumber
= _wtoi(szPortName
+ wcslen(pszCom
));
280 TRACE("COM port number found: %lu\n", dwPortNumber
);
287 /* Determine the port number from its resources ... */
288 if (dwPortNumber
== 0)
289 dwPortNumber
= GetSerialPortNumber(DeviceInfoSet
,
292 if (dwPortNumber
!= 0)
294 /* ... and claim the port number in the database */
295 ComDBClaimPort(hComDB
,
302 /* ... or claim the next free port number */
303 ComDBClaimNextFreePort(hComDB
,
307 /* Build the name of the port device */
308 swprintf(szPortName
, L
"%s%u", pszCom
, dwPortNumber
);
310 /* Close the com port database */
311 if (hComDB
!= HCOMDB_INVALID_HANDLE_VALUE
)
314 /* Set the 'PortName' value */
315 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
322 if (hKey
!= INVALID_HANDLE_VALUE
)
329 (wcslen(szPortName
) + 1) * sizeof(WCHAR
));
334 /* Install the device */
335 if (!SetupDiInstallDevice(DeviceInfoSet
,
338 return GetLastError();
341 /* Get the device description... */
342 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet
,
346 (LPBYTE
)szDeviceDescription
,
350 /* ... and use it to build a new friendly name */
351 swprintf(szFriendlyName
,
358 /* ... or build a generic friendly name */
359 swprintf(szFriendlyName
,
364 /* Set the friendly name for the device */
365 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet
,
368 (LPBYTE
)szFriendlyName
,
369 (wcslen(szFriendlyName
) + 1) * sizeof(WCHAR
));
371 return ERROR_SUCCESS
;
376 InstallParallelPort(IN HDEVINFO DeviceInfoSet
,
377 IN PSP_DEVINFO_DATA DeviceInfoData
)
379 WCHAR szDeviceDescription
[256];
380 WCHAR szFriendlyName
[256];
382 DWORD dwPortNumber
= 0;
387 TRACE("InstallParallelPort(%p, %p)\n",
388 DeviceInfoSet
, DeviceInfoData
);
390 /* Try to read the 'PortName' value and determine the port number */
391 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
398 if (hKey
!= INVALID_HANDLE_VALUE
)
400 dwSize
= sizeof(szPortName
);
401 lError
= RegQueryValueEx(hKey
,
407 if (lError
== ERROR_SUCCESS
)
409 if (_wcsnicmp(szPortName
, pszLpt
, wcslen(pszLpt
)) == 0)
411 dwPortNumber
= _wtoi(szPortName
+ wcslen(pszLpt
));
412 TRACE("LPT port number found: %lu\n", dwPortNumber
);
419 /* ... try to determine the port number from its resources */
420 if (dwPortNumber
== 0)
422 dwPortNumber
= GetParallelPortNumber(DeviceInfoSet
,
424 TRACE("GetParallelPortNumber() returned port number: %lu\n", dwPortNumber
);
427 if (dwPortNumber
== 0)
430 FIXME("Got no valid port numer!\n");
433 if (dwPortNumber
!= 0)
435 swprintf(szPortName
, L
"%s%u", pszLpt
, dwPortNumber
);
439 wcscpy(szPortName
, L
"LPTx");
442 if (dwPortNumber
!= 0)
444 /* Set the 'PortName' value */
445 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
452 if (hKey
!= INVALID_HANDLE_VALUE
)
459 (wcslen(szPortName
) + 1) * sizeof(WCHAR
));
465 /* Install the device */
466 if (!SetupDiInstallDevice(DeviceInfoSet
,
469 return GetLastError();
472 /* Get the device description... */
473 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet
,
477 (LPBYTE
)szDeviceDescription
,
481 /* ... and use it to build a new friendly name */
482 swprintf(szFriendlyName
,
489 /* ... or build a generic friendly name */
490 swprintf(szFriendlyName
,
491 L
"Parallel Port (%s)",
495 TRACE("Friendly name: %S\n", szFriendlyName
);
497 /* Set the friendly name for the device */
498 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet
,
501 (LPBYTE
)szFriendlyName
,
502 (wcslen(szFriendlyName
) + 1) * sizeof(WCHAR
));
504 return ERROR_SUCCESS
;
509 InstallDeviceData(IN HDEVINFO DeviceInfoSet
,
510 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
513 HINF hInf
= INVALID_HANDLE_VALUE
;
514 SP_DRVINFO_DATA DriverInfoData
;
515 PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData
;
516 WCHAR InfSectionWithExt
[256];
520 TRACE("InstallDeviceData()\n");
522 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
532 DriverInfoData
.cbSize
= sizeof(SP_DRVINFO_DATA
);
533 if (!SetupDiGetSelectedDriverW(DeviceInfoSet
,
540 DriverInfoDetailData
= (PSP_DRVINFO_DETAIL_DATA
)buffer
;
541 DriverInfoDetailData
->cbSize
= sizeof(SP_DRVINFO_DETAIL_DATA
);
542 if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet
,
545 DriverInfoDetailData
,
549 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
553 TRACE("Inf file name: %S\n", DriverInfoDetailData
->InfFileName
);
555 hInf
= SetupOpenInfFileW(DriverInfoDetailData
->InfFileName
,
559 if (hInf
== INVALID_HANDLE_VALUE
)
562 TRACE("Section name: %S\n", DriverInfoDetailData
->SectionName
);
564 SetupDiGetActualSectionToInstallW(hInf
,
565 DriverInfoDetailData
->SectionName
,
571 TRACE("InfSectionWithExt: %S\n", InfSectionWithExt
);
573 SetupInstallFromInfSectionW(NULL
,
591 if (hInf
!= INVALID_HANDLE_VALUE
)
592 SetupCloseInfFile(hInf
);
598 GetPortType(IN HDEVINFO DeviceInfoSet
,
599 IN PSP_DEVINFO_DATA DeviceInfoData
)
605 PORT_TYPE PortType
= UnknownPort
;
608 TRACE("GetPortType()\n");
610 hKey
= SetupDiCreateDevRegKeyW(DeviceInfoSet
,
622 dwSize
= sizeof(BYTE
);
623 lError
= RegQueryValueExW(hKey
,
630 TRACE("lError: %ld\n", lError
);
631 TRACE("dwSize: %lu\n", dwSize
);
632 TRACE("dwType: %lu\n", dwType
);
634 if (lError
== ERROR_SUCCESS
&&
635 dwSize
== sizeof(BYTE
) &&
636 dwType
== REG_BINARY
)
639 PortType
= ParallelPort
;
641 PortType
= SerialPort
;
648 TRACE("GetPortType() returns %u \n", PortType
);
655 InstallPort(IN HDEVINFO DeviceInfoSet
,
656 IN PSP_DEVINFO_DATA DeviceInfoData
)
660 InstallDeviceData(DeviceInfoSet
, DeviceInfoData
);
662 PortType
= GetPortType(DeviceInfoSet
, DeviceInfoData
);
666 return InstallParallelPort(DeviceInfoSet
, DeviceInfoData
);
669 return InstallSerialPort(DeviceInfoSet
, DeviceInfoData
);
672 return ERROR_DI_DO_DEFAULT
;
678 RemovePort(IN HDEVINFO DeviceInfoSet
,
679 IN PSP_DEVINFO_DATA DeviceInfoData
)
682 HCOMDB hComDB
= HCOMDB_INVALID_HANDLE_VALUE
;
686 DWORD dwPortNameSize
;
689 /* If we are removing a serial port ... */
690 PortType
= GetPortType(DeviceInfoSet
, DeviceInfoData
);
691 if (PortType
== SerialPort
)
693 /* Open the port database */
694 if (ComDBOpen(&hComDB
) == ERROR_SUCCESS
)
696 /* Open the device key */
697 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
,
703 if (hKey
!= INVALID_HANDLE_VALUE
)
705 /* Query the port name */
706 dwPortNameSize
= sizeof(szPortName
);
707 lError
= RegQueryValueEx(hKey
,
714 /* Close the device key */
717 /* If we got a valid port name ...*/
718 if (lError
== ERROR_SUCCESS
)
720 /* Get the port number */
721 dwPortNumber
= _wtoi(szPortName
+ wcslen(pszCom
));
723 /* Release the port */
724 ComDBReleasePort(hComDB
, dwPortNumber
);
728 /* Close the port database */
733 /* Remove the device */
734 if (!SetupDiRemoveDevice(DeviceInfoSet
, DeviceInfoData
))
735 return GetLastError();
737 return ERROR_SUCCESS
;
743 PortsClassInstaller(IN DI_FUNCTION InstallFunction
,
744 IN HDEVINFO DeviceInfoSet
,
745 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
747 TRACE("PortsClassInstaller(%lu, %p, %p)\n",
748 InstallFunction
, DeviceInfoSet
, DeviceInfoData
);
750 switch (InstallFunction
)
752 case DIF_INSTALLDEVICE
:
753 return InstallPort(DeviceInfoSet
, DeviceInfoData
);
756 return RemovePort(DeviceInfoSet
, DeviceInfoData
);
759 TRACE("Install function %u ignored\n", InstallFunction
);
760 return ERROR_DI_DO_DEFAULT
;