home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 397.lha / DeviceDvrs.txt.pp / DeviceDvrs.txt
Text File  |  1990-07-01  |  42KB  |  1,134 lines

  1. Subject: A guide for prospective device driver writers (LONG)
  2. Keywords: device driver
  3. From: mwandel@bnr-rsc.UUCP (Markus Wandel)
  4. Path: ecsgate!mcnc!uvaarpa!haven!aplcen!uakari.primate.wisc.edu!sdd.hp.com!cs.utexas.edu!news-server.csri.toronto.edu!utgpu!cunews!bcars8!bnrgate!bigsur!bnr-rsc!mwandel
  5. Organization: Bell-Northern Research, Ottawa, Canada
  6. Newsgroups: comp.sys.amiga.tech
  7. Date: 1 Jun 90 02:14:50 GMT
  8.  
  9. Below is a file which I wrote recently about Amiga device drivers.  I think
  10. it might be useful to some people, and lacking other convenient distribution
  11. mechansims, I'll just post it here.  This doesn't have to be the final version
  12. of the document; feedback would be appreciated and if someone wants to write
  13. an additional section covering material I don't, I'd appreciate that too.
  14.  
  15. Is there *any* real documentation from Commodore on this subject?
  16.  
  17. Markus Wandel
  18. uunet!bnrgate!bnr-rsc!mwandel
  19.  
  20. ------------------------------- cut here ------------------------------------
  21.  
  22. AMIGA DEVICE DRIVER GUIDE
  23. -------------------------
  24.  
  25. Copyright (c) 1990 Markus Wandel
  26.  
  27. Version 0.12, May 21, 1990.
  28.  
  29. Distribution: Free in unmodified form.
  30.  
  31. Disclaimer: I don't know what I'm talking about; no guarantee is made of
  32. the correctness of anything in this document.  Not all of this will conform
  33. to Commodore sanctioned programming and documentation practices.  Version
  34. 1.4/2.0 of the Amiga OS may render part of this obsolete, particularly
  35. where I mention the internals of exec functions.
  36.  
  37. Corrections: If you find something wrong and would like it corrected, get
  38. in touch with me so I can have an up-to-date master copy.  Currently
  39. I can be reached at (613) 591-7698.  Should this number become invalid,
  40. call my parents at (705) 785-3383 or (705) 736-2285 (summer) and get the
  41. current one.
  42.  
  43.  
  44. TABLE OF CONTENTS
  45. -----------------
  46.  
  47. 0. INTRODUCTION
  48. 1. DEVICE STRUCTURE
  49.     1.1. DEVICE NODES
  50.     1.2. CONSTRUCTING A DEVICE NODE
  51.     1.3. STANDARD DEVICE FORMAT
  52.     1.4. DEVICES IN ROM
  53.     1.5. DEVICES ON DISK
  54.     1.6. JUMP VECTOR CHECKSUMS
  55. 2. DEVICE I/O PROTOCOL
  56.     2.1. THE I/O REQUEST STRUCTURE
  57.     2.2. OPENING AND CLOSING A DEVICE
  58.     2.3. EXPUNGING A DEVICE
  59.     2.4. UNIT STRUCTURES
  60.     2.5. THE BEGINIO FUNCTION
  61.     2.6. THE ABORTIO FUNCTION
  62.     2.7. EXEC I/O FUNCTIONS
  63.     2.8. CALLING BEGINIO DIRECTLY
  64.     2.8. SYNCHRONOUS I/O
  65.     2.9. ASYNCHRONOUS I/O
  66.         2.9.1. WAITING FOR A SPECIFIC I/O REQUEST
  67.         2.9.2. WAITING ON A SPECIFIC REPLY PORT
  68.         2.9.3. GENERAL CASE
  69. 3. GENERIC COMMAND AND ERROR NUMBERS
  70.     3.1. COMMANDS
  71.         3.1.1. CMD_RESET
  72.         3.1.2. CMD_READ
  73.         3.1.3. CMD_WRITE
  74.         3.1.4. CMD_UPDATE
  75.         3.1.5. CMD_CLEAR
  76.         3.1.6. CMD_STOP
  77.         3.1.7. CMD_START
  78.         3.1.8. CMD_FLUSH
  79.     3.2. ERROR NUMBERS
  80. 4. DISK DEVICE DRIVERS
  81.     4.1. COMMANDS
  82.         4.1.1. CMD_READ AND CMD_WRITE
  83.         4.1.2. TD_MOTOR
  84.         4.1.3. TD_SEEK
  85.         4.1.4. TD_FORMAT
  86.         4.1.5. TD_PROTSTATUS
  87.         4.1.6. TD_RAWREAD AND TD_RAWWRITE
  88.         4.1.7. TD_GETDRIVETYPE
  89.         4.1.8. TD_GETNUMTRACKS
  90.         4.1.9. TD_CHANGESTATE
  91.         4.1.10. OTHER COMMANDS
  92.     4.2. ERROR NUMBERS
  93.     4.3. SCSIDIRECT PROTOCOL
  94.     4.4. A MINIMAL DISK COMMAND SUBSET
  95. 5. REFERENCES
  96. 6. REVISION HISTORY
  97. }i}I_{_{_{wi}i{_}i{M_{_{_}i{_}i{_}i}ikkk
  98.  
  99. 0. INTRODUCTION
  100. ---------------
  101.  
  102. A number of people have asked me to explain Amiga device drivers to them.
  103. There is a lot to explain, and so I decided to write down all I know about
  104. the subject.  Here is the result.
  105.  
  106. This is not a standalone document.  It assumes that you are familiar with
  107. Amiga programming at the multiple task, message passing level.  It assumes
  108. that you have the autodocs, include files, and the example device driver
  109. from Commodore.  A lot of information from these documents is duplicated,
  110. but not all.
  111.  
  112. I wish that I knew more about this subject than I do and that I was a better
  113. writer.  Alas, I don't and I'm not.  This document contains all you need to
  114. write a disk resident, autoloading and expungeable device driver, but you
  115. may have to read it more than once.  To write a good, removeable-media disk
  116. driver, you will have to do some additional research.
  117.  
  118.  
  119. 1. DEVICE STRUCTURE
  120. -------------------
  121.  
  122. This section describes the data structure associated with a loaded device,
  123. and how to get a device into the system.  As far as discussed in this
  124. section, libraries and devices are identical.
  125.  
  126.  
  127. 1.1. DEVICE NODES
  128.  
  129. A device is known to the system by its device node.  The device node
  130. consists of three parts:
  131.  
  132.     (a) a jump table to the device functions
  133.     (b) a library structure
  134.     (c) any private data that the device has
  135.  
  136. The "device address" is the base address of the library node; thus the
  137. jump table is at negative offsets from the address, and everything else
  138. is at positive offsets.
  139.  
  140. Each entry in the jump table is a "jmp" to a 32-bit address.  Thus the
  141. first jump is at offset -6 from the device address, the second at offset
  142. -12, and so forth.  The following four are standard for all devices and
  143. libraries:
  144.  
  145.     -6: Open
  146.    -12: Close
  147.    -18: Expunge
  148.    -24: ExtFunc
  149.  
  150. These are the entry points for opening, closing, and expunging (unloading)
  151. the device, respectively.  The last one appears to be for future expansion.
  152.  
  153. Device drivers have two more standard functions:
  154.  
  155.    -30: BeginIO
  156.    -36: AbortIO
  157.  
  158. These are the entry points for submitting an I/O request and cancelling a
  159. pending one, respectively.
  160.  
  161. The library structure is shown below in "unwound" form.
  162.  
  163.     struct Library {
  164.         struct  Node {
  165.             struct  Node *ln_Succ;
  166.             struct  Node *ln_Pred;
  167.             UBYTE   ln_Type;
  168.                 /*  NT_DEVICE = 3  */
  169.             BYTE    ln_Pri;
  170.             char    *ln_Name;
  171.         } lib_Node;
  172.         UBYTE   lib_Flags;
  173.                 /*  LIBF_SUMMING = 1
  174.                     LIBF_CHANGED = 2
  175.                     LIBF_SUMUSED = 4
  176.                     LIBF_DELEXP  = 8  */
  177.         UBYTE   lib_pad;
  178.         UWORD   lib_NegSize;
  179.         UWORD   lib_PosSize;
  180.         UWORD   lib_Version;
  181.         UWORD   lib_Revision;
  182.         APTR    lib_IdString;
  183.         ULONG   lib_Sum;
  184.         UWORD   lib_OpenCnt;
  185.     };
  186.  
  187. The device is chained on the system device list by the node structure at
  188. the top.  The device list can be found at ExecBase->DeviceList.  Of
  189. interest is the "ln_Type" field, which must be NT_DEVICE, and the
  190. "ln_Name" field, which must be the device name in standard form, such
  191. as "serial.device".
  192.  
  193. The "lib_PosSize" and "lib_NegSize" fields indicate the number of bytes
  194. used above and below the device base address.  Thus "lib_NegSize" is
  195. the size of the jump vector, and "lib_PosSize" is the size of the library
  196. structure plus the user's private data, if any.
  197.  
  198. "lib_Version", "lib_Revision", and "lib_IdString" store more information
  199. about the device.  For "serial.device", version 34, revision 12, the
  200. string would look like this:
  201.  
  202.     "serial 34.12 (27 Mar 1989)"
  203.  
  204. This appears to be the accepted standard format.
  205.  
  206. The "lib_Sum" field, along with the flag bits "LIBF_SUMMING",
  207. "LIBF_CHANGED", and "LIBF_SUMUSED" are for the jump vector checksum
  208. mechanism, which is discussed farther on.
  209.  
  210. The "lib_OpenCnt" field counts the number of times that the
  211. device is currently open.  If this is not zero and an expunge is
  212. requested, the device can use the "LIBF_DELEXP" flag to remember that
  213. it should disappear at the earliest opportunity.
  214.  
  215.  
  216. 1.2. CONSTRUCTING A DEVICE NODE
  217.  
  218. In theory, you could just allocate all the memory needed for the device
  219. node, manually initialize the jump vector and the required fields in the
  220. library node, get ExecBase->DeviceList, do a Forbid(), and add the node
  221. to the list using Enqueue(), AddHead(), or AddTail().  But there is an
  222. easier way.  It is the following function:
  223.  
  224.     AddDevice(device)
  225.               A1
  226.  
  227. This takes an initialized device node, does the Forbid()/Permit(), and
  228. adds the node to ExecBase->DeviceList.  It also calls Sumkick() (discussed
  229. later).  The node itself can be constructed with this function:
  230.  
  231.     library = MakeLibrary(vectors, structure, init, dataSize, segList)
  232.     D0                    A0       A1         A2    D0        D1
  233.  
  234. The first parameter points to the table of function addresses for the
  235. jump vector.  It can have one of the following formats:
  236.  
  237.     (a) Relative
  238.  
  239.         vectors: dc.w   -1
  240.                  dc.w   func1-vectors
  241.                  dc.w   func2-vectors
  242.                  ...
  243.                  dc.w   -1
  244.  
  245.     (b) Absolute
  246.  
  247.         vectors: dc.l   func1
  248.                  dc.l   func2
  249.                  ...
  250.                  dc.l   -1
  251.  
  252. The "dataSize" parameter determines "positive size" of the device node.
  253. It must be at least the size of a library structure.  The "negative
  254. size" is implicit from the number of jump vector entries supplied.
  255.  
  256. The "MakeLibrary" function will allocate the appropriate amount of memory,
  257. fill in the jump vector, then use InitStruct() to clear and initialize
  258. the positive offset area.  The "structure" parameter points to a data
  259. table for the InitStruct() function.  This function is a complex thing,
  260. best used with the macros supplied.  Below is the table in Commodore's
  261. example device driver:
  262.  
  263.     dataTable:
  264.        INITBYTE   LN_TYPE,NT_DEVICE
  265.        INITLONG   LN_NAME,myName
  266.        INITBYTE   LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  267.        INITWORD   LIB_VERSION,VERSION
  268.        INITWORD   LIB_REVISION,REVISION
  269.        INITLONG   LIB_IDSTRING,idString
  270.        DC.L   0
  271.  
  272. It means this:
  273.  
  274.        - store a byte NT_DEVICE at offset LN_TYPE
  275.        - store the device name as a longword (pointer) at LN_NAME
  276.        - store LIBF_SUMUSED!LIBF_CHANGED in the "lib_Flags" field
  277.        - store the version, revision, and IdString in the appropriate fields.
  278.  
  279. If you want to know more about the Initstruct() function (which is very
  280. flexible and can do more than suggested above), you should read the autodoc
  281. for it and possibly the disassembly as well.
  282.  
  283. Finally, we have the "init" and "segList" parameters.  "init" is the
  284. address of the device's own initialization code.  This is called after
  285. construction of the node is complete.  "segList" describes where the device's
  286. code is loaded.  The initialization code is called with the device node
  287. address in D0 and the SegList parameter in A0.  The value it returns
  288. is the value returned by MakeLibrary.  Thus the initialization code
  289. will normally return the device node address as it received it.
  290.  
  291. The only remaining thing to note is that the "structure" and "init" fields
  292. can be set to zero to not initialize the positive offset area and not
  293. call any initialization code, respectively.
  294.  
  295. So to summarize what we have so far, the first-principles way to get a device
  296. into the system is the following:
  297.  
  298.     - LoadSeg() the code into memory, if necessary
  299.     - MakeLibrary() to build the library node
  300.     - AddDevice() with the result to add the node to the device list.
  301.  
  302.  
  303. 1.3. STANDARD DEVICE FORMAT
  304.  
  305. Real devices are in a standard format, which allows them to be loaded
  306. and initialized without any knowledge of their internals.  The standard
  307. format is based on a "resident structure", or "RomTag".  Such structures
  308. tag the various libraries and devices in the system ROM and in the LIBS:
  309. and DEVS: directories on disk.  The structure is the following:
  310.  
  311.     struct Resident {
  312.         UWORD rt_MatchWord;
  313.                 /*  RTC_MATCHWORD = 0x4AFC  */
  314.         struct Resident *rt_MatchTag;
  315.         APTR  rt_EndSkip;
  316.         UBYTE rt_Flags;
  317.                 /*  RTF_COLDSTART = 1
  318.                     RTF_AUTOINIT  = 128 */
  319.         UBYTE rt_Version;
  320.         UBYTE rt_Type;
  321.                 /*  NT_DEVICE = 3 */
  322.         BYTE  rt_Pri;
  323.         char  *rt_Name;
  324.         char  *rt_IdString;
  325.         APTR  rt_Init;
  326.     };
  327.  
  328. The first two fields are special, allowing the structure to be found
  329. during a ROM scan.  They are the official 68000 "illegal instruction",
  330. opcode 0x4AFC, followed by a pointer to the instruction.  The next field
  331. speeds up the ROM scan by pointing to the address at which the scan
  332. should continue, usually at the end of the area tagged by this RomTag.
  333.  
  334. The "rt_Version" field has the familiar version number, and the "rt_Type"
  335. field is NT_DEVICE for our application.  The "rt_Pri" field, together
  336. with the "rt_Version" field, determines which of multiple modules with
  337. the same name will be accepted, should such a situation occur.  The
  338. "rt_Name" and "rt_IdString" fields identify the module; they should be
  339. set to the device name and IdString as discussed earlier for a device
  340. node.
  341.  
  342. Things tagged by RomTags are referred to as "resident modules", and
  343. are initialized like this:
  344.  
  345.     InitResident(resident, segList)
  346.                  A1        D1
  347.  
  348. Here, "resident" points to the RomTag, and "segList" identifies the
  349. code associated with it (this is optional).
  350.  
  351. The InitResident() function first checks if the RTF_AUTOINIT flag is
  352. set in the RomTag.  If it is not, it simply calls the routine pointed to
  353. by "rt_Init" with A0 containing the value passed as "segList", and
  354. returns.
  355.  
  356. If the RTF_AUTOINIT flag is set, then the function does all the device
  357. initialization work for you.  In this case, "rt_Init" points to a data
  358. table of four longwords, containing these parameters for the "MakeLibrary"
  359. function:
  360.  
  361.     - dataSize
  362.     - vectors
  363.     - structure
  364.     - init
  365.  
  366. InitResident calls the MakeLibrary function with these values, plus the
  367. obligatory "segList" parameter.  Unless MakeLibrary() returns null, the
  368. new library node is now added to the appropriate system list, based on
  369. the "ln_Type" field in the node.  If it is NT_DEVICE, the node is added
  370. to the device list, which is what we want.
  371.  
  372. You should now have enough information to create a standard device header
  373. and initialization function, and to understand the one in Commodore's
  374. example device driver.
  375.  
  376.  
  377. 1.4. DEVICES IN ROM
  378.  
  379. Devices in ROM are found during a scan of the entire ROM for RomTag
  380. structures.  This occurs at boot time.  The RomTags which are found
  381. are added to the resident module list in ExecBase.  All those whose
  382. RTF_COLDSTART flag is set are automatically started up with InitResident().
  383.  
  384. Modules can be "ramkicked" using a mechanism which I will not describe
  385. here.  This causes them to survive a reset, be found in RAM, and be
  386. initialized along with the ROM modules at cold start time.  This is how
  387. the RAD: bootable RAM disk works.
  388.  
  389.  
  390. 1.5. DEVICES ON DISK
  391.  
  392. Devices on disk reside in the DEVS: directory.  They are standard object
  393. modules, and loaded with LoadSeg().  After they have been loaded, the
  394. first hunk of the seglist is scanned for a RomTag, and the device is
  395. initialized with an InitResident().  When building a disk resident device,
  396. be careful that the linker does not add a dummy hunk at the front of your
  397. code (old versions of BLINK do this), as this would cause your RomTag not
  398. to be found.
  399.  
  400.  
  401. 1.6. JUMP VECTOR CHECKSUMS
  402.  
  403. The "lib_Sum" field in the library structure can be used to hold a checksum
  404. of the jump vector, to guard against accidental or unauthorized
  405. modification.  The "LIBF_SUMUSED" flag bit indicates that this should be
  406. done.  The "LIBF_CHANGED" flag bit indicates that the jump vector has
  407. been modified and the checksum is invalid.  The following function
  408. implements the mechanism:
  409.  
  410.     SumLibrary(library)
  411.                A1
  412.  
  413. This does the following:
  414.  
  415.     IF the LIBF_SUMUSED flag is set THEN
  416.         Forbid()
  417.         IF the LIBF_CHANGED flag is set THEN
  418.             Compute checksum and store in lib_Sum
  419.             Clear the LIBF_CHANGED flag
  420.         ELSE
  421.             IF the lib_Sum field is zero THEN
  422.                 Compute checksum and store in lib_Sum
  423.             ELSE
  424.                 Compute checksum
  425.                 IF checksum does not match lib_Sum THEN
  426.                     Put up recoverable alert #81000003
  427.                     Store new checksum in lib_Sum
  428.                 ENDIF
  429.             ENDIF
  430.         ENDIF
  431.         Permit()
  432.     ENDIF
  433.  
  434. Thus when creating a new device node, it is best to set the LIBF_SUMUSED
  435. and LIBF_CHANGED bits, so that the first call to SumLibrary() updates the
  436. checksum and future calls detect modifications to the jump vector.
  437.  
  438. The system sets the LIBF_CHANGED bit and calls SumLibrary() as part of the
  439. SetFunction() call to keep the checksum valid.
  440.  
  441.  
  442. 2. DEVICE I/O PROTOCOL
  443. ----------------------
  444.  
  445. This section describes the interface to a device once it is loaded and
  446. initialized.
  447.  
  448.  
  449. 2.1. THE I/O REQUEST STRUCTURE
  450.  
  451. The system communicates with a device driver by use of an "I/O Request"
  452. structure.  The most common version of this is shown below, but all
  453. fields after the "io_Error" field are device driver specific and may
  454. be omitted or redefined.
  455.  
  456.     struct IOStdReq {
  457.         struct  Message {
  458.             struct  Node {
  459.                 struct  Node *ln_Succ;
  460.                 struct  Node *ln_Pred;
  461.                 UBYTE   ln_Type;
  462.                         /*  NT_MESSAGE  = 5
  463.                             NT_REPLYMSG = 7 */
  464.                 BYTE    ln_Pri;
  465.                 char    *ln_Name;
  466.             } mn_Node;
  467.             struct  MsgPort *mn_ReplyPort;
  468.             UWORD   mn_Length;
  469.         } io_Message;
  470.         struct  Device  *io_Device;
  471.         struct  Unit    *io_Unit;
  472.         UWORD   io_Command;
  473.         UBYTE   io_Flags;
  474.                 /*  IOF_QUICK = 1 */
  475.         BYTE    io_Error;
  476.         ULONG   io_Actual;
  477.         ULONG   io_Length;
  478.         APTR    io_Data;
  479.         ULONG   io_Offset;
  480.     };
  481.  
  482. The first field in the I/O request is a standard message structure,
  483. allowing it to be enqueued on message ports and replied to.  The
  484. "io_Device" field points to the device structure, and the "io_Unit"
  485. field points to a "unit" structure maintained by the device driver
  486. for each functional unit (e.g. disk drive).  Thus these two fields
  487. identify the target of the I/O request.
  488.  
  489.  
  490. 2.2. OPENING AND CLOSING A DEVICE
  491.  
  492. To communicate with a device, one needs at least one I/O request,
  493. and a message port to which the device can return I/O requests which
  494. it has finished processing.  These are easily created using the following
  495. two C library functions:
  496.  
  497.     MyPort = CreatePort( name, pri )
  498.     struct MsgPort *MyPort;
  499.     char *name;
  500.     BYTE pri;
  501.  
  502.     ioStdReq = CreateStdIO( ioReplyPort )
  503.     struct IOStdReq *ioStdReq;
  504.     struct MsgPort *ioReplyPort;
  505.  
  506. The first function creates a message port and associated signal bit, and
  507. returns the address of the port.  The second function creates an IOStdReq
  508. structure, fills in the address of the reply port, and returns the
  509. address of the structure.  Then the device driver can be opened using
  510. this function:
  511.  
  512.     error = OpenDevice(devName, unitNumber, iORequest, flags)
  513.     D0                 A0       D0          A1         D1
  514.  
  515. The parameters are the name of the device (e.g. "trackdisk.device", the
  516. unit number (e.g. 0 for the internal drive), the address of the finished
  517. I/O request structure, and a "flags" word containing special information
  518. for the device driver.  The following C code will open the trackdisk
  519. driver for the internal drive, and close it again:
  520.  
  521.     /*
  522.      *  Do not supply a name for the message port, since supplying a name
  523.      *  will put it on the public message port list.
  524.      */
  525.     td_mp = CreatePort(0L,0L);
  526.     if(!td_mp) exit(99);
  527.     td_iob = CreateStdIO(td_mp);
  528.     if(!td_iob) {
  529.         DeletePort(td_mp);
  530.         exit(99);
  531.     }
  532.     if(OpenDevice("trackdisk.device",0L,td_iob,0L)) {
  533.         printf("Unable to open floppy device driver.\n");
  534.         DeleteStdIO(td_iob);
  535.         DeletePort(td_mp);
  536.         exit(99);
  537.     }
  538.  
  539.     /*
  540.      *  I/O request is ready for operations here.
  541.      */
  542.  
  543.     CloseDevice(td_iob);
  544.     DeleteStdIO(td_iob);
  545.     DeletePort(td_mp);
  546.  
  547. OpenDevice() and CloseDevice() are exec functions, but are intercepted by
  548. something called "ramlib.library", which handles the loading and unloading
  549. of disk resident devices and libraries.  Thus the OpenDevice() call may
  550. cause the device to be loaded and initialized, and the CloseDevice() may
  551. cause it to be unloaded.
  552.  
  553. The OpenDevice() eventually results in the initialized device driver being
  554. called through its Open() function (at offset -6 in the jump vector).
  555. This occurs in the context (task) of the calling program.  The device driver
  556. is passed the following information:
  557.  
  558.     D0:  Unit number
  559.     D1:  Flags
  560.     A1:  I/O request pointer
  561.     A6:  Device node pointer
  562.  
  563. The exec will have already cleared the "io_Error" field in the I/O request,
  564. and stored the device node pointer in the "io_Device" field.
  565.  
  566. If the Open() function succeeds, it must initialize the "io_Unit" field
  567. for later uses of the I/O request.  If it fails, it must set the
  568. "io_Error" field to the appropriate number.  The value of the "io_Error"
  569. field on exit is returned by the OpenDevice() function.
  570.  
  571. The device driver should keep track of the number of outstanding opens
  572. using the "lib_OpenCnt" field in its device node.  Some device drivers
  573. can support an arbitrary number of concurrent opens (e.g. disk drivers),
  574. while others can be opened in "exclusive access" modes (e.g. serial ports).
  575.  
  576. The unit number and flags are two 32-bit words whose format is up to
  577. the device driver writer.  For an example unit numbering scheme, see
  578. the include file "devices/scsidisk.h", and for some example uses of the
  579. flag bits, see "devices/serial.h".
  580.  
  581. The CloseDevice() call eventually results in the device driver being
  582. called through its Close() function, at offset -12 in the jump vector.
  583. The I/O request pointer is passed in A1, and the device node pointer in
  584. A6.  The return value determines what happens with the closed device.
  585. If it is zero, the device is kept around.   If it is non-zero, it means
  586. that the device has performed a delayed expunge and wishes to be unloaded.
  587. In this case, the return value is the "segList" parameter which was passed
  588. to the device at initialization time.  More of this in the next section.
  589.  
  590.  
  591. 2.3. EXPUNGING A DEVICE
  592.  
  593. A device can be deleted from the system using this function:
  594.  
  595.     error = RemDevice(device)
  596.     D0                A1
  597.  
  598. The system may issue this function itself, if it runs out of memory and
  599. tries to reclaim space.  Either way, the device is called through its
  600. Expunge() entry point, at offset -18 in the jump vector.  Register A6
  601. is set up to point to the device node.
  602.  
  603. The device should now shut down its activity, i.e. remove interrupt
  604. servers, deallocate buffers, and so on.  Then it should unlink its
  605. device node from the device list, and deallocate the node, thus restoring
  606. things to the state they were in just before it was started up with
  607. InitResident().  Finally, it should return the "segList" parameter which
  608. was passed to it at initialization time.  If the device came from disk,
  609. the system will use this to unload its code.
  610.  
  611. If the device is not idle when the Expunge() call arrives, it can defer the
  612. operation.  To do this, it sets the LIBF_DELEXP flag in the library
  613. structure, and returns zero.  This indicates that it will delete itself
  614. at the earliest opportunity.  When the last Close() call arrives, it
  615. will shut itself down just as described above, and return the segList
  616. value to indicate that it has done so and should be unloaded.
  617.  
  618.  
  619. 2.4. UNIT STRUCTURES
  620.  
  621. Many device drivers manage more than one functional unit.  For example,
  622. the trackdisk driver can handle up to four floppy drives.  The preferred
  623. approach is to use a separate "Unit" structure for each functional unit
  624. (e.g. drive).  Normally, a unit structure consists of at least the following:
  625.  
  626.     struct Unit {
  627.         struct  MsgPort unit_MsgPort;
  628.         UBYTE   unit_flags;
  629.                 /*  UNITF_ACTIVE = 1
  630.                     UNITF_INTASK = 2 */
  631.         UBYTE   unit_pad;
  632.         UWORD   unit_OpenCnt;
  633.     };
  634.  
  635. When the device driver is opened, it uses the unit number to select the
  636. appropriate unit structure, and stores the pointer to this structure in
  637. the I/O request.  Later, it can queue up pending I/O requests on the
  638. message port for processing by the unit task.
  639.  
  640.  
  641. 2.5. THE BEGINIO FUNCTION
  642.  
  643. All I/O requests enter the device driver through the BeginIO() function
  644. in its jump vector.  The device driver is entered in the context of the
  645. requesting task, with A6 pointing to the device node and A1 pointing to
  646. the I/O request structure.
  647.  
  648. Normally, the device driver will now use PutMsg() to enqueue the I/O
  649. request on a message port (in a Unit structure) for processing by an
  650. internal task.  Then it can return from the BeginIO() function.  When
  651. the exec checks to see if the I/O request is completed yet, it checks
  652. its type field, and if it is NT_MESSAGE (as results from the PutMsg()
  653. call) it knows that it is still in progress.  Eventually, the internal
  654. task receives the I/O request, operates on it, and does a ReplyMsg().
  655. This returns the I/O request to the caller's reply port, and also sets
  656. its type to NT_REPLYMSG, signaling that it is finished.
  657.  
  658. It is clear that the device driver does not have to follow this procedure
  659. exactly.  Short commands (such as checking if a disk is ready) can just
  660. be done immediately, in the caller's context.  The I/O request must simply
  661. be returned with ReplyMsg() at the end, and its type field must be
  662. something other than NT_REPLYMSG if the BeginIO() function returns with
  663. the I/O request not completed yet.
  664.  
  665. A special case of I/O processing is signaled by the IOF_QUICK flag.  When
  666. it is set, it means that the requester has used the DoIO() function, and
  667. thus will be doing nothing until the I/O is complete.  In this case, the
  668. device driver can run the whole I/O operation in the caller's context and
  669. return immediately.  Message passing and task switch overhead is eliminated.
  670. When the BeginIO() function returns with the IOF_QUICK bit still set, it
  671. means that the I/O operation is complete.
  672.  
  673. If the device driver sees the IOF_QUICK flag set but cannot perform the
  674. I/O processing inline, it can simply clear the flag and return the I/O
  675. request with ReplyMsg() as usual.
  676.  
  677. The BeginIO() function operates on the command and parameters in the I/O
  678. request, and sets the "io_Error" field to indicate the result.  The exec
  679. I/O functions return the value of this field to the caller; BeginIO() itself
  680. does not return a value.  "io_Error" set to zero means that no error has
  681. occurred.
  682.  
  683.  
  684. 2.6. THE ABORTIO FUNCTION
  685.  
  686. Some device driver operations, such as waiting for a timeout or input on
  687. a serial port, may need to be aborted before they complete.  The AbortIO()
  688. function is provided for this.  The device driver is entered through its
  689. AbortIO() entry point with the address of the I/O request to be aborted
  690. in A1, and the device node pointer in A6.  If the device driver determines
  691. that the I/O request is indeed in progress and can successfully abort it,
  692. it returns zero, otherwise it returns a non-zero error code.
  693.  
  694. A successfully aborted I/O request is returned by the normal method, i.e.
  695. ReplyMsg().  The "io_Error" field should indicate that it did not complete
  696. normally.
  697.  
  698.  
  699. 2.7. EXEC I/O FUNCTIONS
  700.  
  701. The following primitives are provided for communicating with device
  702. drivers.  It is assumed that the driver has been opened with OpenDevice()
  703. and an initialized I/O request exists.
  704.  
  705.     SendIO(iORequest)
  706.            A1
  707.  
  708. This function calls the BeginIO() entry point in the device driver with
  709. IOF_QUICK clear.  This means that the device driver should return the I/O
  710. request with ReplyMsg().
  711.  
  712.     error = DoIO(iORequest)
  713.     D0           A1
  714.  
  715. This function calls the BeginIO() entry point in the device driver with
  716. IOF_QUICK set.  If the device driver leaves IOF_QUICK set, it returns to
  717. the caller immediately.  The return value is the extended value of the
  718. "io_Error" field in the I/O request.  If the IOF_QUICK bit is cleared,
  719. it falls through to WaitIO().
  720.  
  721.     error = WaitIO(iORequest)
  722.     D0             A1
  723.  
  724. This function waits for an I/O request to complete.  If the I/O request
  725. has the IOF_QUICK flag set, it cannot possibly be in progress, so it
  726. returns immediately.  Otherwise, the I/O request will be returned with
  727. ReplyMsg(), and the function proceeds as follows:
  728.  
  729.     Get the signal number from the I/O request's reply port
  730.     Disable()
  731.     WHILE iORequest->io_Message.mn_Node.ln_Type != NT_REPLYMSG DO
  732.         Wait() for the reply port signal
  733.     ENDWHILE
  734.     Unlink the I/O request from the reply port's message queue
  735.     Enable()
  736.  
  737. Finally, it returns "io_Error" from the I/O request, extended to a
  738. longword, as usual.
  739.  
  740.     result = CheckIO(iORequest)
  741.     D0               A1
  742.  
  743. This function checks if the indicated I/O request is complete.  It is
  744. considered complete if its IOF_QUICK bit is set, or if its type is
  745. NT_REPLYMSG.  In this case, the function returns the address of the I/O
  746. request.  If the I/O request is not complete, it returns zero.  This
  747. function does not dequeue the I/O request from the reply port.
  748.  
  749.     error = AbortIO(iORequest)
  750.     D0              A1
  751.  
  752. This function calls the AbortIO() entry point in the device driver, as
  753. discussed earlier.
  754.  
  755.  
  756. 2.8. CALLING BEGINIO DIRECTLY
  757.  
  758. There is one operation which DoIO() and SendIO() cannot handle, and that
  759. is sending an I/O request with the IOF_QUICK flag set, but not waiting
  760. for it to complete.  That is "run this as quickly as possible but if it's
  761. going to take a while, don't wait for it".  For this operation, the
  762. user must set IOF_QUICK manually, then call the device driver directly
  763. through its BeginIO() entry point.  The following C library function
  764. will do the latter:
  765.  
  766.     void BeginIO( ioRequest )
  767.     struct IOStdReq *ioRequest;
  768.  
  769. Since WaitIO() and CheckIO() know about the IOF_QUICK flag, I/O requests
  770. submitted this way can be processed by WaitIO() and CheckIO() as usual.
  771.  
  772.  
  773. 2.8. SYNCHRONOUS I/O
  774.  
  775. Synchronous I/O is done when the caller does not wish to continue until
  776. the I/O operation is complete.  In this case, the caller just sets up
  777. the I/O request and does a DoIO() on it.  When DoIO() returns, the I/O
  778. is complete.
  779.  
  780.  
  781. 2.9. ASYNCHRONOUS I/O
  782.  
  783. Asynchronous I/O is done when the caller wishes to submit an I/O request
  784. and then do other things while it completes.  Such I/O is submitted by
  785. SendIO() or BeginIO() as discussed earlier.  There are a variety of ways
  786. to wait for completion of an asynchronous I/O request; several are discussed
  787. below.
  788.  
  789.  
  790. 2.9.1. WAITING FOR A SPECIFIC I/O REQUEST
  791.  
  792. Waiting for just one specific I/O request is done with the WaitIO()
  793. function.  The function will not return until that particular I/O request
  794. is completed.
  795.  
  796.  
  797. 2.9.2. WAITING ON A SPECIFIC REPLY PORT
  798.  
  799. If a number of I/O requests are outstanding and all will arrive at the
  800. same reply port, then the following can be used:
  801.  
  802.     WHILE I/O requests are outstanding DO
  803.         WaitPort() on the port
  804.         GetMsg() on the port
  805.     ENDWHILE
  806.  
  807.  
  808. 2.9.3. GENERAL CASE
  809.  
  810. Often, a program will be waiting for one of a number of events to occur,
  811. and the only thing these events have in common is that they will set a
  812. signal.  Then the program must get the signal bits from all the I/O reply
  813. ports, merge them with the other signal bits to wait for, and do a Wait()
  814. on the result.  When the Wait() returns with a signal bit set which
  815. corresponds to an I/O reply port, then a GetMsg() can be attempted on
  816. that port to see if an I/O operation has completed.  In this manner,
  817. I/O completions can be handled together with other events in any order.
  818.  
  819.  
  820. 3. GENERIC COMMAND AND ERROR NUMBERS
  821. ------------------------------------
  822.  
  823. This section lists the command and error numbers which are predefined
  824. in the Amiga system for all types of device drivers.
  825.  
  826.  
  827. 3.1. COMMANDS
  828.  
  829. The command number is stored in the "io_Command" field of the I/O request.
  830. The generic command numbers, as found in the include file "exec/io.h", are as
  831. follows:
  832.  
  833.     #define CMD_INVALID 0
  834.     #define CMD_RESET   1
  835.     #define CMD_READ    2
  836.     #define CMD_WRITE   3
  837.     #define CMD_UPDATE  4
  838.     #define CMD_CLEAR   5
  839.     #define CMD_STOP    6
  840.     #define CMD_START   7
  841.     #define CMD_FLUSH   8
  842.  
  843.     #define CMD_NONSTD  9
  844.  
  845. It is seen that command number zero is invalid, and command numbers greater
  846. than 9 are custom defined.  The remaining commands are as follows:
  847.  
  848.  
  849. 3.1.1. CMD_RESET
  850.  
  851. This resets the device to a known initial state.  Pending I/O requests not
  852. processed at the time of this command should be returned with an error.
  853.  
  854.  
  855. 3.1.2. CMD_READ
  856.  
  857. This requests that "io_Length" items of data be read from location
  858. "io_Offset" on the unit, and stored at "io_Data" in the caller's memory.
  859. The actual amount of data transferred is returned in "io_Actual".  The
  860. specifics depend on the device type.
  861.  
  862.  
  863. 3.1.3. CMD_WRITE
  864.  
  865. This requests that data be transferred from the caller's memory
  866. to the I/O unit.  The arguments are the same as for CMD_READ.
  867.  
  868.  
  869. 3.1.4. CMD_UPDATE
  870.  
  871. This requests that all buffered, but unwritten data be forced out
  872. to the I/O unit.  It might write out the track buffer in a disk device,
  873. for example.
  874.  
  875.  
  876. 3.1.5. CMD_CLEAR
  877.  
  878. This requests that all data buffered by the device for the given unit
  879. be invalidated.  Thus, for example, it would throw away data waiting in a
  880. serial input buffer.
  881.  
  882.  
  883. 3.1.6. CMD_STOP
  884.  
  885. This requests that the unit stop processing commands.  I/O requests not
  886. processed at the time of the CMD_STOP will wait until a CMD_START or
  887. CMD_RESET is received or they are aborted.
  888.  
  889.  
  890. 3.1.7. CMD_START
  891.  
  892. This requests that the unit clear a CMD_STOP condition and resume processing
  893. commands.  Only one CMD_START is required, regardless of how many CMD_STOPs
  894. have been received.
  895.  
  896.  
  897. 3.1.8. CMD_FLUSH
  898.  
  899. This requests that the unit flush all pending commands.  All I/O requests
  900. queued but not yet processed should be sent back with an error.
  901.  
  902.  
  903. 3.2. ERROR NUMBERS
  904.  
  905. The include file "exec/errors.h" lists the following standard error numbers.
  906.  
  907.     #define IOERR_OPENFAIL  -1  /* device/unit failed to open */
  908.     #define IOERR_ABORTED   -2  /* request aborted */
  909.     #define IOERR_NOCMD     -3  /* command not supported */
  910.     #define IOERR_BADLENGTH -4  /* not a valid length */
  911.  
  912.  
  913. 4. DISK DEVICE DRIVERS
  914. ----------------------
  915.  
  916. Real device drivers usually support more commands than those listed in
  917. section 3.  This section describes the command set used by disk device
  918. drivers.  This information is needed to write a disk driver compatible
  919. with the existing file systems and disk repair programs.
  920.  
  921. All "normal" disk commands use an I/O request of the structure given earlier.
  922. The "extended" trackdisk commands, which use a larger I/O request, are not
  923. discussed.
  924.  
  925.  
  926. 4.1. COMMANDS
  927.  
  928. The include file "devices/trackdisk.h" lists the following command numbers:
  929.  
  930.     #define TD_MOTOR        (CMD_NONSTD+0)      /*  9 */
  931.     #define TD_SEEK         (CMD_NONSTD+1)      /* 10 */
  932.     #define TD_FORMAT       (CMD_NONSTD+2)      /* 11 */
  933.     #define TD_REMOVE       (CMD_NONSTD+3)      /* 12 */
  934.     #define TD_CHANGENUM    (CMD_NONSTD+4)      /* 13 */
  935.     #define TD_CHANGESTATE  (CMD_NONSTD+5)      /* 14 */
  936.     #define TD_PROTSTATUS   (CMD_NONSTD+6)      /* 15 */
  937.     #define TD_RAWREAD      (CMD_NONSTD+7)      /* 16 */
  938.     #define TD_RAWWRITE     (CMD_NONSTD+8)      /* 17 */
  939.     #define TD_GETDRIVETYPE (CMD_NONSTD+9)      /* 18 */
  940.     #define TD_GETNUMTRACKS (CMD_NONSTD+10)     /* 19 */
  941.     #define TD_ADDCHANGEINT (CMD_NONSTD+11)     /* 20 */
  942.     #define TD_REMCHANGEINT (CMD_NONSTD+12)     /* 21 */
  943.  
  944. Some of these commands are specific to removeable media and/or the
  945. trackdisk.device and need not be supported by a hard disk driver.  More
  946. on this later.  The following sections describe the individual commands.
  947.  
  948.  
  949. 4.1.1. CMD_READ AND CMD_WRITE
  950.  
  951. These are generic commands, but the details are specific to the type of
  952. device.  For disk devices, the "io_Length" and "io_Offset" fields must
  953. be an exact multiple of the sector size supported by the device.  At
  954. present, this is 512 bytes.  The "io_Actual" field could conceivably
  955. return a different value from "io_Length" if an error stopped the operation
  956. part way through.
  957.  
  958.  
  959. 4.1.2. TD_MOTOR
  960.  
  961. This command turns the floppy disk motor on and off.  "io_Length" should
  962. be set to zero to turn it off, or one to turn it on.  "io_Actual" will
  963. return the previous state of the motor.  The motor will turn on automatically
  964. as required, but never off again; thus, the user must issue a TD_MOTOR
  965. command to turn it off.
  966.  
  967.  
  968. 4.1.3. TD_SEEK
  969.  
  970. This command moves the read/write heads to the position indicated in
  971. "io_Offset", which must be an exact multiple of the sector size.  Seeking
  972. is implied in other commands, but this command can be used to "pre-seek"
  973. the device if the needed position is known in advance of the
  974. read/write operation.
  975.  
  976.  
  977. 4.1.4. TD_FORMAT
  978.  
  979. This command takes the same arguments and performs the same operation as
  980. CMD_WRITE, with the following two exceptions:
  981.  
  982.     (a) The area to be written must be a formattable unit, i.e. in the
  983.         trackdisk.device it must be one or more complete tracks.
  984.  
  985.     (b) The area is written with the data regardless of its previous
  986.         contents; it need not already be formatted.
  987.  
  988. This describes the observed behaviour of the trackdisk.device.  The autodoc
  989. for "TD_FORMAT" disagrees with this information.
  990.  
  991. Hard disk drivers typically implement TD_FORMAT as a simple call to
  992. CMD_WRITE.  This allows the hard disk to be "high level formatted" with
  993. the AmigaDOS "format" command.
  994.  
  995. Some ancient SASI/SCSI disk controller boards have a "format track" command,
  996. so a driver targeted specifically at them could implement TD_FORMAT the
  997. same way as the trackdisk.device does.
  998.  
  999.  
  1000. 4.1.5. TD_PROTSTATUS
  1001.  
  1002. If there is a disk in the drive, this command returns "io_Actual" set to
  1003. zero if the disk is writeable, nonzero if protected.  If there is no disk,
  1004. the I/O request returns with the "io_Error" set to "TDERR_DiskChanged".
  1005.  
  1006.  
  1007. 4.1.6. TD_RAWREAD AND TD_RAWWRITE
  1008.  
  1009. These commands read and write whole tracks of raw MFM data on the
  1010. trackdisk.device.  Refer to the autodocs for detailed information.
  1011.  
  1012.  
  1013. 4.1.7. TD_GETDRIVETYPE
  1014.  
  1015. This command is trackdisk.device specific, and returns the type of disk
  1016. drive in "io_Actual".  This is one of the following:
  1017.  
  1018.     1:  3.5", 80 track drive
  1019.     2:  5.25", 40 track drive
  1020.  
  1021.  
  1022. 4.1.8. TD_GETNUMTRACKS
  1023.  
  1024. This command is trackdisk.device specific, and returns the number of tracks
  1025. on the disk unit in "io_Actual".
  1026.  
  1027.  
  1028. 4.1.9. TD_CHANGESTATE
  1029.  
  1030. This command checks to see if there is a disk in a removable-media drive.
  1031. It returns "io_Actual" set to zero if there is, nonzero if there is not.
  1032.  
  1033.  
  1034. 4.1.10. OTHER COMMANDS
  1035.  
  1036. The remaining commands are not described because I am not sufficiently
  1037. familiar with them at this time.  The reader should refer to the appropriate
  1038. autodocs.  In some cases, experimentation with the trackdisk.device will
  1039. be needed to get all the details.
  1040.  
  1041.  
  1042. 4.2. ERROR NUMBERS
  1043.  
  1044. The following error numbers are listed in the include file
  1045. "devices/trackdis.h".
  1046.  
  1047.     #define TDERR_NotSpecified   20 /* general catchall */
  1048.     #define TDERR_NoSecHdr       21 /* couldn't even find a sector */
  1049.     #define TDERR_BadSecPreamble 22 /* sector looked wrong */
  1050.     #define TDERR_BadSecID       23 /* ditto */
  1051.     #define TDERR_BadHdrSum      24 /* header had incorrect checksum */
  1052.     #define TDERR_BadSecSum      25 /* data had incorrect checksum */
  1053.     #define TDERR_TooFewSecs     26 /* couldn't find enough sectors */
  1054.     #define TDERR_BadSecHdr      27 /* another "sector looked wrong" */
  1055.     #define TDERR_WriteProt      28 /* can't write to a protected disk */
  1056.     #define TDERR_DiskChanged    29 /* no disk in the drive */
  1057.     #define TDERR_SeekError      30 /* couldn't find track 0 */
  1058.     #define TDERR_NoMem          31 /* ran out of memory */
  1059.     #define TDERR_BadUnitNum     32 /* asked for a unit > NUMUNITS */
  1060.     #define TDERR_BadDriveType   33 /* not a drive that trackdisk groks */
  1061.     #define TDERR_DriveInUse     34 /* someone else allocated the drive */
  1062.     #define TDERR_PostReset      35 /* user hit reset; awaiting doom */
  1063.  
  1064.  
  1065. 4.3. SCSIDIRECT PROTOCOL
  1066.  
  1067. Most SCSI device drivers support an additional command to issue a generic
  1068. SCSI command.  This is described in detail in the include file
  1069. "devices/scsidisk.h".
  1070.  
  1071.  
  1072. 4.4. A MINIMAL DISK COMMAND SUBSET
  1073.  
  1074. It is clear that to implement a full Amiga disk driver supporting removeable
  1075. media is a considerable task, and I don't even pretend to know all that is
  1076. required.  But if all you want is a simple hard disk driver, a very small
  1077. subset of the commands is sufficient.  To begin with, Expunge() can be
  1078. stubbed out to always return zero, indicating a delayed expunge which will
  1079. never get done.  AbortIO() can be stubbed out to always return a nonzero
  1080. result, indicating that it failed.  Unit structures can be done away with;
  1081. you can store anything in the "io_Unit" field of the I/O request.  In my
  1082. own device driver I just store the SCSI device number and a few flags there.
  1083. You can just return I/O error #20 (general catch-all) for anything that
  1084. went wrong, except possibly unimplemented commands.  Quick I/O need not
  1085. be done; just always clear IOF_QUICK and forget about it.  Send all I/O
  1086. requests to a single internal task for processing.  Finally, the
  1087. commands can be implemented as follows:
  1088.  
  1089.     CMD_READ, CMD_WRITE:        implement fully
  1090.  
  1091.     TD_FORMAT:                  same as CMD_WRITE
  1092.  
  1093.     TD_GETDRIVETYPE:            return 3.5" drive
  1094.  
  1095.     CMD_RESET, CMD_UPDATE,
  1096.     CMD_CLEAR, CMD_STOP,
  1097.     CMD_START, CMD_FLUSH,
  1098.     TD_MOTOR, TD_SEEK,
  1099.     TD_REMOVE, TD_CHANGENUM,
  1100.     TD_CHANGESTATE,
  1101.     TD_PROTSTATUS,
  1102.     TD_ADDCHANGEINT,
  1103.     TD_REMCHANGEINT:            clear "io_Actual" and return
  1104.  
  1105.     Others:                     reject with IOERR_NOCMD
  1106.  
  1107. The resulting driver works perfectly with fast and slow file systems,
  1108. and all the disk edit/repair utilities I've tried it with.  If you are
  1109. bringing up a hard disk from scratch, you can always get a hack driver
  1110. to work, then write a "proper" one with the hard disk running.
  1111.  
  1112.  
  1113. 5. REFERENCES
  1114. -------------
  1115.  
  1116. - 1.3 Include files
  1117.  
  1118. - 1.2 Autodocs
  1119.  
  1120. - Commodore's example disk device driver, from the DevCon 88 disks.
  1121.   Be sure you get the one which launches a task, not the older ones which
  1122.   launch a process.  That doesn't work in an autoboot context.
  1123.  
  1124. - Exec 1.2 disassembly, by myself.  Get it from Fred Fish disk 188.
  1125.  
  1126.  
  1127. 6. REVISION HISTORY
  1128. -------------------
  1129.  
  1130. 0.10  (90/05/20)  Initial version
  1131. 0.11  (90/05/21)  Proofread, minor updates, nicer format
  1132. 0.12  (90/05/21)  Corrected a few typos
  1133.  
  1134.