www.riscos.com Technical Support: |
|
DeviceFS provides a standardised interface to device drivers within the RISC OS environment. Devices are declared within the system, and are seen as objects within the 'devices:' filing system.
Streams can be opened for input or output (as supported) onto these objects within the directory structure. A device is given the device file type of &FCC. A device adopts the access rights relevant to its input or output capabilities.
A device driver is simply a set of routines that handle the input or output of data. The device can specify if it would like to be buffered, but it will never know if this is the case. Devices have access to the special field passed on opening a stream, this can be used to pass extra information about opening streams and configuration required, for instance a serial device may contain its setup within the special field string.
DeviceFS provides a way of calling devices (DeviceFS_CallDevice) with a reason code and control registers. All devices have to support a set of system specific calls, but have a range of reason codes available for their own use. This could, for example, be used for controlling a scanner.
DeviceFS currently only supports character devices; block devices have yet to be implemented.
Most filing system operations can be performed on objects: for example data transfer operations. However, it is not possible to create objects within the directory structure which are not devices, nor is it possible to delete objects.
DeviceFS is not available in RISC OS 2.
Special fields within DeviceFS are commonly used to specify parameters to the device, ie what buffers to be used, if the device should be flushing when a stream is closed and so on.
The device can specify a validation string which is used to parse the special field when the stream is being opened. If this is present then DeviceFS will parse the string and return a block of data relating to the strings contents. This data will remain intact until the stream is closed. If no validation string is specified then it is up to the device to take and manage a copy, also to filter out any unwanted information.
The syntax for validation strings is very simple:
keyword[,keyword]/escape_seq[/escape_seq]...
Keywords are used to associate each command with an escape sequence, there can be more than one keyword associated with a particular escape field, this is provided for two reasons, the first is when a different word has the same meaning, eg. Colour or Color. And secondly when defining the various states for a switch.
The escape sequence describes how the preceding data should be treated and also that to do with the rest of the special field string (up to the next separator).
The following characters are valid in escape sequences:
Within the special field string each parameter is separated by a comma or a character which is out of place, ie a non-numeric in a numerical field. Each keyword within the special field string is separated by a semi-colon.
The buffer passed to the device contains 1 word per escape character, set to &DEADDEAD if the corresponding keyword is not present in the special field string.
Numbers are simply stored into the word; they are decoded using OS_ReadUnsigned and stored away. Switches store the state of the keywords placed, ie:
mike,dennis/S
This yields 0 if 'mike' is present within the string, 1 if 'dennis' is present within the string.
The order of commands within the validation string and the special field string need not match; the commands within the validation string control how the values are returned back to the caller.
R1 = &70 (reason code)
All registers preserved
This call is issued when the module wants the device drivers to re-register with DeviceFS; it is issued during the module initialisation. In this case it is actually issued on a callback to ensure that the module has been correctly linked into the module chain.
R0 = 0
R1 = &71 (reason code)
All registers preserved
This is issued when DeviceFS is about to be killed, the device driver will already have had all of its streams closed and will have received the DeviceFS_DeviceDead service.
R0 = 0
R1 = &79 (reason code)
R2 = handle of device driver
R3 = pointer to device name (if an individual device is being deregistered),
or 0 (if the device driver as a whole is being deregistered)
All registers must be preserved
This is issued to inform a device driver that a specified device has been killed. This is usually caused by another device of the same name being registered, when the original one is therefore killed to stop duplicates.
If a device driver is being deregistered, this service call is issued once for each device using that driver (with R3 pointing to the device name), and is then issued a last time with R3 set to 0.
Opening a device which already has the maximum number of streams open
R1 = &81 (reason code)
R2 = file handle of an open stream on that device
R1 = 0 if the file was closed; otherwise all registers preserved
This service call is issued whenever an attempt is made to open a device for input or output and one of the following applies:
The service call is offered in the hope that one or more 'blocking' streams need no longer be kept open and can be closed, allowing the new stream to be opened.
If your application opened the stream specified by R2, and you no longer need to keep it open, you should close it and then claim the service call to inform DeviceFS that you have done so. Otherwise you should pass on the service call with all registers preserved.
The kernel responds to this service call, because it implicitly opens streams such as the printer and the serial device, which need only be open when actually sending data.
DeviceFS issues this service call for each blocking stream, stopping if sufficient blocking streams have been closed for it to open the new stream, or if this is clearly impossible (eg the service call is not claimed for an output stream that is blocking input to a half-duplex device).
Registers a device driver and its associated devices with DeviceFS
R0 = global flags for devices:
R0 = device driver's handle
This call registers a device driver and its associated devices with DeviceFS. The device driver is the actual interfacing code with the hardware, and the device acts as a port into the driver. A device driver may have many devices within it; for instance you may have devices to support both buffered and unbuffered transfer.
R0 contains a global flags word which describes all the driver's devices. It contains the following bit fields:
An example of a block device is a floppy disc drive, where data is transferred in blocks (sectors) to the caller. Examples of character devices are a parallel port or serial port.
Block devices are not supported under the RISC OS 3 implementation of DeviceFS.
A full duplex device can handle both input and output streams at the same time.
R1 contains a pointer to a list of devices to be associated with this device driver. The list is terminated by a null word, and can be empty as you can use the SWI DeviceFS_RegisterObjects to register devices later. The format of each entry in the list is as follows:
Offset | Meaning |
---|---|
0 | offset to device name |
4 | flags: |
bit 0 set device is buffered | |
bit 1 set create path variable for use as pseudo filing system | |
8 | default flags for the device's RX buffer |
12 | default size of RX buffers |
16 | default flags for the device's TX buffer |
20 | default size of TX buffers |
24 | reserved (must be zero) |
Device names should be registered with Acorn; see Appendix H: Registering names. They are used for several things:
This is used for storing device setup options, and is concatenated with the special field strings when streams are opened.
If the options variable already exists, it is preserved, thus preserving the last setup used for the same device.
The device's buffers are not created until a stream is opened onto it. The flags are passed to the buffer manager; see Buffer_Create.
If for any reason a device in the list should fail to register than all devices specified will be removed.
R2 contains the pointer to the device driver entry point, which is called with various reason codes to access the routines available in the driver. See the chapter entitled Writing a device driver.
R3 and R4 contain parameters which are passed to the device driver whenever its entry point is called. The parameter in R3 is passed to the device driver in R8, and might be used as a private word to indicate which hardware platform is being used; the parameter in R4 is used as a workspace pointer and is passed to the device in R12.
On entry R5 contains the pointer to a validation string used to decode special fields within the device. For a full explanation, see the chapter entitled Special fields.
This value can be 0 which means that the string will be passed to the device unparsed; in these cases any unknown keywords should be ignored, as some keywords used by DeviceFS will still be present.
R6 and R7 contain the maximum number of input and output streams on a device. If a register is zero then the device does not support that operation; if a register is -1 then the device has unlimited support for that type of transfer, and will be called to open streams.
DeviceFS uses these values to range check the number of streams being opened, so the device driver need not worry about this.
You will need to use the returned handle of the device driver to refer to it in any further SWI calls you make to DeviceFS.
Deregisters all devices and their device driver from DeviceFS
R0 = device driver's handle
R0 preserved
This call deregisters all devices and their device driver from DeviceFS. This causes all streams to be closed and any system variables set up for the device to be unset. The exception to this is the DeviceFS$Device$Options variable, which is left intact so that when the device is reloaded it can assume its original setup.
None
R0 = device driver's handle
R1 = pointer to list of devices to be registered with device driver
--
This call registers a list of additional devices with a device driver. This is an extension to the DeviceFS_Register SWI which itself allows devices to be registered at the same time as their device driver.
The list of devices pointed to by R1 has the same format as that used in DeviceFS_Register (see DeviceFS_Register).
None
R0 = device driver's handle
R1 = pointer to device name of the device to remove
--
This call deregisters a device related to a particular device driver, tidying up as required.
None
R0 = reason code
R1 = device driver's handle, or pointer to path, or 0 to broadcast to all devices
R2 - R7 = parameters passed to device driver
R12 = pointer to workspace
Register values returned by device (ie device/call-dependent)
This call is used to make a call to a device with the specified register set. You can direct the call at a specific device or at all devices. When directing a call at a specific device you can specify this either by its device driver's handle, or by its filename within the directory structure (which can include '$').
None
None
Informs DeviceFS of the threshold value to use on buffered devices
R1 = DeviceFS stream handle, as passed to device driver on initialisation
R2 = threshold value to be used, or -1 to read
R1, R2 preserved
This call is made by a device driver to set the threshold value used on buffered devices. DeviceFS will call the device drivers 'Halt' and 'Resume' entry points appropriately when the buffer levels cross the specified threshold.
An error is generated if the device is not buffered.
None
None
Informs DeviceFS that a device driver has received a character
R0 = byte received
R1 = DeviceFS stream handle, as passed to device driver on initialisation
C set byte not transferred, else C clear
This call is made by a device driver when it receives a character. DeviceFS then attempts to process the character as required, unblocking any streams that may be waiting for the character or simply inserting it into a buffer.
For speed, DeviceFS_TransmitCharacter and DeviceFS_ReceivedCharacter do not validate the external handle passed; be warned that some strange effects can occur by passing in bad handles.
The C flag is cleared if the transfer was successful.
None
Informs DeviceFS that a device driver wants to transmit a character
R1 = DeviceFS stream handle, as passed to device driver on initialisation
R0 = character to transmit (8 bits) if C clear
C set unable to read character to be transmitted
This call is made by a device driver when it wants to transmit a character. DeviceFS then attempts to obtain the character to be sent, either by extracting from a buffer or reading it from a waiting stream.
For speed, DeviceFS_TransmitCharacter and DeviceFS_ReceivedCharacter do not validate the external handle passed; be warned that some strange effects can occur by passing in bad handles.
The C flag is cleared if the transfer was successful.