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