clean up MSA/SPD files.
[mirror_edk2.git] / EdkNt32Pkg / Dxe / WinNtThunk / Bus / WinNtBusDriver / WinNtBusDriver.c
1 /*+++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 WinNtBusDriver.c
15
16 Abstract:
17
18 This following section documents the envirnoment variables for the Win NT
19 build. These variables are used to define the (virtual) hardware
20 configuration of the NT environment
21
22 A ! can be used to seperate multiple instances in a variable. Each
23 instance represents a seperate hardware device.
24
25 EFI_WIN_NT_PHYSICAL_DISKS - maps to drives on your system
26 EFI_WIN_NT_VIRTUAL_DISKS - maps to a device emulated by a file
27 EFI_WIN_NT_FILE_SYSTEM - mouts a directory as a file system
28 EFI_WIN_NT_CONSOLE - make a logical comand line window (only one!)
29 EFI_WIN_NT_UGA - Builds UGA Windows of Width and Height
30 EFI_WIN_NT_SERIAL_PORT - maps physical serial ports
31
32 <F>ixed - Fixed disk like a hard drive.
33 <R>emovable - Removable media like a floppy or CD-ROM.
34 Read <O>nly - Write protected device.
35 Read <W>rite - Read write device.
36 <block count> - Decimal number of blocks a device supports.
37 <block size> - Decimal number of bytes per block.
38
39 NT envirnonment variable contents. '<' and '>' are not part of the variable,
40 they are just used to make this help more readable. There should be no
41 spaces between the ';'. Extra spaces will break the variable. A '!' is
42 used to seperate multiple devices in a variable.
43
44 EFI_WIN_NT_VIRTUAL_DISKS =
45 <F | R><O | W>;<block count>;<block size>[!...]
46
47 EFI_WIN_NT_PHYSICAL_DISKS =
48 <drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
49
50 Virtual Disks: These devices use a file to emulate a hard disk or removable
51 media device.
52
53 Thus a 20 MB emulated hard drive would look like:
54 EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512
55
56 A 1.44MB emulated floppy with a block size of 1024 would look like:
57 EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024
58
59 Physical Disks: These devices use NT to open a real device in your system
60
61 Thus a 120 MB floppy would look like:
62 EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512
63
64 Thus a standard CD-ROM floppy would look like:
65 EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048
66
67 EFI_WIN_NT_FILE_SYSTEM =
68 <directory path>[!...]
69
70 Mounting the two directories C:\FOO and C:\BAR would look like:
71 EFI_WIN_NT_FILE_SYSTEM=c:\foo!c:\bar
72
73 EFI_WIN_NT_CONSOLE =
74 <window title>
75
76 Declaring a text console window with the title "My EFI Console" woild look like:
77 EFI_WIN_NT_CONSOLE=My EFI Console
78
79 EFI_WIN_NT_UGA =
80 <width> <height>[!...]
81
82 Declaring a two UGA windows with resolutions of 800x600 and 1024x768 would look like:
83 Example : EFI_WIN_NT_UGA=800 600!1024 768
84
85 EFI_WIN_NT_SERIAL_PORT =
86 <port name>[!...]
87
88 Declaring two serial ports on COM1 and COM2 would look like:
89 Example : EFI_WIN_NT_SERIAL_PORT=COM1!COM2
90
91 EFI_WIN_NT_PASS_THROUGH =
92 <BaseAddress>;<Bus#>;<Device#>;<Function#>
93
94 Declaring a base address of 0xE0000000 (used for PCI Express devices)
95 and having NT32 talk to a device located at bus 0, device 1, function 0:
96 Example : EFI_WIN_NT_PASS_THROUGH=E000000;0;1;0
97
98 ---*/
99
100 #include "WinNtBusDriver.h"
101
102 extern EFI_GUID gWinNtBusDriverGuid;
103 //
104 // DriverBinding protocol global
105 //
106 EFI_DRIVER_BINDING_PROTOCOL gWinNtBusDriverBinding = {
107 WinNtBusDriverBindingSupported,
108 WinNtBusDriverBindingStart,
109 WinNtBusDriverBindingStop,
110 0xa,
111 NULL,
112 NULL
113 };
114
115 #define NT_PCD_ARRAY_SIZE (sizeof(mPcdEnvironment)/sizeof(NT_PCD_ENTRY))
116
117 //
118 // Table to map NT Environment variable to the GUID that should be in
119 // device path.
120 //
121 static NT_PCD_ENTRY mPcdEnvironment[] = {
122 PcdToken(PcdWinNtConsole), &gEfiWinNtConsoleGuid,
123 PcdToken(PcdWinNtUga), &gEfiWinNtUgaGuid,
124 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
125 PcdToken(PcdWinNtGop), &gEfiWinNtGopGuid,
126 #endif
127 PcdToken(PcdWinNtSerialPort), &gEfiWinNtSerialPortGuid,
128 PcdToken(PcdWinNtFileSystem), &gEfiWinNtFileSystemGuid,
129 PcdToken(PcdWinNtVirtualDisk), &gEfiWinNtVirtualDisksGuid,
130 PcdToken(PcdWinNtPhysicalDisk), &gEfiWinNtPhysicalDisksGuid,
131 PcdToken(PcdWinNtCpuModel), &gEfiWinNtCPUModelGuid,
132 PcdToken(PcdWinNtCpuSpeed), &gEfiWinNtCPUSpeedGuid,
133 PcdToken(PcdWinNtMemorySize), &gEfiWinNtMemoryGuid
134 };
135
136 VOID *
137 AllocateMemory (
138 IN UINTN Size
139 )
140 {
141 EFI_STATUS Status;
142 VOID *Buffer;
143
144 Status = gBS->AllocatePool (
145 EfiBootServicesData,
146 Size,
147 (VOID *)&Buffer
148 );
149 if (EFI_ERROR (Status)) {
150 ASSERT (FALSE);
151 return NULL;
152 }
153 return Buffer;
154 }
155
156
157 EFI_STATUS
158 EFIAPI
159 WinNtBusDriverBindingSupported (
160 IN EFI_DRIVER_BINDING_PROTOCOL *This,
161 IN EFI_HANDLE ControllerHandle,
162 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
163 )
164 /*++
165
166 Routine Description:
167
168 Arguments:
169
170 Returns:
171
172 None
173
174 --*/
175 // TODO: This - add argument and description to function comment
176 // TODO: ControllerHandle - add argument and description to function comment
177 // TODO: RemainingDevicePath - add argument and description to function comment
178 // TODO: EFI_UNSUPPORTED - add return value to function comment
179 // TODO: EFI_UNSUPPORTED - add return value to function comment
180 // TODO: EFI_SUCCESS - add return value to function comment
181 // TODO: EFI_SUCCESS - add return value to function comment
182 {
183 EFI_STATUS Status;
184 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
185 EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk;
186 UINTN Index;
187
188 //
189 // Check the contents of the first Device Path Node of RemainingDevicePath to make sure
190 // it is a legal Device Path Node for this bus driver's children.
191 //
192 if (RemainingDevicePath != NULL) {
193 if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH ||
194 RemainingDevicePath->SubType != HW_VENDOR_DP ||
195 DevicePathNodeLength(RemainingDevicePath) != sizeof(WIN_NT_VENDOR_DEVICE_PATH_NODE)) {
196 return EFI_UNSUPPORTED;
197 }
198
199 for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) {
200 if (CompareGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid, mPcdEnvironment[Index].DevicePathGuid)) {
201 break;
202 }
203 }
204
205 if (Index >= NT_PCD_ARRAY_SIZE) {
206 return EFI_UNSUPPORTED;
207 }
208 }
209
210 //
211 // Open the IO Abstraction(s) needed to perform the supported test
212 //
213 Status = gBS->OpenProtocol (
214 ControllerHandle,
215 &gEfiDevicePathProtocolGuid,
216 &ParentDevicePath,
217 This->DriverBindingHandle,
218 ControllerHandle,
219 EFI_OPEN_PROTOCOL_BY_DRIVER
220 );
221 if (Status == EFI_ALREADY_STARTED) {
222 return EFI_SUCCESS;
223 }
224
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228
229 gBS->CloseProtocol (
230 ControllerHandle,
231 &gEfiDevicePathProtocolGuid,
232 This->DriverBindingHandle,
233 ControllerHandle
234 );
235
236 Status = gBS->OpenProtocol (
237 ControllerHandle,
238 &gEfiWinNtThunkProtocolGuid,
239 &WinNtThunk,
240 This->DriverBindingHandle,
241 ControllerHandle,
242 EFI_OPEN_PROTOCOL_BY_DRIVER
243 );
244 if (Status == EFI_ALREADY_STARTED) {
245 return EFI_SUCCESS;
246 }
247
248 if (EFI_ERROR (Status)) {
249 return Status;
250 }
251
252 //
253 // Since we call through WinNtThunk we need to make sure it's valid
254 //
255 Status = EFI_SUCCESS;
256 if (WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
257 Status = EFI_UNSUPPORTED;
258 }
259
260 //
261 // Close the I/O Abstraction(s) used to perform the supported test
262 //
263 gBS->CloseProtocol (
264 ControllerHandle,
265 &gEfiWinNtThunkProtocolGuid,
266 This->DriverBindingHandle,
267 ControllerHandle
268 );
269
270 return Status;
271 }
272
273 EFI_STATUS
274 EFIAPI
275 WinNtBusDriverBindingStart (
276 IN EFI_DRIVER_BINDING_PROTOCOL *This,
277 IN EFI_HANDLE ControllerHandle,
278 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
279 )
280 /*++
281
282 Routine Description:
283
284 Arguments:
285
286 Returns:
287
288 None
289
290 --*/
291 // TODO: This - add argument and description to function comment
292 // TODO: ControllerHandle - add argument and description to function comment
293 // TODO: RemainingDevicePath - add argument and description to function comment
294 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
295 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
296 // TODO: EFI_SUCCESS - add return value to function comment
297 {
298 EFI_STATUS Status;
299 EFI_STATUS InstallStatus;
300 EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk;
301 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
302 WIN_NT_BUS_DEVICE *WinNtBusDevice;
303 WIN_NT_IO_DEVICE *WinNtDevice;
304 UINTN Index;
305 CHAR16 *StartString;
306 CHAR16 *SubString;
307 UINT16 Count;
308 UINTN StringSize;
309 UINT16 ComponentName[MAX_NT_ENVIRNMENT_VARIABLE_LENGTH];
310 WIN_NT_VENDOR_DEVICE_PATH_NODE *Node;
311 BOOLEAN CreateDevice;
312 CHAR16 *TempStr;
313 CHAR16 *PcdTempStr;
314 UINTN TempStrSize;
315
316 Status = EFI_UNSUPPORTED;
317
318 //
319 // Grab the protocols we need
320 //
321 Status = gBS->OpenProtocol (
322 ControllerHandle,
323 &gEfiDevicePathProtocolGuid,
324 &ParentDevicePath,
325 This->DriverBindingHandle,
326 ControllerHandle,
327 EFI_OPEN_PROTOCOL_BY_DRIVER
328 );
329 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
330 return Status;
331 }
332
333 Status = gBS->OpenProtocol (
334 ControllerHandle,
335 &gEfiWinNtThunkProtocolGuid,
336 &WinNtThunk,
337 This->DriverBindingHandle,
338 ControllerHandle,
339 EFI_OPEN_PROTOCOL_BY_DRIVER
340 );
341 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
342 return Status;
343 }
344
345 if (Status != EFI_ALREADY_STARTED) {
346 Status = gBS->AllocatePool (
347 EfiBootServicesData,
348 sizeof (WIN_NT_BUS_DEVICE),
349 (VOID *) &WinNtBusDevice
350 );
351 if (EFI_ERROR (Status)) {
352 return Status;
353 }
354
355 WinNtBusDevice->Signature = WIN_NT_BUS_DEVICE_SIGNATURE;
356 WinNtBusDevice->ControllerNameTable = NULL;
357
358 AddUnicodeString (
359 "eng",
360 gWinNtBusDriverComponentName.SupportedLanguages,
361 &WinNtBusDevice->ControllerNameTable,
362 L"Windows Bus Controller"
363 );
364
365 Status = gBS->InstallMultipleProtocolInterfaces (
366 &ControllerHandle,
367 &gWinNtBusDriverGuid,
368 WinNtBusDevice,
369 NULL
370 );
371 if (EFI_ERROR (Status)) {
372 FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable);
373 gBS->FreePool (WinNtBusDevice);
374 return Status;
375 }
376 }
377
378 //
379 // Loop on the Variable list. Parse each variable to produce a set of handles that
380 // represent virtual hardware devices.
381 //
382 InstallStatus = EFI_NOT_FOUND;
383 for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) {
384 PcdTempStr = (VOID *)LibPcdGetPtr (mPcdEnvironment[Index].Token);
385 ASSERT (PcdTempStr != NULL);
386
387 TempStrSize = StrLen (PcdTempStr);
388 TempStr = AllocateMemory ((TempStrSize * sizeof (CHAR16)) + 1);
389 StrCpy (TempStr, PcdTempStr);
390
391 StartString = TempStr;
392
393 //
394 // Parse the envirnment variable into sub strings using '!' as a delimator.
395 // Each substring needs it's own handle to be added to the system. This code
396 // does not understand the sub string. Thats the device drivers job.
397 //
398 Count = 0;
399 while (*StartString != '\0') {
400
401 //
402 // Find the end of the sub string
403 //
404 SubString = StartString;
405 while (*SubString != '\0' && *SubString != '!') {
406 SubString++;
407 }
408
409 if (*SubString == '!') {
410 //
411 // Replace token with '\0' to make sub strings. If this is the end
412 // of the string SubString will already point to NULL.
413 //
414 *SubString = '\0';
415 SubString++;
416 }
417
418 CreateDevice = TRUE;
419 if (RemainingDevicePath != NULL) {
420 CreateDevice = FALSE;
421 Node = (WIN_NT_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath;
422 if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH &&
423 Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP &&
424 DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)
425 ) {
426 if (CompareGuid (&Node->VendorDevicePath.Guid, mPcdEnvironment[Index].DevicePathGuid) &&
427 Node->Instance == Count
428 ) {
429 CreateDevice = TRUE;
430 }
431 }
432 }
433
434 if (CreateDevice) {
435
436 //
437 // Allocate instance structure, and fill in parent information.
438 //
439 WinNtDevice = AllocateMemory (sizeof (WIN_NT_IO_DEVICE));
440 if (WinNtDevice == NULL) {
441 return EFI_OUT_OF_RESOURCES;
442 }
443
444 WinNtDevice->Handle = NULL;
445 WinNtDevice->ControllerHandle = ControllerHandle;
446 WinNtDevice->ParentDevicePath = ParentDevicePath;
447
448 WinNtDevice->WinNtIo.WinNtThunk = WinNtThunk;
449
450 //
451 // Plus 2 to account for the NULL at the end of the Unicode string
452 //
453 StringSize = (UINTN) ((UINT8 *) SubString - (UINT8 *) StartString) + sizeof (CHAR16);
454 WinNtDevice->WinNtIo.EnvString = AllocateMemory (StringSize);
455 if (WinNtDevice->WinNtIo.EnvString != NULL) {
456 CopyMem (WinNtDevice->WinNtIo.EnvString, StartString, StringSize);
457 }
458
459 WinNtDevice->ControllerNameTable = NULL;
460
461 WinNtThunk->SPrintf (ComponentName, sizeof (ComponentName), L"%s", WinNtDevice->WinNtIo.EnvString);
462
463 WinNtDevice->DevicePath = WinNtBusCreateDevicePath (
464 ParentDevicePath,
465 mPcdEnvironment[Index].DevicePathGuid,
466 Count
467 );
468 if (WinNtDevice->DevicePath == NULL) {
469 gBS->FreePool (WinNtDevice);
470 return EFI_OUT_OF_RESOURCES;
471 }
472
473 AddUnicodeString (
474 "eng",
475 gWinNtBusDriverComponentName.SupportedLanguages,
476 &WinNtDevice->ControllerNameTable,
477 ComponentName
478 );
479
480 WinNtDevice->WinNtIo.TypeGuid = mPcdEnvironment[Index].DevicePathGuid;
481 WinNtDevice->WinNtIo.InstanceNumber = Count;
482
483 WinNtDevice->Signature = WIN_NT_IO_DEVICE_SIGNATURE;
484
485 Status = gBS->InstallMultipleProtocolInterfaces (
486 &WinNtDevice->Handle,
487 &gEfiDevicePathProtocolGuid,
488 WinNtDevice->DevicePath,
489 &gEfiWinNtIoProtocolGuid,
490 &WinNtDevice->WinNtIo,
491 NULL
492 );
493 if (EFI_ERROR (Status)) {
494 FreeUnicodeStringTable (WinNtDevice->ControllerNameTable);
495 gBS->FreePool (WinNtDevice);
496 } else {
497 //
498 // Open For Child Device
499 //
500 Status = gBS->OpenProtocol (
501 ControllerHandle,
502 &gEfiWinNtThunkProtocolGuid,
503 &WinNtThunk,
504 This->DriverBindingHandle,
505 WinNtDevice->Handle,
506 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
507 );
508 if (!EFI_ERROR (Status)) {
509 InstallStatus = EFI_SUCCESS;
510 }
511 }
512 }
513
514 //
515 // Parse Next sub string. This will point to '\0' if we are at the end.
516 //
517 Count++;
518 StartString = SubString;
519 }
520
521 gBS->FreePool (TempStr);
522 }
523
524 return EFI_SUCCESS;
525 }
526
527
528 EFI_STATUS
529 EFIAPI
530 WinNtBusDriverBindingStop (
531 IN EFI_DRIVER_BINDING_PROTOCOL *This,
532 IN EFI_HANDLE ControllerHandle,
533 IN UINTN NumberOfChildren,
534 IN EFI_HANDLE *ChildHandleBuffer
535 )
536 /*++
537
538 Routine Description:
539
540 Arguments:
541
542 Returns:
543
544 None
545
546 --*/
547 // TODO: This - add argument and description to function comment
548 // TODO: ControllerHandle - add argument and description to function comment
549 // TODO: NumberOfChildren - add argument and description to function comment
550 // TODO: ChildHandleBuffer - add argument and description to function comment
551 // TODO: EFI_SUCCESS - add return value to function comment
552 // TODO: EFI_DEVICE_ERROR - add return value to function comment
553 // TODO: EFI_SUCCESS - add return value to function comment
554 {
555 EFI_STATUS Status;
556 UINTN Index;
557 BOOLEAN AllChildrenStopped;
558 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
559 WIN_NT_BUS_DEVICE *WinNtBusDevice;
560 WIN_NT_IO_DEVICE *WinNtDevice;
561 EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk;
562
563 //
564 // Complete all outstanding transactions to Controller.
565 // Don't allow any new transaction to Controller to be started.
566 //
567
568 if (NumberOfChildren == 0) {
569 //
570 // Close the bus driver
571 //
572 Status = gBS->OpenProtocol (
573 ControllerHandle,
574 &gWinNtBusDriverGuid,
575 &WinNtBusDevice,
576 This->DriverBindingHandle,
577 ControllerHandle,
578 EFI_OPEN_PROTOCOL_GET_PROTOCOL
579 );
580 if (EFI_ERROR (Status)) {
581 return Status;
582 }
583
584 gBS->UninstallMultipleProtocolInterfaces (
585 ControllerHandle,
586 &gWinNtBusDriverGuid,
587 WinNtBusDevice,
588 NULL
589 );
590
591 FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable);
592
593 gBS->FreePool (WinNtBusDevice);
594
595 gBS->CloseProtocol (
596 ControllerHandle,
597 &gEfiWinNtThunkProtocolGuid,
598 This->DriverBindingHandle,
599 ControllerHandle
600 );
601
602 gBS->CloseProtocol (
603 ControllerHandle,
604 &gEfiDevicePathProtocolGuid,
605 This->DriverBindingHandle,
606 ControllerHandle
607 );
608 return EFI_SUCCESS;
609 }
610
611 AllChildrenStopped = TRUE;
612
613 for (Index = 0; Index < NumberOfChildren; Index++) {
614
615 Status = gBS->OpenProtocol (
616 ChildHandleBuffer[Index],
617 &gEfiWinNtIoProtocolGuid,
618 &WinNtIo,
619 This->DriverBindingHandle,
620 ControllerHandle,
621 EFI_OPEN_PROTOCOL_GET_PROTOCOL
622 );
623 if (!EFI_ERROR (Status)) {
624
625 WinNtDevice = WIN_NT_IO_DEVICE_FROM_THIS (WinNtIo);
626
627 Status = gBS->CloseProtocol (
628 ControllerHandle,
629 &gEfiWinNtThunkProtocolGuid,
630 This->DriverBindingHandle,
631 WinNtDevice->Handle
632 );
633
634 Status = gBS->UninstallMultipleProtocolInterfaces (
635 WinNtDevice->Handle,
636 &gEfiDevicePathProtocolGuid,
637 WinNtDevice->DevicePath,
638 &gEfiWinNtIoProtocolGuid,
639 &WinNtDevice->WinNtIo,
640 NULL
641 );
642
643 if (EFI_ERROR (Status)) {
644 gBS->OpenProtocol (
645 ControllerHandle,
646 &gEfiWinNtThunkProtocolGuid,
647 (VOID **) &WinNtThunk,
648 This->DriverBindingHandle,
649 WinNtDevice->Handle,
650 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
651 );
652 } else {
653 //
654 // Close the child handle
655 //
656 FreeUnicodeStringTable (WinNtDevice->ControllerNameTable);
657 gBS->FreePool (WinNtDevice);
658 }
659 }
660
661 if (EFI_ERROR (Status)) {
662 AllChildrenStopped = FALSE;
663 }
664 }
665
666 if (!AllChildrenStopped) {
667 return EFI_DEVICE_ERROR;
668 }
669
670 return EFI_SUCCESS;
671 }
672
673 EFI_DEVICE_PATH_PROTOCOL *
674 WinNtBusCreateDevicePath (
675 IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath,
676 IN EFI_GUID *Guid,
677 IN UINT16 InstanceNumber
678 )
679 /*++
680
681 Routine Description:
682 Create a device path node using Guid and InstanceNumber and append it to
683 the passed in RootDevicePath
684
685 Arguments:
686 RootDevicePath - Root of the device path to return.
687
688 Guid - GUID to use in vendor device path node.
689
690 InstanceNumber - Instance number to use in the vendor device path. This
691 argument is needed to make sure each device path is unique.
692
693 Returns:
694
695 EFI_DEVICE_PATH_PROTOCOL
696
697 --*/
698 {
699 WIN_NT_VENDOR_DEVICE_PATH_NODE DevicePath;
700
701 DevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH;
702 DevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP;
703 SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE));
704
705 //
706 // The GUID defines the Class
707 //
708 CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID));
709
710 //
711 // Add an instance number so we can make sure there are no Device Path
712 // duplication.
713 //
714 DevicePath.Instance = InstanceNumber;
715
716 return AppendDevicePathNode (
717 RootDevicePath,
718 (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath
719 );
720 }