4502d5f2ca8809dc45aa5ed7293d52bb7c8529b3
[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
250 TRACE("InstallSerialPort(%p, %p)\n",
251 DeviceInfoSet, DeviceInfoData);
252
253 /* Open the com port database */
254 ComDBOpen(&hComDB);
255
256 dwPortNumber = GetSerialPortNumber(DeviceInfoSet,
257 DeviceInfoData);
258 if (dwPortNumber != 0)
259 {
260 swprintf(szPortName, L"COM%u", dwPortNumber);
261
262 ComDBClaimPort(hComDB,
263 dwPortNumber,
264 FALSE,
265 NULL);
266 }
267 else
268 {
269 wcscpy(szPortName, L"COMx");
270 }
271
272 /* Close the com port database */
273 if (hComDB != HCOMDB_INVALID_HANDLE_VALUE)
274 ComDBClose(hComDB);
275
276 /* Install the device */
277 if (!SetupDiInstallDevice(DeviceInfoSet,
278 DeviceInfoData))
279 {
280 return GetLastError();
281 }
282
283 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
284 DeviceInfoData,
285 SPDRP_DEVICEDESC,
286 NULL,
287 (LPBYTE)szDeviceDescription,
288 256 * sizeof(WCHAR),
289 NULL))
290 {
291 swprintf(szFriendlyName,
292 L"%s (%s)",
293 szDeviceDescription,
294 szPortName);
295 }
296 else
297 {
298 swprintf(szFriendlyName,
299 L"Serial Port (%s)",
300 szPortName);
301 }
302
303 /* Set the friendly name for the device */
304 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
305 DeviceInfoData,
306 SPDRP_FRIENDLYNAME,
307 (LPBYTE)szFriendlyName,
308 (wcslen(szFriendlyName) + 1) * sizeof(WCHAR));
309
310 return ERROR_SUCCESS;
311 }
312
313
314 static DWORD
315 InstallParallelPort(IN HDEVINFO DeviceInfoSet,
316 IN PSP_DEVINFO_DATA DeviceInfoData)
317 {
318 WCHAR szDeviceDescription[256];
319 WCHAR szFriendlyName[256];
320 WCHAR szPortName[5];
321 DWORD dwPortNumber;
322
323 TRACE("InstallParallelPort(%p, %p)\n",
324 DeviceInfoSet, DeviceInfoData);
325
326 dwPortNumber = GetParallelPortNumber(DeviceInfoSet,
327 DeviceInfoData);
328 if (dwPortNumber != 0)
329 {
330 swprintf(szPortName, L"LPT%u", dwPortNumber);
331 }
332 else
333 {
334 wcscpy(szPortName, L"LPTx");
335 }
336
337
338 /* Install the device */
339 if (!SetupDiInstallDevice(DeviceInfoSet,
340 DeviceInfoData))
341 {
342 return GetLastError();
343 }
344
345 if (SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
346 DeviceInfoData,
347 SPDRP_DEVICEDESC,
348 NULL,
349 (LPBYTE)szDeviceDescription,
350 256 * sizeof(WCHAR),
351 NULL))
352 {
353 swprintf(szFriendlyName,
354 L"%s (%s)",
355 szDeviceDescription,
356 szPortName);
357 }
358 else
359 {
360 swprintf(szFriendlyName,
361 L"Serial Port (%s)",
362 szPortName);
363 }
364
365 /* Set the friendly name for the device */
366 SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet,
367 DeviceInfoData,
368 SPDRP_FRIENDLYNAME,
369 (LPBYTE)szFriendlyName,
370 (wcslen(szFriendlyName) + 1) * sizeof(WCHAR));
371
372 return ERROR_SUCCESS;
373 }
374
375
376 VOID
377 InstallDeviceData(IN HDEVINFO DeviceInfoSet,
378 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
379 {
380 HKEY hKey = NULL;
381 HINF hInf = INVALID_HANDLE_VALUE;
382 SP_DRVINFO_DATA DriverInfoData;
383 PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
384 WCHAR InfSectionWithExt[256];
385 BYTE buffer[2048];
386 DWORD dwRequired;
387
388 TRACE("InstallDeviceData()\n");
389
390 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
391 DeviceInfoData,
392 DICS_FLAG_GLOBAL,
393 0,
394 DIREG_DRV,
395 NULL,
396 NULL);
397 if (hKey == NULL)
398 goto done;
399
400 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
401 if (!SetupDiGetSelectedDriverW(DeviceInfoSet,
402 DeviceInfoData,
403 &DriverInfoData))
404 {
405 goto done;
406 }
407
408 DriverInfoDetailData = (PSP_DRVINFO_DETAIL_DATA)buffer;
409 DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
410 if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet,
411 DeviceInfoData,
412 &DriverInfoData,
413 DriverInfoDetailData,
414 2048,
415 &dwRequired))
416 {
417 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
418 goto done;
419 }
420
421 TRACE("Inf file name: %S\n", DriverInfoDetailData->InfFileName);
422
423 hInf = SetupOpenInfFileW(DriverInfoDetailData->InfFileName,
424 NULL,
425 INF_STYLE_WIN4,
426 NULL);
427 if (hInf == INVALID_HANDLE_VALUE)
428 goto done;
429
430 TRACE("Section name: %S\n", DriverInfoDetailData->SectionName);
431
432 SetupDiGetActualSectionToInstallW(hInf,
433 DriverInfoDetailData->SectionName,
434 InfSectionWithExt,
435 256,
436 NULL,
437 NULL);
438
439 TRACE("InfSectionWithExt: %S\n", InfSectionWithExt);
440
441 SetupInstallFromInfSectionW(NULL,
442 hInf,
443 InfSectionWithExt,
444 SPINST_REGISTRY,
445 hKey,
446 NULL,
447 0,
448 NULL,
449 NULL,
450 NULL,
451 NULL);
452
453 TRACE("Done\n");
454
455 done:;
456 if (hKey != NULL)
457 RegCloseKey(hKey);
458
459 if (hInf != INVALID_HANDLE_VALUE)
460 SetupCloseInfFile(hInf);
461 }
462
463
464
465 PORT_TYPE
466 GetPortType(IN HDEVINFO DeviceInfoSet,
467 IN PSP_DEVINFO_DATA DeviceInfoData)
468 {
469 HKEY hKey = NULL;
470 DWORD dwSize;
471 DWORD dwType = 0;
472 BYTE bData = 0;
473 PORT_TYPE PortType = UnknownPort;
474 LONG lError;
475
476 TRACE("GetPortType()\n");
477
478 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet,
479 DeviceInfoData,
480 DICS_FLAG_GLOBAL,
481 0,
482 DIREG_DRV,
483 NULL,
484 NULL);
485 if (hKey == NULL)
486 {
487 goto done;
488 }
489
490 dwSize = sizeof(BYTE);
491 lError = RegQueryValueExW(hKey,
492 L"PortSubClass",
493 NULL,
494 &dwType,
495 &bData,
496 &dwSize);
497
498 TRACE("lError: %ld\n", lError);
499 TRACE("dwSize: %lu\n", dwSize);
500 TRACE("dwType: %lu\n", dwType);
501
502 if (lError == ERROR_SUCCESS &&
503 dwSize == sizeof(BYTE) &&
504 dwType == REG_BINARY)
505 {
506 if (bData == 0)
507 PortType = ParallelPort;
508 else
509 PortType = SerialPort;
510 }
511
512 done:;
513 if (hKey != NULL)
514 RegCloseKey(hKey);
515
516 TRACE("GetPortType() returns %u \n", PortType);
517
518 return PortType;
519 }
520
521
522 static DWORD
523 InstallPort(IN HDEVINFO DeviceInfoSet,
524 IN PSP_DEVINFO_DATA DeviceInfoData)
525 {
526 PORT_TYPE PortType;
527
528 InstallDeviceData(DeviceInfoSet, DeviceInfoData);
529
530 PortType = GetPortType(DeviceInfoSet, DeviceInfoData);
531 switch (PortType)
532 {
533 case ParallelPort:
534 return InstallParallelPort(DeviceInfoSet, DeviceInfoData);
535
536 case SerialPort:
537 return InstallSerialPort(DeviceInfoSet, DeviceInfoData);
538
539 default:
540 return ERROR_DI_DO_DEFAULT;
541 }
542 }
543
544
545 DWORD
546 WINAPI
547 PortsClassInstaller(IN DI_FUNCTION InstallFunction,
548 IN HDEVINFO DeviceInfoSet,
549 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
550 {
551 TRACE("PortsClassInstaller(%lu, %p, %p)\n",
552 InstallFunction, DeviceInfoSet, DeviceInfoData);
553
554 switch (InstallFunction)
555 {
556 case DIF_INSTALLDEVICE:
557 return InstallPort(DeviceInfoSet, DeviceInfoData);
558
559 default:
560 TRACE("Install function %u ignored\n", InstallFunction);
561 return ERROR_DI_DO_DEFAULT;
562 }
563 }
564
565 /* EOF */