[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
[reactos.git] / dll / win32 / msports / classinst.c
1 /*
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
7 */
8
9 #include "precomp.h"
10
11 #include <wchar.h>
12
13 #define NTOS_MODE_USER
14 #include <ndk/cmtypes.h>
15
16 typedef enum _PORT_TYPE
17 {
18 UnknownPort,
19 ParallelPort,
20 SerialPort
21 } PORT_TYPE;
22
23 LPWSTR pszCom = L"COM";
24 LPWSTR pszLpt = L"LPT";
25
26
27 BOOL
28 GetBootResourceList(HDEVINFO DeviceInfoSet,
29 PSP_DEVINFO_DATA DeviceInfoData,
30 PCM_RESOURCE_LIST *ppResourceList)
31 {
32 WCHAR DeviceInstanceIdBuffer[128];
33 HKEY hEnumKey = NULL;
34 HKEY hDeviceKey = NULL;
35 HKEY hConfigKey = NULL;
36 LPBYTE lpBuffer = NULL;
37 DWORD dwDataSize;
38 LONG lError;
39 BOOL ret = FALSE;
40
41 FIXME("GetBootResourceList()\n");
42
43 *ppResourceList = NULL;
44
45 if (!SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
46 DeviceInfoData,
47 DeviceInstanceIdBuffer,
48 ARRAYSIZE(DeviceInstanceIdBuffer),
49 &dwDataSize))
50 {
51 ERR("SetupDiGetDeviceInstanceIdW() failed\n");
52 return FALSE;
53 }
54
55 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
56 L"SYSTEM\\CurrentControlSet\\Enum",
57 0,
58 KEY_QUERY_VALUE,
59 &hEnumKey);
60 if (lError != ERROR_SUCCESS)
61 {
62 ERR("RegOpenKeyExW() failed (Error %lu)\n", lError);
63 goto done;
64 }
65
66 lError = RegOpenKeyExW(hEnumKey,
67 DeviceInstanceIdBuffer,
68 0,
69 KEY_QUERY_VALUE,
70 &hDeviceKey);
71 if (lError != ERROR_SUCCESS)
72 {
73 ERR("RegOpenKeyExW() failed (Error %lu)\n", lError);
74 goto done;
75 }
76
77 lError = RegOpenKeyExW(hDeviceKey,
78 L"LogConf",
79 0,
80 KEY_QUERY_VALUE,
81 &hConfigKey);
82 if (lError != ERROR_SUCCESS)
83 {
84 ERR("RegOpenKeyExW() failed (Error %lu)\n", lError);
85 goto done;
86 }
87
88 /* Get the configuration data size */
89 lError = RegQueryValueExW(hConfigKey,
90 L"BootConfig",
91 NULL,
92 NULL,
93 NULL,
94 &dwDataSize);
95 if (lError != ERROR_SUCCESS)
96 {
97 ERR("RegQueryValueExW() failed (Error %lu)\n", lError);
98 goto done;
99 }
100
101 /* Allocate the buffer */
102 lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwDataSize);
103 if (lpBuffer == NULL)
104 {
105 ERR("Failed to allocate the resource list buffer\n");
106 goto done;
107 }
108
109 /* Retrieve the configuration data */
110 lError = RegQueryValueExW(hConfigKey,
111 L"BootConfig",
112 NULL,
113 NULL,
114 (LPBYTE)lpBuffer,
115 &dwDataSize);
116 if (lError == ERROR_SUCCESS)
117 {
118 ERR("RegQueryValueExW() failed (Error %lu)\n", lError);
119 ret = TRUE;
120 }
121
122 done:
123 if (ret == FALSE && lpBuffer != NULL)
124 HeapFree(GetProcessHeap(), 0, lpBuffer);
125
126 if (hConfigKey)
127 RegCloseKey(hConfigKey);
128
129 if (hDeviceKey)
130 RegCloseKey(hDeviceKey);
131
132 if (hEnumKey)
133 RegCloseKey(hEnumKey);
134
135 if (ret != FALSE)
136 *ppResourceList = (PCM_RESOURCE_LIST)lpBuffer;
137
138 return ret;
139 }
140
141
142 DWORD
143 GetSerialPortNumber(IN HDEVINFO DeviceInfoSet,
144 IN PSP_DEVINFO_DATA DeviceInfoData)
145 {
146 PCM_RESOURCE_LIST lpResourceList = NULL;
147 PCM_PARTIAL_RESOURCE_DESCRIPTOR lpResDes;
148 ULONG i;
149 DWORD dwBaseAddress = 0;
150 DWORD dwPortNumber = 0;
151
152 TRACE("GetSerialPortNumber(%p, %p)\n",
153 DeviceInfoSet, DeviceInfoData);
154
155 if (GetBootResourceList(DeviceInfoSet,
156 DeviceInfoData,
157 &lpResourceList))
158 {
159 TRACE("Full resource descriptors: %ul\n", lpResourceList->Count);
160 if (lpResourceList->Count > 0)
161 {
162 TRACE("Partial resource descriptors: %ul\n", lpResourceList->List[0].PartialResourceList.Count);
163
164 for (i = 0; i < lpResourceList->List[0].PartialResourceList.Count; i++)
165 {
166 lpResDes = &lpResourceList->List[0].PartialResourceList.PartialDescriptors[i];
167 TRACE("Type: %u\n", lpResDes->Type);
168
169 switch (lpResDes->Type)
170 {
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;
177 break;
178
179 case CmResourceTypeInterrupt:
180 TRACE("Interrupt: Level: %lu Vector: %lu\n",
181 lpResDes->u.Interrupt.Level,
182 lpResDes->u.Interrupt.Vector);
183 break;
184 }
185 }
186 }
187
188 HeapFree(GetProcessHeap(), 0, lpResourceList);
189 }
190
191 switch (dwBaseAddress)
192 {
193 case 0x3f8:
194 dwPortNumber = 1;
195 break;
196
197 case 0x2f8:
198 dwPortNumber = 2;
199 break;
200
201 case 0x3e8:
202 dwPortNumber = 3;
203 break;
204
205 case 0x2e8:
206 dwPortNumber = 4;
207 break;
208 }
209
210 return dwPortNumber;
211 }
212
213
214 DWORD
215 GetParallelPortNumber(IN HDEVINFO DeviceInfoSet,
216 IN PSP_DEVINFO_DATA DeviceInfoData)
217 {
218 PCM_RESOURCE_LIST lpResourceList = NULL;
219 PCM_PARTIAL_RESOURCE_DESCRIPTOR lpResDes;
220 ULONG i;
221 DWORD dwBaseAddress = 0;
222 DWORD dwPortNumber = 0;
223
224 TRACE("GetParallelPortNumber(%p, %p)\n",
225 DeviceInfoSet, DeviceInfoData);
226
227 if (GetBootResourceList(DeviceInfoSet,
228 DeviceInfoData,
229 &lpResourceList))
230 {
231 TRACE("Full resource descriptors: %ul\n", lpResourceList->Count);
232 if (lpResourceList->Count > 0)
233 {
234 TRACE("Partial resource descriptors: %ul\n", lpResourceList->List[0].PartialResourceList.Count);
235
236 for (i = 0; i < lpResourceList->List[0].PartialResourceList.Count; i++)
237 {
238 lpResDes = &lpResourceList->List[0].PartialResourceList.PartialDescriptors[i];
239 TRACE("Type: %u\n", lpResDes->Type);
240
241 switch (lpResDes->Type)
242 {
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;
249 break;
250
251 case CmResourceTypeInterrupt:
252 TRACE("Interrupt: Level: %lu Vector: %lu\n",
253 lpResDes->u.Interrupt.Level,
254 lpResDes->u.Interrupt.Vector);
255 break;
256 }
257
258 }
259
260 }
261
262 HeapFree(GetProcessHeap(), 0, lpResourceList);
263 }
264
265 switch (dwBaseAddress)
266 {
267 case 0x378:
268 dwPortNumber = 1;
269 break;
270
271 case 0x278:
272 dwPortNumber = 2;
273 break;
274 }
275
276 return dwPortNumber;
277 }
278
279
280 static DWORD
281 InstallSerialPort(IN HDEVINFO DeviceInfoSet,
282 IN PSP_DEVINFO_DATA DeviceInfoData)
283 {
284 WCHAR szDeviceDescription[256];
285 WCHAR szFriendlyName[256];
286 WCHAR szPortName[8];
287 DWORD dwPortNumber = 0;
288 DWORD dwSize;
289 HCOMDB hComDB = HCOMDB_INVALID_HANDLE_VALUE;
290 HKEY hKey;
291 LONG lError;
292
293 TRACE("InstallSerialPort(%p, %p)\n",
294 DeviceInfoSet, DeviceInfoData);
295
296 /* Open the com port database */
297 ComDBOpen(&hComDB);
298
299 /* Try to read the 'PortName' value and determine the port number */
300 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
301 DeviceInfoData,
302 DICS_FLAG_GLOBAL,
303 0,
304 DIREG_DEV,
305 NULL,
306 NULL);
307 if (hKey != INVALID_HANDLE_VALUE)
308 {
309 dwSize = sizeof(szPortName);
310 lError = RegQueryValueEx(hKey,
311 L"PortName",
312 NULL,
313 NULL,
314 (PBYTE)szPortName,
315 &dwSize);
316 if (lError == ERROR_SUCCESS)
317 {
318 if (_wcsnicmp(szPortName, pszCom, wcslen(pszCom)) == 0)
319 {
320 dwPortNumber = _wtoi(szPortName + wcslen(pszCom));
321 TRACE("COM port number found: %lu\n", dwPortNumber);
322 }
323 }
324
325 RegCloseKey(hKey);
326 }
327
328 /* Determine the port number from its resources ... */
329 if (dwPortNumber == 0)
330 dwPortNumber = GetSerialPortNumber(DeviceInfoSet,
331 DeviceInfoData);
332
333 if (dwPortNumber != 0)
334 {
335 /* ... and claim the port number in the database */
336 ComDBClaimPort(hComDB,
337 dwPortNumber,
338 FALSE,
339 NULL);
340 }
341 else
342 {
343 /* ... or claim the next free port number */
344 ComDBClaimNextFreePort(hComDB,
345 &dwPortNumber);
346 }
347
348 /* Build the name of the port device */
349 swprintf(szPortName, L"%s%u", pszCom, dwPortNumber);
350
351 /* Close the com port database */
352 if (hComDB != HCOMDB_INVALID_HANDLE_VALUE)
353 ComDBClose(hComDB);
354
355 /* Set the 'PortName' value */
356 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
357 DeviceInfoData,
358 DICS_FLAG_GLOBAL,
359 0,
360 DIREG_DEV,
361 NULL,
362 NULL);
363 if (hKey != INVALID_HANDLE_VALUE)
364 {
365 RegSetValueExW(hKey,
366 L"PortName",
367 0,
368 REG_SZ,
369 (LPBYTE)szPortName,
370 (wcslen(szPortName) + 1) * sizeof(WCHAR));
371
372 RegCloseKey(hKey);
373 }
374
375 /* Install the device */
376 if (!SetupDiInstallDevice(DeviceInfoSet,
377 DeviceInfoData))
378 {
379 return GetLastError();
380 }
381
382 /* Get the device description... */
383 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
384 DeviceInfoData,
385 SPDRP_DEVICEDESC,
386 NULL,
387 (LPBYTE)szDeviceDescription,
388 256 * sizeof(WCHAR),
389 NULL))
390 {
391 /* ... and use it to build a new friendly name */
392 swprintf(szFriendlyName,
393 L"%s (%s)",
394 szDeviceDescription,
395 szPortName);
396 }
397 else
398 {
399 /* ... or build a generic friendly name */
400 swprintf(szFriendlyName,
401 L"Serial Port (%s)",
402 szPortName);
403 }
404
405 /* Set the friendly name for the device */
406 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
407 DeviceInfoData,
408 SPDRP_FRIENDLYNAME,
409 (LPBYTE)szFriendlyName,
410 (wcslen(szFriendlyName) + 1) * sizeof(WCHAR));
411
412 return ERROR_SUCCESS;
413 }
414
415
416 static DWORD
417 InstallParallelPort(IN HDEVINFO DeviceInfoSet,
418 IN PSP_DEVINFO_DATA DeviceInfoData)
419 {
420 WCHAR szDeviceDescription[256];
421 WCHAR szFriendlyName[256];
422 WCHAR szPortName[8];
423 DWORD dwPortNumber = 0;
424 DWORD dwSize;
425 DWORD dwValue;
426 LONG lError;
427 HKEY hKey;
428
429 TRACE("InstallParallelPort(%p, %p)\n",
430 DeviceInfoSet, DeviceInfoData);
431
432 /* Try to read the 'PortName' value and determine the port number */
433 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
434 DeviceInfoData,
435 DICS_FLAG_GLOBAL,
436 0,
437 DIREG_DEV,
438 NULL,
439 NULL);
440 if (hKey != INVALID_HANDLE_VALUE)
441 {
442 dwSize = sizeof(szPortName);
443 lError = RegQueryValueEx(hKey,
444 L"PortName",
445 NULL,
446 NULL,
447 (PBYTE)szPortName,
448 &dwSize);
449 if (lError == ERROR_SUCCESS)
450 {
451 if (_wcsnicmp(szPortName, pszLpt, wcslen(pszLpt)) == 0)
452 {
453 dwPortNumber = _wtoi(szPortName + wcslen(pszLpt));
454 TRACE("LPT port number found: %lu\n", dwPortNumber);
455 }
456 }
457
458 RegCloseKey(hKey);
459 }
460
461 /* ... try to determine the port number from its resources */
462 if (dwPortNumber == 0)
463 {
464 dwPortNumber = GetParallelPortNumber(DeviceInfoSet,
465 DeviceInfoData);
466 TRACE("GetParallelPortNumber() returned port number: %lu\n", dwPortNumber);
467 }
468
469 if (dwPortNumber == 0)
470 {
471 /* FIXME */
472 FIXME("Got no valid port numer!\n");
473 }
474
475 if (dwPortNumber != 0)
476 {
477 swprintf(szPortName, L"%s%u", pszLpt, dwPortNumber);
478 }
479 else
480 {
481 wcscpy(szPortName, L"LPTx");
482 }
483
484 if (dwPortNumber != 0)
485 {
486 /* Set the 'PortName' value */
487 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
488 DeviceInfoData,
489 DICS_FLAG_GLOBAL,
490 0,
491 DIREG_DEV,
492 NULL,
493 NULL);
494 if (hKey != INVALID_HANDLE_VALUE)
495 {
496 RegSetValueExW(hKey,
497 L"PortName",
498 0,
499 REG_SZ,
500 (LPBYTE)szPortName,
501 (wcslen(szPortName) + 1) * sizeof(WCHAR));
502
503 /*
504 * FIXME / HACK:
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.
508 *
509 * We should probably also fix IO manager to actually give devices a
510 * chance to register without an IRQ. CORE-9645
511 */
512 dwValue = 0;
513 RegSetValueExW(hKey,
514 L"FilterResourceMethod",
515 0,
516 REG_DWORD,
517 (LPBYTE)&dwValue,
518 sizeof(dwValue));
519
520 RegCloseKey(hKey);
521 }
522 }
523
524 /* Install the device */
525 if (!SetupDiInstallDevice(DeviceInfoSet,
526 DeviceInfoData))
527 {
528 return GetLastError();
529 }
530
531 /* Get the device description... */
532 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
533 DeviceInfoData,
534 SPDRP_DEVICEDESC,
535 NULL,
536 (LPBYTE)szDeviceDescription,
537 256 * sizeof(WCHAR),
538 NULL))
539 {
540 /* ... and use it to build a new friendly name */
541 swprintf(szFriendlyName,
542 L"%s (%s)",
543 szDeviceDescription,
544 szPortName);
545 }
546 else
547 {
548 /* ... or build a generic friendly name */
549 swprintf(szFriendlyName,
550 L"Parallel Port (%s)",
551 szPortName);
552 }
553
554 TRACE("Friendly name: %S\n", szFriendlyName);
555
556 /* Set the friendly name for the device */
557 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
558 DeviceInfoData,
559 SPDRP_FRIENDLYNAME,
560 (LPBYTE)szFriendlyName,
561 (wcslen(szFriendlyName) + 1) * sizeof(WCHAR));
562
563 return ERROR_SUCCESS;
564 }
565
566
567 VOID
568 InstallDeviceData(IN HDEVINFO DeviceInfoSet,
569 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
570 {
571 HKEY hKey = NULL;
572 HINF hInf = INVALID_HANDLE_VALUE;
573 SP_DRVINFO_DATA DriverInfoData;
574 PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
575 WCHAR InfSectionWithExt[256];
576 BYTE buffer[2048];
577 DWORD dwRequired;
578
579 TRACE("InstallDeviceData()\n");
580
581 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
582 DeviceInfoData,
583 DICS_FLAG_GLOBAL,
584 0,
585 DIREG_DRV,
586 NULL,
587 NULL);
588 if (hKey == NULL)
589 goto done;
590
591 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
592 if (!SetupDiGetSelectedDriverW(DeviceInfoSet,
593 DeviceInfoData,
594 &DriverInfoData))
595 {
596 goto done;
597 }
598
599 DriverInfoDetailData = (PSP_DRVINFO_DETAIL_DATA)buffer;
600 DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
601 if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet,
602 DeviceInfoData,
603 &DriverInfoData,
604 DriverInfoDetailData,
605 2048,
606 &dwRequired))
607 {
608 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
609 goto done;
610 }
611
612 TRACE("Inf file name: %S\n", DriverInfoDetailData->InfFileName);
613
614 hInf = SetupOpenInfFileW(DriverInfoDetailData->InfFileName,
615 NULL,
616 INF_STYLE_WIN4,
617 NULL);
618 if (hInf == INVALID_HANDLE_VALUE)
619 goto done;
620
621 TRACE("Section name: %S\n", DriverInfoDetailData->SectionName);
622
623 if (!SetupDiGetActualSectionToInstallW(hInf,
624 DriverInfoDetailData->SectionName,
625 InfSectionWithExt,
626 256,
627 NULL,
628 NULL))
629 goto done;
630
631 TRACE("InfSectionWithExt: %S\n", InfSectionWithExt);
632
633 SetupInstallFromInfSectionW(NULL,
634 hInf,
635 InfSectionWithExt,
636 SPINST_REGISTRY,
637 hKey,
638 NULL,
639 0,
640 NULL,
641 NULL,
642 NULL,
643 NULL);
644
645 TRACE("Done\n");
646
647 done:
648 if (hKey != NULL)
649 RegCloseKey(hKey);
650
651 if (hInf != INVALID_HANDLE_VALUE)
652 SetupCloseInfFile(hInf);
653 }
654
655
656
657 PORT_TYPE
658 GetPortType(IN HDEVINFO DeviceInfoSet,
659 IN PSP_DEVINFO_DATA DeviceInfoData)
660 {
661 HKEY hKey = NULL;
662 DWORD dwSize;
663 DWORD dwType = 0;
664 BYTE bData = 0;
665 PORT_TYPE PortType = UnknownPort;
666 LONG lError;
667
668 TRACE("GetPortType()\n");
669
670 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
671 DeviceInfoData,
672 DICS_FLAG_GLOBAL,
673 0,
674 DIREG_DRV,
675 NULL,
676 NULL);
677 if (hKey == NULL)
678 {
679 goto done;
680 }
681
682 dwSize = sizeof(BYTE);
683 lError = RegQueryValueExW(hKey,
684 L"PortSubClass",
685 NULL,
686 &dwType,
687 &bData,
688 &dwSize);
689
690 TRACE("lError: %ld\n", lError);
691 TRACE("dwSize: %lu\n", dwSize);
692 TRACE("dwType: %lu\n", dwType);
693
694 if (lError == ERROR_SUCCESS &&
695 dwSize == sizeof(BYTE) &&
696 dwType == REG_BINARY)
697 {
698 if (bData == 0)
699 PortType = ParallelPort;
700 else
701 PortType = SerialPort;
702 }
703
704 done:
705 if (hKey != NULL)
706 RegCloseKey(hKey);
707
708 TRACE("GetPortType() returns %u \n", PortType);
709
710 return PortType;
711 }
712
713
714 static DWORD
715 InstallPort(IN HDEVINFO DeviceInfoSet,
716 IN PSP_DEVINFO_DATA DeviceInfoData)
717 {
718 PORT_TYPE PortType;
719
720 InstallDeviceData(DeviceInfoSet, DeviceInfoData);
721
722 PortType = GetPortType(DeviceInfoSet, DeviceInfoData);
723 switch (PortType)
724 {
725 case ParallelPort:
726 return InstallParallelPort(DeviceInfoSet, DeviceInfoData);
727
728 case SerialPort:
729 return InstallSerialPort(DeviceInfoSet, DeviceInfoData);
730
731 default:
732 return ERROR_DI_DO_DEFAULT;
733 }
734 }
735
736
737 static DWORD
738 RemovePort(IN HDEVINFO DeviceInfoSet,
739 IN PSP_DEVINFO_DATA DeviceInfoData)
740 {
741 PORT_TYPE PortType;
742 HCOMDB hComDB = HCOMDB_INVALID_HANDLE_VALUE;
743 HKEY hKey;
744 LONG lError;
745 DWORD dwPortNumber;
746 DWORD dwPortNameSize;
747 WCHAR szPortName[8];
748
749 /* If we are removing a serial port ... */
750 PortType = GetPortType(DeviceInfoSet, DeviceInfoData);
751 if (PortType == SerialPort)
752 {
753 /* Open the port database */
754 if (ComDBOpen(&hComDB) == ERROR_SUCCESS)
755 {
756 /* Open the device key */
757 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
758 DeviceInfoData,
759 DICS_FLAG_GLOBAL,
760 0,
761 DIREG_DEV,
762 KEY_READ);
763 if (hKey != INVALID_HANDLE_VALUE)
764 {
765 /* Query the port name */
766 dwPortNameSize = sizeof(szPortName);
767 lError = RegQueryValueEx(hKey,
768 L"PortName",
769 NULL,
770 NULL,
771 (PBYTE)szPortName,
772 &dwPortNameSize);
773
774 /* Close the device key */
775 RegCloseKey(hKey);
776
777 /* If we got a valid port name ...*/
778 if (lError == ERROR_SUCCESS)
779 {
780 /* Get the port number */
781 dwPortNumber = _wtoi(szPortName + wcslen(pszCom));
782
783 /* Release the port */
784 ComDBReleasePort(hComDB, dwPortNumber);
785 }
786 }
787
788 /* Close the port database */
789 ComDBClose(hComDB);
790 }
791 }
792
793 /* Remove the device */
794 if (!SetupDiRemoveDevice(DeviceInfoSet, DeviceInfoData))
795 return GetLastError();
796
797 return ERROR_SUCCESS;
798 }
799
800
801 DWORD
802 WINAPI
803 PortsClassInstaller(IN DI_FUNCTION InstallFunction,
804 IN HDEVINFO DeviceInfoSet,
805 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
806 {
807 TRACE("PortsClassInstaller(%lu, %p, %p)\n",
808 InstallFunction, DeviceInfoSet, DeviceInfoData);
809
810 switch (InstallFunction)
811 {
812 case DIF_INSTALLDEVICE:
813 return InstallPort(DeviceInfoSet, DeviceInfoData);
814
815 case DIF_REMOVE:
816 return RemovePort(DeviceInfoSet, DeviceInfoData);
817
818 default:
819 TRACE("Install function %u ignored\n", InstallFunction);
820 return ERROR_DI_DO_DEFAULT;
821 }
822 }
823
824 /* EOF */