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,
              &amp;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 ==&gt; device driver is in RAM
   
   <P>0 ==&gt; 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 ==&gt; the <CODE>dCtlDriver</CODE> field of the DCE is
   a handle
   
   <P>0 ==&gt; 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&ccedil;ois Grieu for his invaluable contribution
to this effort.</P>
 
<P>If you find any problems with this sample, please mail
&lt;DTS@apple.com&gt; 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&ccedil;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>