Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "NSD Command Specifications"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
 
(7 intermediate revisions by the same user not shown)
Line 34: Line 34:
 
Let's make a quick list about the most basic requirements for any new style device. Keep it in mind when reading on.
 
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
+
# IOERR_NOCMD support
- no redefinition of standard V40 or reserved commands
+
# No redefinition of standard V40 or reserved commands
- no 3rd party commands in reserved areas
+
# No 3rd party commands in reserved areas
- NSCMD_DEVICEQUERY is supported
+
# NSCMD_DEVICEQUERY is supported
- lib_IdString must contain the name, version, and creation
+
# 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
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".
 
   
  +
Some devices may have additional requirements. These will be listed in [[NSD_Device_Specifics|NSD Device Specifics]].
   
 
= Device Types =
 
= 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.
+
There are various types of devices in AmigaOS. 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.
   
#define NSDEVTYPE_UNKNOWN 0 /* No suitable category, anything */
+
; 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.
Any device that does not fit in a group mentioned below. Think
 
  +
: V40 Command Numbers: 1-8
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.
 
   
  +
; NSDEVTYPE_GAMEPORT (1) like gameport.device
V40 Command Numbers: 1-8
 
  +
: gameport.device <devices/gameport.h>
  +
: V40 Command Numbers: 1-13
   
  +
; NSDEVTYPE_TIMER (2) like timer.device
  +
: timer.device <devices/timer.h>
  +
: V40 Command Numbers: 1-11
   
#define NSDEVTYPE_GAMEPORT 1 /* like gameport.device */
+
; NSDEVTYPE_KEYBOARD (3) like keyboard.device
gameport.device <devices/gameport.h>
+
: keyboard.device <devices/keyboard.h>
  +
: V40 Command Numbers: 1-13
   
  +
; NSDEVTYPE_INPUT (4) like input.device
V40 Command Numbers: 1-13
 
  +
: input.device <devices/input.h>
  +
: V40 Command Numbers: 1-16
   
  +
; 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.
#define NSDEVTYPE_TIMER 2 /* like timer.device */
 
timer.device <devices/timer.h>
 
   
  +
; NSDEVTYPE_CONSOLE (6) like console.device
V40 Command Numbers: 1-11
 
  +
: console.device <devices/console.h>
  +
: V40 Command Numbers: 1-12
   
  +
; NSDEVTYPE_SANA2 (7) A >=SANA2R2 networking device
  +
: any SANA-II device <devices/sana2.h>
  +
: V40 Command Numbers: 1-26
   
#define NSDEVTYPE_KEYBOARD 3 /* like keyboard.device */
+
; NSDEVTYPE_AUDIO (8) like audio.device
keyboard.device <devices/keyboard.h>
+
: audio.device <devices/audio.h>
  +
: V40 Command Numbers: 1-14,32
   
  +
; NSDEVTYPE_CLIPBOARD (9) like clipboard.device
V40 Command Numbers: 1-13
 
  +
: clipboard.device <devices/clipboard.h>
  +
: V40 Command Numbers: 1-12
   
  +
; NSDEVTYPE_PRINTER (10) like printer.device
  +
: printer.device <devices/printer.h>
  +
: V40 Command Numbers: 1-12
   
#define NSDEVTYPE_INPUT 4 /* like input.device */
+
; NSDEVTYPE_SERIAL (11) like serial.device
input.device <devices/input.h>
+
: serial.device <devices/serial.h>
  +
: V40 Command Numbers: 1-11
 
V40 Command Numbers: 1-16
 
 
 
#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.
 
 
#define NSDEVTYPE_CONSOLE 6 /* like console.device */
 
console.device <devices/console.h>
 
 
V40 Command Numbers: 1-12
 
 
 
#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
 
 
 
#define NSDEVTYPE_AUDIO 8 /* like audio.device */
 
audio.device <devices/audio.h>
 
 
V40 Command Numbers: 1-14,32
 
 
 
#define NSDEVTYPE_CLIPBOARD 9 /* like clipboard.device */
 
