Logo (click for homepage)
BlockDriver Module Specification
Version 0.11 - updated 21 December 2017

This page explains the use of the BlockDriver Module that is part of the current distribution of the BlockDrivers. Its intention is to make writing a BlockDriver much easier. In fact, when your device is known by DeviceFS, the module can do most of the work for you. The module is located inside !SerialDev and will be loaded into memory when it is first seen by the filer. !SerialDev is usually installed in !Boot.Resources. The use of the Module is not mandatory, but is strongly advised.

If your interface software is implemented as a DeviceFS device, and is visible in Resources:$, the BlockDriver Module knows how to address it, which makes the implementation of a BlockDriver a lot easier. But even if it does not support DeviceFS, the module provides some useful utilities that can help to improve your work. If you have written your own driver, which is not available through DeviceFS, you are advised to register it as a fake device with the BlockDriver Module, so that it can keep track of it. This allows a monitoring application, such as !Serial, to show its status.

BlockDriver module
The BlockDriver Module provides an Application Programmers Interface (API) for developers of a BlockDriver. The main interface is through a series of SWI calls that are explained in more detail below. In addition there are several *-commands that can be accessed from the command line. For each port that is handled or monitored, the module allocates a Channel. When registering a port, a pointer to the channel's workspace is returned, which should be quoted in all further calls.

SWI Calls
All SWI calls have a (registered) offset of 0x56F00. This offset has been omitted in the tables below, in order to improve readability. The SWIs can also be called by their names.
0   BlockDriver_Register
1   BlockDriver_Deregister
2   BlockDriver_PutByte
3   BlockDriver_GetByte
4   BlockDriver_ExamineByte
5   BlockDriver_PutBlock
6   BlockDriver_GetBlock
7   BlockDriver_CheckTXBuffer
8   BlockDriver_CheckRXBuffer
9   BlockDriver_FlushTXBuffer
10   BlockDriver_FlushRXBuffer
11   BlockDriver_ControlLines
12   BlockDriver_ReadRXErrors
13   BlockDriver_SendBreak
14   BlockDriver_BaudRateTX
15   BlockDriver_BaudRateRX
16   BlockDriver_DataFormat
17   BlockDriver_Handshaking
18   BlockDriver_EnumerateBaudRates
19   BlockDriver_GetInfo
20   BlockDriver_SetInfo
21   BlockDriver_Platform
22   BlockDriver_Devices

Command line
In addition, the following *-commands are available:

  • BDinfo
  • BDclose
  • BDspeed
Errors
All errors have a (registered) offset of 0x56F00. This offset has been omitted in the tables below, in order to improve readability.
0   Address in r6 is out of bounds
1   Channel not in use
2   File already closed
3   Can't open stream,
4   Too many open channels

SWI calls in more detail
BlockDriver_Register   0x56F00
This call is used to register a BlockDriver with the BlockDriver Module. Although registering is not mandatory, it is strongly advised. It claims the port for the current application and will reject any further clients. BlockDrivers should only register them­selves, when they are actually going to be used by the parent application, which is when they are called through Device_Initialise with a valid port number in r1. When the parent application calls Device_Initialise with r1 = -1 (pre-initialise), the driver should not register itself with the module.

Entry
r0   → Device name (as known by DeviceFS, e.g. 'Serial1')
r1   → Special field (or 0 if not used)
r2   Initialisation flags (see below)
r3   → Device description (or 0 if not used)
r4   Driver number (as allocated by us)
r5   Port number (or 0 if not used)

Exit
r0   Error (0 if successful, otherwise → to error block)
r1   → Channel block 1
r2   RX file handle
r3   TX file handle
r4   RX buffer handle
r5   TX buffer handle

Initialisation flags (r2 on entry)
0   Shared device
1   Fake device 2
2   Statistics
3   NoBuffer
4   Removable
5   Location
6   Serno
7-31   Reserved for future expansion

Possible errors
3   Can't open stream,
4   Too many open channels

  1. Channel block is a pointer to an internal structure that is used by the module, to keep track of each allocated channel. Your driver should remember this pointer and specify it in all further calls to the module.
  2. A device should register itself as a Fake device, if it does not provide an interface through DeviceFS. This means that the BlockDriver module can not handle the device on your behalf. In such cases you should fully implement your own driver, and call the module only to keep it informed of any status changes.


BlockDriver_Deregister   0x56F01
You driver should call this entry when the interface is not longer needed by the parent application. Although registering is not mandatory, once the driver has been registered, it must be deregistered when it is no longer needed, as otherwise the port will not be available to any future clients. The module will close any open files/streams on your behalf.

Entry
r0   Close flags (see below)
r6   → Channel block

Exit
r0   Error (0 if successful, otherwise → to error block)

Close flag bits (r0 on entry)
0   Force close down

Possible errors
0   Address in r6 is out of bounds
1   Channel not in use
2   File already closed

