PATH 
ADC Home > Documentation > Hardware > Device Managers and Drivers > PCI Card Services > Designing PCI Cards and Drivers for Power Macintosh Computers


  

Using NVRAM to Store Name Registry Properties

NVRAM can be used to store device properties permanently. However, such storage is necessary only for devices used during Mac OS startup, because other devices can store an unlimited amount of permanent information on disk in the Preferences folder.

If the kRegPropertyValueIsSavedToNVRAM modifier of a property entry is set, the contents of that property entry will be preserved in NVRAM. During Mac OS startup, the Macintosh firmware will retrieve the entry value from NVRAM and place it in the device tree. This modifier is described in Data Structures and Constants.

Properties stored in NVRAM are available to boot devices before the devices have been installed. For example, properties stored in NVRAM can be used to configure a primary display or to define the net address of a network boot device. In both cases, the device driver can access user-changeable information before disk storage services are available.

To provide facilities for multiple boot devices, each node in the Name Registry can store a single, small property in NVRAM. Depending on the version of the Name Registry the format of the information is different. Versions of the Name Registry prior to version 1.2 use the following format to store NVRAM properties:

There are two ways to determine of the version 1.2 Name Registry rules apply. Try and create a property that doesn't follow the rules, for example create an 8-byte name. If it succeeds, you know the 1.2 rules apply. Or, you can check the version number of the Name Registry.

Note

Using a creator ID (instead of a generic mnemonic) as the name of an NVRAM property value offers protection against acquiring the wrong value when a user configures a system and then moves a hardware device to a different slot or bus. If all drivers define their NVRAM property names with unique creator IDs, a driver can determine whether an NVRAM value is owned by its device.

Use the Name Registry routines described in Chapter 10 to access nodes saved to NVRAM. The Macintosh firmware will return an error message if a driver or application performs one of the following illegal actions:

Because only a single property may be stored in NVRAM for each device, drivers will need to protect themselves against accessing an old NVRAM property that may already be in place. The recommended algorithm is as follows:

  1. Iterate to find all properties for the device.
  2. If a property has the NVRAM modifier bit set, then check the property name.
  3. If the property name is correct, use the property value.
  4. If the property name is incorrect, delete the property and use default settings.
  5. Exit and use the found property value. Use default settings if no property was set or an incorrectly named property was deleted.

Listing 12-1 shows four sample routines that are useful when manipulating NVRAM:

Listing 12-1 Sample NVRAM manipulation code

#define CopyOSTypeToCString(osTypePtr, resultString) do {\
        BlockCopy(osTypePtr, resultString, sizeof(OSType));\
        resultString[sizeof (OSType)] = 0;\
    } while (0)


/******************************************
* RetrieveDriverNVRAMParameter retrieve the single property stored in nonvolatile
* memory (NVRAM).By convention, this property is named using our registered
* creator code. Because the PCI system stores properties indexed by physical slot
* number, we may retrieve an incorrect property if the user moves cards around.
* To protect against this, we check the property name.
*
* This function must be called from an initialization context.
*
* Return status:
* noErr            Success: the NVRAM property was retrieved.
* nrNotFoundErr    Failure: there was no NVRAM property.
* paramErr         Failure: there was an NVRAMproperty, but not ours.
* other            Failure: unexpected Name Registry error.
*/
OSErr
RetrieveDriverNVRAMProperty(
    RegEntryIDPtr   regEntryIDPtr,          /* driver's NameRegistryID */
    OSType          driverCreatorID,        / * registered creator code */
    UInt8           driverNVRAMRecord[8]
)
{
    OSErr                   status;
    RegPropertyIter         cookie;
    RegPropertyNameBuf      propertyName;
    RegPropertyValueSize    regPropertyValueSize;
    RegPropertyModifiers    propertyModifiers;
    Boolean                 done;
    char                    creatorNameString[sizeof (OSType) + 1];

        /*
        * search our properties for one with the NVRAM modifier set
        */
        status = RegistryPropertyIterateCreate(regEntryIDPtr, &cookie);
        if (status == noErr){
            while (status == noErr){
            /*
            * Get the next property and check its modifier. Break if this is the
            * NVRAM property (there can be only one for our entryID).
            */
                status = RegistryPropertyIterate(&cookie, propertyName, &done);
                if (status == noErr && done == FALSE){
                    status = RegistryPropertyGetMod(
                                regEntryIDPtr,
                                propertyName,
                                &propertyModifiers
                                );
                    if (status == noErr
                    && (propertyModifiers &kRegPropertyValueIsSavedToNVRAM) != 0)
                    break;
                }
                /*
                * There was no NVRAM property. Return nrNotFoundErrbyconvention.
                */
                if (status == noErr && done)
                    status = nrNotFoundErr;
            }
            RegistryPropertyIterateDispose(&cookie);
            /*
            * If status == noErr,we have found an NVRAMproperty. Now,
            *   1.  If it is our creator code,we have found the property, so
            *       we retrieve the values and store them in the driver's globals.
            *   2.  If it was found with a different creator code, the user has
            *       moved our card to as lot that previously had a different card
            *       installed, so delete this property and return (noErr) to use
            *       the factory defaults.
            *   3.  If it was not found, the property was not set, so we exit
            *       (noErr); the caller will have preset the values to
            *       "factory defaults."
            */
            if (status == noErr){
                /*
                * Cases 1 or 2, check the property.
                */
                CopyOSTypeToCString(&driverCreatorID, creatorNameString);
                if (CStrCmp(creatorNameString, propertyName) == 0) {    /* Match */
                    status = RegistryPropertyGetSize(
                                regEntryIDPtr,
                                propertyName,
                                &regPropertyValueSize
                            );
                    if (status == noErr
                    && regPropertyValueSize == sizeofdriverNVRAMRecord){
                        status = RegistryPropertyGet(
                                regEntryIDPtr,
                                propertyName,
                                driverNVRAMRecord,
                                &regPropertyValueSize
                            );
                    }
                }
                else{
                    /*
                    * This is an NVRAMproperty, but it isn't ours. Delete the
                    * property and return an error status so the caller uses
                    * "factorysettings"
                    */
                    status = RegistryPropertyDelete(
                                regEntryIDPtr,
                                propertyName
                            );
                    /*
                    * Since we're returning an error anyway, we ignore the
                    * statuscode.
                    */
                    status = paramErr;
                }
            }
        }
        return(status);
}