clipboard.device <devices/clipboard.h>
 
 
V40 Command Numbers: 1-12
 
 
 
#define NSDEVTYPE_PRINTER 10 /* like printer.device */
 
printer.device <devices/printer.h>
 
 
V40 Command Numbers: 1-12
 
 
 
#define NSDEVTYPE_SERIAL 11 /* like serial.device */
 
serial.device <devices/serial.h>
 
 
V40 Command Numbers: 1-11
 
 
 
#define NSDEVTYPE_PARALLEL 12 /* like parallel.device */
 
parallel.device <devices/parallel.h>
 
 
V40 Command Numbers: 1-10
 
 
   
  +
; NSDEVTYPE_PARALLEL (12) like parallel.device
  +
: parallel.device <devices/parallel.h>
  +
: V40 Command Numbers: 1-10
   
 
= The meaning of "No Command Redefinition" =
 
= The meaning of "No Command Redefinition" =
Line 148: Line 108:
 
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.
 
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
+
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.
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
+
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.
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 =
 
= General commands =
Line 158: Line 116:
 
At the moment there is just a single new style general command:
 
At the moment there is just a single new style general command:
   
  +
<syntaxhighlight>
 
#define NSCMD_DEVICEQUERY 0x4000
 
#define NSCMD_DEVICEQUERY 0x4000
  +
</syntaxhighlight>
   
 
It is required for all new style devices.
 
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
+
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.
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.
 
   
  +
<syntaxhighlight>
 
struct NSDeviceQueryResult
 
struct NSDeviceQueryResult
 
{
 
{
Line 182: Line 142:
 
/* May be extended in the future! Check SizeAvailable! */
 
/* May be extended in the future! Check SizeAvailable! */
 
};
 
};
  +
</syntaxhighlight>
   
 
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.
 
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
+
; 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
Tells you how much of the structure contains valid data. It
 
  +
: 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.
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.
 
   
  +
: 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.
DeviceType
 
   
  +
: 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.
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.
 
   
  +
: 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.
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.
 
   
  +
: It is also illegal to use the results of an NSCMD_DEVICEQUERY without testing DeviceType first.
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.
 
   
  +
: The NSD device types are listed and explained above in the section "Device Types".
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.
 
   
  +
: More types will be defined by the AmigaOS Development Team 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_Device_Specifics|NSD Device Specifics]]. 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.
It is also illegal to use the results of an
 
NSCMD_DEVICEQUERY without testing DeviceType first.
 
   
  +
; DeviceSubType
The NSD device types are listed and explained above in the
 
section "Device Types".
 
   
  +
: 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.
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.
 
   
  +
; SupportedCommands
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.
 
   
  +
: 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.
 
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.
+
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 =
 
= New Style Check in C =
Line 267: Line 180:
 
A code fragment that could help you set up a new device query follows.
 
A code fragment that could help you set up a new device query follows.
   
  +
<syntaxhighlight>
 
struct IOStdReq *io;
 
struct IOStdReq *io;
 
struct NSDeviceQueryResult nsdqr;
 
struct NSDeviceQueryResult nsdqr;
Line 278: Line 192:
 
...
 
...
 
/* See important *CAVEAT* below! */
 
/* See important *CAVEAT* below! */
  +
io = IExec->AllocSysObjectTags(ASOT_IOREQUEST,
io = CreateIORequest(replyport, sizeof(struct IOStdReq) + 128);
 
  +
ASOIOR_ReplyPort, replyport,
  +
ASOIOR_Size, sizeof(struct IOStdReq) + 128,
  +
TAG_END);
 
/* Add error checking in production code! */
 
/* Add error checking in production code! */
   
Line 289: Line 206:
 
io->io_Length = sizeof(nsdqr);
 
io->io_Length = sizeof(nsdqr);
 
io->io_Data = (APTR)&nsdqr;
 
io->io_Data = (APTR)&nsdqr;
error = DoIO((struct IORequest *)io);
+
error = IExec->DoIO((struct IORequest *)io);
 
