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