/******************************************
* Get the NVRAM property. Return an error if it does not exist, is the wrong size,
* or is not marked "storeinNVRAM." This may be called from a
* noninitialization context.
* Errors:
* nrNotFoundErr        Not found in the registry
* nrDataTruncatedErr   Wrong size
* paramErr             Not marked "storeinNVRAM"
*/
OSErr
GetDriverNVRAMProperty(
        RegEntryIDPtr   regEntryIDPtr,          /* driver's NameRegistryID */
        OSType          driverCreatorID,        /* registered creator code */
        UInt8           driverNVRAMRecord[8]    /* mandatedsize */
)
{
        OSErr                   status;
        char                    creatorNameString[sizeof (OSType) + 1];
        RegPropertyValueSize    size;
        RegPropertyModifiers    modifiers;
        CopyOSTypeToCString(&driverCreatorID, creatorNameString);
        status = RegistryPropertyGetSize(
            regEntryIDPtr,
            creatorNameString,
            &size
        );
        if (status == noErr && size != sizeofdriverNVRAMRecord)
            status = nrDataTruncatedErr;
        if (status == noErr){
            status = RegistryPropertyGetMod(
                    regEntryIDPtr,
                    creatorNameString,
                    &modifiers
                    );
        }
        if (status == noErr
        && (modifiers &kRegPropertyValueIsSavedToNVRAM) == 0)
            status = paramErr;
        if (status == noErr){
            status = RegistryPropertyGet(
                        regEntryIDPtr,
                        creatorNameString,
                        driverNVRAMRecord,
                        &size
                    );
        }
        return (status);
}


/******************************************
* Update the NVRAM property. Return an error if it was not created. This maybe
* called from PBStatus (or other noninitialization context).
*/
OSErr
UpdateDriverNVRAMProperty(
        RegEntryIDPtr       regEntryIDPtr,          /* driver's NameRegistryID */
        OSType              driverCreatorID,        /* registered creator code */
        UInt8               driverNVRAMRecord[8]    /* mandatedsize */
)
{
        OSErr               status;
        char                creatorNameString[sizeof (OSType) + 1];
        CopyOSTypeToCString(&driverCreatorID, creatorNameString);
        /*
        * Replace the current value of the property with its new value. In this
        * example, we are replacing the entire value and, potentially, changing
        * its size. In production software, you may need to read an existing
        * property and modify its contents. This shouldn't be too hard to do.
        */
        status = RegistryPropertySet(       /* update existing value */
                    regEntryIDPtr,
                    creatorNameString,
                    driverNVRAMRecord,
                    sizeofdriverNVRAMRecord
                );
        return (status);
}


/******************************************
* Create the NVRAM property. This must be called from the driver
 * initialization function.
*/
OSErr
CreateDriverNVRAMProperty(
        RegEntryIDPtr       regEntryIDPtr,          /*driver'sNameRegistryID */
        OSType              driverCreatorID,        /*registeredcreatorcode */
        UInt8               driverNVRAMRecord[8]    /*mandatedsize */
)
{
        OSErr                   status;
        char                    creatorNameString[sizeof (OSType) + 1];
        RegPropertyValueSize    size;
        RegPropertyModifiers    modifiers;
        CopyOSTypeToCString(&driverCreatorID, creatorNameString);
        /*
        * Does the property currently exist (with the correct size)?
        */
        status = RegistryPropertyGetSize( /* returns noErr if the property exists */
                    regEntryIDPtr,
                    creatorNameString,
                    &size
                );
            if (status == noErr){
            /*
            * Replace the current value of the property with its new value. In this
            * example, we are replacing the entire value and, potentially, changing
            * its size. In production software, you may need to read an existing
            * property and modify its contents. Thiss houldn't be too hard to do.
            */
            status = RegistryPropertySet( /* update existing value */
                        regEntryIDPtr,
                        creatorNameString,
                        driverNVRAMRecord,
                        sizeofdriverNVRAMRecord
                    );
        }
        else{
            status=RegistryPropertyCreate( /* make a new property */
                        regEntryIDPtr,
                        creatorNameString,
                        driverNVRAMRecord,
                        sizeofdriverNVRAMRecord
                    );
        }
        /*
        * If status equals noErr, the property has been stored; set its "saveto
        * nonvolatile RAM" bit.
        */
        if (status == noErr){
            status = RegistryPropertyGetMod(
                        regEntryIDPtr,
                        creatorNameString,
                        &modifiers
                    );
        }
        if (status == noErr){
            /*
            * Set the NVRAM bit and update the modifiers.
            */
            modifiers != kRegPropertyValueIsSavedToNVRAM;
            status = RegistryPropertySetMod(
                        regEntryIDPtr,
                        creatorNameString,
                        modifiers
                    );
        }
        return (status);
}

© 1999 Apple Computer, Inc. – (Last Updated 26 March 99)