1.0b6
The TradDriverLoaderLib provides a bunch of routines helpful for
installing traditional Mac OS device drivers ('DRVR'
s).
While there have been many samples of how to do this in the past,
this sample has a number of advantages:
'ndrv'
) and traditional Mac OS drivers
('DRVR'
). The PCI "DriverLoaderLib" is documented in
Designing
PCI Cards and Drivers for Power Macintosh Computers.
'DRVR'
s to use this
library where appropriate.
TradDriverLoaderLib has been used by many developers (and quite a few system software projects) in the 2 years since it was first distributed.
The distribution contains the following files:
'DRVR'
that's used by the test
application.
TradDriverLoaderLib also depends on the following MoreIsBetter libraries:
The distribution includes a copy of both the 68K and PPC builds of the test application (TestTradDriverLoader-68K and TestTradDriverLoader-PPC). To run the test application, just double click it in the Finder which, amongst other things, installs and removes 494 copies of the test driver!
Installing and opening a 'DRVR'
using
TradDriverLoaderLib is very simple. You need to take the following
steps:
err = TradInstallDriverFromResource(0, "\p.MyDriverName", 48, TradHighestUnitNumber() + 1, &gDriverRefNum); if (err == noErr || err == dupFNErr) { err = TradOpenInstalledDriver(gDriverRefNum, fsRdWrPerm); } |
Installing and opening a 'DRVR'
using
TradDriverLoaderLib is very simple. You need to take the following
steps:
driverName := '.MyDriverName'; err := TradInstallDriverFromResource(0, @driverName, 48, TradHighestUnitNumber + 1, gDriverRefNum); if (err = noErr) or (err = dupFNErr) then begin err := TradOpenInstalledDriver(gDriverRefNum, fsRdWrPerm); end; (* if *) |
The sample was built using the standard MoreIsBetter build environment (CodeWarrior Pro 2 compiler with Universal Interfaces 3.2). You should be able to build the project in CodeWarrior Pro 4 without difficulty. To build the test application, open the "TestTradDriverLoader.mcp" project and choose a target (either 68K or PPC), and choose Make from the Project menu. This will build either TestTradDriverLoader-68K or TestTradDriverLoader-PPC.
All of the routines in the API are described in detail in the comments in the "TradDriverLoaderLib.h" file. I suggest you look there for more in-depth information about the services provided by the library.
The most important routine in TradDriverLoaderLib is
TradInstallDriverFromPtr
. Both
TradInstallDriverFromHandle
and
TradInstallDriverFromResource
call through to this
routine. This routine takes a pointer to an 'DRVR'
that
has been loaded in the system heap and creates a Device Control Entry
(DCE) in the system's unit table for that driver. The driver uses an
interesting variant of DriverInstall
(namely
DriverInstallReserveMem
) to ensure that the driver's DCE
is loaded as low in the system heap as possible.
When you call TradInstallDriverFromHandle
, it creates
an appropriately sized pointer block in the system heap and copies
the 'DRVR'
you supply into that block. It then calls
TradInstallDriverFromPtr
on that block. This ensures
that the driver code is loaded as low in the system heap as possible.
TradInstallDriverFromResource
simply calls through to
TradInstallDriverFromHandle
.
The source code contains many comments on the specific details of installing a driver in the unit table.
Because TradInstallDriverFromPtr
takes a pointer to
the driver and just jams it into the dCtlDriver
field of
the DCE without interpretation, you can use this routine to share
code between device drivers. This is useful for things like serial
drivers, which traditionally install two different drivers with
different names. You can create one big chunk of code that has
multiple driver headers in it, and then install that code into two
different DCEs using TradInstallDriverFromPtr
.
Obviously, this is not for the faint of heart (&endash;:
dRAMBased
and dNeedLock
The dctlFlags
field of the DCE has a bit known as
dRAMBased
. Most people interpret this bit as:
1 ==> device driver is in RAM
0 ==> driver is in ROM
This interpretation is wrong! The name
dRAMBased
is a historical artifact of the time when the
system had ROM based drivers for hardware and RAM based driver for
desk accessories.
The correct interpretation of this bit is:
1 ==> the
dCtlDriver
field of the DCE is a handle0 ==> the
dCtlDriver
field of the DCE is a pointer
So you don't have to set this bit to load your driver into RAM. In additon, pointer-based driver are also more efficient because the Device Manager does not have to dereference the handle each time.
dNeedLock
controls whether the Device Manager locks
the DCE for your driver. If you set dNeedLock
, the
Device Manager will lock your driver's DCE whenever your driver is
active.
Devices that operate at interrupt time (either accepting
asynchronous requests or completing requests) must never have
dRAMBased
set and must always have
dNeedLock
set. Failing to do this will result
in the Device Manager calling Memory Manager routines at interrupt
time, with unpredictable and possibly catastrophic results.
TradDriverLoaderLib implements this recomendation and always loads
drivers into RAM, making sure that dRAMBased
is clear
and dNeedLock
is set.
dNeedLock
This sample always sets dNeedLock
. This is necessary
to prevent the Device Manager from locking and unlocking the DCE
while the driver operates. Instead the Device Manager notices that
dNeedLock
is set and locks the DCE once when the driver
is opened. This is good for much the same reasons :
HLock
and HUnlock
routines at interrupt
time. Devices that operate at interrupt time (either
accepting asynchronous requests or completing requests) must
always have dNeedLock
set.
There are no known caveats at this time.
Thanks for François Grieu for his invaluable contribution to this effort.
If you find any problems with this sample, mail <DTS@apple.com> with "Attn: Quinn" as the first line of your mail and I'll try to fix them up.
1.0b1 (Jan 1997) was distributed to a couple of developers.
1.0b2 (Feb 1997) is the first official release version.
1.0b3 (Feb 1997) incorporates changes from the original DTS
reviewers. In addition, TradDriverLoaderLib now calls
CloseDriver
instead of FSClose
.
1.0b4 (Mar 1997) incorporates changes and suggestions from
François Grieu. Tidied up the description of
dNeedLock
and dRAMBased
in the
documentation, and made TradGetDriverInformation
more
paranoid about bogus drivers.
1.0b5 (Jul 1997) can now build PPC native
TradDriverLoaderLib
using snazzy MixedMode glue for
DriverInstallReserveMem
(which is not in InterfaceLib).
Also increased kMaximumNumberOfUnitTableEntries
to 1024
to reflect the new limit used by the PCI DriverLoaderLib included
with Mac OS 8. Cosmetic documentation and code changes.
1.0b6 (Feb 1999) Integrated the library into MoreIsBetter.
TradRemoveDriver
and TradRenameDriver
now
check that the driver is a 'DRVR'
(as opposed to an
'ndrv'
) and refuse to remove it otherwise. Recast the
documention in HTML. Minor stylistic changes.
Share and Enjoy.
Quinn "The Eskimo!"
Apple Developer Technical Support
Networking, Communications, Hardware
26 Feb 1999