BlockDriver_PutByte   0x56F02
This can can be used to send a single byte to the output file (i.e. the selected port). The entry Driver_PutByte of your BlockDriver can call this SWI directly. Even if you are handling the device yourself (which means you have registered it as a fake device), you should call this entry, to allow the module to keep track of its activity. This activity is reflected in the !Serial application.

Entry
r2   Byte to send
r6   → Channel block

Exit
r0   Result (0 when successful, or -1 when not)

BlockDriver_GetByte   0x56F03
This can can be used to get a single byte from the input file (i.e. the selected port). The entry Driver_GetByte of your BlockDriver can call this SWI directly. Even if you are handling the device yourself (which means you have registered it as a fake device), you should call this entry, to allow the module to keep track of its activity. This activity is reflected in the !Serial application.

Entry
r6   → Channel block

Exit
r0   Received byte (or -1 if no byte available)

BlockDriver_ExamineByte   0x56F04
This call is similar to the one above, but does not removed the by from the input buffer. It can be used to inspect the next byte before actually using it.

Entry
r6   → Channel block

Exit
r0   Received byte (or -1 if no byte available)

BlockDriver_PutBlock   0x56F05
Send a block of data (bytes) to the output file. There is no guarantee that all bytes will be transferred, so your driver should check the returned number of successfully inserted bytes and call the SWI again later if there are still bytes pending.

Entry
r2   → Data block
r3   Number of bytes to transfer
r6   → Channel block

Exit
r0   Number of bytes successfully transferred

BlockDriver_GetBlock   0x56F06
Read a block of data (bytes) from the input file. There is no guarantee that all requested bytes are transferred, so your driver should check the returned value.

Entry
r2   → Data block
r3   Maximum number of bytes to be transferred
r6   → Channel block

Exit
r0   Number of bytes successfully transferred

BlockDriver_CheckTXBuffer   0x56F07
This call returns the number of free bytes in the output (TX) buffer. The parent application can use this to determine if and when to send more data.

Entry
r6   → Channel block

Exit
r0   Number of bytes free in TX buffer

BlockDriver_CheckRXBuffer   0x56F08
This call returns the number of free bytes in the input (RX) buffer. The parent application can use this to determine if and when it should collect data.

Entry
r6   → Channel block

Exit
r0   Number of bytes used in RX buffer (or -1 if channel is invalid)

BlockDriver_FlushTXBuffer   0x56F09
Clear the output (TX) buffer.

Entry
r6   → Channel block

Exit
  No return parameters

BlockDriver_FlushTXBuffer   0x56F0A
Clear the input (RX) buffer.

Entry
r6   → Channel block

Exit
  No return parameters

BlockDriver_ControlLines   0x56F0B
This can be used to read or write the status of the modem control lines of the device, in any of three different formats. The first one (DeviceFS format) provides the most flexible options. The other formats are provided for legacy reasons.

Entry
r0   Format (see below)
r2   Control lines (bitmask), or -1 to read
r6   → Channel block

Exit
r0   Control lines status (in requested format)

Format (r0 on entry)
0   DeviceFS format
1   BlockDriver (8) format
2   BlockDriver (9) format

Control lines bits - DeviceFS format (0)
0   DTR
1   RTS
16   CTS
17   DSR
18   RI
19   DCD
20   FIFO

Control lines bits - BlockDriver (8) format (1)
0   DTR
1   RTS

Control lines bits - BlockDriver (9) format (2)
0   CTS
1   DSR
2   RI
3   DCD

BlockDriver_ReadRXErrors   0x56F0C
Currently not implemented

This call reads the error flags of a selected device. It is currently not implemented for DeviceFS devices, and always returns '0' in r0.

Entry
r6   → Channel block

Exit
r0   Error state

Error state bits (r0 on exit)
0   Overrun error
1   Parity error
2   Framing error
3   Break received

BlockDriver_SendBreak   0x56F0D
Currently not implemented

This call issues a break on the selected interface/port. Is is currently not implemented for DeviceFS devices.

Entry
r2   Time [cs]
r6   → Channel block

BlockDriver_BaudRateTX   0x56F0E
Set the transmission speed, also known as the baudrate of the outgoing (TX) channel of the selected port. If the device does not support split baudrates (check bit 1 of the driver flags), the call also updates the RX baudrate. On exit of the call, r0 contains the actual speed as reported by the device. This may be different from the requested speed.

Entry
r2   Speed [baud], or -1 to read the current speed
r6   → Channel block

Exit
r0   Speed

BlockDriver_BaudRateRX   0x56F0F
Set the reception speed, also known as the baudrate of the incoming (RX) channel of the selected port. If the device does not support split baudrates (check bit 1 of the driver flags), the call also updates the TX baudrate. On exit of the call, r0 contains the actual speed as reported by the device. This may be different from the requested speed.

