Copyright (c) Hyperion Entertainment and contributors.

NSD Command Specifications

From AmigaOS Documentation Wiki
Revision as of 17:39, 11 April 2013 by Steven Solie (talk | contribs) (Created page with "= Revision = Version 1.6 (1997-05-15) = NSD Command Space = As of January 1st, 1996, Amiga International, Inc. reserves two ranges in the set of command values for future e...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Revision

Version 1.6 (1997-05-15)

NSD Command Space

As of January 1st, 1996, Amiga International, Inc. reserves two ranges in the set of command values for future enhancements. Only commands as specified by Amiga International, Inc. may be used here. It is illegal for a device developer to randomly "add" custom commands or command features in the reserved are!

There are 65536 command values possible with io_Command:

   $0000 - $3FFF       old style and 3rd party commands
   $4000 - $7FFF       RESERVED AREA!
   $8000 - $BFFF       old style and 3rd party commands
   $C000 - $FFFF       RESERVED AREA!

To say it again: Commands in the reserved areas may only be assigned and specified by Amiga International, Inc.. Any "custom" implementation of these commands or other commands in these reserved areas is illegal and violates programming standards!

Design Basis

A device driver is REQUIRED to return IOERR_NOCMD on any command it does not understand. This requirement is very old. It has been documented publically in 1991 already. If the device understands a command but the underlying HW can not handle it, IOERR_NOCMD should not be returned. IOERR_NOCMD should be an indicator for non supported, i.e., non-implemented, commands of the device, not for those that just cannot be executed due to environment constraints.


What will new style commands do for you?

With old style devices it is impossible to find out about the type of device you are accessing. You don't know if the command set is serial.device like or trackdisk like. You don't know either what kind of request structure is appropriate. New style commands will let you query the device for its capabilities. As capabilities are added to a device, device users can use more features transparently without compatibility hacks.

There are two types of new style commands. "General" commands are the same for all new style devices. Depending on the device type there are device specific commands, too.

General commands will be defined in the range $4000-$7FFF, device specific commands are using the range $C000-$FFFF. It is illegal to use a device specific command before using the general commands to confirm the device's capabilities.

With a new style device, you can be sure that no 3rd party command will interact with the standard meaning of all the device's commands as documented for V40 of the OS.


Basic requirements

Let's make a quick list about the most basic requirements for any new style device. Keep it in mind when reading on.

   - IOERR_NOCMD support
   - no redefinition of standard V40 or reserved commands
   - no 3rd party commands in reserved areas
   - NSCMD_DEVICEQUERY is supported
   - lib_IdString must contain the name, version, and creation
     date of the device and any other readable information to make
     unique identification of a device for 3rd party command use
     possible.
   - Check mn_Length of the request on OpenDevice() for the minimum
     required length

Some devices may have additional requirements. These will be listed in the sub document "NSD-DeviceSpecifics".


Device Types

There are various types of devices in the V40 OS. audio.device is substantially different from serial.device, just like input.device is different from a SANA-II device like a2065.device. NSD does not want to describe the semantics behind each type of device. It puts the different V40 command sets needed for different types of devices into useful groups and tags these groups with an NSD device type identifier. This is to make sure that the existing standard V40 command set in each group is not redefined arbitrarily. The NSD device type identifier does not refer to specific functionality. User's of an NSD device must be able to fall back on these standard commands when they are implemented and get results that match usage of the respective V40 devices listed below. When a device is "like" a certain type mentioned, the emphasis is put on the the command set being alike to allow for grouping. Here is an annotated list of NSD device types, naming the respective V40 devices and headers which define the command numbers that may not be redefined if they are implemented.

  1. define NSDEVTYPE_UNKNOWN 0 /* No suitable category, anything */
   Any device that does not fit in a group mentioned below. Think
   hard if you really need this category. Most likely you want an
   exact identification then as described below to make sure what
   you got. This category is dangerous as you can't say anything
   about most of the old style command set without an exact NSD
   identification.
       V40 Command Numbers: 1-8


  1. define NSDEVTYPE_GAMEPORT 1 /* like gameport.device */
   gameport.device     <devices/gameport.h>
       V40 Command Numbers: 1-13


  1. define NSDEVTYPE_TIMER 2 /* like timer.device */
   timer.device        <devices/timer.h>
       V40 Command Numbers: 1-11


  1. define NSDEVTYPE_KEYBOARD 3 /* like keyboard.device */
   keyboard.device     <devices/keyboard.h>
       V40 Command Numbers: 1-13


  1. define NSDEVTYPE_INPUT 4 /* like input.device */
   input.device        <devices/input.h>
       V40 Command Numbers: 1-16


  1. define NSDEVTYPE_TRACKDISK 5 /* like trackdisk.device */
   trackdisk.device    <devices/trackdisk.h>
   scsi.device         <devices/scsidisk.h>
   cd.device           <devices/cd.h>
   mfm.device          similar to <devices/trackdisk.h>
       V40 Command Numbers: 1-23,28-29,32-46,
                            $8002-$8005,$8009-$800B,$8010-$8011


   The command sets of these three devices are sufficiently alike
   to put them under a single label. It is expected that the
   device interface for devices like these converge over time.
  1. define NSDEVTYPE_CONSOLE 6 /* like console.device */
   console.device      <devices/console.h>
       V40 Command Numbers: 1-12


  1. define NSDEVTYPE_SANA2 7 /* A >=SANA2R2 networking device */
   any SANA-II device  <devices/sana2.h> (from the SANA-II archive)
       V40 Command Numbers: 1-26


  1. define NSDEVTYPE_AUDIO 8 /* like audio.device */
   audio.device        <devices/audio.h>
       V40 Command Numbers: 1-14,32


  1. define NSDEVTYPE_CLIPBOARD 9 /* like clipboard.device */
   clipboard.device    <devices/clipboard.h>
       V40 Command Numbers: 1-12


  1. define NSDEVTYPE_PRINTER 10 /* like printer.device */
   printer.device      <devices/printer.h>
       V40 Command Numbers: 1-12


  1. define NSDEVTYPE_SERIAL 11 /* like serial.device */
   serial.device       <devices/serial.h>
       V40 Command Numbers: 1-11


  1. define NSDEVTYPE_PARALLEL 12 /* like parallel.device */
   parallel.device     <devices/parallel.h>
       V40 Command Numbers: 1-10


The meaning of "No Command Redefinition"

An NSD device of a certain type is not allowed to redefine any V40 command or any command from the NSD reserved ranges. Each NSD device type as described above groups the corresponding V40 devices with similar command sets. Each of these devices has an established, documented, and implemented set of commands with documented meaning. An NSD device must always handle all these commands, if implemented, like the respective V40 device or like the set of V40 devices for that NSD device type. It is not acceptable if a CMD_READ suddenly turns into functionality of CMD_WRITE or if HD_SCSICMD will suddenly be like a TD_EJECT. If you find, e.g., HD_SCSICMD or CD_INFO in the supported command list of a NSDEVTYPE_TRACKDISK device, you shall be sure that these commands behave like the V40 commands of the respective devices would behave. Note that if you find one command supported for an NSD device type, this does not mean that other commands for that NSD device type are necessarily supported. Check for the command set that you need.

For the common eight usable Exec standard commands, intentionally no distinction is made between different V40 devices which may fall under the same NSD device type. The device I/O operations should be consistent and uniform according to the RKM and NSD does not try to differentiate between possible execution differences for the Exec standard commands. Because of this requirement for consistency and uniformity, the standard Exec commands obviously may not be redefined arbitrarily either. If an Exec standard command is implemented in a device, the implementation must not deviate from the specification for that device type or common usage for that command.

All command slots that are not part of the V40 command set for the respective devices under the NSD device types or of the reserved NSD areas are free to be used for 3rd party extensions. NSD neither defines nor restricts their usage. From the NSD perspective, the meaning of any implemented 3rd party command is undefined. The user software is responsible for an exact device identification then to use 3rd party commands safely via the device's lib_IDString as described below.

General commands

At the moment there is just a single new style general command:

  1. define NSCMD_DEVICEQUERY 0x4000

It is required for all new style devices.

You set up io_Data and io_Length pointing to a struct NSDeviceQueryResult below. You must clear SizeAvailable and set up DevQueryFormat before sending the command to the device. A new style device will set up the data in the buffer appropriately. If the command executed successfully the returned io_Actual value must be greater than zero and equal to the SizeAvailable value that has been set by the device. As with device usage in general, an io_Actual value that is alrger than the passed in io_Length value should be considered an error. The device may only be considered a new style device if these conditions are met. And only in this case the results of the query may be considered valid.

struct NSDeviceQueryResult {

   /*
   ** Standard information
   */
   ULONG   DevQueryFormat;         /* this is type 0               */
   ULONG   SizeAvailable;          /* bytes available              */
   /*
   ** Common information (READ ONLY!)
   */
   UWORD   DeviceType;             /* what the device does         */
   UWORD   DeviceSubType;          /* depends on the main type     */
   UWORD   *SupportedCommands;     /* 0 terminated list of cmd's   */
   /* May be extended in the future! Check SizeAvailable! */

};

The device will fill in the struct NSDeviceQueryResult with read only data for the caller. All data must remain constant and valid as long as the device is open. After CloseDevice(), all bets are off.

   SizeAvailable
       Tells you how much of the structure contains valid data. It
       is measured in bytes. Do not try to use fields in the
       structure that are not fully included in the SizeAvailable
       range. SizeAvailable must include SupportedCommands for any
       successful query. So the minimum valid value is 16.
   DeviceType
       This tells you about the NSD type of device you are
       accessing. The type names often match existing devices in
       AmigaOS. If a device returns such a type, the device must
       be able to at least handle all the documented features for
       V40 of the operating system that the respective original
       device has. If the NSD device type refers to a group of V40
       devices, at least the basic command subset as for the
       device named by the NSD device type shall be handled.
       Note well that while all the documented features for an
       implemented command shall be handled, it is permissible
       to return error codes or appropriate dummy returns for non
       existing features in the NSD device as long as the handling
       conforms to the original specification.
       If an old style or new style command cannot be supported in
       a compatible manner, the device is required to return
       IOERR_NOCMD for safety reasons. Modification of the
       specification is not allowed. Add a 3rd party command if
       needed.
       It is illegal to "reuse" command numbers of documented
       standard commands that cannot be supported for other
       purposes. E.g. a device driver of type NSDEVTYPE_TRACKDISK
       that does not support TD_GETGEOMETRY and uses this command
       for different functionality can never be a new style device
       and may not support new style commands.
       It is also illegal to use the results of an
       NSCMD_DEVICEQUERY without testing DeviceType first.
       The NSD device types are listed and explained above in the
       section "Device Types".
       More types will be defined by Amiga International, Inc. as
       necessary and requested. Each NSD device type represents a
       certain command set that the device must handle. If the
       type does not match a device that does exist in OS V40, the
       exact requirements are defined below or in
       "NSD-DeviceSpecifics". Note that some DeviceType entries
       may cover multiple types of devices, so you have to check
       the documentation carefully, when considering the standard
       command set for a specific type.
   DeviceSubType
       There might be special incarnations of a device with
       special capabilities beyond the standard set. At the moment
       none are defined and a device is required to return 0 here.
       As extensions that are marked by this field have to be
       upwards compatible, this field need not be tested by users
       who don't need any special capabilities beyond the standard
       set. Otherwise it must be tested first.
   SupportedCommands
       This points to a 0 terminated list of io_Command values
       that are supported by the device. This list must contain
       all legal command values, old style, new style, and special
       3rd party commands that are understood by the device and do
       not cause an IOERR_NOCMD right away.


You might notice the similarity to the SANA2-R2 (S2R2) S2_DEVICEQUERY command. It is intentional.

If you are developing software that needs to use 3rd party commands, you must try an *exact* 3rd party device identification via the lib_IdString in the device base and reject all devices that you don't know for a new style device.


New Style Check in C

A code fragment that could help you set up a new device query follows.

   struct IOStdReq *io;
   struct NSDeviceQueryResult nsdqr;
   LONG error;
   BOOL newstyle = FALSE;
   BOOL does64bit = FALSE;
   BOOL doesETD64bit = FALSE;
   UWORD *cmdcheck;
   struct MsgPort *replyport;
   ...
   /* See important *CAVEAT* below! */
   io = CreateIORequest(replyport, sizeof(struct IOStdReq) + 128);
   /* Add error checking in production code! */
   ...
   nsdqr.SizeAvailable  = 0;
   nsdqr.DevQueryFormat = 0;
   io->io_Command = NSCMD_DEVICEQUERY;
   io->io_Length  = sizeof(nsdqr);
   io->io_Data    = (APTR)&nsdqr;
   error = DoIO((struct IORequest *)io);
   if((!error) &&
      (io->io_Actual >= 16) &&
      (io->io_Actual <= sizeof(nsdqr)) &&
      (nsdqr.SizeAvailable == io->io_Actual))
   {
       /* Ok, this must be a new style device */
       newstyle = TRUE;
       /* Device specific code follows here */
       if(nsdqr.DeviceType == NSDEVTYPE_TRACKDISK)
       {
           /* Is it safe to use 64 bits with this driver? We can reject
            * bad mounts pretty easily via this check!
            */
           for(cmdcheck = nsdqr.SupportedCommands;
               *cmdcheck;
               cmdcheck++)
           {
               if(*cmdcheck == NSCMD_TD_READ64)
               {
                   /* This trackdisk style device supports the basic
                    * 64 bit command set without returning IOERR_NOCMD!
                    */
                   does64bit = TRUE;
               } /* if */
               if(*cmdcheck == NSCMD_ETD_READ64)
               {
                   /* This trackdisk style device supports the extended
                    * 64 bit command set without returning IOERR_NOCMD!
                    * According to specs, this implies does64bit == TRUE!
                    */
                   doesETD64bit = TRUE;
               } /* if */
           } /* for */
       } /* if */
   } /* if */


      • CAVEAT ***: There are some noteworthy points about this code fragment:

The check of io_Actual filters out anything that is obviously wrong. An NSD device may not return less than the minimum query structure and of course it may not try to return more than the buffer space available.

Error checking for request allocation has been left out for brevity. Obviously, production code should contain decent error checking code.

This code fragment uses a pointer to a struct IOStdReq to do the checks. Unfortunately, using a request of this size may result in severe problems with certain devices like SANA-II devices, which need a larger request structure. A current device should at minimum check in its OpenDevice() code if the passed in request is of at least the minimum required size to work with via its mn_Length field and fail to open if it isn't. This is a simple but effective paranoia check with the effect that surely broken request structures will be rejected right away. Unfortunately most devices don't do that check. Two basic assumptions can be relevant here:

   1. The trusting assumption
       You simply use the type and size of request structure
       appropriate for the type of device you intend to use and
       assume that the user did not give you the wrong type
       of device. This may fail and result in a system crash.
   2. The safer assumption
       You use the type of request for the device type your are
       expecting (or an IOStdReq for a general check) with an
       extra 128 zeroed bytes when opening and checking a device.
       This will be very safe as current devices are required to
       check the minimum request length before opening
       successfully. So any wrong type of device will not cause
       problems here unless it both
           - uses a really strange long request that is
             referenced on OpenDevice() time
       and
           - does not implement the required mn_Length check
       You only need that one larger request for the check on
       opening the device. Afterwards you know what you are
       working with and can use reasonably sized requests.

Obviously we cannot approve of the trusting assumption, because device access should be as safe as possible. So we require you to implement the safer assumption. Again, the basic idea behind this is that you should always strive to make device access as safe as possible. Some little things like validating the request structure on OpenDevice() will increase stability of the device system a lot at hardly any extra cost. Play it as safe as you can. The user might have some messed up code accessing the device!

It is wise to avoid writing devices that need arguments set up in the request structure for an OpenDevice() call. If you have to write a device like this, validate the request structure well and fail gracefully if you don't find the arguments needed.

It is valid and strongly suggested behaviour for a device to reject all new style commands except NSCMD_DEVICEQUERY with IOERR_NOCMD unless the caller executed a valid and successful NSCMD_DEVICEQUERY at least once before. This is intentionally stretching the meaning of IOERR_NOCMD to protect old software.

Recommended use

Anyone who wants to take advantage of the new style device interface should do this:

   - OpenDevice() as described above
   - Try a NSCMD_DEVICEQUERY as described above
   - If successful according to the rules mentioned above,
     use the commands as listed in "SupportedCommands".
   - Otherwise it must be an old style device. Hope and pray that
     you got what you wanted.

Note: The above description and the code fragment shown assumes that you use OpenDevice() with a freshly created and appropriately initialised request structure. If you intend to reuse a previously used request structure for another OpenDevice() to make a general query, you should set at least the following fields to zero before calling OpenDevice(): io_Actual, io_Length, io_Data, io_Offset. It is strongly recommended to always do a query with a freshly set up request structure.

Old Style and/or 3rd party vs. NSD

NSD conforming devices may only be identified via NSCMD_DEVICEQUERY. NSD does not make any judgements about old style devices or their usage. NSD does not make any judgements about 3rd party features within the NSD framework. If NSD is not available in a device, you are free to use other functionality as you see fit for the underlying old style device. If an NSD feature is not available, you are free to use other functionality not conflicting with the NSD specification.