if((!error) &&
 
if((!error) &&
 
(io->io_Actual >= 16) &&
 
(io->io_Actual >= 16) &&
Line 327: Line 244:
 
} /* if */
 
} /* if */
 
} /* if */
 
} /* if */
  +
</syntaxhighlight>
   
  +
'''CAVEAT'''
   
*** CAVEAT ***: There are some noteworthy points about this code fragment:
+
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.
 
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.
Line 335: Line 254:
 
Error checking for request allocation has been left out for brevity. Obviously, production code should contain decent error checking code.
 
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
+
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
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:
 
  +
:: 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.
 
1. The trusting assumption
+
: 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:
 
  +
:: a) uses a really strange long request that is referenced on OpenDevice() time
You simply use the type and size of request structure
 
  +
::: and
appropriate for the type of device you intend to use and
 
  +
:: b) does not implement the required mn_Length check
assume that the user did not give you the wrong type
 
  +
:: 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.
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!
 
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!
Line 376: Line 274:
 
Anyone who wants to take advantage of the new style device interface should do this:
 
Anyone who wants to take advantage of the new style device interface should do this:
   
- OpenDevice() as described above
+
# OpenDevice() as described above
- Try a NSCMD_DEVICEQUERY as described above
+
# Try a NSCMD_DEVICEQUERY as described above
- If successful according to the rules mentioned 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.
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.
 
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.

Latest revision as of 19:42, 11 April 2013

Revision

Version 1.7 (2013-04-11)

NSD Command Space

The AmigaOS Development Team reserves two ranges in the set of command values for future enhancements. Only commands as specified by the AmigaOS Development Team 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 the AmigaOS Development Team. 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 publicly in 1991 already. If the device understands a command but the underlying hardware 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.

  1. IOERR_NOCMD support
  2. No redefinition of standard V40 or reserved commands
  3. No 3rd party commands in reserved areas
  4. NSCMD_DEVICEQUERY is supported
  5. 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.
  6. Check mn_Length of the request on OpenDevice() for the minimum required length

Some devices may have additional requirements. These will be listed in NSD Device Specifics.

Device Types

There are various types of devices in AmigaOS. 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.

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
NSDEVTYPE_GAMEPORT (1) like gameport.device
gameport.device <devices/gameport.h>
V40 Command Numbers: 1-13
NSDEVTYPE_TIMER (2) like timer.device
timer.device <devices/timer.h>
V40 Command Numbers: 1-11
NSDEVTYPE_KEYBOARD (3) like keyboard.device
keyboard.device <devices/keyboard.h>
V40 Command Numbers: 1-13
NSDEVTYPE_INPUT (4) like input.device
input.device <devices/input.h>
V40 Command Numbers: 1-16
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.
NSDEVTYPE_CONSOLE (6) like console.device
console.device <devices/console.h>
V40 Command Numbers: 1-12
NSDEVTYPE_SANA2 (7) A >=SANA2R2 networking device
any SANA-II device <devices/sana2.h>
V40 Command Numbers: 1-26
NSDEVTYPE_AUDIO (8) like audio.device
audio.device <devices/audio.h>
V40 Command Numbers: 1-14,32
NSDEVTYPE_CLIPBOARD (9) like clipboard.device
clipboard.device <devices/clipboard.h>
V40 Command Numbers: 1-12
NSDEVTYPE_PRINTER (10) like printer.device
printer.device <devices/printer.h>
V40 Command Numbers: 1-12
NSDEVTYPE_SERIAL (11) like serial.device
serial.device <devices/serial.h>
V40 Command Numbers: 1-11
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:

#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 the AmigaOS Development Team 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 Device Specifics. 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 = IExec->AllocSysObjectTags(ASOT_IOREQUEST,
        ASOIOR_ReplyPort, replyport,
        ASOIOR_Size, sizeof(struct IOStdReq) + 128,
        TAG_END);
    /* 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 = IExec->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:
a) uses a really strange long request that is referenced on OpenDevice() time
and
b) 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:

  1. OpenDevice() as described above
  2. Try a NSCMD_DEVICEQUERY as described above
  3. If successful according to the rules mentioned above, use the commands as listed in "SupportedCommands".
  4. 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.