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