Entry
r2   Speed [baud], or -1 to read the current speed
r6   → Channel block

Exit
r0   Speed

BlockDriver_DataFormat   0x56F10
This call sets or reads the bit format of a single data word, also known as the word format, consisting of the number of start bits, the number of data bits and the number of stop bits. It also defines any parity error checking.

Entry
r2   Data format (see below), or -1 to read
r6   → Channel block

Exit
r0   Data format

Data format bits
0-1   Data length (0 = 8 bits, 1 = 7 bits, 2 = 6 bits, 3 = 5 bits)
2   Stop bits (0 = 1 stop bit, 1 = 2 stop bits)
3   Use parity (0 = no parity, 1 = parity on)
4   Even parity (0 = odd parity, 1 = even parity)

BlockDriver_Handshaking   0x56F11
Define what type of handshaking is used. Also known as flow control. Note that not all serial ports support all types of handshaking. In most cases, the computer's primary serial port is fully implemented and has all modem control lines. Additional ports may be less complete. Also note that DTR/DSR handshaking is not supported by most modern ports.

Entry
r2   Handshaking type (see below), or -1 to read
r6   → Channel block

Exit
r0   Handshaking type

Handshaking types
0   No flow control
1   RTS/CTS
2   XON/XOFF
3   DTR/DSR

BlockDriver_EnumerateBaudRates   0x56F12
This call returns a pointer to a NULL-terminated list of baudrates that are supported by the device. Each baudrate is represented by a single 32-bit word. It can be used by your BlockDriver to dynamically build a list of valid baudrates in the driver's header.

Entry
r0   → Buffer to hold the results
r6   → Channel block

Exit
r0   → Buffer to hold the results (preserved)

BlockDriver_GetInfo   0x56F13
Read global information about the BlockDriver module, or read information about a specific channel. A channel is a block of workspace, allocated to an active port, or a port that has previously been active.

Entry
r0   Reason code
r1   Channel number from 0 onwards (only when r0 > 1)
r6   → Channel block (only when r0 > 1)

Reason codes (r0)
0   Read global information
1   Read channel-specific information

Exit (r0 = 0)
r0   Number of active channels
r1   Maximum number of channels allowed
r2   Stamp 1
r3   Highest channel currently in use
r4   DeviceFS stamp 2
r5-r7   Reserved

Exit (r0 > 0)
r0   → Device name
r1   → Description string
r2   Current baud rate
r3   Current data format
r4   Current handshake setting
r5   Status of the control lines
r6   → Channel block (structure)
r7   Length of data structure in r6

  1. The value of Stamp is incremented on each change. A monitoring application polling the module, can use it to determine if anything has changed since the last poll.
  2. DeviceFS stamp is changed whenever a new device appears or an existing one disappears through DeviceFS. This can be useful when handling removable devices, such as USB-to-Serial adapters.


BlockDriver_SetInfo   0x56F14
Overwrite specific parameters of a given channel. This only works for fake channels. When called for a device that is supported by the DeviceFS interface, it will be ignored.

Entry
r0   Reason code
r1   Value
r6   → Channel block (only when r0 > 1)

Reason codes (r0)
0   Reserved
1   Set RX file handle
2   Set TX file handle
3   Set RX buffer handle
4   Set TX buffer handle

BlockDriver_Platform   0x56F15
This call tries to work out what hardware platform the software is running on. It can be useful when determining which features and ports are available on a given platform. As there is no way in RISC OS to determine the hardware platform, the call inspects the fixed part of the computer's unique ID and reports this back in r0.

Entry
r0   Reason code (should be 0 for now)

Exit
r0   Vendor ID (see below)
r1   → Platform name (string)
r2   IDL (lower 32-bits of unique ID)
r3   IDH (upper 32 bits of unique ID)
r4   Reserved

Recognised Vendor IDs
0x0000   Unknown
0x17FB   Freescale iMX6 hardware
0x0995   IYONIX PC
0xD063B4   CuBox iMX6

BlockDriver_Devices   0x56F16
This call can be used to find the actual DeviceFS names under which the interfaces of a given sub-system are known by the OS. It can also be used to count the number of ports available on a given sub-system, by specifying r0 = -1 on entry to the call.

Entry
r0   Port 1 , or -1 to read number of ports
r1   → Prefix 2

Exit (r0 = -1)
r0   Number of ports found 3

Exit (r0 ≥ 0)
r0   → DeviceFS name for this port 3

  1. The ports of a given sub-system are numbered from 0 onwards.
  2. The Prefix should specify the name of the sub-system (e.g. 'Serial' or 'USBSerial').
  3. The EQ flag is set if no ports are found.


Further information
Any links shown in red are currently unavailable. © X-Ample Technology BV.
Created: Wednesday 26 April 2017. Last changed: Thursday, 28 September 2023 - 14:12 CET.
Click for homepage