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