xref: /reactos/dll/win32/msports/classinst.c (revision cc439606)
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 */
825