Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MoreDevices/TradDriverLoaderLib/ReadMe.html
<HTML> |
<HEAD> |
<TITLE>Read Me</TITLE> |
</HEAD> |
<BODY BGCOLOR="#FFFFFF"> |
<H1>Read Me About TradDriverLoaderLib</H1> |
<P>1.0b7</P> |
<P>The TradDriverLoaderLib provides a bunch of routines helpful for |
installing traditional Mac OS device drivers (<CODE>'DRVR'</CODE>s). |
While there have been many samples of how to do this in the past, |
this sample has a number of advantages:</P> |
<UL> |
<LI>It works. Some of the other samples out there don't, at least |
not in all possible cases.</LI> |
<LI>It mimicks the API of the PCI "DriverLoaderLib" as much as |
possible, which makes the TradDriverLoaderLib easier to use in an |
environment supporting both PCI native drivers |
(<CODE>'ndrv'</CODE>) and traditional Mac OS drivers |
(<CODE>'DRVR'</CODE>). The PCI "DriverLoaderLib" is documented in |
<A HREF="http://developer.apple.com/macos/opentransport/docs/dev/Designing_PCI_Cards_Drivers.pdf">Designing |
PCI Cards and Drivers for Power Macintosh Computers</A>.</LI> |
<LI>It has both C and Pascal interfaces.</LI> |
<LI>I have revised all DTS sample <CODE>'DRVR'</CODE>s to use this |
library where appropriate.</LI> |
<LI>You can build it into both 68K and PPC clients.</LI> |
</UL> |
<P>TradDriverLoaderLib has been used by many developers (and quite a |
few system software projects) in the 4 years since it was first |
distributed.</P> |
<H2>Packing List</H2> |
<P>The distribution contains the following files:</P> |
<UL> |
<LI>ReadMe.html -- This document.</LI> |
<LI>TradDriverLoaderLib.c -- C source for the library.</LI> |
<LI>TradDriverLoaderLib.h -- C interface to the library.</LI> |
<LI>TradDriverLoaderLib.p -- Pascal interface to the library.</LI> |
<LI>TestTradDriverLoaderLib -- A folder containing Pascal source |
to an application used to test TradDriverLoaderLib. This folder |
also contains a subfolder, TestDriver, which contains the source |
to an extremely simple <CODE>'DRVR'</CODE> that's used by the test |
application.</LI> |
</UL> |
<P>TradDriverLoaderLib also depends on the following MoreIsBetter |
libraries:</P> |
<UL> |
<LI>MoreInterfaceLib.h -- A header file that exports versions of |
system routines that are not exported by InterfaceLib.</LI> |
<LI>MoreInterfaceLib.c -- C glue that implements certain system |
routines that should be included in InterfaceLib but are not. You |
must add this glue to any PPC client of TradDriverLoaderLib. 68K |
clients should not include this glue.</LI> |
</UL> |
<H2>Using the Sample</H2> |
<H4>Running the Test Program</H4> |
<P>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!</P> |
<H4>Using the API from C</H4> |
<P>Installing and opening a <CODE>'DRVR'</CODE> using |
TradDriverLoaderLib is very simple. You need to take the following |
steps:</P> |
<OL> |
<LI>Add "TradDriverLoaderLib.c" to your project.</LI> |
<LI>If you are building a PPC client, add "MoreInterfaceLib.c" to |
your project.</LI> |
<LI>Include "TradDriverLoaderLib.h" in your source.</LI> |
<LI>When you want to install a driver, execute the following:</LI> |
</OL> |
<P><TABLE BORDER=0> |
<TR> |
<TD BGCOLOR="#EEEEEE"> |
<PRE>err = TradInstallDriverFromResource(0, "\p.MyDriverName", |
48, |
TradHighestUnitNumber() + 1, |
&gDriverRefNum); |
if (err == noErr || err == dupFNErr) { |
err = TradOpenInstalledDriver(gDriverRefNum, fsRdWrPerm); |
}</PRE> |
</TD> |
</TR> |
</TABLE> |
</P> |
<H4>Using the API from Pascal</H4> |
<P>Installing and opening a <CODE>'DRVR'</CODE> using |
TradDriverLoaderLib is very simple. You need to take the following |
steps:</P> |
<OL> |
<LI>Add "TradDriverLoaderLib.c" to your project.</LI> |
<LI>If you are building a PPC client, add "MoreInterfaceLib.c" to |
your project.</LI> |
<LI>Use "TradDriverLoaderLib.p" in your source.</LI> |
<LI>When you want to install a driver, execute the following:</LI> |
</OL> |
<P><TABLE BORDER=0> |
<TR> |
<TD BGCOLOR="#EEEEEE"> |
<PRE>driverName := '.MyDriverName'; |
err := TradInstallDriverFromResource(0, @driverName, |
48, |
TradHighestUnitNumber + 1, |
gDriverRefNum); |
if (err = noErr) or (err = dupFNErr) then begin |
err := TradOpenInstalledDriver(gDriverRefNum, fsRdWrPerm); |
end; (* if *)</PRE> |
</TD> |
</TR> |
</TABLE> |
</P> |
<H2>Building the Sample</H2> |
<P>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.</P> |
<H2>Advanced Topics</H2> |
<H3>API Reference</H3> |
<P>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.</P> |
<H3>Internal Implementation Details</H3> |
<P>The most important routine in TradDriverLoaderLib is |
<CODE>TradInstallDriverFromPtr</CODE>. Both |
<CODE>TradInstallDriverFromHandle</CODE> and |
<CODE>TradInstallDriverFromResource</CODE> call through to this |
routine. This routine takes a pointer to an <CODE>'DRVR'</CODE> 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 <CODE>DriverInstall</CODE> (namely |
<CODE>DriverInstallReserveMem</CODE>) to ensure that the driver's DCE |
is loaded as low in the system heap as possible.</P> |
<P>When you call <CODE>TradInstallDriverFromHandle</CODE>, it creates |
an appropriately sized pointer block in the system heap and copies |
the <CODE>'DRVR'</CODE> you supply into that block. It then calls |
<CODE>TradInstallDriverFromPtr</CODE> on that block. This ensures |
that the driver code is loaded as low in the system heap as |
possible.</P> |
<P><CODE>TradInstallDriverFromResource</CODE> simply calls through to |
<CODE>TradInstallDriverFromHandle</CODE>.</P> |
<P>The source code contains many comments on the specific details of |
installing a driver in the unit table.</P> |
<H3>Sharing Driver Code Between Multiple Instances</H3> |
<P>Because <CODE>TradInstallDriverFromPtr</CODE> takes a pointer to |
the driver and just jams it into the <CODE>dCtlDriver</CODE> 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 <CODE>TradInstallDriverFromPtr</CODE>.</P> |
<P>Obviously, this is not for the faint of heart (&endash;:</P> |
<H3><CODE>dRAMBased</CODE> and <CODE>dNeedLock</CODE></H3> |
<P>The <CODE>dctlFlags</CODE> field of the DCE has a bit known as |
<CODE>dRAMBased</CODE>. Most people interpret this bit as:</P> |
<BLOCKQUOTE>1 ==> device driver is in RAM |
<P>0 ==> driver is in ROM</P></BLOCKQUOTE> |
<P><STRONG>This interpretation is wrong!</STRONG> The name |
<CODE>dRAMBased</CODE> is a historical artifact of the time when the |
system had ROM based drivers for hardware and RAM based driver for |
desk accessories.</P> |
<P>The correct interpretation of this bit is:</P> |
<BLOCKQUOTE>1 ==> the <CODE>dCtlDriver</CODE> field of the DCE is |
a handle |
<P>0 ==> the <CODE>dCtlDriver</CODE> field of the DCE is a |
pointer</P></BLOCKQUOTE> |
<P>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.</P> |
<P><CODE>dNeedLock</CODE> controls whether the Device Manager locks |
the DCE for your driver. If you set <CODE>dNeedLock</CODE>, the |
Device Manager will lock your driver's DCE whenever your driver is |
active.</P> |
<P><STRONG>Devices that operate at interrupt time (either accepting |
asynchronous requests or completing requests) must never have |
<CODE>dRAMBased</CODE> set and must always have |
<CODE>dNeedLock</CODE> set.</STRONG> Failing to do this will result |
in the Device Manager calling Memory Manager routines at interrupt |
time, with unpredictable and possibly catastrophic results.</P> |
<P>TradDriverLoaderLib implements this recomendation and always loads |
drivers into RAM, making sure that <CODE>dRAMBased</CODE> is clear |
and <CODE>dNeedLock</CODE> is set.</P> |
<H3>Setting <CODE>dNeedLock</CODE></H3> |
<P>This sample always sets <CODE>dNeedLock</CODE>. This is necessary |
to prevent the Device Manager from locking and unlocking the DCE |
while the driver operates. Instead the Device Manager notices that |
<CODE>dNeedLock</CODE> is set and locks the DCE once when the driver |
is opened. This is good for much the same reasons :</P> |
<OL> |
<LI>It saves a few CPU cycles.</LI> |
<LI>It avoids the Device Manager calling the Memory Manager |
<CODE>HLock</CODE> and <CODE>HUnlock</CODE> routines at interrupt |
time. <STRONG>Devices that operate at interrupt time (either |
accepting asynchronous requests or completing requests) must |
always have <CODE>dNeedLock</CODE> set.</STRONG></LI> |
</OL> |
<H2>Caveats</H2> |
<P>There are no known caveats at this time.</P> |
<H2>Credits and Version History</H2> |
<P>Thanks for François Grieu for his invaluable contribution |
to this effort.</P> |
<P>If you find any problems with this sample, please mail |
<DTS@apple.com> and I'll try to fix them up.</P> |
<P>1.0b1 (Jan 1997) was distributed to a couple of developers.</P> |
<P>1.0b2 (Feb 1997) is the first official release version.</P> |
<P>1.0b3 (Feb 1997) incorporates changes from the original DTS |
reviewers. In addition, TradDriverLoaderLib now calls |
<CODE>CloseDriver</CODE> instead of <CODE>FSClose</CODE>.</P> |
<P>1.0b4 (Mar 1997) incorporates changes and suggestions from |
François Grieu. Tidied up the description of |
<CODE>dNeedLock</CODE> and <CODE>dRAMBased</CODE> in the |
documentation, and made <CODE>TradGetDriverInformation</CODE> more |
paranoid about bogus drivers.</P> |
<P>1.0b5 (Jul 1997) can now build PPC native |
<CODE>TradDriverLoaderLib</CODE> using snazzy MixedMode glue for |
<CODE>DriverInstallReserveMem</CODE> (which is not in InterfaceLib). |
Also increased <CODE>kMaximumNumberOfUnitTableEntries</CODE> to 1024 |
to reflect the new limit used by the PCI DriverLoaderLib included |
with Mac OS 8. Cosmetic documentation and code changes.</P> |
<P>1.0b6 (Feb 1999) Integrated the library into MoreIsBetter. |
<CODE>TradRemoveDriver</CODE> and <CODE>TradRenameDriver</CODE> now |
check that the driver is a <CODE>'DRVR'</CODE> (as opposed to an |
<CODE>'ndrv'</CODE>) and refuse to remove it otherwise. Recast the |
documention in HTML. Minor stylistic changes.</P> |
<P>1.0b7 (Dec 2000) Fixed a bug where |
<CODE>TradInstallDriverFromHandle</CODE> was failing to test |
<CODE>MemError</CODE> in one case. Converted test program to C |
because the latest MIB development environment (CWPro6) does not |
currently support Pascal.</P> |
<P>Share and Enjoy.</P> |
<P>Apple Developer Technical Support<BR> |
Networking, Communications, Hardware</P> |
<P>26 Dec 2000</P> |
</BODY> |
</HTML> |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14