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