Dynamic device matching using driver candidate lists5630076Abstract A method and mechanism for automatically correlating a device to its appropriate driver within a computer system utilizing candidate matching. A device tree indicating devices coupled to a computer system is available from an operating system. Within the device tree are device nodes which specify a particular device's name (device name) and a property which indicates compatible device names (compatible names) to the particular device. Drivers for devices can be located in RAM, ROM, or in another storage media (such as disk drive). Drivers can include a data field indicating a driver name indicative of a corresponding device with which they operate. For a particular device, the system constructs a candidate list of drivers by comparing (1) the device name and (2) the compatible names from the device tree against all the driver names of data fields of all known drivers. The candidate list is sorted so that matches by device name and proper version number are higher priority. The system then sequentially attempts installation of the drivers from the candidate list to the particular device (based on priority order) to determine the appropriate driver (e.g., probing the device using diagnostic operations). Drivers are skipped that cause an error or that do not properly configure the device. The process can be repeated for all devices in the computer system. The process is dynamic in that it is operable on boot up and upon any system change that allows more drives to be recognized. Claims What is claimed is: Description A portion of the disclosure of this patent document contains material which is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or the patent disclosure, as it appears in the Patent and Trademark Office patent file or records, but otherwise reserves all copyright rights whatsoever. Copyright Apple Computer, Inc.
______________________________________
struct DriverDescription {
OSType driverDescSignature;
DriverDescVersion driverDescVersion;
DriverType driverType;
DriverOSRuntime driverOSRuntimeInfo;
DriverOSService driverServices
};
typedef
struct DriverDescription
DriverDescription;
typedef
struct DriverDescription
*DriverDescriptionPtr;
enum {
kTheDescriptionSignature = `mtej`
/*first long of
DriverDescription*/
};
typedef UInt32 DriverDescVersion;
enum {
kInitialDriverDescriptor = 0 /*Version 1 of
DriverDescription*/
};
Field descriptions:
driverDescSignature
Signature of this DriverDescription structure;
currently `mtej`.
driverDescVersion
Version of this Driver Description structure, used to
distinguish different versions of DriverDescription
that have the same driverDescSignature.
driverType
Structure that contains driver name and version.
driverOSRuntimeInfo
Structure that contains driver runtime information,
which determines how a driver is handled when Mac
OS finds it. This structure also provides the driver's
name to Mac OS and specifies the driver's ability to
support concurrent requests.
driverServices
Structure used to declare the driver's supported
programming interfaces.
______________________________________
Driver Type Structure The DriverType structure contains the driver name 80c and version information about a driver, which is used by the present invention to match the driver to a specific device. A driver type structure is shown below:
______________________________________
struct DriverType {
Str31 nameInfoStr;
NumVersion version;
typedef UInt32
DeviceTypeMember;
typedef struct
DriverType DriverType;
typedef struct
DriverType *DriverTypePtr;
Field descriptions:
nameInfoStr
Name used to identify the driver and distinguish
between various versions of the driver when an
expert is searching for drivers. This string of type
Str31 is used to match the PCI name property in
the Name Registry.
version Version resource used to obtain the newest driver
when several identically-named drivers (that is,
drivers with the same value of nameInfoStr) are
available on disk.
______________________________________
Driver Runtime Structure The DriverOSRuntime structure contains information that controls how the driver is used at run time as shown below:
______________________________________
struct DriverOSRuntime {
RuntimeOptions driverRuntime;
Str31 driverName;
UInt32 driverDescReserved[8];
};
typedef
OptionBits
RuntimeOptions;
typedef
struct DriverOSRuntime
DriverOSRuntime;
typedef struct DriverOSRuntime *DriverOSRuntimePtr;
enum { /*DriverOSRuntime bit*/
/*constants*/
kdriverIsLoadedUponDiscovery
= 1,/*auto-load driver when
discovered*/
kdriverIsOpenedUponLoad
= 2,/*auto-open driver when
it is loaded*/
kdriverIsUnderExpertControl
= 4,/*I/O expert handles
loads and opens*/
kdriverIsConcurrent
= 8,/*supports concurrent
requests*/
kdriverQueuesIOPB = 0x10 /*Device Manager 90
does not queue IOPB*/
};
Field descriptions
driverRuntime
Options used to determine runtime behavior of
the driver. The bits in this field have these
meanings:
Bit Meaning
0 system loads driver when driver is
discovered
1 system opens driver when driver is loaded
2 device family expert handles driver loads
and opens
3 driver is capable of handling concurrent
requests
4 the Device Manager 90 does not queue the
IOPB to the DCE request before calling the
driver.
driverName Driver name used by Mac OS if driver type
is ndrv. Mac OS copies this name to the
name field of the DCE. This field is unused
for other driver types.
driverDescReserved
Reserved for future use.
______________________________________
Driver Services Structure The DriverOSService structure describes the services supported by the driver that are available to applications and other software. Each device family has a particular set of required and supported services. A driver may support more than one set of services. In such cases, nServices should be set to indicate the number of different sets of services that the driver supports, see below:
______________________________________
struct DriverOSService {
ServiceCount nServices;
DriverServiceInfo service[1]
};
typedef UInt32 ServiceCount;
typedef struct DriverOSService DriverOSService;
typedef struct DriverOSService *DriverOSServicePtr;
Field descriptions
nServices
The number of services supported by this driver. This
field is used to determine the size of the service array
that follows.
service
An array of DriverServiceInfo structures that specifies
the supported programming interface sets.
______________________________________
Driver Services Information Structure The DriverServiceInfo structure describes the category, type, and version of a driver's programming interface services.
______________________________________
struct DriverServiceInfo {
OsType serviceCategory;
OST,vpe serviceType;
NumVersion serviceVersion;
};
typedef
struct DriverServiceInfo
DriverServiceInfo;
typedef
struct DriverServiceInfo
*DriverServiceInfoPtr;
enum { /*used in*/
/*serviceCategory*/
kServiceCategoryDisplay = `disp`,
/*display*/
kServiceCategoryopentransport = `otan`,
/*open transport*/
kServiceCategorvblockstorage = `blok`,
/*block storage*/
kServiceCategorySCSISim = `scsi`,
/*SCSI SIM*/
kServiceCategoryndrvdriver = `ndrv`
/*generic*/
};
Field descriptions:
serviceCategory Specifies driver support services for given device
family. The following device families are
currently defined:
Name Supports services defined for:
`blok` block drivers family
`disp` video display family
`ndrv` gneric native driver devices
`otan` Open Transport
`scsi` SCSI interface module
serviceType
Subcategory (meaningful only in a given service
category).
serviceVersion
Version resource (`vers`) used to specify the
version of a set of services. It lets interfaces be
modified over time.
______________________________________
DoDriverIO Entry Point Genetic `ndrv` drivers must provide a single code entry point DoDriverIO, which responds to Open, Close, Read, Write, Control, Status, KillIO, Initialize, Finalize, Replace, and Superseded commands.
______________________________________
OSErr DoDriverIO
(AddressSpaceID
spaceID
IOCommandID ID,
IOCommandContents
contents,
IOCommandCode code,
IOCommandKind kind);
typedef KernelID AddressSpaceID;
spaceID
The address space containing the buffer to be prepared.
Mac OS 7.5 provides only one address space, so this
field must be specified as kCurrentAddressSpaceID.
ID CommandID
contents
An IOCommandContents I/O parameter block. Use
the InitializationInfo union member when calling to
initialize the driver, FinalizationInfo when removing
the driver, DriverReplaceInfo when replacing,
DriverSupersededInfo when superseding, and
ParmBlkPtr for all other I/O actions.
code Selector used to determine I/O actions.
kind Options used to determine how I/O actions are
performed. The bits in this field have these meanings:
Bit Meaning
0 synchronous I/O
1 asynchronous I/O
2 immediate I/O
______________________________________
DoDriverIO Parameter Data Structures The data types and structures that the DoDriverIO entry point uses have the following declarations:
______________________________________
typedef
UInt32 IOCommandID;
enum {
kInvalidID = 0
};
union IOCommandContents {
/* Contents are command*/
/* specific*/
ParmBlkPtr pb;
DriverInitInfoPtr
initialInfo;
DriverFinalInfoPtr
finalInfo;
DriverReplaceInf oPtr
replaceInf o;
DriverSupersededInfoPtr
supersededInfo;
};
typedef union IOCommandContents IOCommandContents;
typedef UInt3 2 IOCommandCode;
enum{ /*`ndrv` driver services*/
kOpenCommand, /*open command*/
kCloseCommand, /*close command*/
kReadCommand, /*read command*/
kWriteCommand, /*write command*/
kControlCommand, /*control command*/
kStatusCommand, /*status command*/
kKillIOCommand, /*kill I/O command*/
kInitializeCommand,
/*initialize command*/
kFinalizeCommand,
/*finalize command*/
kReplaceCommand, /*replace driver command*/
kSupersededCommand
/*driver superseded command*/
};
typedef UInt32 IOCommandKind;
enum{
kSynchronousIOCommandKind = 1,
kAsynchronousIOCommandKind = 2,
kImmediateIOCommandKind = 4
};
struct DriverInitInfo {
DriverRefNum
refNum;
RegEntryID deviceEntry;
};
struct DriverFinalInfo {
DriverRefNum
refNum;
RegEntryID deviceEntry;
};
typedef
struct DriverInit-
DriverInitInfo,
*DriverInitInfo-
Info Ptr;
typedef
struct DriverInit-
DriverReplaceInfo,
Info *DriverReplaceInfoPtr;
typedef
struct Driver- DriverFinalInfo,
FinalInfo *DriverFinalInfoPtr;
typedef
struct Driver- DriverSupersededInfo,
FinalInfo *DriverSupersededInfoPtr;
struct InitializationInfo {
refNum refNum;
RegEntryID deviceEntry;
};
struct FinalizationInfo {
refNum refNum;
RegEntryID deviceEntry;
};
______________________________________
Getting Command Information Any command in progress that the Device Manager 90 has sent to a native driver can be examined using GetIOCommandInfo. GetIOCommandInfo
______________________________________
OSErr Get- (IOCommandID theID,
IOCommandInfo
IOCommandContents
*theContents,
IOCommandCode *theCommand,
IOCommandKind *theKind);
theID Command ID
theContents
Pointer to the IOPB or Initialize/Finalize
contents
theCommand Command code
theKind Command kind (synchronous, asynchronous,
or immediate)
GetIOCommandInfo returns information about an active native
driver I/O command. It will not work after a driver has
completed a request.
typedef
struct InitializationInfo
InitializationInfo;
typedef
struct InitializationInfo
*InitializationInfoPtr;
typedef
struct FinalizationInfo
FinalizationInfo;
typedef
struct FinalizationInfo
*FinalizationInfoPtr;
______________________________________
Responding to Device Manager 90 Requests Native drivers 80 respond to Device Manager 90 requests by handling a single call, DoDriverIO. Native drivers 80 must also keep track of I/O permissions for each instance of multiple open actions and return error cedes if permissions are violated. The DoDriverIO call interface is described in the above discussion. The following sections discuss some of the internal procedures a driver 80 uses to service DoDriverIO requests. Initialization and Finalization Routines The Device Manager 90 sends Initialize and Finalize commands to a native driver as its first and last commands. The Initialize command gives the driver startup information and the Finalize command informs the driver that the system would like to unload it. Open and Close actions are separate from initialization and finalization rather than using Open and Close calls as the initialization and finalization mechanism. A typical framework for a generic driver handler for Device Manager 90 finalization and CFM initialization and termination commands is shown below:
______________________________________
refNum MyReferenceNumber;
RegEntryID
MyDeviceID;
OSErr DoInitializeCommand
(refNum myRefNum, regEntryIDPtr myDevice)
//Remember our refNum and Registry Entry Spec
MyReferenceNumber = myRefNum;
MyDeviceID = *myDevice;
return noErr;
}
OSErr DoFinalizeCommand
(refNum myRefNum, RegEntryIDPtr myDevice)
{
#pragma unused (myRefNum, myDevice)
return noErr;
}
CFMInitialize ( )
{
return noErr;
}
CFMTerminate ( )
{
return noErr;
}
______________________________________
The driver's initialization procedure first check the device's AAPL, address property to see that needed resources have been allocated. The initialization code also allocates any private storage the driver requires and place a pointer to it in the static data area that the Code Fragment Manager 40 provides for each instance of the driver. After allocating memory, the initialization procedure performs any other preparation required by the driver. If the handier fails to allocate memory for private storage it returns an appropriate error code to notify the Device Manager 90 that the driver did not initialize itself. In an exemplary embodiment, if the Open Firmware FCode in the device's expansion ROM 103 does not furnish either a driver, AAPL, MAacOS, PowerPC property or a unique name property, or if the driver's PCI vendor-id and device-id properties are generic, then the initialization procedure checks that the device is the correct one for the driver. If the driver has been incorrectly matched, the initialization procedure must return an error code so the Device Manager 90 can attempt to make a match. The driver's finalization procedure must reverse the effects of the initialization procedure by releasing any memory allocated by the driver, removing interrupt handlers, and canceling outstanding timers. If the finalization procedure cannot complete the finalization request it can return an error result code. In any event, however, the driver will be removed. Open and Close Routines A native device driver 80 utilizes both an open procedure and a close procedure. The current system software does not require that these procedures perform any specific tasks, however, the driver should keep track of open calls to match them with close calls. Open and close procedures are immediate. Typical code for keeping track of open and close commands is shown below:
______________________________________
long myOpenCount;
OSErr DoOpenCommand (ParmBlkPtr thePb)
myOpenCount++;
return noErr;
}
OSErr DoCloseCommand (ParmBlkPtr thePb)
{
myOpenCount--;
return noErr;
}
______________________________________
Read and Write Routines Driver read and write procedures implement I/O requests. These procedures can execute synchronously or asynchronously. A synchronous read or write procedure must complete an entire I/O request before returning to the Device Manager 90, an asynchronous read or write procedure can begin an I/O transaction and then return to the Device Manager 90 before the request is complete. In this case, the I/O request continues to be executed, typically when more data is available, by other procedures such as interrupt handlers or completion procedures. Below is an example listing:
______________________________________
short myLastErr; /* Globals */
long myLastCount;
OSErr DoReadCommand (IOpb pb)
long numsytes;
short myErr;
numbytes = pb.fwdarw.IORegCount;
{
/* do the read into pb.fwdarw.iobuffer*/
}
myLastErr = myErr; /* store in globals */
return (myErr);
}
______________________________________
Control and Status Routines Control and status procedures are normally used to send and receive driver-specific information. Control and status procedures can execute synchronously or asynchronously. Below shows a sample control procedure. DoControlCommand.
______________________________________
MyDriverGlobalsPtr
dStore;
OSErr DoControlCommand (ParamBlkPtr pb)
switch (pb.fwdarw.csCode)
{
case kClearAll:
dStore.fwdarw.byteCount = 0;
dStore.fwdarw.lastErr = 0;
return(noErr);
default: /* always return controlErr for unknown */
/* csCode */
return(controlErr);
}
}
______________________________________
The status procedure should work in a similar manner. The Device Manager 90 uses the csCode field to specify the type of status information requested. The status procedure should respond to whatever requests are appropriate for the driver and return the error code statusErr for any unsupported csCode value. The Device Manager 90 interprets a status request with a csCode value of 1 as a special case. When the Device Manager 90 receives such a status request, it returns a handle to the driver's device control entry. The driver's status procedure never receives this request. KillIO Routine Native driver killIO procedures take the following form:
______________________________________
OSErr DoKillIOCommand (ParmBlkPtr thePb)
{ /* Check internal queue for request to be killed; if
found, remove from queue and free request */
return noErr;
} /* Else, if no request located */
return abortErr;
thePb Pointer to a Device Manager parameter block
______________________________________
When the Device Manager 90 receives a KillIO request, it removes the specified parameter block from the driver I/O queue. If the driver responds to any requests asynchronously, the part of the driver that completes asynchronous requests (for example, an interrupt handler) might expect the parameter block for the pending request to be at the head of the queue. The Device Manager 90 notifies the driver of KillIO requests so it can take the appropriate actions to stop work on any pending requests. The driver must return control to the Device Manager 90 by calling IOCommandIsComplete. Replace and Superseded Routines Under certain conditions, it may be desirable to replace an installed driver 80. For example, a display card may use a temporary driver during system startup and then replace it with a better version from disk once the file system is running and initialized. Replacing an installed driver is a two-step process. First, the driver to be replaced is requested to give up control of the device. Second, the new driver is installed and directed to take over management of the device. In one embodiment, two native driver commands are reserved for these tasks. The kSupersededCommand selector tells the outgoing driver to begin the replacement process. The command contents are the same as with kFinalizeCommand. The outgoing driver should take the following actions: (1) If it is a concurrent driver, it should wait for current I/O actions to finish. (2) Place the device in a "quiet" state. The definition of this state is device-specific, but it can involve such tasks as disabling device interrupts. (3) Remove any installed interrupt handlers. (4) Store the driver and the device state in the Name Registry as one or more properties attached to the device entry. (5) Return noErr to indicate that the driver is ready to be replaced. (6) The kReplaceCommand selector tells the incoming driver to begin assume control of the device. The command contents are the same as a kInitializeCommand. The incoming driver should take the following actions: (1) Retrieve the state stored in the Name Registry and delete the properties stored by the Superseded command. (2) Install interrupt handlers. (3) Place the device in an active state. (4) Return noErr to indicate that the driver is ready to be used. IV. Driver Loader Library With reference to FIG. 6, the Driver Loader Library 45 (DLL) of the present invention is further discussed. FIG. 6 illustrates the relationships of the DLL 45, ROM 103, the Device Manager 90, and a driver 80 of the present invention. The Device Manager 90 communicates with a native driver 80 (for example, open, close, read, write, control, status, killIO, Replace, and Superceded commands). The Device Manager 90 also communicates with the DLL 45. The DLL 45 gives commands to the native driver 80 such as Initialize and finalize commands. In one implementation, the DLL 45 is a CFM shared-library extension of the Device Manager 90 and provides services to locate, install, and remove genetic drivers. The DLL 45 utilizes procedures of the CFM 40 for operation. The DLL 45 provides services that control aspects of driver to device matching under the present invention and also driver loading and installation. Under the present invention, driver loading is an automatic processes that frees drivers from having to perform device matching themselves. FIG. 7 illustrates functions of the DLL 45 of the present invention. At logic block 200, the present invention performs driver loading which includes determination of a particular driver for a particular device of the device tree 10 database. In order to perform this, logic block 200 interfaces with the name registry (also called device tree 10 database) and also with RAM unit 102 and ROM unit 103. Drivers may be located in these memory units. The file storage 104 (where drivers may be located in the device driver folder) is also coupled to communicate with the logic block 200. The CFM 40 is also coupled with block 200. The DLL 45 performs device loading in block 200 as well as device installation 210 once an appropriate driver is selected for a device. At block 220, information retrieval is performed which allows a user to retrieve particular information about a recognized driver. Also, the DLL 45 of the present invention performs driver removal at block 240. These functions will be discussed in further detail to follow. FIG. 8 illustrates a flow diagram of processing performed by the DLL 45 of the present invention for automatically matching device drivers 80 to a particular identified or selected device of the devices reported in the device tree 10 database using candidate lists and sorting. This process is repeated for each device of the device tree 10 starting from the top and continuing downward through the tree 10. Processing 200 is invoked upon a request to locate a driver for a given or "selected" device. Processing logic 200 starts at block 305 wherein a candidate list is constructed and is associated with the selected device. This list contains a grouping of those drivers having a driver name that matches with the given device's device name or compatible device name. These drivers represent a set of drivers that perhaps will properly configure the given device. FIG. 9 illustrates the steps performed by logic block 305 in more detail. With reference to FIG. 8, after a candidate list is constructed, the present invention flows to logic block 310 wherein the candidate list is sorted by priority ranking as to which members of the candidate list are more than likely to match with the selected device and those drivers that are less likely to match with the selected device. The steps performed by logic block 310 are further described with reference to FIG. 10. With reference to FIG. 8, at block 315 the present invention determines if a request was made to the DLL 45 to actually install a driver to the selected device (e.g., or just report the "best" driver candidate). If not, then at block 340 the present invention returns the calling procedure with (1) the top candidate of the sorted candidate list and/or (2) the entire sorted candidate list. Process 200 then exits after this function is complete. With reference to FIG. 8, if block 315 determines that the calling entity requires that a driver be installed with respect to the selected device, then at block 320 the present invention determines the first driver of the sorted candidate list with the highest priority matching with the selected driver. This is performed by sequentially installing the drivers of the sorted candidate list and determining if the installation is successful. At block 320, a driver can be determined or an error message can be returned indicating that no driver of the candidate list properly matched with the selected device. If the latter occurs, then processing returns out of block 200 without an installation and the selected device is not active. If at the completion of processing logic block 320, it is determined that a particular driver of the candidate list properly validated with the selected device, then at logic block 330, the present invention verifies that any resources needed for the driver's proper operation are actually available within the computer system 120. At block 330, the present invention instructs the operating system 30 to scan the devices of the computer system 120 to determine if all of the devices that the selected device needs to operate (the "parent devices") are present within the computer system 120. If the parent devices are present, then the selected driver can be installed. Since devices of the device tree 10 database are processed through the DLL 45 of the present invention from top to bottom, the parent devices for a particular selected device should be operational (e.g., processed through blocks 200 and 210) before the selected device is processed by the present invention. If the required parent devices are not operational yet or not present, then block 210 is avoided. If the required resources are available, then at block 210 the present invention performs an installation wherein the determined driver is installed with respect to the selected device and the device becomes active. It is appreciated that the processing of logic blocks 200 and 210 are typically performed at initialization for each device of the device tree 10 database, starting with the top node and working down the device tree 10 so that parent devices are configured first before their child devices are configured. With reference to FIG. 9, a flow diagram is illustrated describing the logic steps of the logic 305 of the present invention DLL 45 in constructing a candidate list of drivers for the selected device. Logic 305 starts at block 410 wherein pertinent information regarding the device nodes of the device tree 10 database are accessed for the particular device. If the particular device has an associated driver within its node of the device tree 10 (e.g., a "default driver"), processing continues because this default driver can become replaced by an updated driver depending on the priority of the drivers in the candidate list built for the selected device. At block 410, the present invention obtains the following properties: (1) the device name 50; and (2) the compatible names 60a of the selected device (see FIG. 4) located within the compatible property 60. After the information of logic block 410 is accessed, the present invention at logic block 420 then access the available drivers recognized in the system to construct a first set of drivers. These drivers may reside in the device tree 10 database, in the ROM 103, in RAM 102 and in the extensions folder (e.g., device driver folder) of the disk drive 104. At block 430, the present invention selects a first driver for comparison. This driver is the "given driver." At block 430, the candidate list for the selected device is then cleared so the new list can be created. At logic block 440, the present invention examines the DriverDescription 80a information for this given driver to determine the driver name 80c (FIG. 5) of the given driver which is stored in the DriverDescription, in one embodiment, as the "nameinfostr field" of the deviceType structure for the given driver. Importantly, at logic block 440, the present invention performs a comparison between: (1) the device name 50 of the selected device and the driver name 80c of the given driver; and also between (2) each compatible name 60a of the selected device against the driver name 80c of the given driver. If there is a match between (1) or (2) above, then the match characteristics are recorded (e.g., was it match by (1) or by (2)) and at logic block 450, the given driver is added to the candidate list for the selected device if a match in 440 happened. It is appreciated the candidate list can be stored in RAM 102. The processing of the present invention then flows to logic block 460. If there was not a match at block 440, then the present invention flows to block 460 without adding the given driver to the candidate list. At block 460, the present invention determines if the given driver is the last driver of the drivers discovered in block 420 (e.g., those drivers recognized by the computer system 120). If so, then the process 305 exits from block 460. If not, then logic block 460 is exited and processing flows to block 470 wherein the present invention selects the next driver of the set of drivers discovered in block 420. This next driver is then the "given driver" and processing returns to block 440 to determine if this next given driver should be added to the selected device's candidate list. As with any driver, the next driver selected at block 470 can reside in RAM 102, in an extension ROM 103 within the device tree 10, or within a file on the disk 104. At the completion of process 305, an unsorted candidate list is then constructed for the selected driver and is stored in RAM 102. With reference to FIG. 10, the logic steps of logic block 310 are illustrated. Block 310 performs the candidate list sorting for a particular candidate list associated with the selected driver. At block 460, the candidate list for the selected device is accessed in RAM 102. This is a candidate list generated by logic 305 and is particular to the selected driver. At block 470, the present invention sorts the candidate list and places those drivers at the top or head of the candidate list that have a driver name 80c that matched with the device name 50 of the selected device. At the same time or sequentially, block 480 resolves any prioritization ties by using version information stored in the driver description between drivers of the candidate list. Those drivers with a more appropriate version (e.g., highest version or version closest to the selected driver) are placed higher in the candidate list priority. Block 470 then places in lower priority those drivers having a driver name 80c that matched with the selected driver's compatible names 60a. Again, version information (in logic block 480) with respect to these drivers is used to perform prioritization the same as discussed above. At the completion of block 480, the candidate list for the selected device is sorted by priority of most likely for validation (e.g., most likely to be compatible with the selected device). With reference to FIG. 11, the logic steps of logic block 320 of the present invention are illustrated. Block 320 performs a procedure of attempted installation of the drivers of the candidate list for the particular device (e.g., a trial and error approach based on the prior information compiled by the present invention). At logic step 510, the present invention accesses the sorted candidate list for the particular device. At block 520, the present invention accesses or "gets" the first driver of this candidate list. At block 530, the present invention attempts to install this selected driver with the selected device to validate the match. The selected driver validates the match by probing the device and performing some diagnostic operations between the selected driver and the device. Any number of different diagnostic operations can be used within the scope of the present invention for this step. Assuming the selected driver is appropriate, at logic block 540, the selected driver confirms the validation by returning a "no error" status flag to the DLL 45. If an error status was returned, or the "no error" status fails to return, then processing flows to logic block 570 wherein the present invention determines if the selected driver was the last driver of the selected candidate list for the selected device. If not, processing flows to block 560 wherein the present invention selects the next driver in sequential (e.g., priority) order from the sorted candidate list of the selected device. Processing then flows back to block 530 to determine if the next driver will validate the match with the selected device. At block 570, if the selected driver happens to be the last driver of the sorted candidate list, then at block 580, the present invention returns an error code indicating that no compatible driver could be found for the selected device. Returning to block 540, the present invention flows to logic 550 if the selected driver did indeed match with the selected device. At block 550, the selected driver's category information is then compared against the category information of the selected device which is stored in the device tree 10 as property information. If no match is performed between the categories, then the match is not validated, so processing returns to logic block 570. If the categories match, then at block 555, the selected driver is said to be determined and a proper validation of the match occurs between it and the selected device. This information is then returned from block 320. The operating system 30 can utilize the above logic of the present invention at various times, but in one embodiment it is used during the boot phase and at any time a new device is added to the device tree 10 (which can also add new drivers to the available list of drivers used by the present invention). It is appreciated that as the system boots and new devices are configured and "wake up" and are added to the device tree 10 (by IEEE P.1275), it is possible for a device to be assigned a driver via the present invention and then re-assigned a newer or more appropriate driver later as they become available during the boot phase. In other words, drivers located on the hard disk are not available until the hard disk itself becomes configured as a device. In such case, the scope of drivers available at block 420 (FIG. 9) of the present invention is dynamic during the boot phase and will increase as soon the as hard drive is properly configured. In this example, a particular device can be initially configured with a driver from ROM and subsequently can be reconfigured with a more appropriate driver from the driver folder of the hard drive because the new driver will become higher in the candidate list (over the old driver) upon subsequent processing of the particular device by the present invention. Therefore, the candidate lists for a particular device are dynamic in that they will grow depending on the set of drivers that are available within the computer system 120 and recognized by the present invention. More specifically, the processing for matching a driver with a particular device can operate at a first time given a first set of drivers recognized by the system. A high priority driver from a first candidate list can then be determined from the present information. Later, at some subsequent time a new, larger set of device drivers can become available that will lead the present invention to generate a second, updated candidate list which will indicate a new, more updated high priority driver. If this occurs, the present invention will remove the original high priority driver from the particular device and replace it with the updated high priority driver, see below under "Driver Replacement." Below is a description of a particular, exemplary, embodiment of the present invention DLL 45 service procedures and driver handling. It is appreciated that while a particular platform is presented below, the functionality of the present invention can be readily adapted to a variety of different platforms and the below discussion is exemplary only of a particular implementation. Loading and Unloading In one embodiment, a driver 80 of the present invention may be loaded from any CFM container (in memory, files, or resources) as well as from a device's driver property in the Name Registry 10. The following services are provided for this purpose: (1) GetDriverMemoryFragment loads a driver from a memory range; (2) GetDriverDiskFragment loads a driver from a file; (3) FindDriverCandidates and ScanDriverCandidates prepare a list of file-based drivers that potentially match a device; (4) FindDriversForDevice finds the "best" drivers for a device, searching both ROM and disk, without making a CFM connection; (5) GetDriverForDevice finds the "best" driver for a device and returns its CFM connection ID; (6) SetDriverClosureMemory determines whether or not memory is held for a driver. One circumstance in which FindDriversForDevice or GetDriverForDevice is required is when there is a device node in the device tree 10 that does not have an associated driver. One instance when this might happen is if a PCI card is entered in the device tree 10 after system startup. FindDriversForDevice does not create a CFM connection for the driver it finds. This service is useful if there is a need to browse potential drivers for a device without loading them. GetDriverForDevice finds the driver and creams a CFM connection for it. In one embodiment, the successful load of a driver yields the following results: (1) a CFM ConnectionID; (2) a pointer to the Driver Description; (3) a pointer to the DoDriverIO entry point. If the driver has a CFM initialization procedure, it will be executed. The initialization procedure should return noErr to indicate a successful load. Note that multiple drivers may be loaded in order to determine the best device to driver match. Therefore, a driver's CFM initialization procedure should not allocate resources that cannot be released in its termination procedure. GetDriverMemoryFragment GetDriverMemoryFragment loads a code fragment driver from an area of memory.
______________________________________
OSErr GetDriverMemoryFragment
(Ptr memAddr,
long length,
Str63 fragName,
ConnectionID *fragmentConnID,
NuDriverEntryPointPtr
*fragmentMain,
DriverDescriptionPtr
*theDriverDesc);
memAddr pointer to the beginning of the fragment in
memory
length length of the fragment in memory
fragName optional name of the fragment (primarily
used by debugger)
fragmentConnID
resulting CFM connectionID
fragmentMain resulting pointer to DoDriverIO (may be
nil)
theDriverDesc
resulting pointer to DriverDescription
______________________________________
Given a pointer to the beginning of a driver code fragment in memAddr and the length of that fragment in length, GetDriverMemoryFragment loads the driver. It returns the loaded driver's CFM connectionID value in fragmentConnID, a pointer to its DoDriverIO entry point in fragmentMain, and a pointer to its driver description structure in theDriverDesc.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
All CFM errors
______________________________________
GetDriverDiskFragment GetDriverDiskFragment loads a code fragment driver from a file using the CFM search path.
______________________________________
OSErr GetDriverDiskFragment
(FSSpecPtr theFragmentSpec,
ConnectionID *fragmentConnID,
NuDriverEntryPointPtr
*fragmentMain,
DriverDescriptionPtr
theDriverDesc);
fragmentSpec
pointer to a file system specification
fragmentConnID
resultingCFM connectionID
fragmentMain
resulting pointer to DoDriverIO
driverDesc resulting pointer to DriverDescription
______________________________________
Given a pointer to a CFM file system specification, GetDriverDiskFragment uses the CFM search path to find and load a driver code fragment. It returns the loaded driver's CFM connectionID value in fragmentConnID, a pointer to its DoDriverIO entry point in fragmentMain, and a pointer to its Driver Description in theDriverDesc.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnfErr -43 File not found
All CFM errors
______________________________________
FindDriverCandidates
______________________________________
OSErr FindDriverCandidates
(RegEntryIDPtr deviceID,
Ptr *propBasedDriver,
RegPropertyValueSize
*propBasedDriverSize,
StringPtr deviceName,
DriverType *propBasedDriverType,
Boolean *gotPropBasedDriver,
FileBasedDriverRecordPtr
fileBasedDrivers,
ItemCount *nFileBasedDrivers);
deviceID Name Registry ID of target device
propBasedDriver
Address of property-based driver
propBasedDriverSize
Size of property-based driver
deviceName Name of device
propBasedDriverType
Type of property-based driver
gotPropBasedDriver
True if property-based driver was found
fileBasedDrivers
List of sorted file-based driver records
nFileBaseDrivers
Count of file-based driver records
______________________________________
Given the name entry ID of a device, FindDriverCandidates constructs a candidate list of file-based drivers that match the device name 50 or one of the device-compatible names 60a. The list is sorted from best match to least favorable match. In one embodiment, drivers 80 that match the device name are listed before drivers that match a compatible name. Each of these groups are further sorted by version numbers, using the HigherDriverVersion service. Property-based drivers are always matched using the device name and are returned separately from file-based drivers. An I/O expert can determine a property-based driver's randing using the HigherDriverVersion service. If a property-based driver is not found, all outputs are zeroed. If a nil list output buffer is passed, only the count of matched file-based drivers is returned. An I/O expert can call FindDriverCandidates first with a nil buffer, allocate a buffer large enough for the list, and then call FindDriverCandidates again with the appropriately-sized buffer. If a nil value is passed in deviceID, all drivers from the Extensions folder are returned. When using this option, pass nil values for all parameters except fileBasedDrivers and nFileBasedDrivers. The list of matched drivers consists of an array of file-based driver records:
______________________________________
struct FileBasedDriverRecord {
FSSpec theSpec; /* file specification*/
DriverType theType; /* nameInfoStr + version
/* number*/
Boolean compatibleProp;
/* true if matched using a
compatible name*/
UInt8 pad[3]; /* alignment*/
};
typedef
struct FileBasedDriverRecord
FileBasedDriverRecord, *FileBasedDriverRecordPtr;
______________________________________
A file-based driver consists of a file specification, the driver's type, and whether the driver was matched using the device name or a compatible device name. An I/O expert can use the program logic summarized below to cycle through a list of file-based candidates.
______________________________________
FindDriverCandidates ( );
/* get list of candidates for a device*/
while (Candidates in the list)
GetDriverFromFile (FSSpec-in-Record,
&driverConnectionID);
if (initializeThisDriver(Candidate) ==
NotMyHardwareError))
{
// Unhold this failed drivers memory
// and Close its CFM Connection
UnloadTheDriver (driverConnectionID);
// Advance to next position in the list.
GetNextCandidate( );
}
else
break; // driver loaded and initialized.
}
______________________________________
ScanDriverCandidates
______________________________________
OSErr ScanDriverCandidates
(RegEntryIDPtr deviceID,
FileBasedDriverRecordPtr
fileBasedDrivers,
ItemCount nFileBasedDrivers,
FileBasedDriverRecordPtr
matchingDrivers,
ItemCount *nMatchingDrivers);
deviceID Name Registry ID of target device
fileBasedDrivers
List of sorted file-based driver records
nFileBasedDrivers
Count of file-based driver records
matchingDrivers
File-based driver records (a subset of
fileBasedDrivers)
nMatchingDrivers
Count of driver records
(<= nFileBasedDrivers)
______________________________________
Given the name entry ID of a device and a list of FileBasedDriverRecord elements, ScanDriverCandidates constructs a list of matching file-based drivers that match the device name or one of the device-compatible names. The list is sorted from best match to least favorable match. Input to this service is an array FileBasedDriverRecord elements. Applications can use ScanDriverCandidates to match drivers from a static list of candidates without having to incur the overhead of disk I/O operations.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnfErr -43 File not found
All CFM errors
______________________________________
FindDriversForDevice FindDriversForDevice finds the driver from a file or from a device tree property that represents the "best" driver for a device--that is, the latest version of the most appropriate driver. The procedure for determining a best driver is described with reference to FIG. 11 of the present invention.
______________________________________
OSErr FindDriversForDevice
(RegEntryIDPtr
device,
FSSpec *fragment-
Spec,
Driver- *file-
Description Driver-
Desc,
Ptr *memAddr,
long *length,
StringPtr fragName,
Driver- *mem-
Description Driver-
Desc);
device device ID
fragmentSpec pointer to a file system specification
fileDriverDesc
pointer to the Driver Description of
driver in a file
memAddr pointer to driver address
length length of driver code
fragName name of driver fragment
memDriverDesc
pointer to the Driver Description of
driver in memory
______________________________________
Given a pointer to the RegEntrvID value of a device, FindDriversForDevice finds the most suitable driver for that device. If the driver is located in a file, it returns a pointer to the driver's CFM file system specification in fragmentSpec and a pointer to its Driver Description in fileDriverDesc. If the driver is a fragment located in memory, FindDriversForDevice returns a pointer to its address in memAddr, its length in length, its name in fragName, and a pointer to its Driver Description in memDriverDesc.FindDriversForDevice initializes all outputs to nil before searching for drivers.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnfErr -43 File not found
All CFM errors
______________________________________
GetDriverForDevice GetDriverForDevice loads the "best" driver for a device from memory. The procedure for determining the best driver for a selected device is described in with reference to FIG. 11.
______________________________________
OSErr GetDriverForDevice
(RegEntrvIDPtr
device,
ConnectionID *fragment-
ConnID,
DriverEntrvPoint-
*fragment-
Ptr Main
Driver- *driverDesc);
DescriptionPtr
device device ID
fragmentConnID
pointer to a fragment connection ID
fragmentMain
pointer to DoDriverIO
driverDesc pointer to the Driver Description of driver
______________________________________
Given a pointer to the RegEntrvID value of a device, GetDriverForDevice loads from memory the most suitable driver for that device. It returns the loaded driver's CFM connectionID value in fragmentConnID, a pointer to its DoDriverIO entry point in fragmentMain, and a pointer to its Driver Description.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnfErr -43 Filenotfound
All CFM errors
______________________________________
SetDriverClosureMemory
______________________________________
OSErr SetDriverClosureMemory
(CFragConnectionID
fragmentConnID,
Boolean holdDriverMemory);
fragmentConnID
ID of driver closure (returned from other
DLL loading services)
holdDriverMemory
true to hold the memory of a driver closure;
false to unhold.
______________________________________
In one embodiment, a driver 80 and all its libraries is called a driver closure. When a driver 80 is loaded and prepared for initialization by the DLL, memory for its closure may be held as the final step in implementing GetDriverMemoryFragment and GetDriverDiskFragment. SetDriverClosureMemory lets one do this by setting the holdDriverMemory parameter true. SetDriverClosureMemory can also be use to free memory held for a driver closure by setting the holdDriverMemory parameter false. To undo the effects of GetDriverMemoryFragment or GetDriverDiskFragment, an I/O expert can call SetDriverMemoryClosureMemory (cfmID, false) followed by CloseConnection (&cfmID). This has the effect of unloading the driver. Listing below shows a sample procedure to perform this task.
______________________________________
void UnloadTheDriver (CFragConnectionID fragID)
OSErr Status;
THz theCurrentZone =GetZone ( );
// Make sure the fragment is attached to the system
// context (System 7.5.2 CFM keys context from the
// current heap zone)
SetZone (SystemZone ( ));
Status = SetDriverClosureMemory (fragID), false);
if (Status != noErr)
printf ("Couldn't unhold pages of Driver Closure!
(Err==%x) .backslash.n",Status);
Status=CloseConnection (&fragID);
if (Status != noErr)
printf ("Couldn't close Driver Connection!
(Err==%x) .backslash.n", Status);
//Reset the zone
SetZone (theCurrentZone);
}
______________________________________
Installation Once loaded, a driver must be installed in a Unit Table (stored in memory) to become available to Device Manager clients ("applications"). This process begins with a CFM fragment connection ID and results in a refNum. The installing software can specify a desired range of unit numbers in the Unit Table. For example, SCSI drivers use the range 32 to 38 as a convention to their clients. If the driver cannot be installed within that range, an error is returned. The Unit Table grows to accommodate the new driver as well. In one embodiment, the unit table may grow only if the unit number is between some defined number (for example 48) and the current highest unit number as returned by the HighestUnitNumber procedure. When installing a native driver, the caller also passes the RegEntryIDPtr of the device which the driver is to manage. This pointer (along with the refNum) is given to the driver as a parameter in the initialization command. The driver may use this pointer to iterate through a device's property list, as an aid to initialization. The native driver should return noErr to indicate a successful initialization command. These functions, described in the below, operate on a loaded driver fragment: (1) verifyFragmentAsDriver verifies fragment contents as driver; (2) InstallDriverFromFragment places a driver fragment in the Unit Table; (3) InstallDriverFromDisk places a disk-based driver in the Unit Table; and (4) OpenInstalledDriver opens a driver that is already installed in the Unit Table VerifyFragmentAsDriver VerifyFragmentAsDriver guarantees that there is a driver in a given fragment.
______________________________________
OSErr VerifyFragmentAsDriver
(ConnectionID fragmentConnID,
NuDriverEntryPointPtr
*fragmentMain,
DriverDescriptionPtr *driverDesc);
fragmentConnID
CFM connectionID
fragmentMain
resulting pointer to DoDriverIO
driverDesc resulting pointer to DriverDescription
______________________________________
Given a CFM connectionID value for a code fragment, VerifyFragmentAsDriver verifies that the fragment is a driver. It returns a pointer to the driver's DoDriverIO entry point in fragmentMain and a pointer to its Driver Description in driverDesc.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
All CFM errors
______________________________________
InstallDriverFromFragment InstallDriverFromFragment installs a driver fragment in the Unit Table.
______________________________________
OSErr InstallDriverFromFragment
(ConnectionID fragmentConnID,
RegEntryIDPtr device,
UnitNumber beginningUnit,
UnitNumber endingUnit,
refNum *refNum);
fragmentConnID
CFM connectionID
device pointer to Name Registry specification
beginningUnit
low unit number in Unit Table range
endingUnit high unit number in Unit Table range
refNum resulting Unit Table refNum
______________________________________
InstallDriverFromFragment installs a driver that is located in a CFM code fragment, using the standard code fragment search path, anywhere within the specified unit number range of the Unit Table. It invokes the driver's Initialize command, passing the RegEntryIDPtr to it. The driver's initialization code must return noErr for InstallDriverFromFragment to complete successfully. This function returns the driver's refNum but it does not open the driver. If the requested Unit Table range is from the determined number (e.g., 48) to the highest unit number currently available, as returned by the HighestUnitNumber procedure, and if that range is currently filled, the Unit Table will expand to accept the new driver. If the Device Manager 90 has already enlarged the Unit Table to its maximum possible size, however, InstallDriverFromFragment will return unitTblFullErr.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
badUnitErr -21 Bad unit number
unitTblFullErr
-29 Unit table or requested range full
Specific returns Initialize, Replace, Superseded
All CFM errors
______________________________________
InstallDriverFromDisk InstallDriverFromDisk locates a file in the Extensions folder that is in the Mac OS System folder, verifies that the file's contents are a native driver, and loads and installs the driver.
______________________________________
OSErr InstallDriverFromDisk
(Ptr driverName,
RegEntryIDPtr device,
UnitNumber beginningUnit,
UnitNumber endingUnit,
DriverRefNum *refNum);
driverName
Name of a disk file containing a driver
device Pointer to entry in the Name Registry
beginningUnit
First Unit Table number of range acceptable for
installation
endingUnit
Last Unit Table number of range acceptable for
installation
refNum Reference number returned by InstallDriverFrom-
Disk
______________________________________
InstallDriverFromDisk installs a driver that is located on disk 104 anywhere within the specified unit number range of the Unit Table and invokes the driver's Initialize command, passing the RegEntryIDPtr to it. The driver's initialization code must return noErr for InstallDriverFromDisk to complete successfully. This function returns the driver's refNum but it does not open the driver. If the requested Unit Table range is from the determined number (e.g., 48) to the highest unit number currently available, as returned by the HighestUnitNumber procedure, and if that range is currently filled, the Unit Table will expand to accept the new driver. If the Device Manager 90 has already enlarged the Unit Table to its maximum possible size, however, InstallDriverFromDisk will return unitTblFullErr.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnfErr -43 File not found
badUnitErr -21 Bad unit number
unitTblFullErr
-29 Unit table or requested range full
All CFM errors
______________________________________
OpenInstalledDriver OpenInstalledDriver opens a driver that is already installed in the Unit Table.
______________________________________
OSErr OpenInstalledDriver
(DriverRefNum
refNum,
SInt8 ioPermission);
refNum Unit Table reference number
ioPermission
I/O permission code:
fsCurPerm
0 retain current permission
fsRdPerm 1 allow read actions only
fsWrPerm 2 allow write actions only
fsRdWrPerm
3 allow both read and write actions
______________________________________
Given an installed driver's Unit Table reference number, OpenInstalledDriver opens the driver. The Device Manager 90 ignores the ioPermission parameter; it is included only to provide easy communication with the driver.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
badUnitErr -21 Bad unit number
unitEmptyErr -22 Empty unit number
______________________________________
Load and Install Option Callers wishing to combine the loading and installation process in one service may want to use one of the following functions, described in the next sections: (1) InstallDriverFromFile loads and installs a file-based driver, and (2) InstallDriverFromMemory loads and installs a memory-based driver InstallDriverFromFile InstallDriverFromFile loads a driver from a file and installs it.
______________________________________
OSErr InstallDriverFromFile
(FSSpecPtr fragmentSpec,
RegEntryIDPtr
device,
UnitNumber beginningUnit,
UnitNumber endingUnit,
refNum *refNum);
fragmentSpec pointer to a file system specification
device pointer to Name Registry Specification
beginningUnit low unit number in Unit Table Range
endingUnit high unit number in Unit Table Range
refNum resulting Unit Table refNum
______________________________________
InstallDriverFromFile installs a driver that is located on disk 104 anywhere within the specified unit number range of the Unit Table and invokes the driver's Initialize command, passing the RegEntryIDPtr to it. The driver's initialization code must return noErr for InstallDriverFromFile to complete successfully. This function returns the driver's refNum but it does not open the driver. If the requested Unit Table range is from the determined number (e.g., 48) to the highest unit number currently available, as returned by the HighestUnitNumber procedure, and if that range is currently filled, the Unit Table will expand to accept the new driver. If the Device Manager has already enlarged the Unit Table to its maximum possible size, however, InstallDriverFromFile will return unitTblFullErr.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnfErr -43 File not found
badUnitErr -21 Bad unit number
unitTblFullErr
-29 Unit table or requested range full
All CFM errors
______________________________________
InstallDriverFromMemory InstallDriverFromMemory loads a driver from a range of memory and installs it.
______________________________________
OSErr InstallDriverEromMemory
(Ptr memory,
long length,
Str63 fragName,
RegEntryIDPtr
device,
UnitNumber
beginningUnit,
UnitNumber
endingUnit,
refNum *refNum);
memory pointer to beginning of fragment in memory
length length of fragment in memory
fragName An optional name of the fragment (primarily used
by debugger)
device pointer to Name Registry specification
beginningUnit
low unit number in Unit Table range
endingUnit
high unit number in Unit Table range
refNum resulting Unit Table refNum
______________________________________
InstallDriverFromMemory installs a driver that is located in a CFM code fragment, using the standard code fragment search path, anywhere within the specified unit number range of the Unit Table. It invokes the driver's Initialize command, passing the RegEntryIDPtr to it. The driver's initialization code must return noErr for InstallDriverFromMemory to complete successfully. This function returns the driver's refNum but it does not open the driver. If the requested Unit Table range is from the determined number (e.g., 48) to the highest unit number currently available, as returned by the HighestUnitNumber procedure, and if that range is currently filled, the Unit Table will expand to accept the new driver. If the Device Manager has already enlarged the Unit Table to its maximum possible size, however, InstallDriverFromMemory will return unitTblFullErr.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
badUnitErr -21 Bad unit number
unitTblFullErr
-29 Unit table or requested range full
All CFM errors
______________________________________
Match, Load and Install Those wishing to combine the matching of the best driver for a device, with the loading and installation process in one service, may use InstallDriverForDevice and HigherDriverVersion, described in this section. The DriverDescription data structure is used to compare a driver's functionality with a device's needs as discussed above. The Driver Loader Library picks the best driver for the device by looking for drivers in the Extensions folder (device driver folder) and comparing those against drivers in the device's property list. InstallDriverForDevice InstallDriverForDevice installs the "best" driver for a device. The procedure for determining the best driver is described in FIG. 11.
______________________________________
OSErr InstallDriverForDevice
(RegEntryIDPtr device,
UnitNumber beginningUnit,
UnitNumber endingUnit,
refNum *refNum);
device pointer to Name Registry specification
beginningUnit
low unit number in Unit Table range
endingUnit high unit number in Unit Table range
refNum resulting Unit Table refNum
______________________________________
InstallDriverForDevice finds, loads, and installs the best driver for a device identified by its RegEntryID value. In one embodiment, it installs the driver anywhere within the specified unit number range of the Unit Table and invokes its Initialize command, passing the RegEntryIDPtr to it. The driver's initialization code must return noErr for InstallDriverForDevice to complete successfully. This function returns the driver's refNum but it does not open the driver. If the requested Unit Table range is from the determined number (e.g,. 48) to the highest unit number currently available, as returned by the HighestUnitNumber procedure, and if that range is currently filled, the Unit Table will expand to accept the new driver. If the Device Manager 90 has already enlarged the Unit Table to its maximum possible size, however, InstallDriverForDevice will return unitTblFullErr.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
fnf Err -43 File not found
badUnitErr -21 Bad unit number
unitTblFullErr
-29 Unit table or requested range full
All CFM errors
______________________________________
HigherDriverVersion HigherDriverVersion compares two driver version numbers, normally the values in their DriverDescription structures. It returns a value that indicates which driver is later. This service may be used by any software that loads or evaluates drivers.
______________________________________
short HigherDriverVersion
(NumVersion *V1,NumVersion
*V2);
struct NumVersion {
UInt8 majorRev; /*1st part of version*/
/*number in BCD*/
UInt8 minorAndBugRev;
/*2nd and 3rd part of*/
/*version number share a*/
/*byte*/
UInt8 stage; /*stage code: dev, alpha,*/
/*beta, final*/
UInt8 nonRelRev; /*rev level of non-*/
/*released version*/
};
V1 First version number being compared
V2 Second version number being compared
______________________________________
HigherDriverVersion returns 0 if v1 and v2 are equal. It returns a negative number if Vl<V2 and a positive number greater than 0 if V1>V2. If both drivers have stage values of final, a nonRelRev value of 0 is evaluated as greater than any nonzero number. Stage codes are the following: developStage=0.times.20 alphaStage=0.times.40 betaStage=0.times.60 finalStage=0.times.80 Driver Removal Applications wishing to remove an installed driver can use RemoveDriver, see block 240 of FIG. 7. RemoveDriver RemoveDriver removes an installed driver.
______________________________________
OSErr RemoveDriver (refNum refNum,
Boolean Immediate);
refNum refNum of driver to remove
Immediate true means don't wait for driver to become idle
______________________________________
RemoveDriver accepts a refNum and unloads a code fragment driver from the Unit Table. It invokes the driver's Finalize command. If called as immediate, it does not wait for driver to become inactive.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
badUnitErr -21 Bad unit number
unitEmptyErr -22 Empty unit number
______________________________________
Getting Driver Information Applications wishing to acquire information about an installed driver can use GetDriverInformation. GetDriverInformation GetDriverInformation returns a number of pieces of information about an installed driver, see block 220 of FIG. 7.
______________________________________
OSErr GetDriverInformation
(DriverRefNum refNum,
UnitNumber *unitNum,
DriverFlags *flags,
DriverOpenCount *count,
StringPtr name,
RegEntryID *device,
CFragHFSLocator *driverLoadLocation,
CFragConnectionID * fragmentConnID,
DriverEntryPointPtr
*fragmentMain,
DriverDescription *driverDesc);
refNum refNum of driver to examine
unit resulting unit number
flags resulting DCE flag bits
count number of times driver has been opened
name resulting driver name
device resulting Name Registry device specification
driverLocation
resulting CFM fragment locator (from which
the driver was loaded)
fragmentConnID
resulting CFM connection ID
fragmentMain
resulting pointer to DoDriverIO
driverDesc resulting pointer to DriverDescription
______________________________________
Given the Unit Table reference number of an installed driver, GetDriverInformation returns the driver's unit number in unit, its DCE flags in flags, the number of times it has been opened in count, its name in name, its RegEntryID value in device, its CFM fragment locator in driverLocation, its CFM connection 112) infragmentConnID, its DoDriverIO entry point in fragmentMain, and its Driver Description in driverDesc.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
badUnitErr -21 Bad unit number
unitEmptyErr -22 Empty unit number
______________________________________
Searching For Drivers The exemplary procedures described in this section help clients iterate through the Unit Table, locating installed drivers. HighestUnitNumber HighestUnitNumber returns the currently highest valid unit number in the Unit Table. UnitNumber HighestUnitNumber (void); HighestUnitNumber takes no parameters. It returns a UnitNumber value that represents the highest unit number in the Unit Table. LookupDrivers LookupDrivers is used to iterate through the contents of the Unit Table.
______________________________________
OSErr LookupDrivers
(UnitNumber beginningUnit,
UnitNumber endingUnit,
Boolean emptyUnits,
ItemCount *returnedRefNums,
DriverRefNum
*refNums);
beginningUnit
First unit in range of units to scan
endingUnit Last unit in range of units to scan
emptyUnits true: retum available units
false: retum allocated units
returnedRefNums
Maximum number of reference numbers to
return; on completion, contains actual number
of refNums returned
refNums resulting array of returned refNums
______________________________________
Given the first and last unit numbers to scan, LookupDrivers returns the reference numbers of both native and 68K drivers. The emptyUnits parameter tells it to return either available or allocated units and returnedRefNums tells it the maximum number of reference numbers to return. When LookupDrivers finishes, returnedRefNums contains the actual number of refNums returned. The sample code shown below uses HighestUnitNumber and LookupDrivers to print out the reference numbers of all installed drivers and obtain driver information.
______________________________________
RESULT CODES
______________________________________
noErr 0 No error
paramErr -50 Bad parameter
FindAllDrivers( )
ItemCount theCount = 1;
UnitNumber theUnit = 0;
DriverRefNum
theRefNum, *fullSizedRefNumBuffer;
//Method #1:
Iterate with a small output buffer
while ( (theUnit <= HighestUnitNumber( ) ) &&
(LookupDrivers (theUnit, theUnit, false, &theCount,
&theRefNum) == noErr)
{
if (theCount == 1) printf ("Refnum;#%d is
allocated. .backslash.n", theRefNum);
theCount = 1;
theUnit++;
}
// Method #2: Get all refnums with one call
fullSizedRefNumBuffer = NewPtr
((HighestUnitNumber( ) + 1) *
sizeof(DriverRefNum));
theCount = (HighestUnitNumber( ) + 1);
LookupDrivers (0, HighestUnitNumber( ), false, &theCount,
fullSizedRefNumBuffer);
for(theUnit=0,theUnit < theCount | ||||||
