2 * Functions related to drivers. Original copyright notices below....
5 * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
6 * This program and the accompanying materials are licensed and made available under
7 * the terms and conditions of the BSD License that accompanies this distribution.
8 * The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php.
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 * Main code for the boot menu
19 * Copyright (c) 2006-2010 Christoph Pfisterer
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are
26 * * Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
29 * * Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the
34 * * Neither the name of Christoph Pfisterer nor the names of the
35 * contributors may be used to endorse or promote products derived
36 * from this software without specific prior written permission.
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 * Modifications copyright (c) 2012-2016 Roderick W. Smith
53 * Modifications distributed under the terms of the GNU General Public
54 * License (GPL) version 3 (GPLv3), or (at your option) any later version.
58 * This program is free software: you can redistribute it and/or modify
59 * it under the terms of the GNU General Public License as published by
60 * the Free Software Foundation, either version 3 of the License, or
61 * (at your option) any later version.
63 * This program is distributed in the hope that it will be useful,
64 * but WITHOUT ANY WARRANTY; without even the implied warranty of
65 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66 * GNU General Public License for more details.
68 * You should have received a copy of the GNU General Public License
69 * along with this program. If not, see <http://www.gnu.org/licenses/>.
72 #include "driver_support.h"
74 #include "mystrings.h"
76 #include "../include/refit_call_wrapper.h"
79 #define DRIVER_DIRS L"drivers,drivers_x64"
81 #define DRIVER_DIRS L"drivers,drivers_ia32"
82 #elif defined (EFIAARCH64)
83 #define DRIVER_DIRS L"drivers,drivers_aa64"
86 #ifdef __MAKEWITH_GNUEFI
87 // Following "global" constants are from EDK2's AutoGen.c....
88 EFI_GUID gEfiLoadedImageProtocolGuid
= { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
89 EFI_GUID gEfiDriverBindingProtocolGuid
= { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
90 EFI_GUID gEfiDriverConfiguration2ProtocolGuid
= { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
91 EFI_GUID gEfiDriverConfigurationProtocolGuid
= { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
92 EFI_GUID gEfiDriverDiagnosticsProtocolGuid
= { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
93 EFI_GUID gEfiDriverDiagnostics2ProtocolGuid
= { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
94 EFI_GUID gEfiComponentNameProtocolGuid
= { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
95 EFI_GUID gEfiComponentName2ProtocolGuid
= { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
96 EFI_GUID gEfiDevicePathProtocolGuid
= { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
97 EFI_GUID gEfiDiskIoProtocolGuid
= { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
98 EFI_GUID gEfiBlockIoProtocolGuid
= { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
99 EFI_GUID gEfiSimpleFileSystemProtocolGuid
= { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
101 struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
;
102 struct EFI_FILE_PROTOCOL
;
106 (EFIAPI
*EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME
)(
107 IN
struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
108 OUT
struct EFI_FILE_PROTOCOL
**Root
111 typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
{
113 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume
;
114 } EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
;
116 typedef struct _EFI_FILE_PROTOCOL
{
119 EFI_FILE_CLOSE Close
;
120 EFI_FILE_DELETE Delete
;
122 EFI_FILE_WRITE Write
;
123 EFI_FILE_GET_POSITION GetPosition
;
124 EFI_FILE_SET_POSITION SetPosition
;
125 EFI_FILE_GET_INFO GetInfo
;
126 EFI_FILE_SET_INFO SetInfo
;
127 EFI_FILE_FLUSH Flush
;
130 typedef struct _EFI_BLOCK_IO_PROTOCOL
{
132 EFI_BLOCK_IO_MEDIA
*Media
;
133 EFI_BLOCK_RESET Reset
;
134 EFI_BLOCK_READ ReadBlocks
;
135 EFI_BLOCK_WRITE WriteBlocks
;
136 EFI_BLOCK_FLUSH FlushBlocks
;
137 } EFI_BLOCK_IO_PROTOCOL
;
140 /* LibScanHandleDatabase() is used by rEFInd's driver-loading code (inherited
141 * from rEFIt), but has not been implemented in GNU-EFI and seems to have been
142 * dropped from current versions of the Tianocore library. This function was
143 * taken from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec,
144 * The original files are copyright 2006-2011 Intel and BSD-licensed. Minor
145 * modifications by Roderick Smith are GPLv3.
148 LibScanHandleDatabase (EFI_HANDLE DriverBindingHandle
, OPTIONAL
149 UINT32
*DriverBindingHandleIndex
, OPTIONAL
150 EFI_HANDLE ControllerHandle
, OPTIONAL
151 UINT32
*ControllerHandleIndex
, OPTIONAL
153 EFI_HANDLE
**HandleBuffer
,
154 UINT32
**HandleType
) {
157 EFI_GUID
**ProtocolGuidArray
;
160 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
164 BOOLEAN DriverBindingHandleIndexValid
;
166 DriverBindingHandleIndexValid
= FALSE
;
167 if (DriverBindingHandleIndex
!= NULL
) {
168 *DriverBindingHandleIndex
= 0xffffffff;
171 if (ControllerHandleIndex
!= NULL
) {
172 *ControllerHandleIndex
= 0xffffffff;
176 *HandleBuffer
= NULL
;
180 // Retrieve the list of all handles from the handle database
183 Status
= refit_call5_wrapper(BS
->LocateHandleBuffer
,
190 if (EFI_ERROR (Status
)) {
194 *HandleType
= AllocatePool (*HandleCount
* sizeof (UINT32
));
195 if (*HandleType
== NULL
) {
199 for (HandleIndex
= 0; HandleIndex
< *HandleCount
; HandleIndex
++) {
201 // Assume that the handle type is unknown
203 (*HandleType
)[HandleIndex
] = EFI_HANDLE_TYPE_UNKNOWN
;
205 if (DriverBindingHandle
!= NULL
&&
206 DriverBindingHandleIndex
!= NULL
&&
207 (*HandleBuffer
)[HandleIndex
] == DriverBindingHandle
209 *DriverBindingHandleIndex
= (UINT32
) HandleIndex
;
210 DriverBindingHandleIndexValid
= TRUE
;
213 if (ControllerHandle
!= NULL
&& ControllerHandleIndex
!= NULL
&& (*HandleBuffer
)[HandleIndex
] == ControllerHandle
) {
214 *ControllerHandleIndex
= (UINT32
) HandleIndex
;
219 for (HandleIndex
= 0; HandleIndex
< *HandleCount
; HandleIndex
++) {
221 // Retrieve the list of all the protocols on each handle
224 Status
= refit_call3_wrapper(BS
->ProtocolsPerHandle
,
225 (*HandleBuffer
)[HandleIndex
],
229 if (!EFI_ERROR (Status
)) {
231 for (ProtocolIndex
= 0; ProtocolIndex
< ArrayCount
; ProtocolIndex
++) {
233 if (CompareGuid (ProtocolGuidArray
[ProtocolIndex
], &gEfiLoadedImageProtocolGuid
) == 0) {
234 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_IMAGE_HANDLE
;
237 if (CompareGuid (ProtocolGuidArray
[ProtocolIndex
], &gEfiDriverBindingProtocolGuid
) == 0) {
238 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE
;
241 if (CompareGuid (ProtocolGuidArray
[ProtocolIndex
], &gEfiDriverConfigurationProtocolGuid
) == 0) {
242 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE
;
245 if (CompareGuid (ProtocolGuidArray
[ProtocolIndex
], &gEfiDriverDiagnosticsProtocolGuid
) == 0) {
246 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE
;
249 if (CompareGuid (ProtocolGuidArray
[ProtocolIndex
], &gEfiComponentNameProtocolGuid
) == 0) {
250 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE
;
253 if (CompareGuid (ProtocolGuidArray
[ProtocolIndex
], &gEfiDevicePathProtocolGuid
) == 0) {
254 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_DEVICE_HANDLE
;
257 // Retrieve the list of agents that have opened each protocol
260 Status
= refit_call4_wrapper(BS
->OpenProtocolInformation
,
261 (*HandleBuffer
)[HandleIndex
],
262 ProtocolGuidArray
[ProtocolIndex
],
266 if (!EFI_ERROR (Status
)) {
268 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
269 if (DriverBindingHandle
!= NULL
&& OpenInfo
[OpenInfoIndex
].AgentHandle
== DriverBindingHandle
) {
270 if ((OpenInfo
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) == EFI_OPEN_PROTOCOL_BY_DRIVER
) {
272 // Mark the device handle as being managed by the driver specified by DriverBindingHandle
274 (*HandleType
)[HandleIndex
] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE
| EFI_HANDLE_TYPE_CONTROLLER_HANDLE
);
276 // Mark the DriverBindingHandle as being a driver that is managing at least one controller
278 if (DriverBindingHandleIndexValid
) {
279 (*HandleType
)[*DriverBindingHandleIndex
] |= EFI_HANDLE_TYPE_DEVICE_DRIVER
;
284 OpenInfo
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
285 ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
288 // Mark the DriverBindingHandle as being a driver that is managing at least one child controller
290 if (DriverBindingHandleIndexValid
) {
291 (*HandleType
)[*DriverBindingHandleIndex
] |= EFI_HANDLE_TYPE_BUS_DRIVER
;
295 if (ControllerHandle
!= NULL
&& (*HandleBuffer
)[HandleIndex
] == ControllerHandle
) {
297 OpenInfo
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
298 ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
300 for (ChildIndex
= 0; ChildIndex
< *HandleCount
; ChildIndex
++) {
301 if ((*HandleBuffer
)[ChildIndex
] == OpenInfo
[OpenInfoIndex
].ControllerHandle
) {
302 (*HandleType
)[ChildIndex
] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE
| EFI_HANDLE_TYPE_CHILD_HANDLE
);
309 if (DriverBindingHandle
== NULL
&& OpenInfo
[OpenInfoIndex
].ControllerHandle
== ControllerHandle
) {
310 if ((OpenInfo
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) == EFI_OPEN_PROTOCOL_BY_DRIVER
) {
311 for (ChildIndex
= 0; ChildIndex
< *HandleCount
; ChildIndex
++) {
312 if ((*HandleBuffer
)[ChildIndex
] == OpenInfo
[OpenInfoIndex
].AgentHandle
) {
313 (*HandleType
)[ChildIndex
] |= EFI_HANDLE_TYPE_DEVICE_DRIVER
;
319 OpenInfo
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
320 ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
322 (*HandleType
)[HandleIndex
] |= EFI_HANDLE_TYPE_PARENT_HANDLE
;
323 for (ChildIndex
= 0; ChildIndex
< *HandleCount
; ChildIndex
++) {
324 if ((*HandleBuffer
)[ChildIndex
] == OpenInfo
[OpenInfoIndex
].AgentHandle
) {
325 (*HandleType
)[ChildIndex
] |= EFI_HANDLE_TYPE_BUS_DRIVER
;
332 MyFreePool (OpenInfo
);
336 MyFreePool (ProtocolGuidArray
);
343 MyFreePool (*HandleType
);
344 MyFreePool (*HandleBuffer
);
347 *HandleBuffer
= NULL
;
351 } /* EFI_STATUS LibScanHandleDatabase() */
353 #ifdef __MAKEWITH_GNUEFI
354 /* Modified from EDK2 function of a similar name; original copyright Intel &
355 * BSD-licensed; modifications by Roderick Smith are GPLv3. */
356 EFI_STATUS
ConnectAllDriversToAllControllers(VOID
)
359 UINTN AllHandleCount
;
360 EFI_HANDLE
*AllHandleBuffer
;
363 EFI_HANDLE
*HandleBuffer
;
369 Status
= LibLocateHandle(AllHandles
,
374 if (EFI_ERROR(Status
))
377 for (Index
= 0; Index
< AllHandleCount
; Index
++) {
379 // Scan the handle database
381 Status
= LibScanHandleDatabase(NULL
,
383 AllHandleBuffer
[Index
],
388 if (EFI_ERROR (Status
))
392 if (HandleType
[Index
] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE
)
394 if (HandleType
[Index
] & EFI_HANDLE_TYPE_IMAGE_HANDLE
)
399 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
400 if (HandleType
[HandleIndex
] & EFI_HANDLE_TYPE_PARENT_HANDLE
)
405 if (HandleType
[Index
] & EFI_HANDLE_TYPE_DEVICE_HANDLE
) {
406 Status
= refit_call4_wrapper(BS
->ConnectController
,
407 AllHandleBuffer
[Index
],
415 MyFreePool (HandleBuffer
);
416 MyFreePool (HandleType
);
420 MyFreePool (AllHandleBuffer
);
422 } /* EFI_STATUS ConnectAllDriversToAllControllers() */
424 EFI_STATUS
ConnectAllDriversToAllControllers(VOID
) {
425 BdsLibConnectAllDriversToAllControllers();
431 * ConnectFilesystemDriver() is modified from DisconnectInvalidDiskIoChildDrivers()
432 * in Clover (https://sourceforge.net/projects/cloverefiboot/), which is derived
433 * from rEFIt. The refit/main.c file from which this function was taken continues
434 * to bear rEFIt's original copyright/licence notice (BSD); modifications by
435 * Roderick Smith (2016) are GPLv3.
438 * Some UEFI's (like HPQ EFI from HP notebooks) have DiskIo protocols
439 * opened BY_DRIVER (by Partition driver in HP case) even when no file system
440 * is produced from this DiskIo. This then blocks our FS drivers from connecting
441 * and producing file systems.
442 * To fix it: we will disconnect drivers that connected to DiskIo BY_DRIVER
443 * if this is partition volume and if those drivers did not produce file system,
444 * then try to connect every unconnected device to the driver whose handle is
445 * passed to us. This should have no effect on systems unaffected by this EFI
448 VOID
ConnectFilesystemDriver(EFI_HANDLE DriverHandle
) {
450 UINTN HandleCount
= 0;
453 EFI_HANDLE
*Handles
= NULL
;
454 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
455 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
456 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
458 EFI_HANDLE DriverHandleList
[2];
461 // Get all DiskIo handles
463 Status
= refit_call5_wrapper(gBS
->LocateHandleBuffer
,
465 &gEfiDiskIoProtocolGuid
,
469 if (EFI_ERROR(Status
) || HandleCount
== 0)
473 // Check every DiskIo handle
475 for (Index
= 0; Index
< HandleCount
; Index
++) {
477 // If this is not partition - skip it.
478 // This is then whole disk and DiskIo
479 // should be opened here BY_DRIVER by Partition driver
480 // to produce partition volumes.
482 Status
= refit_call3_wrapper(gBS
->HandleProtocol
,
484 &gEfiBlockIoProtocolGuid
,
486 if (EFI_ERROR (Status
))
488 if (BlockIo
->Media
== NULL
|| !BlockIo
->Media
->LogicalPartition
)
492 // If SimpleFileSystem is already produced - skip it, this is ok
494 Status
= refit_call3_wrapper(gBS
->HandleProtocol
,
496 &gEfiSimpleFileSystemProtocolGuid
,
498 if (Status
== EFI_SUCCESS
)
502 // If no SimpleFileSystem on this handle but DiskIo is opened BY_DRIVER
503 // then disconnect this connection and try to connect our driver to it
505 Status
= refit_call4_wrapper(gBS
->OpenProtocolInformation
,
507 &gEfiDiskIoProtocolGuid
,
510 if (EFI_ERROR (Status
))
512 DriverHandleList
[1] = NULL
;
513 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
514 if ((OpenInfo
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) == EFI_OPEN_PROTOCOL_BY_DRIVER
) {
515 Status
= refit_call3_wrapper(gBS
->DisconnectController
,
517 OpenInfo
[OpenInfoIndex
].AgentHandle
,
519 if (!(EFI_ERROR(Status
))) {
520 DriverHandleList
[0] = DriverHandle
;
521 refit_call4_wrapper(gBS
->ConnectController
,
532 } // VOID ConnectFilesystemDriver()
534 // Scan a directory for drivers.
535 // Originally from rEFIt's main.c (BSD), but modified since then (GPLv3).
536 static UINTN
ScanDriverDir(IN CHAR16
*Path
)
539 REFIT_DIR_ITER DirIter
;
541 EFI_FILE_INFO
*DirEntry
;
542 CHAR16 FileName
[256];
544 CleanUpPathNameSlashes(Path
);
545 // look through contents of the directory
546 DirIterOpen(SelfRootDir
, Path
, &DirIter
);
547 while (DirIterNext(&DirIter
, 2, LOADER_MATCH_PATTERNS
, &DirEntry
)) {
548 if (DirEntry
->FileName
[0] == '.')
549 continue; // skip this
551 SPrint(FileName
, 255, L
"%s\\%s", Path
, DirEntry
->FileName
);
553 Status
= StartEFIImage(FileDevicePath(SelfLoadedImage
->DeviceHandle
, FileName
),
554 L
"", TYPE_EFI
, DirEntry
->FileName
, 0, NULL
, FALSE
, TRUE
);
556 Status
= DirIterClose(&DirIter
);
557 if ((Status
!= EFI_NOT_FOUND
) && (Status
!= EFI_INVALID_PARAMETER
)) {
558 SPrint(FileName
, 255, L
"while scanning the %s directory", Path
);
559 CheckError(Status
, FileName
);
562 } // static UINTN ScanDriverDir()
565 // Load all EFI drivers from rEFInd's "drivers" subdirectory and from the
566 // directories specified by the user in the "scan_driver_dirs" configuration
568 // Originally from rEFIt's main.c (BSD), but modified since then (GPLv3).
569 VOID
LoadDrivers(VOID
) {
570 CHAR16
*Directory
, *SelfDirectory
;
571 UINTN i
= 0, Length
, NumFound
= 0;
573 // load drivers from the subdirectories of rEFInd's home directory specified
574 // in the DRIVER_DIRS constant.
575 while ((Directory
= FindCommaDelimited(DRIVER_DIRS
, i
++)) != NULL
) {
576 SelfDirectory
= SelfDirPath
? StrDuplicate(SelfDirPath
) : NULL
;
577 CleanUpPathNameSlashes(SelfDirectory
);
578 MergeStrings(&SelfDirectory
, Directory
, L
'\\');
579 NumFound
+= ScanDriverDir(SelfDirectory
);
580 MyFreePool(Directory
);
581 MyFreePool(SelfDirectory
);
584 // Scan additional user-specified driver directories....
586 while ((Directory
= FindCommaDelimited(GlobalConfig
.DriverDirs
, i
++)) != NULL
) {
587 CleanUpPathNameSlashes(Directory
);
588 Length
= StrLen(Directory
);
590 NumFound
+= ScanDriverDir(Directory
);
592 MyFreePool(Directory
);
595 // connect all devices
597 ConnectAllDriversToAllControllers();
598 } /* VOID LoadDrivers() */