What is this about?
===================

Up to and including OS 3.1 (V40), custom device commands usually
started at CMD_NONSTD. Each developer added commands for custom
device features freely. This lead to messy and incompatible
devices and strange compatibility tricks to identify device
capabilities.

As of January 1st, 1996, Amiga International reserves two ranges in
the set of command values for future enhancements. Only commands as
specified by Amiga International 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. Any "custom"
implementation of these commands or other commands in these
reserved areas is illegal and violates programming standards!

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.

Commands in the reserved ranges are called "new style". A device
that supports new style commands correctly as described in this
document is called a "new style device".


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 it is serial.device
like or a trackdisk style device. 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.

Some devices may have additional requirements. These will be listed
below.


General commands
================

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

#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. 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
        strutcure 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 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 an old style or new style command can not 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 that does not support
        TD_GETGEOMETRY and uses it for something else 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.

#define NSDEVTYPE_UNKNOWN       0   /* No suitable category, anything */
#define NSDEVTYPE_GAMEPORT      1   /* like gameport.device */
#define NSDEVTYPE_TIMER         2   /* like timer.device */
#define NSDEVTYPE_KEYBOARD      3   /* like keyboard.device */
#define NSDEVTYPE_INPUT         4   /* like input.device */
#define NSDEVTYPE_TRACKDISK     5   /* like trackdisk.device */
#define NSDEVTYPE_CONSOLE       6   /* like console.device */
#define NSDEVTYPE_SANA2         7   /* A >=SANA2R2 networking device */
#define NSDEVTYPE_AUDIOARD      8   /* like audio.device */
#define NSDEVTYPE_CLIPBOARD     9   /* like clipboard.device */
#define NSDEVTYPE_PRINTER       10  /* like printer.device */
#define NSDEVTYPE_SERIAL        11  /* like serial.device */
#define NSDEVTYPE_PARALLEL      12  /* like parallel.device */

        More types will be defined by Amiga International as
        necessary and requested. Each device type represents a
        certain set of minimum capabilities that the device must
        support. If the type does not match a device that does
        exist in OS V40, the exact requirements are defined below.

    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, special
        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* device identification via the
lib_IdString in the device base and reject all devices that you
don't know for a new style device.

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;
    UWORD *cmdcheck;

    ...
    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) &&
       (nsdqr.SizeAvailable == io->io_Actual) &&
       (nsdqr.DeviceType == NSDEVTYPE_TRACKDISK))
    {
        /* Ok, this must be a new style trackdisk device */
        newstyle = TRUE;

        /* 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 complete
                 * 64 bit command set without returning IOERR_NOCMD!
                 */
                does64bit = TRUE;
            } /* if */
        } /* for */
    } /* if */



Device specific requirements
============================

Depending on the type returned by NSCMD_DEVICEQUERY, a device may
support device specific commands in the $c000-$ffff range.

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.

There is also a minimum list of requirements for some types of
devices.

If a device type is not listed below, no device specific commands
are defined for it at this time. The device might still support
special custom 3rd party commands outside the reserved range,
though. If a device type is listed below, the device driver must
conform to the mentioned specifications. A new style device
specific command may possibly match an old style extended command
exactly to avoid future identification troubles or code
misunderstanding.


Device specific commands and behaviour
--------------------------------------

NSDEVTYPE_TRACKDISK

    May support all V40 trackdisk.device commands and
    possibly HD_SCSICMD as scsidisk.device is obviousy a trackdisk
    like driver. If it doesn't, IOERR_NOCMD must be returned for
    the respective command. 3rd party commands may be added in
    slots that don't conflict with the V40 command set or the
    reserved areas.

    A new style trackdisk like device *must* also return this
    new identifier for TD_GETDRIVETYPE. You should use
    TD_GETGEOMETRY on a new style driver to obtain geometry hints
    if needed.

        #define DRIVE_NEWSTYLE  (0x4E535459L)   /* 'NSTY' */


    At the moment, only four new style commands in the device
    specific range may be implemented.

    #define NSCMD_TD_READ64     0xc000
    #define NSCMD_TD_WRITE64    0xc001
    #define NSCMD_TD_SEEK64     0xc002
    #define NSCMD_TD_FORMAT64   0xc003

        These commands behave almost like the trackdisk commands
        CMD_READ, CMD_WRITE, TD_FORMAT, respectively, but support 64
        bit handling for large storage devices. The upper 32 bits,
        bit 32 to 63, need to be put into io_Actual before the
        commands are executed. io_Actual can be named io_HighOffset
        in that case.

        If you choose to implement the 64 bit commands, you must
        implement all of them, even if some of them would possibly
        return dummy results. A partial implementation with some 64
        bit commands returning IOERR_NOCMD is not acceptable.

        A detailed description of the 64 bit commands can be found
        in the document "trackdisk64". Implementors are required to
        read this document.


Recommended use
===============

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

    - OpenDevice() as usual
    - Try a NSCMD_DEVICEQUERY
    - 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.

*** EOT ***

Heinz Wrobel
<heinz@amiga.de>
