@X @~
~V7 56 2 -5
~L3 COUK1247
80
~D10
~H                    MUSS
~
~
~D10
~H             SYS072
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL
~
~
                                                           ISSUE 11~
~V9 -1
~P
~V9 1
~YSYS072
~V2 -6
~M~OSYS IMPLEMENTATION DESCRIPTION~
~
~M~OSection 7  Version 2~
~S1~OSection 7.2 Input/Output and Communications Management~
~S1~O1. General Description~
~BThe Input/Output and Communications Manager (I/O Manager) is
responsible for controlling all the character input/output devices and
communications lines.
Its function is to allow communication between users
and processes in the system, via the peripherals.
Processes communicate with the I/O Manager either via messages
(indirect I/O), or through command procedures (direct I/O).
Most input is converted by the I/O Manager into messages to processes in the
system, and most output originates as messages sent to the I/O Manager.
Certain messages are interpreted as commands by the I/O Manager, for
example to log in a device.
The direct I/O, on the other hand, by-passes the message system
and provides a closer link between character devices and processes.
All commands, command messages and other conventions
for communicating with the I/O Manager are described in the MUSS
System Programmers Manual.
~BTo enable the peripheral configuration to be altered dynamically, a
number of interface procedures are also provided for use by the Configuration
Manager, so that it can determine which devices are used by the
I/O Manager.
~S1~O2. Interfaces~
~
Other modules used~
   Section 14 (Virtual Store Manager)~
   Section 17 (User Manager)~
   Section 19 (Configuration Manager)~
   Section 20 (Process Zero)~
Hardware registers used~
   V.IO.DEV.NO~
   V.IO.CONTROL~
   V.IO.ADDRESS~
   V.IO.COUNT~
   V.IO.INT~
   V.IO.P.DEV.PARS~
   V.IO.P.DEV.NO~
   V.IO.P.DEV.MODE~
   V.IO.P.DEV.TYPE~
   V.IO.P.DEV.PROTOCOL~
Organisational command interface~
   CONFIG.ENQ (DEVICE NO)~
   CHANGE.CHANNEL (SPN, STATE, PHYSICAL MODE)~
   READ.CH (DEVICE.NO)~
   WRITE.CH (DEVICE.NO, CH)~
Command level interface procedures~
   CONNECT (DEVICE.NO, LOGICAL DEVICE STATUS, BUFFER VA,~
      BUFFER RA, PHYSICAL DEVICE ID, PHYSICAL DEVICE MODE,~
      PHYSICAL DEVICE PARS, PAIR DEVICE NO)~
   DISCONNECT (DEVICE NO)~
   HOLD (DEVICE NO)~
   RETURN DOC (DEVICE NO)~
   RESTART (DEVICE NO)~
   NOTE PERI MESSAGE (PROCESS)~
Configuration parameters~
   SYS19.NO.OF.DEVICES~
   SYS19.NO.OF.GROUPS~
   SYS19.PERI.BUFF.SIZE~
   SYS19.MAX.DATA.TRANSFER~
~S1~O2.1 Hardware Interface
~BAll input/output and communications devices are attached to the system
via a standard hardware interface known as a ~Wsocket. Each socket corresponds
to a unidirectional channel, so a typical full duplex terminal or communications
link will combine two sockets, one for input and one for output.
~BTwo different kinds of socket are
distinguished: ~Wcharacter and ~Wcommunications sockets. A character
socket receives/transmits data in 7-bit ISO character form,
and interprets control sequences embedded within the data to determine
the start and end of messages, etc. This kind of socket is
mainly used for controlling peripheral devices. A communications
socket receives/transmits full binary data, with no interpretation of the
data and hence no restriction on what can be
transmitted. Clearly this is more suitable for connecting processors
together. In order to distinguish the start and end of messages,
and to signal the acceptance or rejection of messages received, the
CONTROL register (see 2.1.4) for a communications socket needs to contain
some extra status bits not present in a character socket.
This information is supplied via extra, optional connections to
the socket; thus a socket may act as a character or a
communications device, depending on what is connected to it.

~BEach socket is under the control of the operator, via a set of
control buttons and lamps, and the I/O Manager via a set of control registers.
Generally, the operator's controls are concerned with operational aspects
such as switching power on to the device and starting and stopping it, while the
 I/O Manager controls
the actual input/output operations. Both sets of controls vary slightly
depending upon exactly what kind of device is connected to a socket.
~S1~O2.1.1 Device Operability
~BThe device operability is controlled by the operator via
commands which switch a device between configured IN and OUT
states.  These commands control the configuration state of the socket.
~S1OPERABILITY STATES
~
~T% 20
~
IN~IA device in the ~WIN state is fully operable and available for use by
the operating system.~
~
OUT~IIn the ~WOUT state, the device is operable, but has been configured out
of the system and will not be used by the I/O Manager. A device configured
OUT in this way may then be allocated for private use, for example to run
online diagnostics.~
~BA system restart causes all devices to be switched to the OUT state.
~S1~O2.1.2 Input / Output Operations
~BThe input/output operations are controlled by software, by
writing to a set of control registers (see 2.1.4).
In the IN and
OUT states, the socket responds correctly to commands; however,
the I/O Manager will only issue commands to a device in the IN
state.
~BThere are four major states involved in the operation of an
input / output socket, known as INITIAL, IDLE, IN TRANSFER and
DISENGAGED.
~S1OPERATIONAL STATES
~
~T% 20
~
INITIAL~IThe socket enters its ~WINITIAL state whenever it is
configured OUT. In this state, the only command which may be
used is the INITIALISE command, which switches the device to its
IDLE state, if an output device, and DISENGAGED state
if an input device.
~
IDLE~IIn the ~WIDLE state, all commands are accepted by the device. In
particular, the START TRANSFER command initiates an input / output
transfer, and switches the device to the IN TRANSFER state. It may
also be switched to the INITIAL and DISENGAGED states, via
an explicit device command.
~
IN TRANSFER~IFrom the ~WIN ~WTRANSFER state, a socket normally returns automatic
ally
to the IDLE state through the TRANSFER COMPLETE or TRANSFER FAILED
interrupts. It may also be switched to the INITIAL state
by the configure out command.
~
DISENGAGED~IFrom the IDLE state, input devices may be switched
into the ~WDISENGAGED state, and subsequently re-engaged
using an ENGAGE / DISENGAGE  button. On being disengaged, a device
terminates the current transfer (if any) at a convenient point.
On being re-engaged, an
interrupt is generated. The ENGAGE / DISENGAGE mechanism is used by the
I/O Manager in order to temporarily disengage devices which are
not used, until they are required again.
Devices may also be disengaged by software, in situations where operator
intervention is required, for example to change stationery.
~
~P~BThe following diagram summarises the transitions between the
major states, annotated with the possible causes for each transition.~
~3
~Q 47
~
~
~
~
                     INITIAL~
                       (1)~
~
~
          ~WCommand:           ~WCommand:          ~WCommand:~
          INITIALISE(output) CONFIGURE OUT      CONFIGURE OUT~
~
~
                                                             ~WCommand:~
                                                             INITIALISE~
                                                               (input)~
                                   ~WOperator:~
                                   ENGAGE~
~
~
                       IDLE                       DISEN-~
                       (2)                        GAGED~
                                                   (4)~
~WCommand:~
CONFIGURE OUT~
                                   ~WCommand:~
                                   DISENGAGE~
~
~
          ~OCommand~O:            ~ODevice~O:~
          START TRANSFER      TRANSFER COMPLETE or~
                              TRANSFER FAILED~
                           ~Oor~O ~OOperator~O:~
                              ABANDON / BREAK~
                           ~Oor~O ~OCommand~O:~
                              STOP~
                              INITIALISE (output)~
~
~
~
~
                        IN~
                     TRANSFER~
                        (3)~
~0
~
~
~OCommand~O: indicates a command issued via the control registers,
and does not result in any interrupt immediately.~
~
~OOperator~O: indicates an operator action and always generates
an interrupt.~
~
~ODevice~O: indicates a device action, and always generates an interrupt.~
~
~
~V6 0
~3
~Q 32
~M~OOperational State Transitions
~O                                                                           ~O~
|TRANSITION|                          |                                   |~
|----------| CAUSE OF STATE TRANSITION|EFFECTS OF STATE TRANSITION        |~
|~OFROM|  TO |                          |                                   ~O|~
|~O 1  |  2  |Command:INITIALISE(output)|Device initialisation to IDLE state~O|~
|~O 2  |  1  |Command:  CONFIGURE OUT   |Device operability changed         ~O|~
|~O 2  |  3  |Command:  START TRANSFER  |Device initiates I/O transfer      ~O|~
|~O 2  |  4  |Command:  DISENGAGE       |Device is disengaged               ~O|~
|~O 3  |  1  |Command:  CONFIGURE OUT   |Device operability changed         ~O|~
| 3  |  2  |Successful or unsuccessful|Interrupt: TRANSFER COMPLETE       |~
|    |     |~Ocompletion of transfer    |       or: TRANSFER FAILED         ~O|~
|    |     |Termination of transfer by|Interrupt: TRANSFER COMPLETE       |~
|    |     |~Othe BREAKIN or ABANDON key|        +: BREAKIN / ABANDON       ~O|~
|    |     |Command:  STOP            |Device returned to IDLE state      |~
|~O    |     |     or INITIALISE(output)|                                   ~O|~
| 4  |  1  |~O                          |                                   ~O|~
|~O    |     |Command: CONFIGURE OUT    |Device Operability Changed         ~O|~
|~O 4  |  2  |Operator: ENGAGE          |Interrupt: STATE CHANGE            ~O|~
|~O 1  |  4  |Command:INITIALISE(input) |Device initialisation to DISENGAGED~O|~
~0
~V2 -6
~V6 3
~V2 0
~S1~O2.1.3 Operator Controls
~
~T% 20
~
ENGAGE/DISENGAGE~I[~Ocharacter devices~O]~
~IDISENGAGE temporarily halts the device; ENGAGE re-starts it. The
device may also be disengaged automatically when operator intervention
is necessary. Again in this case, ENGAGE is used to re-start it.
~
~
ABANDON~I[~OBatch character output devices~O]~
~ICauses the current output document to be abandoned.~
~
BREAKIN~I[~OInteractive character input devices~O]~
~ICauses any transfer currently in progress on the input device, and
its associated output device, to be abandoned, and interrupts the
currently logged in process.~
~S1~O2.1.4 Device Registers
~BAll sockets are initialised and controlled through a set of
eight registers.  These registers act as a window on to a pool of
individual socket registers.  Writing to the V.IO.DEV.NO selects
a particular socket.  At the same time, it causes the values of the
registers of that socket to be returned in the eight ideal registers.
~BEach socket is controlled using a set of eight registers~
~
~M(B)
~
~
~OV.IO.ADDRESS~O is used to specify the real address,
in byte units, of the buffer to/from which a transfer is to be
performed. On completion of a transfer, it will have been increased
by the number of bytes actually transferred (which may be zero).~
~
~OV.IO.COUNT~O is used to specify the maximum number of bytes
to be transferred. On completion of a transfer, it will have been
decreased by the number of bytes actually transferred (which may be zero).~
~
~OV.IO.CONTROL~O is used to send commands to the socket, and
to receive status information. Its detailed format is shown below.
~
~
The CONTROL register bits are grouped into three categories: Device status,
interrupt status, and command. The device status bits are read-only, and give
the current state of the socket. The interrupt status bits give the reason
for an interrupt when the socket interrupts, and are cleared whenever the
control register is written to. The command bits are used to write commands
to the device, and may be read to discover the last command actually requested.~
~BThe following diagram illustrates the form of the V.IO.CONTROL
register.~
~3
~Q 11
~
       |Device      Interrupt   Command|~
       ~O|status |    status     |       |~O~
       ~O| | | | | | | | | | | | |       |~O~
          | | |     | | | | | |~O  ~O TRANSFER COMPLETE~
OUT ~O      ~O| | |     | | | | |~O    ~O TRANSFER FAILED~
INITIAL ~O    ~O| |     | | |~O        ~O BREAK / ABANDON / RESTARTED~
DISENGAGED ~O   ~O|     | | |~O        ~O STATE CHANGE~
                    | |~O          ~O SOM / ACK RECEIVED~
                    |~O            ~O EOM / NAK RECEIVED~
~0
~BMore detail about the fields of the V.IO.CONTROL can be found
in 2.1.4.1 to 2.1.4.3.
~BThe physical characteristics of a socket are controlled using five
registers.  These registers pass device (physical device) dependent
information.  Their formats and possible contents are described in
the MUSS System Programmers Manual.~
~
~
V.IO.P.DEV.TYPE is used to specify the type of the physical device.
Each type refers to a certain physical cluster of devices (e.g. a
multiplexer).~
~
~
V.IO.P.DEV.NO is used to specify the corresponding device number
within that physical type.~
~
~
V.IO.P.DEV.PARS is used to specify the parameters of the physical
device, including parity, character size, stop bits, and transfer
rate.~
~
~
V.IO.P.DEV.MODE is used to specify the mode of the operation of
the physical device.  It contains information which determines
the actions to be taken on each special character.~
~
~
V.IO.P.DEV.PROTOCOL is used to specify the protocol associated
with a physical device.
~S1~O2.1.4.1 Device Status
~
0000 Socket is IDLE or IN TRANSFER~
0001           DISENGAGED~
001?           in INITIAL state~
~P
~S~O2.1.4.2 Commands
~
~T% 23
~3
~
0000  STOP~ITerminates the current transfer if any, and clears any interrupts.
~
~
0001  INITIALISE~IOnly valid for a devicein INITIAL state.  Switches
the device into the DISENGAGED state.~
~
0010  CONFIGURE OUT~I No interrupt occurs as a result of this command.~
~
0011  DISENGAGE~IOnly valid for a character device in the IDLE state. The device
 is switched to
the DISENGAGED state. No interrupt occurs as a result of this command.~
01??  START TRANSFER~IOnly valid for a device in the IDLE state. A transfer is s
tarted, using
the buffer indicated by the ADDRESS and COUNT registers. The two least
significant command bits are used to qualify the command, as indicated below. Fo
r a character device, the transfer is terminated prematurely on
reading a newline character.~
0001  SOM / ACK~
      SOM~I~O[Output devices]~
~IWhen set as a qualifying bit for a START TRANSFER to an output device, this
bit indicates that the transfer is the first of a message, i.e. a header.
For character devices this may result in the information being displayed
in some special format. For communications devices, the information is passed
to the receiving socket via its SOM RECEIVED status bit.~
      ACK~I~O[Communications input devices]~
~IWhen set as a qualifying bit for a START TRANSFER to a communications
input device, this bit indicates acknowlegement of the last complete
message received. It should only be used in the first transfer after
an EOM has been received, and is communicated to the transmitting
socket via its ACK RECEIVED status bit. The transfer may be null (i.e.
COUNT = 0) if desired.~
0010  EOM / NAK~I~
      EOM~I~O[Output devices]~
~IWhen set as a qualifying bit for a START TRANSFER to an output device, this
bit indicates that the transfer is the last of a message. For character
devices, this may result in some special display action (e.g. paperthrow).
For communications devices, the information is passed to the receiving
socket via its EOM RECEIVED status bit.~
      NAK~I~O[Communications input devices]~
~IWhen set as a qualifying bit for a START TRANSFER to a communications
input device, this bit indicates rejection of the current message. It
may be used with any transfer, and is communicated to the transmitting
socket via its NAK RECEIVED status bit. The transfer may be null (i.e.
COUNT = 0) if desired.~
~0
~S1~O2.1.4.3 Interrupt Status
~BNote that ~Wany interrupt will always terminate the current transfer.
Thus, when a device is IN TRANSFER, the next interrupt to occur will ~Walways
have a TRANSFER COMPLETE or TRANSFER FAIL set, possibly with other interrupt
status bits. The BREAK and STATE CHANGE conditions interrupt immediately if
no transfer is in progress. The ABANDON bit for a character output device does
not interrupt unless the device is in transfer.
~
~T% 21
~3
~
TRANSFER COMPLETE~I~O[All devices]~
~IIndicates the successful completion of the current transfer.~
TRANSFER FAILED~I~O[All devices]~
~IIndicates the failure of the current transfer.~
BREAK / ABANDON~I~O[Character devices]~
~IFor character devices, this represents an attempt by the operator
to abandon the current document, using the BREAK or ABANDON button.~
RESTARTED~I~O[Communications devices]~
~IIn the case of a communications socket, this implies that an
INITIALISE command has been issued on the socket with which it
communicates.~
STATE CHANGE~I~O[All devices]~
~ISet whenever any of the Device Status bits changes, except as a
result of an explicit DISENGAGE command.~
SOM / ACK RECEIVED~I~
   SOMR~I~O[Communications input devices]~
~IFor a communications input socket, this bit occurs as qualifying
information with a TRANSFER COMPLETE interrupt, to indicate that
the transfer is the first of a new message (i.e. a header).~
   ACKR~I~O[Communications output devices]~
~IFor a communications output socket, this bit indicates that the socket
with which it communicates has acknowledged the receipt of the last
message sent. It should only occur after a transfer qualified by EOM
has been transmitted, and will occur as a qualifying bit for
the TRANSFER COMPLETE interrupt.~
EOM / NAK RECEIVED~I~
   EOMR~I~O[Communications input devices]~
~IFor a communications input socket, this bit occurs as qualifying information
with a TRANSFER COMPLETE interrupt, to indicate that the transfer is the last
of a message. [Note SOMR+EOMR means that the message consists of a header only].
~
   NAKR~I~O[Communications output devices]~
~IFor a communications output socket, this bit indicates that the socket with
which it communicates has rejected the current document. It may occur after
any transfer, and will occur as a qualifying bit for the TRANSFER COMPLETE
interrupt.~
~0
~S~O2.1.5 Interrupt Register
~BIn order to facilitate a faster detection of interrupting sockets,
all sockets are divided into a number of groups.  Each group contains
16 sockets (on a sequential device number basis), and there is a
V.IO.INT register associated with each group.  Each bit in the
V.IO.INT corresponds to a socket, and when it is set, it indicates
an interrupting socket.
~S1~O2.2 Software Interface
~BThe main function of the I/O Manager is to provide
an interface between users on the one hand, and processes within
the system on the other. The conventions for communicating
with the I/O manager are described in detail in the MUSS System
Programmers Manual.
~BThe I/O Manager is responsible only for the routine
operation of the input / output sockets. Longer term
considerations, of device availability for example, are dealt
with by a separate module, the Configuration Manager (section 19).
The Configuration Manager is responsible for discovering the local
system configuration on startup - what devices are connected to
which sockets - and keeping this information up to date in the light
of peripheral breakdowns and re-configurations. It also has to
intercept and re-route messages directed at output devices which are
not available. Obviously, therefore, the Configuration Manager has
a requirement to be informed of, and to some extent to control, the
operability of the sockets under its management.
~BThere is also an interface procedure, NOTE.PERI.MESSAGE, for
use by the message system to inform the I/O Manager of the arrival
of a message for it (see 2.2.2).
~S1~O2.2.1 Configuration Management Interface
~BFrom the point of view of the Configuration Manager,
each socket may be in one of four states at any given
time: DISCONNECTED, READY, CONNECTED and HELD.
These are in fact a higher level form of the device operability states
described in 2.1.2, and there is a correspondence between the two
sets of states.
Transitions between configuration states are largely under the
Configuration Manager's control, via a set of I/O Manager
interface procedures. Those transitions which are not
directly caused by the Configuration Manager's actions
are signalled to it via interrupt-like interface procedures.~
~S1CONFIGURATION STATES
~
~T% 20
~
DISCONNECTED~IA device which is ~WDISCONNECTED is not to be considered as part
of the system configuration, and will not be serviced by the
I/O Manager. Operator action is required
to remove the device from this state, by invoking the CONNECT command. When this
 occurs, the device becomes
connected.~
CONNECTED~IIn the ~WCONNECTED state, a device is under the control of the I/O Ma
nager.
It may become disconnected again, as a result of using the DISCONNECT command.
A CONNECTED device may also be removed temporarily from the I/O Manager's
control through use of the HOLD interface procedure, which switches
it to the HELD state. A transfer fail on any device,
and a BREAK/ABANDON or any serious message error on a communications device
also causes it to
become held, and the Configuration Manager to be informed.~
HELD~IIn the ~WHELD state, the I/O Manager will not service the device,
but operation may be resumed without operator intervention, via the
RESTART procedure which switches the device back to the CONNECTED
state. A device in the HELD state may also become disconnected,
through the DISCONNECT interface procedure.
~
~
~BAll devices are initially in the DISCONNECTED state, but on a system
restart normally immediately switch to the CONNECTED condition.
~Q20
The following diagram summarises the possible state transitions and their
causes.~
~3
~Q 35
~
~
~
                    DISCON-~
                    NECTED~
                      (1)~
~
~
   ~OCommand~O                  ~OCommand~O:~
   DISCONNECT                CONNECT~
~
                             ~OCommand~O:        ~OCommand~O:~
                             RESTART         DISCONNECT~
~
                    CON-~
                    NECTED                   HELD~
                      (2)                    (3)~
~
                             ~ODevice~O:~
                             TRANSFER FAIL~
                             RESTARTED (Communications devices)~
                             FAULTY MESSAGES (Communications devices)~
                          ~Oor~O ~OCommand~O:~
                             HOLD~
~0
~
~
~OOperator~O: indicates a transition resulting from an operator action.
Such a transition always generates an "interrupt" - i.e. a call of a
Configuration Manager interface procedure.~
~
~ODevice~O: indicates a transition resulting from some action or condition
of the device. Such a transition always generates an "interrupt".~
~
~OCommand~O: indicates a transition requested explicitly by the Configuration
Manager by calling an I/O Manager interface procedure. Such transitions never
generate an "interrupt".~
~
~
The "interrupts" mentioned above consist of calls to the following
Configuration Manager interface procedures:~
~3
~Q 4
~
                 HELD (DEVICE NO, REASON)~
                 DISCONNECTED (DEVICE NO, REASON, HEADER, SEGMENT~
~S1~M~OConfiguration State Transitions
~Q 38
~V2 -20
~
~O                                                                     ~
|TRANSITION |                         |                           |~
|-----------|                         |                           |~
|FROM |  TO |CAUSE OF STATE TRANSITION|EFFECTS OF STATE TRANSITION|~
~O|     |     |                         |                           |~
|     |     |                         |                           |~
|  1  |  2  |Command:  CONNECT        |                           |~
~O|     |     |                         |                           |~
|     |     |                         |                           |~
|  2  |  1  |Command: DISCONNECT      |Interrupt: DISCONNECTED    |~
~O|     |     |                         |                           |~
|     |     |                         |                           |~
|  2  |  3  |Device:   TRANSFER FAIL  |Interrupt: HELD            |~
|     |     |    or:   COMMUNICATIONS |                           |~
|     |     |             FAILURES    |                           |~
|     |     ~O|                         |                           |~
|     |     |                         |                           |~
|     |     |Command:  HOLD           |                           |~
~O|     |     |                         |                           |~
|     |     |                         |                           |~
|  3  |  1  |                         |                           |~
|     |     ~O|                         |                           |~
|     |     |                         |                           |~
|     |     |Command:  DISCONNECT     |                           |~
~O|     |     |                         |                           |~
|     |     |                         |                           |~
|  3  |  2  |Command:  RESTART        |                           |~
~O|     |     |                         |                           |~
~0
~
~V2 -6
~S1Interface Procedures~
~
~
~G1) CONNECT(DEVICE.NO,LOGICAL.DEV.STATUS,CHANNEL,BUFFER.VA,~
   ~GBUFFER.RA,PHYSICAL.DEV.ID,PHYSICAL.DEV.MODE,~G
   ~GPHYSICAL.DEV.PARS,PAIR.DEV.NO)~G~
~BThis procedure is used to request the I/O Manager to connect a socket
in to the
system, thus passing control of it to the I/O Manager. The socket must
be in the DISCONNECTED state.
LOGICAL.DEV.STATUS indicates the type (lower 8 bits) and the device
class (next 8 bits).
~3
~Q 11
~
 ~O                        ~O~
|~O   8   | | | | | | | | ~O| 0        /        1~
    |      | | | | | |~
    |      | | | | |  --character  / communications~
    |      | | | |  ----input      / output~
    |      | | |  ------single     / paired~
    |      | |  --------shareable  / dedicated~
    |      |  ----------short      / long messages~
    |       ------------spooled    / interactive~
     -------------------device class~
~0
~T% 16
~BThe following notes help to explain the type field:~
~
paired~Iimplies the device is one of an input-output pair (such as
an interactive terminal) and so any logging in or logging
out operation should apply to both members of the pair.~
dedicated~I(output devices only) means the device must be dedicated to
one process at a time (i.e. its message channel should be
dedicated on logging in).~
long messages~Imeans that long messages can be input/output via this
socket.  For very slow devices, the use of long messages may
be prohibitively expensive since it involves locking a page
of data into core during the transfer.~
interactive~I(character devices only) distinguishes between batch and
interactive devices, since the controls for the two types of
device are slightly different.~
~BThe device class field, represents the kind of device handling and
protocols required to drive a device.  The following are some of the
permissible values:~
~T% 21
~
%0 character input device~
%1 character output device~
%2 MUSS communications input device~
%3 MUSS communications output device~
%4 talk input device~
%5 talk output device.~
~
~
CHANNEL: for an output device, indicates the message channel
to which messages for the device are directed; for an input device, gives
the channel number to which error messages should be sent.~
~
~
BUFFER.VA and BUFFER.RA: give the virtual and physical addresses
of the device buffer.~
~
~
PHYSICAL.DEV.ID: gives the physical type (high byte), and the
device number (low byte) within that type.  (See 2.1.4 for
more information).~
~
~
PHYSICAL.DEV.MODE: gives the mode of the operation of the physical
device.  (See 2.1.4 for move information).~
~
~
PHYSICAL.DEV.PARS: gives the parameters of the physical device.
(See 2.1.4 for more information).~
~
~
PAIR.DEV.NO: gives the number of the logical device (if any) to
which this device is paired, and is negative if the device is
not paired.
~S12) DISCONNECT (DEVICE.NO)~
~BThis procedure disconnects a device from the system configuration,
abandoning the document currently being processed (if any). The device must
be in the  HELD state when the procedure is called.
~S13) HOLD (DEVICE.NO)
~BThis procedure switches a device from the CONNECTED to the HELD state.
It will not subsequently be serviced by the I/O Manager unless it is
re-started by the RESTART procedure.
~S14) RETURN.DOC (DEVICE.NO, HEADER, SEGMENT)
~BThis procedure may only be used on an output device in the HELD
state, and returns the header and segment number of the current
document, if any, for possible re-routing.
~S15) RESTART (DEVICE.NO)
~BThis procedure switches a device from the HELD to the CONNECTED
state. The current document, if any, is discarded.
~S16) SYS19.NO.OF.DEVICES
~BThis integer constant controls the maximum number of sockets
which the I/O Manager will service.
~S17) SYS19.NO.OF.GROUPS
~BThis integer constant controls the maximum number of
groups (16 devices in each) of devices.
~S18) SYS19.PERI.BUFF.SIZE
~BThis integer constant gives the size of the device buffer.
~S19) SYS19.MAX.DATA.TRANSFER
~BThis DATAVEC of integers, gives the maximum transfer size for each
type of device (based on character/comms and input/output).
~S1~O2.2.2 Interface with the message system
~S11) NOTE.PERI.MESSAGE (CHANNEL)~
~BThis procedure is called by the message system whenever a message
is routed to a peripheral channel, to activate the appropriate device.
CHANNEL gives the channel to which the message has been sent.
~P
~S1~O3. Implementation~
~S1~O3.1 Outline of Operation~
~BThe I/O Manager provides two types of interfaces for processes:
message-based (indirect) and command-based (direct).  The latter
allows processes to directly access logical device buffers, and
control the timing of I/O transfers.  The I/O Manager deactivates
a process which is requesting a direct I/O service which cannot
be achieved immediately.  However, much of theoperation of the I/O
Manager is the same irrespective of the type of interface.
~BThe module comprises an interrupt process, a task
procedure, and a set of command level interface procedures.
The interrupt process handles initial interrupt servicing, and
normally passes control of a device to task level after clearing
the interrupt. However, in the case of buffered documents (long
messages), an entire document is spooled at interrupt
level before returning control of the device to task level,
unless an error condition arises. The command level interface
procedures deal with the configuration management
and direct I/O interfaces.
~BControl of a device can be regarded as passing between
interrupt level, task level, and
the operator. In the DISCONNECTED state, control is with the operator.
When the operator makes the device operable, the
state switches to
CONNECTED , in this mode control
is with the I/O Manager.~
~BWithin the I/O Manager, control alternates between task
and interrupt level, with the operator occasionally taking control
through the HOLD/RESTART mechanism. Task level can be regarded
as being "in charge", passing control to interrupt level only to
perform specific tasks, namely~
~3
~
~M   input/output contents of the buffer
~N   input/output a short message~
~Nor input/output a segment.~
~0
~
Control is passed from task to interrupt level by setting a
software interrupt request for the device. This results in a
command being sent to the device, as specified by variables
in the data structure associated with it (ADDRESS, COUNT,
CONTROL OF IO.VARS [DEV.NO]). On the next interrupt for the device,
control is returned to task level unless the interrupt is a
straightforward TRANSFER COMPLETE and a buffered document is being
processed. This return of control to task level is by setting a
task request for the device.~
~BIn the case of direct I/O, the interrupt level is also responsible
for deactivating processes which need to wait until an operation
is finished.  Moreover, they activate the process as soon as the
operation is completed.
~BWhile the device is in the control of task level or the
Configuration Manager, interrupts may still occur for it. Any
such interrupt is notified immediately to task level, and then
to the Configuration Manager if necessary.~
~S1~O3.2 Data Structures~
~3
~T% 20
~
~
V.IO.DEV.NO~IA V-line, used to specify a logical device number.~
V.IO.ADDRESS~IAn ADDRESS V-lines.  (See 2.1.4).~
V.IO.COUNT~IA COUNT V-lines.  (See 2.1.4).~
V.IO.CONTROL~IA CONTROL V-lines.
(See 2.1.4). Individual
fields within the control line is accessed
using the literals:~
   :OUT~I%4000  Device status - OUT~
   :INITIAL~I%2000  Device status - INITIAL~
   :DISENGAGED~I%1000  Device status - DISENGAGED~
   :INOPERABLE~I%F000  Device status - all bits~
   :TR.COMP~I%0010  Interrupt status - TRANSFER COMPLETE~
   :TR.FAIL~I%0020  Interrupt status - TRANSFER FAIL~
   :BREAKIN~I%0040  Interrupt status - BREAK~
   :ABANDON~I%0040  Interrupt status - ABANDON~
   :RESTARTED~I%0040  Interrupt status - RESTARTED~
   :STATE.CHANGE~I%0080  Interrupt status - STATE CHANGE~
   :SOMR~I%0100  Interrupt status - SOM RECEIVED~
   :ACKR~I%0100  Interrupt status - ACK RECEIVED~
   :EOMR~I%0200  Interrupt status - EOM RECEIVED~
   :NAKR~I%0200  Interrupt status - NAK RECEIVED~
   :INT.MASK~I%03F0  Interrupt status - all bits~
   :STOP.CMD~I%0000  Command - STOP~
   :CON.OUT.CMD~I%0002  Command - CONFIGURE OUT~
   :DISENGAGE.CMD~I%0003  Command - DISENGAGE~
   :START.TR.CMD~I%0004  Command - START TRANSFER~
   :SOM.CMD~I%0005  Command - START TRANSFER + SOM~
   :ACK.CMD~I%0005  Command - START TRANSFER + ACK~
   :EOM.CMD~I%0006  Command - START TRANSFER + EOM~
   :NAK.CMD~I%0006  Command - START TRANSFER + NAK~
   :SOM.EOM.CMD~I%0007  Command - START TRANSFER + SOM + EOM~
V.IO.P.DEV.TYPE~IA P.DEV.TYPE V-line.  (See 2.1.4).~
V.IO.P.DEV.NO~IA P.DEV.NO V-line.  (See 2.1.4).~
V.IO.P.DEV.PARS~IA P.DEV.PARS V-line.  (See 2.1.4).~
V.IO.P.DEV.MODE~IA P.DEV.MODE V-lines.  (See 2.1.4).~
V.IO.P.DEV.PROTOCOL~IA P.DEV.PROTOCOL V-line.  (See 2.1.4).~
V.IO.INT~IAn array of INTERRUPT V-lines, indexed by group
number, and gives the interrupting devices within
each group. (See 2.1.4).~
IO.VARS~IAn array, indexed by device number, holding all
the information relating to the control of a
particular device.  Each entry is a record with
the following fields:~
   :INT.STATUS~IA copy of the CONTROL V-line,
used to pass information from interrupt to task level.
This is necessary because the interrupt
status bits of V.IO.CONTROL must be cleared (to clear
the interrupt) before task level is entered. Thus to read
the interrupt status bits, task level code uses INT.STATUS
instead of V.IO.CONTROL. All other bits are read directly
from V.IO.CONTROL, to obtain the most up-to-date
information.~
   :IO.STATUS~IGives
status information about each device. The
information is bit-significant, and is accessed
using the following literals:~
      :COMMS~IDevice is a communications device. (See 2.2.1 CONNECT).~
      :OUTPUT~IDevice is an output device. (See 2.2.1 CONNECT).~
      :PAIRED~IDevice is paired. (See 2.2.1 CONNECT).~
      :DEDICATED~IDevice is dedicated. (See 2.2.1 CONNECT).~
      :LMESS~ILong messages are allowed. (See 2.2.1 CONNECT).~
      :INTERACTIVE~IDevice is interactive. (See 2.2.1 CONNECT).~
      :SOFTWARE.INT~IA software interrupt request has been set for
this device. (See 3.1 Outline of Operation).~
      :TASK.REQUEST~IAttention at task level is requested for this
device. (See 3.1 Outline of Operation).~
      :LOGGED.IN~IFor an input device, indicates that it is
logged in and so a destination is known
for incoming messages.~
      :WAITING~IFor an output device, indicates that no document
is currently being processed and the device is
awaiting the arrival of a message.~
      :LONG.MESS~IFor an output device, indicates that the document
currently being processed is a long message.~
      :BUFFERED~IFor either an input or an output device, indicates
that the interrupt level process is currently working
on the segment part of a long message.~
      :NEWLINE~IFor a character input device, indicates that the
last completed input transfer finished with a newline
character. This is used to ensure that ***
commands are only detected at the start of
a line.~
      :DIRECT.IO~IIndicates that the direct I/O is being used.~
   :SOFTWARE.STATE~IGives the
configuration state of the device. (See 2.2.1).
The following literals define the values of the
entries:~
      :DISCONNECTED~IDevice is disconnected.~
      :CONNECTED~IDevice is connected.~
      :HELD~IDevice is held.~
   :ADDRESS~IThis is used to communicate between interrupt and
task level the value of the ADDRESS V-line.  On a
software interrupt, it contains the value to be
written into the V-LINE; on a task request it
contains the current value of the V-line.~
   :COUNT~IAs above, but for the COUNT V-line.~
   :CONTROL~IThis is used to communicate between interrupt and
task level the value of the CONTROL V-line. On a
software interrupt, it contains the value to be written
into the V-line; on a task request it contains the
last value written to the V-line.~
   :BUF.RA~IThe real address of the buffer allocated to this
device (see 2.2.1 CONNECT).~
   :BUF.SIZE~IThe size in bytes of the buffer allocated to
this device (see 2.2.1 CONNECT).~
   :MAX.TR~I(Output devices only) the maximum
transfer size permitted for this device (see 2.2.1 CONNECT).~
   :CH.NO~IThe channel number associated with this device
(see 2.2.1 CONNECT).~
   :PAIR.NO~IThe paired device number, if any (see 2.2.1 CONNECT).~
   :HEADER~IThe address of a vector of bytes to be used in sending/reading messa
ges
on behalf of this device.~
   :SEG~IThe segment number, when a long message is
being processed.~
   :BLOCK.NO~IThe current block number of the segment being
processed by interrupt level.~
   :BLOCK.RA~IThe real address of the currently processed block.~
   :DOC.SIZE~I(Output devices only). Number of characters still
to be output in the current document after completion
of the current block.~
   :BLOCK.COUNT~I(Output devices only). Number of characters still
to be output in the current block after completion
of the current transfer. Thus, DOC.SIZE + BLOCK.COUNT
+ COUNT gives the total number of characters left for
the current document.~
   :SEG.PTR~I(Character input devices only). This is a pointer
into the current block for a character input device. It
is used to copy input characters into the block.~
   :PTR~I(Character input devices only). This is an index into
SEG.PTR, used to copy input characters into the
current block.~
   :DEST~IA vector of 4 elements indicating the
destination process for messages
sent from the device.~
   :COST~IThe cost of the current (output) document,
expressed as a number of bytes output.~
   :UID~IThe UID of the sender of the message to a device.~
   :DEVICE.CLASS~IGives the current class of the device.~
   :OLD.DEVICE.CLASS~IGives the old class of the device.~
   :TALK.DEST.SPN.PID~IUsed in task operations and gives the id of the
destination talk channel.~
   :TALK.DEST.UNAME~IGives the user destination for the talk.~
IO.TASKS~IAn array of Logical16, indexed by group number,
giving the device for which a task is set.~
IO.SW.INT~IAn array of Logical16, indexed by group number,
giving the device for which a software interrupt
is required.~
~0
~S1~O3.3 Special Notes~
~BOperators can control operation of devices through
control buttons and commands.  For devices that do not
possess appropriate switches, a command procedure is provided
which simulates the effect of usingthose buttons.
~BThis module incorporates several sub-modules.  Each sub-module belongs to
a specific class of device.  The current sub-modules are:~
~3
~
~
    SYS073~Icharacter input/output management~
    SYS074~Icommunications input/output management~
    SYS074~Italk input/output management.~
~0
~Y
~V9 -1
~P
~D15
~HFLOWCHARTS
~
~
~H                SYS072
~V9 -1
~F
@TITLE SYS07(2,10)
@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
INPUT / OUTPUT MANAGEMENT
@BOX 4.0
PROCEDURES IN MODULE:
   INT1 IO INTERRUPT
   INT2 SET IO INTERRUPT
   INT3 SET IO TASK
   INT4 CLEAR IO TASK
   INT5 START DEVICE
   INT6 DEVICE COMMAND
   CMD1 CONNECT
   CMD2 DISCONNECT
   CMD3 HOLD
   CMD4 RETURN DOC
   CMD5 RESTART
   CMD6 NOTE PERI MESSAGE
   CMD7 TINI IO
   CMD8 CONFIG ENQ
   CMD9 CHANGE CHANNEL
   CMD10 READ CH
   CMD11 WRITE CH
   CMD12 CHANGE P MODE
   TSK1 IO TASK
   TSK2 COMMAND LINE
   TSK3 SEND MESS
   TSK4 MONITOR
   TSK5 MAP SEG
   TSK6 UPDATE SEG
   TSK7 TALK
   TSK8 PROCESS NAME
   TSK9 TALK COMMAND LINE
   TSK10 FIND NAME
@BOX 5.0
I/O INITIALISATION
#SYS07/3
@BOX 6.0
END
@BOX 1.1
#SYS07/1
MODULE SYS07 (IO.INTERRUPT, IO.TASK, CONNECT, DISCONNECT, HOLD, RETURN.DOC,
   RESTART, NOTE.PERI.MESSAGE, TINI.IO, CONFIG.ENQ, CHANGE.CHANNEL,
   READ.CH, WRITE.CH);
@BOX 2.1
TYPE IO.VARS.TYPE IS
   INTEGER32 BUF.RA, ADDRESS, DOC.SIZE, BLOCK.RA, TALK.DEST.SPN.PID, PTR
   INTEGER BUF.SIZE, MAX.TR, CH.NO, PAIR.NO, COUNT, CONTROL, SEG, BLOCK.NO
   INTEGER BLOCK.COUNT, UID, DEVICE.CLASS, OLD.DEVICE.CLASS
   ADDR [LOGICAL8] HEADER, SEG.PTR
   LOGICAL16 IO.STATUS, INT.STATUS
   LOGICAL8 SOFTWARE.STATE, OLD.P.DEV.MODE
   LOGICAL64 TALK.DEST.UNAME
   INTEGER [4] DEST;
TYPE ADDRESS8 IS
   ADDR [LOGICAL8] ADDRESS;
@BOX 3.1
#SYS07/2
@BOX 4.1
::*INIT %6000;
::*CODE 2;
PSPEC IO.INTERRUPT ();
PSPEC SET.IO.INT (LOGICAL, LOGICAL);
PSPEC SET.IO.TASK (LOGICAL, LOGICAL);
PSPEC CLEAR.IO.TASK (LOGICAL, LOGICAL);
PSPEC START.DEVICE (LOGICAL, LOGICAL);
PSPEC DEVICE.COMMAND (LOGICAL, LOGICAL);
::*INIT %7000;
::*CODE 17;
PSPEC NOTE.PERI.MESSAGE (INTEGER);
::*CODE 18;
PSPEC CONNECT (INTEGER, LOGICAL, INTEGER, ADDR, LOGICAL32,
   LOGICAL, LOGICAL, LOGICAL, INTEGER);
PSPEC DISCONNECT (INTEGER);
PSPEC HOLD (INTEGER);
PSPEC RETURN.DOC (INTEGER, ADDR ADDRESS8, ADDR INTEGER);
PSPEC RESTART (INTEGER);
LSPEC CONFIG.ENQ (INTEGER);
LSPEC CHANGE.CHANNEL (INTEGER, INTEGER, LOGICAL);
LSPEC READ.CH (INTEGER) / LOGICAL16;
LSPEC WRITE.CH (INTEGER, LOGICAL8);
PSPEC CHANGE.P.MODE (INTEGER, LOGICAL) / LOGICAL;
::*CODE 19;
PSPEC TINI.IO (INTEGER);
::*CODE 4;
PSPEC IO.TASK ();
PSPEC COMMAND.LINE (INTEGER, ADDR [LOGICAL8]) / INTEGER;
PSPEC SEND.MESS (INTEGER) / INTEGER;
PSPEC MONITOR (INTEGER, INTEGER);
PSPEC MAP.SEG (INTEGER) / ADDR;
PSPEC UPDATE.SEG (INTEGER);
PSPEC TALK (INTEGER, ADDR [LOGICAL8], INTEGER) / INTEGER;
PSPEC PROCESS.NAME (ADDR [LOGICAL8]);
PSPEC TALK.COMMAND.LINE (INTEGER, ADDR [LOGICAL8]) / INTEGER;
PSPEC FIND.NAME (ADDR [LOGICAL8], INTEGER) / INTEGER;
::SUB-MODULES PSPECS AND PROC DATAVECS
#SYS07/4
::*INIT %6000;
*CODE 2;
   #SYSINT07.1
   #SYSINT07.2
   #SYSINT07.3
   #SYSINT07.4
   #SYSINT07.5
   #SYSINT07.6
::*INIT %7000;
*CODE 17;
   #SYSCMD07.6
*CODE 18;
   #SYSCMD07.1
   #SYSCMD07.2
   #SYSCMD07.3
   #SYSCMD07.4
   #SYSCMD07.5
   #SYSCMD07.8
   #SYSCMD07.9
   #SYSCMD07.10
   #SYSCMD07.11
   #SYSCMD07.12
*CODE 19;
   #SYSCMD07.7
*CODE 4;
   #SYSTSK07.1
   #SYSTSK07.2
   #SYSTSK07.3
   #SYSTSK07.4
   #SYSTSK07.5
   #SYSTSK07.6
   #SYSTSK07.7
   #SYSTSK07.8
   #SYSTSK07.9
   #SYSTSK07.10
@BOX 5.1
::*INIT %6000;
::I/O INITIALISATION
#SYS07/3
::INCLUDE SUB-MODULES CODES
::SUB1 **IN SUBMOD1
::SUB2 **IN SUBMOD2
::SUB3 **IN SUBMOD3
@BOX 6.1
*END
@END
@TITLE SYS07/1(2,10)
@COL 1S-2R-3R-4R
@FLOW 1-2-3-4

@BOX 1.0
OTHER MODULES REFERENCED
@BOX 4.0
SYS01 COORDINATOR
SYS13 PROCESS MANAGER
SYS14 VIRTUAL STORE MANAGER
SYS15 MESSAGE MANAGEMENT
SYS17 USER MANAGEMENT
SYS19 CONFIGURATION MANAGER
SYS20 PROCESS ZERO
@BOX 1.1
::EXTERNAL ENVIRONMENT
@BOX 2.1
IMPORT VSTORE LOGICAL V.IO.DEV.NO, V.IO.CONTROL, V.IO.COUNT;
IMPORT VSTORE LOGICAL32 V.IO.ADDRESS;
IMPORT VSTORE LOGICAL16 V.IO.INT [], V.IO.P.DEV.PARS;
IMPORT VSTORE LOGICAL8 V.IO.P.DEV.NO, V.IO.P.DEV.TYPE, V.IO.P.DEV.MODE,
   V.IO.P.DEV.PROTOCOL;
IMPORT VSTORE V.MC.NO;
@BOX 3.1
INTEGER VERSION.NO;
@BOX 4.1
IMPORT LITERAL SYS01.IO.ACTIVITY;
PSPEC SYS01.CLEAR.INTERRUPT ();
PSPEC SYS01.NEXT.ACTIVITY ();
PSPEC SYS01.SET.INTERRUPT (LOGICAL, LOGICAL);
PSPEC SYS01.CHECKIN (INTEGER, INTEGER);
PSPEC SYS01.CHECKOUT (INTEGER, INTEGER);
IMPORT LITERAL SYS06.IO.SUS;
PSPEC SYS06.DEACTIVATION (LOGICAL, LOGICAL);
PSPEC SYS06.ACTIVATION (INTEGER, LOGICAL);
PSPEC FORCE.INT (INTEGER, INTEGER, LOGICAL);
INTEGER SYS13.CURRENT.SPN;
PSPEC LOOK.UP.PROCESS (LOGICAL64, LOGICAL64);
PSPEC SYS13.INT.PROC (LOGICAL, LOGICAL);
PSPEC SYS13.ENTER.INT.LEVEL (ADDR SYS13.INT.PROC, LOGICAL, LOGICAL);
IMPORT LITERAL SYS14.PAGE.SIZE, SYS14.PAGE.SHIFT, SYS14.X.SEG.SIZE, SYS14.SEG.SH
IFT;
IMPORT LITERAL SYS14.IO.BUF.SEG, SYS14.IO.BUF.SEG.2, IO.MSEG, IO.BUF.SEG, IO.BUF
.BLK;
PSPEC SYS14.MAP.ADDRESS (INTEGER32, INTEGER) / ADDR [LOGICAL8];
PSPEC SYS14.GET.BLOCK (INTEGER, INTEGER) / INTEGER32;
PSPEC SYS14.REL.BLOCK (INTEGER32);
PSPEC SYS14.UPDATE.BLOCK (INTEGER32);
PSPEC SYS13.CHECK.PRIV ();
PSPEC MAP (INTEGER, INTEGER, INTEGER);
PSPEC CREATE.X.SEGMENT (INTEGER);
PSPEC RELEASE.SEGMENT (INTEGER);
PSPEC CHANGE.SIZE (INTEGER, ADDR);
PSPEC READ.SEGMENT.STATUS (INTEGER);
PSPEC COPY.BLOCK (INTEGER, INTEGER, INTEGER, INTEGER);
PSPEC SEND.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER], INTEGER, INTEGER, INTEGER,
LOGICAL);
PSPEC READ.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER], INTEGER, INTEGER);
PSPEC SYS15.SEND.PERI.MESSAGE (ADDR [LOGICAL8], INTEGER);
PSPEC SYS15.READ.PERI.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER], INTEGER, INTEGER
);
PSPEC SYS15.SET.PERI.CH.STATUS (INTEGER, LOGICAL, INTEGER, INTEGER);
PSPEC SYS15.SET.ID (INTEGER32, INTEGER32, INTEGER32);
PSPEC SYS17.FIND.UID (LOGICAL64);
PSPEC SYS17.FIND.NAMES (INTEGER);
LOGICAL64 SYS18.MACHINE.NAME;
IMPORT LITERAL SYS19.NO.OF.DEVICES, SYS19.NO.OF.GROUPS,
   SYS19.TALK.IN.DEVICE.CLASS, SYS19.TALK.OUT.DEVICE.CLASS,
   SYS19.PERI.BUFF.SIZE;
INTEGER [4] SYS19.MAX.DATA.TRANSFER;
PSPEC SYS19.HELD (INTEGER, LOGICAL);
PSPEC SYS19.DISCONNECTED (INTEGER, LOGICAL, ADDR [LOGICAL8], INTEGER);
IMPORT LITERAL SYS20.IO.TASK;
PSPEC SYS20.SET.TASK (INTEGER, INTEGER);
ADDR PW0, PW1, PW2, PW3, PW4, PW5, PW6;
LOGICAL64 PWW1, PWW2, PWW3;
@END
@TITLE SYS07/2(2,10)

@COL 1S

@BOX 1.1
*GLOBAL 5;
:: V.IO.CONTROL LITERALS
LITERAL OFF = %8000, OUT = %4000, INITIAL = %2000, DISENGAGED = %1000,
   EOMR = %200, NAKR = %200, SOMR = %100, ACKR = %100,
   STATE.CHANGE = %80, BREAKIN = %40, RESTARTED = %40, ABANDON = %40,
   TR.FAIL = %20, TR.COMP = %10,
   INT.MASK = %3F0, INOPERABLE = %F000,
   STOP.CMD = 0, INIT.CMD = 1, CON.OUT.CMD = 2, DISENGAGE.CMD = 3,
   START.TR.CMD = 4, SOM.CMD = 5, ACK.CMD = 5,
   EOM.CMD = 6, NAK.CMD = 6, SOM.EOM.CMD = 7, ENQ.CMD = 8;
:: IO.STATUS LITERALS
LITERAL COMMS = 1, OUTPUT = 2, PAIRED = 4, DEDICATED = 8,
   LMESS = %10, INTERACTIVE = %20,
   WAITING = %1000, LOGGED.IN  = %2000, DIRECT.IO = %4000,
   LONG.MESS = %800, BUFFERED = %400, NEWLINE = %200;
:: SOFTWARE STATE LITERALS
LITERAL DISCONNECTED = 1, CONNECTED = 3, HELD = 4;
LITERAL / ADDR [LOGICAL8] NIL.NAME =;
INTEGER TASK.DEV.NO;
LOGICAL16 IO.P.DEV.PARS;
LOGICAL8 IO.P.DEV.NO, IO.P.DEV.TYPE, IO.P.DEVMODE,
   IO.P.DEV.PROTOCOL;
*GLOBAL 29;
IO.VARS.TYPE [SYS19.NO.OF.DEVICES] IO.VARS;
*GLOBAL 5;
LOGICAL16 [SYS19.NO.OF.GROUPS] IO.TASKS, IO.SW.INT;
DATAVEC BIT.VEC (LOGICAL16)
   %8000 %4000 %2000 %1000
   %800  %400  %200  %100
   %80   %40   %20   %10
   %8    %4    %2    %1
END
DATAVEC LOG.IN (LOGICAL8)
   59 0 0 0
   "MUSS"
   0
   " ISSUE "
   0
   "11 VERSION 1 ON$L"
   0 0 0 0 0 0 0 0
   " DEVICE 00 CHANNEL 00$L"
END
DATAVEC MSG.FAULT (LOGICAL8)
   30 0 0 0
   "DEV00/MESSAGE FAULT$L"
   7[10]
END
DATAVEC TERM.FAULT (LOGICAL8)
   34 0 0 0
   "DEV00/TERMINATION FAULT$L"
   7[10]
END
DATAVEC NUL.MESS (LOGICAL8)
   0 0 0 0
END
DATAVEC TALK.FAULT (LOGICAL8)
   17 0 0 0
   "DEV00/TALK FAULT$L"
END
DATAVEC MONITOR.MSG (ADDR [LOGICAL8])
   LOG.IN
   MSG.FAULT
   TERM.FAULT
   TALK.FAULT
END
@END
@TITLE SYS07/3(2,10)
@COL 1S

@BOX 1.0
I/O INITIALISATION
@BOX 1.1
::I/O INITIALISATION
*CODE 7;
PSPEC INIT.SYS07 ();
INIT.SYS07 ();
PROC INIT.SYS07;
INTEGER INIT.DEV;
FOR INIT.DEV < SYS19.NO.OF.DEVICES DO
   DISCONNECTED => SOFTWARE.STATE OF IO.VARS [INIT.DEV];
OD
END
@END
@TITLE SYS07/4(2,10)
@COL 1S

@BOX 1.0
SUB-MODULE PSPECS
@BOX 1.1
::CHARACTER INPUT/OUTPUT MANAGEMENT
::SUB1 PSPEC CHAR.INPUT.TR.COMP (INTEGER) / INTEGER;
::SUB1 PSPEC CHAR.OUTPUT.TR.COMP (INTEGER) / INTEGER;
::SUB1 PSPEC CHAR.INPUT.TASK (INTEGER) / INTEGER;
::SUB1 PSPEC CHAR.OUTPUT.TASK (INTEGER) / INTEGER;
::COMMUNICATIONS INPUT/OUTPUT MANAGEMENT
::SUB2 PSPEC COMMS.INPUT.TR.COMP (INTEGER) / INTEGER;
::SUB2 PSPEC COMMS.OUTPUT.TR.COMP (INTEGER) / INTEGER;
::SUB2 PSPEC COMMS.INPUT.TASK (INTEGER) / INTEGER;
::SUB2 PSPEC COMMS.OUTPUT.TASK (INTEGER) / INTEGER;
::TALK INPUT/OUTPUT MANAGEMENT
::SUB3 PSPEC TALK.INPUT.TASK (INTEGER) / INTEGER;
::SUB3 PSPEC TALK.OUTPUT.TASK (INTEGER) / INTEGER;
PSPEC IO.PROC (INTEGER) / INTEGER;
PSPEC DUMMY.PROC (INTEGER) / INTEGER;
DATAVEC IO.INT.PROCS (ADDR IO.PROC)
::SUB1    CHAR.INPUT.TR.COMP
::SUB1    CHAR.OUTPUT.TR.COMP
::SUB2    COMMS.INPUT.TR.COMP
::SUB2    COMMS.OUTPUT.TR.COMP
END
DATAVEC IO.TASK.PROCS (ADDR IO.PROC)
::SUB1    CHAR.INPUT.TASK
::SUB1    CHAR.OUTPUT.TASK
::SUB2    COMMS.INPUT.TASK
::SUB2    COMMS.OUTPUT.TASK
::SUB3    TALK.INPUT.TASK
::SUB3    TALK.OUTPUT.TASK
END
@END
@TITLE SYSINT07.1(2,11)
@COL 1S-2N-3T-5T-7T-24R-6T-8R-10T-9R-21R-20R-27N
@COL 16N-4N-17R-18R-14R-15R-26N-19R-25N-11R-23F
@ROW 2-16
@ROW 3-4
@ROW 5-18
@ROW 6-26
@ROW 9-11
@FLOW 1-2-3FOUND-5NO-7TR COMP-24-6BUFFERED-8-10NO-9-21-20-27-2
@FLOW 3NONE-4-17-18-16-2
@FLOW 5YES-14-15-25-10
@FLOW 7OTHERS-26-19-25-10
@FLOW 6UNBUFFERED-26-19
@FLOW 10YES-11-27
@BOX 1.0
I/O INTERRUPT PROCESS
@BOX 3.0
FIND A DEVICE TO SERVICE
@BOX 5.0
SOFTWARE INTERRUPT?
@BOX 6.0
BUFFERED OR UNBUFFERED?
@BOX 7.0
TRANSFER COMPLETE INTERRUPT?
@BOX 8.0
SERVICE TRANSFER COMPLETE INTERRUPT
@BOX 9.0
SAVE DEVICE STATUS AND
CLEAR HARDWARE INTERRUPTS
@BOX 10.0
DEVICE OPERABLE AND
NO TASK REQUEST SET?
@BOX 11.0
RESTART DEVICE
@BOX 14.0
FETCH BUFFER BLOCK TO CORE
IF NECESSARY [SYS14]
@BOX 15.0
CLEAR SOFTWARE INTERRUPT
FOR THE DEVICE
@BOX 17.0
CLEAR SOFTWARE INTERRUPT
@BOX 18.0
WAIT FOR INTERRUPT
@BOX 19.0
SET TASK REQUEST
FOR THE DEVICE
@BOX 20.0
SET TASK FOR I/O MANAGER
@BOX 21.0
RELEASE CURRENT BUFFER BLOCK
IF NECESSARY [SYS14]
@BOX 23.0
END
@BOX 24.0
READ ADDRESS AND COUNT
FROM V-LINES
@BOX 1.1
PROC IO.INTERRUPT;
INTEGER DEV.NO, GROUP.NO, TASK.REQS;
LOGICAL16 IO.REQS;
ADDR IO.PROC IO.PROC.CALL;
@BOX 3.1
0 => DEV.NO => GROUP.NO;
WHILE DEV.NO < SYS19.NO.OF.DEVICES
   AND V.IO.INT [GROUP.NO] ! IO.SW.INT [GROUP.NO]
   => IO.REQS = 0 DO
   1 +> GROUP.NO;
   16 +> DEV.NO;
OD
IF DEV.NO >= SYS19.NO.OF.DEVICES
@BOX 5.1
WHILE IO.REQS & %8000 = 0 DO
   1 +> DEV.NO;
   IO.REQS <<- 1 => IO.REQS;
OD
BIT.VEC [DEV.NO & %F] => IO.REQS;
0 => TASK.REQS;
SELECT IO.VARS [DEV.NO];
DEV.NO => V.IO.DEV.NO;
IF IO.SW.INT [GROUP.NO] & IO.REQS /= 0
@BOX 6.1
IF IO.STATUS & BUFFERED = 0
@BOX 7.1
IF (TR.COMP ! ABANDON) & V.IO.CONTROL /= TR.COMP
@BOX 8.1
IO.INT.PROCS [DEVICE.CLASS] => IO.PROC.CALL;
IO.PROC.CALL^ (DEV.NO) => TASK.REQS;
DEV.NO => V.IO.DEV.NO;
@BOX 9.1
INT.STATUS & INOPERABLE -=> INT.STATUS;
V.IO.CONTROL !> INT.STATUS;
STOP.CMD => V.IO.CONTROL;
@BOX 10.1
IF V.IO.CONTROL & INOPERABLE = 0
   AND TASK.REQS = 0
   AND SOFTWARE.STATE /= HELD
@BOX 11.1
ADDRESS => V.IO.ADDRESS;
COUNT => V.IO.COUNT;
CONTROL => V.IO.CONTROL;
@BOX 14.1
IF IO.STATUS & BUFFERED /= 0 THEN
   SYS14.GET.BLOCK (SEG, BLOCK.NO) => BLOCK.RA;
   DEV.NO => V.IO.DEV.NO;
   IF IO.STATUS & (COMMS ! OUTPUT) /= 0 THEN
      BLOCK.RA +> ADDRESS;
   FI
FI
@BOX 15.1
IO.REQS -=> IO.SW.INT [GROUP.NO];
0 => INT.STATUS;
@BOX 17.1
SYS01.CLEAR.INTERRUPT ();
@BOX 18.1
SYS01.NEXT.ACTIVITY ();
SYS01.SET.INTERRUPT (SYS01.IO.ACTIVITY, 0);
@BOX 19.1
1 => TASK.REQS;
@BOX 20.1
IF IO.STATUS & DIRECT.IO = 0 THEN
   SET.IO.TASK (DEV.NO, 0);
ELSE
   SYS06.ACTIVATION (DEST [0] ->> 9, SYS06.IO.SUS);
   IF (DISENGAGED ! BREAKIN) & INT.STATUS /= 0 THEN
      DIRECT.IO -=> IO.STATUS;
      SET.IO.TASK (DEV.NO, 0);
   FI
FI
@BOX 21.1
IF BLOCK.RA /= 0 THEN
   IF IO.STATUS & (COMMS ! OUTPUT) /= 0 THEN
      BLOCK.RA -> ADDRESS;
   FI
   IF IO.STATUS & OUTPUT = 0 THEN
      SYS14.UPDATE.BLOCK (BLOCK.RA);
   FI
   SYS14.REL.BLOCK (BLOCK.RA);
   0 => BLOCK.RA;
FI
@BOX 23.1
END
@BOX 24.1
V.IO.ADDRESS => ADDRESS;
V.IO.COUNT => COUNT;
@END
@TITLE SYSINT07.2(2,10)

@COL 1S-3R-4F

@FLOW 1-3-4

@BOX 1.0
SET IO INTERRUPT (DEVICE NO, DUMMY)
@BOX 3.0
SET SOFTWARE INTERRUPT FOR DEVICE
@BOX 4.0
END
@BOX 1.1
PROC SET.IO.INT (DEV.NO, DUMMY);
@BOX 3.1
BIT.VEC [DEV.NO & %F] !> IO.SW.INT [DEV.NO ->> 4];
SYS01.SET.INTERRUPT (SYS01.IO.ACTIVITY, 0);
SYS01.NEXT.ACTIVITY ();
@BOX 4.1
END
@END
@TITLE SYSINT07.3(2,10)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
SET IO TASK (DEVICE NO, DUMMY)
@BOX 2.0
SET TASK FOR I/O MANAGER
@BOX 3.0
END
@BOX 1.1
PROC SET.IO.TASK (DEV.NO, DUMMY);
@BOX 2.1
BIT.VEC [DEV.NO & %F] !> IO.TASKS [DEV.NO ->> 4];
SYS20.SET.TASK (SYS20.IO.TASK, 0);
@BOX 3.1
END
@END
@TITLE SYSINT07.4(2,10)

@COL 1S-2R-3T-4R-5F
@COL 6R

@ROW 4-6

@FLOW 1-2-3NO-4-5
@FLOW 3YES-6-5

@BOX 1.0
CLEAR IO TASK (SW INTERRUPT REQUEST, DUMMY)
@BOX 2.0
SET SOFTWARE INTERRUPT FOR DEVICE, IF NECESSARY
@BOX 3.0
FIND A DEVICE WITH TASK REQUEST SET?
@BOX 4.0
RESET TASK REQUEST FOR THE DEVICE
@BOX 5.0
END
@BOX 6.0
START THE INTERRUPT ACTIVITY
@BOX 1.1
PROC CLEAR.IO.TASK (SW.INT.REQS, DUMMY);
LOGICAL16 TASK.REQS;
INTEGER GROUP.NO;
@BOX 2.1
IF SW.INT.REQS > 0 THEN
   BIT.VEC [TASK.DEV.NO & %F]
      !> IO.SW.INT [TASK.DEV.NO ->> 4];
FI
@BOX 3.1
0 => TASK.DEV.NO => GROUP.NO;
WHILE TASK.DEV.NO < SYS19.NO.OF.DEVICES
   AND IO.TASKS [GROUP.NO] => TASK.REQS = 0 DO
   1 +> GROUP.NO;
   16 +> TASK.DEV.NO;
OD
IF TASK.DEV.NO >= SYS19.NO.OF.DEVICES
@BOX 4.1
WHILE TASK.REQS & %8000 = 0 DO
   1 +> TASK.DEV.NO;
   TASK.REQS <<- 1 => TASK.REQS;
OD
BIT.VEC [TASK.DEV.NO & %F]
   -=> IO.TASKS [GROUP.NO];
@BOX 5.1
END
@BOX 6.1
-1 => TASK.DEV.NO;
SYS01.SET.INTERRUPT (SYS01.IO.ACTIVITY, 0);
SYS01.NEXT.ACTIVITY ();
@END

@TITLE SYSINT07.5(2,10)

@COL 1S-2R-8T-3R-4T-5R-6F
@COL 7R-9R

@ROW 5-7

@FLOW 1-2-8NO-3-4NO-5-6
@FLOW 4TR COMP-7-9-6
@FLOW 8YES-5

@BOX 1.0
START DEVICE (DEVICE NO., DUMMY)
@BOX  2.0
SELECT DEVICE
@BOX 3.0
START TRANSFER
@BOX 4.0
TRANSFER COMPLETE?
@BOX 5.0
DEACTIVATE USER PROCESS
[SYS06]
@BOX 6.0
END
@BOX 7.0
NOTE COUNT
@BOX 8.0
DEVICE DISENGAGED?
@BOX 9.0
CHECKOUT
[SYS01]
@BOX 1.1
PROC START.DEVICE (DEV.NO, DUMMY);
@BOX 2.1
SELECT IO.VARS [DEV.NO];
DEV.NO => V.IO.DEV.NO;
@BOX 3.1
ADDRESS => V.IO.ADDRESS;
COUNT => V.IO.COUNT;
START.TR.CMD => V.IO.CONTROL;
@BOX 4.1
IF (ABANDON ! TR.COMP) & V.IO.CONTROL = TR.COMP
@BOX 5.1
SYS06.DEACTIVATION (SYS06.IO.SUS, 0);
@BOX 6.1
END
@BOX 7.1
V.IO.CONTROL => INT.STATUS;
V.IO.COUNT => COUNT;
STOP.CMD => V.IO.CONTROL;
@BOX 8.1
0 => INT.STATUS;
IF V.IO.CONTROL & DISENGAGED /= 0
@BOX 9.1
SYS01.CHECKOUT (0, 0);
@END


@TITLE SYSINT07.6(2,10)

@COL 1S-2R-3T-4R-5R-6F
@COL 7R

@ROW 4-7

@FLOW 1-2-3NO-4-5-6
@FLOW 3YES-7-6

@BOX 1.0
DEVICE COMMAND (DEVICE NO., COMMAND)
@BOX 2.0
SELECT DEVICE
@BOX 3.0
DEVICE ENQUIRY?
@BOX 4.0
EXECUTE COMMAND
@BOX 5.0
CLEAR INTERRUPT
@BOX 6.0
END
@BOX 7.0
RETURN PHYSICAL DEVICE
STATUS
@BOX 1.1
PROC DEVICE.COMMAND (DEV.NO, COMMAND);
@BOX 2.1
DEV.NO => V.IO.DEV.NO;
@BOX 3.1
IF COMMAND = ENQ.CMD
@BOX 4.1
SELECT IO.VARS [DEV.NO];
0 => INT.STATUS;
IF COMMAND = INIT.CMD THEN
   IO.P.DEV.NO => V.IO.P.DEV.NO;
   IO.P.DEV.TYPE => V.IO.P.DEV.TYPE;
   IO.P.DEV.MODE => V.IO.P.DEV.MODE;
   IO.P.DEV.PARS => V.IO.P.DEV.PARS;
   IO.P.DEV.PROTOCOL => V.IO.P.DEV.PROTOCOL;
FI
COMMAND => V.IO.CONTROL;
@BOX 5.1
V.IO.CONTROL => INT.STATUS;
STOP.CMD => V.IO.CONTROL;
@BOX 6.1
END
@BOX 7.1
V.IO.P.DEV.NO => IO.P.DEV.NO;
V.IO.P.DEV.TYPE => IO.P.DEV.TYPE;
V.IO.P.DEV.MODE => IO.P.DEV.MODE;
V.IO.P.DEV.PARS => IO.P.DEV.PARS;
V.IO.P.DEV.PROTOCOL => IO.P.DEV.PROTOCOL;
@END


@TITLE SYSCMD07.1(2,10)
@COL 1S-3R-4R-5F
@FLOW 1-3-4-5
@BOX 1.0
CONNECT (DEVICE NO, LOGICAL DEVICE STATUS, CHANNEL, BUFFER VA, BUFFER RA,
   PHYSICAL DEVICE ID, PHYSICAL DEVICE MODE, PHYSICAL DEVICE PARS,
   PAIR DEVICE NO.)
@BOX 3.0
SET UP DEVICE PARAMETERS
@BOX 4.0
SET COMMAND TO INITIALISE
DEVICE IF REQUIRED
@BOX 5.0
END
@BOX 1.1
PROC CONNECT (DEV.NO, LOGICAL.DEV.STATUS, CHANNEL, BUFFER.VA, BUFFER.RA,
   PHYSICAL.DEV.ID, PHYSICAL.DEV.MODE, PHYSICAL.DEV.PARS, PAIR.DEV.NO);
INTEGER P.DEV.NO;
LOGICAL32 TEMP;
SELECT IO.VARS [DEV.NO];
@BOX 3.1
CONNECTED => SOFTWARE.STATE;
PAIR.DEV.NO => PAIR.NO;
CHANNEL => CH.NO;
LOGICAL.DEV.STATUS & %FF00 ->> 8 => DEVICE.CLASS;
LOGICAL.DEV.STATUS & %FF ! WAITING => IO.STATUS;
MAKE (LOGICAL8, SYS19.PERI.BUFF.SIZE => BUF.SIZE, BUFFER.VA) => HEADER;
BUFFER.RA => BUF.RA;
SYS19.MAX.DATA.TRANSFER [IO.STATUS & 3] => MAX.TR;
@BOX 4.1
SYS15.SET.PERI.CH.STATUS (CH.NO, 1, 0, 0);
IF DEVICE.CLASS /= SYS19.TALK.OUT.DEVICE.CLASS THEN
   SYS13.ENTER.INT.LEVEL (^SYS01.CHECKIN, 0, 0);
   PHYSICAL.DEV.ID & %FF => IO.P.DEV.NO;
   PHYSICAL.DEV.ID ->> 8 & %FF => IO.P.DEV.TYPE;
   PHYSICAL.DEV.MODE => IO.P.DEV.MODE => OLD.P.DEV.MODE;
   PHYSICAL.DEV.PARS => IO.P.DEV.PARS;
   DEVICE.CLASS => IO.P.DEV.PROTOCOL;
   SYS13.ENTER.INT.LEVEL (^DEVICE.COMMAND, DEV.NO, INIT.CMD);
   SYS13.ENTER.INT.LEVEL (^SYS01.CHECKOUT, 0, 0);
FI
@BOX 5.1
END
@END
@TITLE SYSCMD07.2(2,10)
@COL 1S-6T-3R-5R-7F
@FLOW 1-6YES-3-5-7
@FLOW 6YES-7
@BOX 1.0
DISCONNECT (DEVICE NO)
@BOX 3.0
NOTE DEVICE IS DISCONNECTED AND
ABANDON CURRENT DOCUMENT
@BOX 5.0
CONFIGURE DEVICE OUT
@BOX 6.0
ALREADY DISCONNECTED?
@BOX 7.0
END
@BOX 1.1
PROC DISCONNECT (DEV.NO);
SELECT IO.VARS [DEV.NO];
@BOX 3.1
DISCONNECTED => SOFTWARE.STATE;
IF IO.STATUS & BUFFERED /= 0 THEN
   RELEASE.SEGMENT (SEG);
FI
@BOX 5.1
SYS13.ENTER.INT.LEVEL (^DEVICE.COMMAND, DEV.NO, CON.OUT.CMD);
@BOX 6.1
IF SOFTWARE.STATE = DISCONNECTED
@BOX 7.1
END
@END
@TITLE SYSCMD07.3(2,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
HOLD (DEVICE NO)
@BOX 2.0
SET DEVICE INTO 'HELD' STATE
@BOX 3.0
END
@BOX 1.1
PROC HOLD (DEV.NO);
SELECT IO.VARS [DEV.NO];
@BOX 2.1
HELD => SOFTWARE.STATE;
@BOX 3.1
END
@END
@TITLE SYSCMD07.4(2,11)
@COL 1S-4R-6F
@FLOW 1-4-6
@BOX 1.0
RETURN DOCUMENT (DEVICE NO, HEADER, SEGMENT)
@BOX 4.0
RETURN INFORMATION
ABOUT CURRENT DOCUMENT
@BOX 6.0
END
@BOX 1.1
PROC RETURN.DOC (DEV.NO, HEADERP, SEGMENTP);
SELECT IO.VARS [DEV.NO];
@BOX 4.1
HEADER => ADDRESS OF HEADERP^;
SEG => SEGMENTP^;
LONG.MESS ! BUFFERED & IO.STATUS -=> IO.STATUS;
0 => SEG;
WAITING !> IO.STATUS;
@BOX 6.1
END
@END
@TITLE SYSCMD07.5(2,10)
@COL 1S-3R-4R-5F
@FLOW 1-3-4-5
@BOX 1.0
RESTART (DEVICE NO)
@BOX 3.0
MARK DEVICE AS CONNECTED
@BOX 4.0
SET TASK REQUEST FOR THE DEVICE AND
TRIGGER I/O MANAGEMENT TASK
@BOX 5.0
END
@BOX 1.1
PROC RESTART (DEV.NO);
SELECT IO.VARS [DEV.NO];
@BOX 3.1
CONNECTED => SOFTWARE.STATE;
0 => INT.STATUS;
@BOX 4.1
SYS13.ENTER.INT.LEVEL (^SET.IO.TASK, DEV.NO, 0);
@BOX 5.1
END
@END
@TITLE SYSCMD07.6(2,10)
@COL 1S-2R-4F
@FLOW 1-2-4
@BOX 1.0
NOTE PERIPHERAL MESSAGE (CHANNEL)
@BOX 2.0
SET TASK REQUEST FOR A WAITING DEVICE
CONNECTED TO THIS MESSAGE CHANNEL
@BOX 4.0
END
@BOX 1.1
PROC NOTE.PERI.MESSAGE (CH);
INTEGER DEV.NO;
@BOX 2.1
-1 => DEV.NO;
WHILE 1 +> DEV.NO < SYS19.NO.OF.DEVICES DO
   SELECT IO.VARS [DEV.NO];
   IF (WAITING ! OUTPUT) & IO.STATUS = (WAITING ! OUTPUT) AND
      CH = CH.NO THEN
      SYS13.ENTER.INT.LEVEL (^SET.IO.TASK, DEV.NO, 0);
      SYS19.NO.OF.DEVICES => DEV.NO;
   FI
OD
@BOX 4.1
END
@END
@TITLE SYSCMD07.7(2,10)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
TINI IO (PID)
@BOX 2.0
LOG OUT ALL DEVICES LOGGED IN
TO THE PROCESS
@BOX 3.0
END
@BOX 1.1
PROC TINI.IO (PID);
INTEGER DEV.NO;
@BOX 2.1
FOR DEV.NO < SYS19.NO.OF.DEVICES DO
   SELECT IO.VARS [DEV.NO];
   IF IO.STATUS & LOGGED.IN /= 0 AND DEST [1] = PID THEN
      LOGGED.IN -=> IO.STATUS;
      DIRECT.IO & IO.STATUS -=> IO.STATUS;
      IF PAIR.NO > 0 THEN
         SYS15.SET.PERI.CH.STATUS (CH.NO, 1, 0, 0);
         DIRECT.IO & IO.STATUS OF IO.VARS [PAIR.NO]
            -=> IO.STATUS OF IO.VARS [PAIR.NO];
      FI
      DISENGAGE.CMD => CONTROL;
      SYS13.ENTER.INT.LEVEL (^SET.IO.INT, DEV.NO, 0);
   FI
OD
@BOX 3.1
END
@END
@TITLE SYSCMD07.8(2,10)

@COL 1S-2T-3T-4R-5R-6R-7R-8F
@COL 10R

@ROW 10-3

@FLOW 1-2OK-3OK-4-5-6-7-8
@FLOW 2INVALID-10-8
@FLOW 3NOT LOGGED IN-8

@BOX 1.0
CONFIG ENQ (DEVICE NO)
@BOX 2.0
CHECK DEVICE NUMBER
@BOX 3.0
CHECK DEVICE AVAILABLE TO
PROCESS
@BOX 4.0
CHECKIN
[SYS01]
@BOX 5.0
READ PHYSICAL DEVICECE STATE
@BOX 6.0
RETURN DEVICE INFORMATION
@BOX 7.0
CHECKOUT
[SYS01]
@BOX 8.0
END
@BOX 10.0
RETURN FAULT STATUS -92
(INVALID I/O DEVICE NUMBER)
@BOX 1.1
PROC CONFIG.ENQ (DEV.NO);
0 => PW0;
@BOX 2.1
IF DEV.NO < 0 OR DEV.NO >= SYS19.NO.OF.DEVICES
@BOX 3.1
SELECT IO.VARS [DEV.NO];
SYS13.CHECK.PRIV ();
IF PW0 /= 0 AND
   [IO.STATUS & LOGGED.IN /= 0 OR
      SYS13.CURRENT.SPN <<- 9 ! V.MC.NO /= DEST [0]]
@BOX 4.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 5.1
SYS13.ENTER.INT.LEVEL (^DEVICE.COMMAND, DEV.NO, ENQ.CMD);
@BOX 6.1
IO.P.DEV.TYPE <<- 8 ! IO.P.DEV.NO => PW1;
PAIR.NO => PW2;
CH.NO => PW3;
DEVICE.CLASS <<- 8 ! (IO.STATUS & %FF) => PW4;
IO.P.DEV.MODE => PW5;
IO.P.DEV.PARS => PW6;
@BOX 7.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECKOUT, 0, 0);
@BOX 8.1
END
@BOX 10.1
-92 => PW0;
@END


@TITLE SYSCMD07.9(2,10)

@COL 9R
@COL 1S-2T-3T-4T-5R-6R-7R-8F
@COL 10R

@ROW 10-4
@ROW 9-5

@FLOW 1-2OK-3FOUND-4OK-5-6-7-8
@FLOW 2INVALID-10-8
@FLOW 3NOT FOUND-10
@FLOW 4NOT LOGGED IN-9-8

@BOX 1.0
CHANGE CHANNEL (PERIPHERAL SPN, I/O STATE, PHYSICAL MODE)
@BOX 2.0
CHECK PERIPHERAL SPN
@BOX 3.0
FIND RELEVANT INPUT DEVICE
@BOX 4.0
CHECK DEVICE LOGGED IN TO
PROCESS
@BOX 5.0
CHANGE PHYSICAL MODE
[SYSCMD07.12]
@BOX 6.0
NOTE NEW I/O STATE
@BOX 7.0
RETURN RESULTS
@BOX 8.0
END
@BOX 9.0
RETURN FAULT STATUS -94
(DEVICE NOT AVAILABLE TO PROCESS)
@BOX 10.0
RETURN FAULT STATUS -93
(ILLEGAL PERIPHERAL CHANNEL)
@BOX 1.1
PROC CHANGE.CHANNEL (PERI.SPN, IO.STATE, P.MODE);
INTEGER DEV.NO, CHANNEL.NO, OLD.P.MODE;
0 => PW0;
@BOX 2.1
IF PERI.SPN & %100 = 0 OR
   PERI.SPN & %FF /= V.MC.NO
@BOX 3.1
-1 => DEV.NO;
PERI.SPN ->> 9 => CHANNEL.NO;
WHILE 1 +> DEV.NO < SYS19.NO.OF.DEVICES AND
   [CH.NO OF IO.VARS [DEV.NO] /= CHANNEL.NO OR
      IO.STATUS OF IO.VARS [DEV.NO] & OUTPUT /= 0] DO OD
IF DEV.NO = SYS19.NO.OF.DEVICES
@BOX 4.1
SELECT IO.VARS [DEV.NO];
IF IO.STATUS & LOGGED.IN = 0 OR
   SYS13.CURRENT.SPN <<- 9 ! V.MC.NO /= DEST [0]
   OR PAIR.NO < 0
   OR IO.STATUS OF IO.VARS [PAIR.NO] & DEDICATED = 0
@BOX 5.1
CHANGE.P.MODE (DEV.NO, P.MODE & %FF) => OLD.P.MODE;
CHANGE.P.MODE (PAIR.NO, P.MODE ->> 8) <<- 8
   !> OLD.P.MODE;
@BOX 6.1
IF IO.STATE = 0 THEN
   DIRECT.IO !> IO.STATUS;
   BUF.SIZE => PTR;
ELSE
   DIRECT.IO & IO.STATUS -=> IO.STATUS;
   DIRECT.IO & IO.STATUS OF IO.VARS [PAIR.NO]
     -=> IO.STATUS OF IO.VARS [PAIR.NO];
FI
@BOX 7.1
DEV.NO => PW1;
OLD.P.MODE => PW2;
@BOX 8.1
END
@BOX 9.1
-90 => PW0;
@BOX 10.1
-90 => PW0;
@BOX 11.1
DIRECT.IO !> IO.STATUS;
0 => PTR;
@END


@TITLE SYSCMD07.10(2,10)

@COL 11N-8R-10R
@COL 1S-2T-3T-4T-5T-6R-7F
@COL 9R

@ROW 11-4
@ROW 8-6-9

@FLOW 1-2NO-3LOGGED IN-4DIRECT I/O-5NO-6-7
@FLOW 2YES-9-7
@FLOW 3NOT LOGGED IN-9
@FLOW 4NORMAL I/O-9
@FLOW 5YES-8-10-11-4

@BOX 1.0
READ CHARACTER (DEVICE NO)
@BOX 2.0
DEVICE OUT OF RANGE?
@BOX 3.0
CHECK DEVICE LOGGED IN
@BOX 4.0
CHECK DEVICE TYPE
@BOX 5.0
BUFFER EMPTY?
@BOX 6.0
READ NEXT CHARACTER FROM BUFFER
@BOX 7.0
END
@BOX 8.0
ENTER INTERRUPT LEVEL TO
START THE DEVICE
@BOX 9.0
RETURN FAULT STATUS -92 IN PW0
(INVALID I/O DEVICE NUMBER)
@BOX 10.0
RESET POINTER
@BOX 1.1
PROC READ.CH (DEV.NO);
0 => PW0;
@BOX 2.1
IF DEV.NO < 0 OR DEV.NO >= SYS19.NO.OF.DEVICES
@BOX 3.1
SELECT IO.VARS [DEV.NO];
IF IO.STATUS & LOGGED.IN = 0 OR
SYS13.CURRENT.SPN <<- 9 ! V.MC.NO /= DEST [0]
@BOX 4.1
IF IO.STATUS & DIRECT.IO = 0
@BOX 5.1
IF PTR >= BUF.SIZE - COUNT
@BOX 6.1
HEADER^ [PTR] => PW1;
IF 1 +> PTR >= BUF.SIZE - COUNT THEN
   %100 !> PW1;
FI
@BOX 7.1
END
@BOX 8.1
BUF.SIZE => COUNT;
BUF.RA => ADDRESS;
START.TR.CMD => CONTROL;
SYS13.ENTER.INT.LEVEL (^SYS01.CHECKIN, 0, 0);
SYS13.ENTER.INT.LEVEL (^START.DEVICE, DEV.NO, 0);
@BOX 9.1
-92 => PW0;
@BOX 10.1
IF INT.STATUS & TR.COMP = 0 THEN
   BUF.SIZE => COUNT;
FI
0 => PTR;
@END
@TITLE SYSCMD07.11(2,10)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
WRITE CH (DEVICE NO, CHAR)
@BOX 2.0
NOT IMPLEMENTED
@BOX 3.0
END
@BOX 1.1
PROC WRITE.CH (DEV.NO, CHAR);
0 => PW0;
@BOX 2.1
::NOT IMPLEMENTED
@BOX 3.1
END
@END
@TITLE SYSCMD07.12(2,10)

@COL 1S-2R-3R-4R-5R-6R-7F

@FLOW 1-2-3-4-5-6-7

@BOX 1.0
CHANGE PHYSICAL MODE (DEVICE NO, PHYSICAL MODE)
@BOX 2.0
CHECKIN
[SYS01]
@BOX 3.0
CONFIGURE OUT DEVICE
@BOX 4.0
CHANGE MODE
@BOX 5.0
RE-INITIALIZE DEVICE
@BOX 6.0
CHECKOUT
[SYS01]
@BOX 7.0
END
@BOX 1.1
PROC CHANGE.P.MODE (DEV.NO, P.MODE);
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECKIN, 0, 0);
@BOX 3.1
SYS13.ENTER.INT.LEVEL (^DEVICE.COMMAND, DEV.NO, CON.OUT.CMD);
@BOX 4.1
SYS13.ENTER.INT.LEVEL (^DEVICE.COMMAND, DEV.NO, ENQ.CMD);
IO.P.DEV.MODE => CHANGE.P.MODE;
P.MODE => IO.P.DEV.MODE;
@BOX 5.1
SYS13.ENTER.INT.LEVEL (^DEVICE.COMMAND, DEV.NO, INIT.CMD);
@BOX 6.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECKOUT, 0, 0);
@BOX  7.1
END
@END


@TITLE SYSTSK07.1(2,10)

@COL 1S-2T-3R-4T-9T-10R-19N
@COL 12F-15R-18N

@ROW 3-12
@ROW 10-15
@ROW 19-18

@FLOW 1-2FOUND-3-4OTHERS-9NO-10-19-2
@FLOW 2NONE-12
@FLOW 4HELD/DISCONNECTED-2
@FLOW 9YES-15-18-19

@BOX 1.0
I/O MANAGEMENT TASK
@BOX 2.0
FIND A DEVICE TO SERVICE
@BOX 3.0
NOTE TASK REQUEST FOR THE DEVICE
@BOX 4.0
IS THE DEVICE INOPERABLE?
@BOX 9.0
TRANSFER FAIL OR RESTART?
@BOX 10.0
SERVICE THE TASK REQUEST
@BOX 12.0
END
@BOX 15.0
SWITCH TO HELD STATE,
INFORM CONFIGURATION MANAGER
@BOX 1.1
PROC IO.TASK;
INTEGER DEV.NO, SW.INT.REQS, TSEG;
LOGICAL REASON;
ADDRESS8 THEADER;
ADDR IO.PROC IO.PROC.CALL;
0 => SW.INT.REQS;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^CLEAR.IO.TASK, SW.INT.REQS, 0);
IF TASK.DEV.NO < 0
@BOX 3.1
0 => SW.INT.REQS;
SELECT IO.VARS [TASK.DEV.NO => DEV.NO];
@BOX 4.1
IF SOFTWARE.STATE = HELD OR
   SOFTWARE.STATE = DISCONNECTED
@BOX 9.1
IF IO.STATUS & COMMS /= 0 AND
   INT.STATUS & RESTARTED /= 0
   OR INT.STATUS & TR.FAIL /= 0
@BOX 10.1
-1 => SW.INT.REQS;
WHILE SW.INT.REQS < 0 DO
   IO.TASK.PROCS [DEVICE.CLASS] => IO.PROC.CALL;
   IO.PROC.CALL^ (DEV.NO) => SW.INT.REQS;
OD
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^SET.IO.INT, TASK.VEC, SW.INT.VEC);
@BOX 12.1
END
@BOX 15.1
HOLD (DEV.NO);
SYS19.HELD (DEV.NO, INT.STATUS);
@END
@TITLE SYSTSK07.2(2,11)
@COL 1S-2T-24T-4T-3T-5T-8N-21T-6T-17T-18R-19R-15N-10F
@COL 25R-14R-20R-22N
@ROW 3-25
@ROW 21-14
@ROW 20-19
@ROW 15-22
@FLOW 1-2***-24NO-4OTHER-3A, M OR S-5-8-21-6***A INPUT-17OK-18-19-15-10
@FLOW 2DATA-15
@FLOW 24YES-25-22
@FLOW 4***Z-14-22-15
@FLOW 17FAIL-20-22
@FLOW 21FAIL-15
@FLOW 6***M-15
@FLOW 3OTHER-15
@FLOW 5***A OUTPUT-15
@BOX 1.0
PROCESS COMMAND LINE (DEVICE NO, BUFFER) STATUS
@BOX 2.0
ORDINARY DATA LINE?
@BOX 3.0
IS IT ***A, ***M OR ***S?
@BOX 4.0
IS IT ***Z?
@BOX 5.0
***A ON AN OUTPUT DEVICE?
@BOX 6.0
***M/B OR ***A INPUT?
@BOX 10.0
END
@BOX 14.0
LOG OUT DEVICE
@BOX 17.0
CREATE BUFFER SEGMENT
@BOX 18.0
SET POINTERS FOR BUFFERED
CHARACTER INPUT
@BOX 19.0
COPY HEADER INTO SEGMENT
FOR USE IN SEND MESS
@BOX 20.0
LOG OUT DEVICE
@BOX 21.0
LOG IN DEVICE
#SYSTSK07.2.1
@BOX 24.0
TALK COMMAND?
@BOX 25.0
CHANGE TO TALK DEVICE CLASS
@BOX 1.1
PROC COMMAND.LINE (DEV.NO, HDR);
INTEGER IN, OUT, I, J,
   SEG.START, BYTE.NO;
LOGICAL8 CH;
0 => COMMAND.LINE;
SELECT IO.VARS [DEV.NO];
@BOX 2.1
IF HDR^ [0] < 4 OR
   HDR^ [4] /= "*" OR
   HDR^ [5] /= "*" OR
   HDR^ [6] /= "*"
@BOX 3.1
IF CH /= "A" /= "M" /= "S"
@BOX 4.1
IF CH = "Z"
@BOX 5.1
IF CH = "A" AND
   IO.STATUS & OUTPUT /= 0
@BOX 6.1
IF CH /= "A"
@BOX 10.1
END
@BOX 14.1
::LOG OUT DEVICE
#SYSTSK07.2.2
@BOX 17.1
CREATE.X.SEGMENT (MAX.TR);
IF PW0 /= 0
@BOX 18.1
PW1 => SEG;
0 => BLOCK.NO;
LONG.MESS ! BUFFERED !> IO.STATUS;
MAKE (LOGICAL8, SYS14.PAGE.SIZE,
   MAP.SEG (SEG)) => SEG.PTR;
@BOX 19.1
FOR I < 4 + HDR^ [0] DO
   HDR^ [I] => SEG.PTR^ [I];
OD
I - 1 => PTR;
UPDATE.SEG (SEG);
@BOX 20.1
LOGGED.IN ! IO.STATUS -=> IO.STATUS;
@BOX 21.1
::LOG IN DEVICE
#SYSTSK07.2.1
IF PW0 < 0
@BOX 24.1
IF HDR^ [7] => CH = "T"
   AND (OUTPUT ! LOGGED.IN ! INTERACTIVE)
   & IO.STATUS = (LOGGED.IN ! INTERACTIVE)
@BOX 25.1
-1 => COMMAND.LINE;
DEVICE.CLASS => OLD.DEVICE.CLASS;
SYS19.TALK.IN.DEVICE.CLASS => DEVICE.CLASS;
76 => HDR^ [0];
@END
@TITLE SYSTSK07.2.1(2,11)
@COL 18N-17R
@COL 1S-16T-2R-3T-12R-4R-5T-6R-7T-8R-10F
@ROW 18-16
@FLOW 1-16NO-2-3OK-12-4-5NO-6-7NO-8-10
@FLOW 16YES-18-17-12
@FLOW 3FAULTY-10
@FLOW 5YES-7
@FLOW 7YES-10
@BOX 1.0
LOG IN DEVICE
@BOX 2.0
READ PROCESS NAME AND
DELETE FROM BUFFER
@BOX 3.0
LOOK UP PROCESS
@BOX 4.0
DETERMINE INPUT AND
OUTPUT DEVICE NUMBERS
@BOX 5.0
IS THE OUTPUT DEVICE
NON-EXISTENT OR SHAREABLE
@BOX 6.0
DEDICATE THE OUTPUT
DEVICE CHANNEL
@BOX 7.0
IS THE INPUT DEVICE
NON-EXISTENT?
@BOX 8.0
LOG IN THE INPUT DEVICE
@BOX 10.0
END
@BOX 12.0
CLEAR NAME FROM HEADER
@BOX 16.0
***S?
@BOX 17.0
READ SPN AND PID
OF THE PROCESS
@BOX 1.1
LOG.IN: BEGIN
INTEGER I, J, IN, OUT, B.COUNT, CHAR, VALUE;
:: IO.VARS [DEV.NO] SELECTED
@BOX 2.1
FIND.NAME (HDR, 8) => J;
@BOX 3.1
LOOK.UP.PROCESS (PWW1, PWW2);
IF PW0 /= 0
@BOX 4.1
IF IO.STATUS & OUTPUT /= 0 THEN
   DEV.NO => OUT;
   PAIR.NO => IN;
ELSE
   DEV.NO => IN;
   PAIR.NO => OUT;
FI
@BOX 5.1
IF OUT < 0 OR
   IO.STATUS OF IO.VARS [OUT] & DEDICATED = 0
@BOX 6.1
SYS15.SET.PERI.CH.STATUS (CH.NO, 2, PW2 =>
   DEST [1] OF IO.VARS [OUT], 0);
@BOX 7.1
IF IN < 0
@BOX 8.1
BEGIN
:: SAFE TO SELECT IO.VARS [IN]
   SELECT IO.VARS [IN];
   LOGGED.IN !> IO.STATUS;
   PW1 => DEST [0];
   PW2 => DEST [1];
   PW3 => DEST [2];
   0 => DEST [3];
END
@BOX 10.1
END
@BOX 12.1
3 => I;
WHILE 1 +> I < J DO
   " " => HDR^ [I];
OD
@BOX 16.1
IF CH = "S"
@BOX 17.1
8 => PW3;
HDR^ [0] + 4 => B.COUNT;
8 => J;
FOR I < 2 DO
   0 => VALUE;
   WHILE HDR^ [J] /= "$L" =< " " AND
      J < B.COUNT DO
      1 +> J;
   OD
   WHILE J < B.COUNT AND
      [[HDR^ [J] => CHAR >= "0" =< "9"] OR
         [CHAR >= "A" =< "F"]] DO
      VALUE <<- 4 => VALUE;
      IF CHAR >= "0" =< "9" THEN
         CHAR - "0" +> VALUE;
      ELSE
         CHAR - "A" + 10 +> VALUE;
      FI
   1 +> J;
   OD
   IF I = 0 THEN
      VALUE => PW1;
   ELSE
      VALUE => PW2;
   FI
OD
@END
@TITLE SYSTSK07.2.2(2,11)

@COL 1S-2R-3R-4F

@FLOW 1-2-3-4

@BOX 1.0
LOG OUT DEVICE
@BOX 2.0
LOG THE DEVICE OUT
@BOX 3.0
REMOVE ***Z FROM BUFFER
@BOX 4.0
END
@BOX 1.1
::LOG OUT DEVICE
BEGIN
::IO.VARS [DEV.NO] SELECTED
@BOX 2.1
IF IO.STATUS & OUTPUT /= 0 THEN
   DEV.NO => OUT;
   PAIR.NO => IN;
ELSE
   DEV.NO => IN;
   PAIR.NO => OUT;
FI
IF IN >= 0 THEN
   LOGGED.IN & IO.STATUS OF IO.VARS [IN]
      -=> IO.STATUS OF IO.VARS [IN];
FI
IF OUT >= 0 AND
   IO.STATUS & DEDICATED /= 0 THEN
   SYS15.SET.PERI.CH.STATUS (CH.NO, 1, 0, 0);
FI
@BOX 3.1
0 => HDR^ [0];
@BOX 4.1
END
@END
@TITLE SYSTSK07.3(2,11)
@COL 1S-2T-3T-4R-5R-6T-7R-8T-15R-11F
@COL 13R-10R
@ROW 7-13
@ROW 15-10
@FLOW 1-2NO-3NO-4-5-6CHAR-7-8YES-10-11
@FLOW 2YES-15
@FLOW 3YES-6
@FLOW 6COMMS-13-8
@FLOW 8NO-15-11
@BOX 1.0
SEND MESS (DEVICE NO) STATUS
@BOX 2.0
IS DEVICE LOGGED OUT?
@BOX 3.0
IS DEVICE OPERATING
IN UNBUFFERED MODE?
@BOX 4.0
CHANGE SIZE OF
BUFFER SEGMENT
@BOX 5.0
FORM HEADER AND
INSERT CHARACTER COUNT
IF CHARACTER DEVICE
@BOX 6.0
CHARACTER OR COMMUNICATIONS DEVICE?
@BOX 7.0
SEND MESSAGE
@BOX 8.0
SEND MESSAGE OK?
@BOX 10.0
RETURN SUCCESS STATUS
@BOX 11.0
END
@BOX 13.0
SEND PERI MESSAGE
@BOX 14.0
DISCARD BUFFER SEGMENT
@BOX 15.0
RETURN FAULT STATUS
@BOX 1.1
PROC SEND.MESS (DEV.NO);
INTEGER I, J, DISP, BYTE.NO;
INTEGER32 SPN.PID, SEG.COUNT, SEG.SIZE;
SELECT IO.VARS [DEV.NO];
@BOX 2.1
IF COMMS ! LOGGED.IN & IO.STATUS = 0
@BOX 3.1
IF IO.STATUS & BUFFERED = 0
@BOX 4.1
READ.SEGMENT.STATUS (SEG);
BLOCK.NO + 1 <<- SYS14.PAGE.SHIFT + PTR => SEG.SIZE;
IF PW2 & %20 /= 0 THEN
   SEG.SIZE ->> SYS14.PAGE.SHIFT => SEG.SIZE;
FI
CHANGE.SIZE (SEG, SEG.SIZE);
@BOX 5.1
IF IO.STATUS & COMMS = 0 THEN
   MAKE (LOGICAL8, SYS14.PAGE.SIZE, MAP.SEG (SEG)) => SEG.PTR;
   FOR BYTE.NO < 4 DO
      DISP <<- 8 ! SEG.PTR^ [3 - BYTE.NO] => DISP;
   OD
   FOR BYTE.NO < DISP + 4 DO
      SEG.PTR^ [BYTE.NO] => HEADER^ [BYTE.NO];
      " " => SEG.PTR^ [BYTE.NO];
   OD
   "$L" => SEG.PTR^ [BYTE.NO - 1];
   BLOCK.NO <<- SYS14.PAGE.SHIFT + PTR - 4 + 1 => SEG.COUNT;
   FOR BYTE.NO < 4 DO
      SEG.COUNT => SEG.PTR^ [BYTE.NO];
      SEG.COUNT ->> 8 => SEG.COUNT;
   OD
   UPDATE.SEG (SEG);
FI
@BOX 6.1
IF IO.STATUS & COMMS /= 0
@BOX 7.1
CH.NO <<- 9 ! %100 ! V.MC.NO => SPN.PID;
SYS15.SET.ID (SPN.PID, SPN.PID, 0);
SEND.MESSAGE (HEADER, ^DEST, 8, 0, SEG, %1E);
@BOX 8.1
IF PW0 = 0
@BOX 10.1
0 => SEND.MESS;
@BOX 11.1
END
@BOX 13.1
SYS15.SEND.PERI.MESSAGE (HEADER, SEG);
@BOX 15.1
1 => SEND.MESS;
@END
@TITLE SYSTSK07.4(2,11)
@COL 1S-3R-4R-5F
@FLOW 1-3-4-5
@BOX 1.0
MONITOR (DEVICE NO, ERROR)
@BOX 3.0
SELECT AND SET ERROR MESSAGE
   LOGIN PROMPT
   MESSAGE FAULT
   INCORRECTLY TERMINATED DOCUMENT
   TALK FAULT
@BOX 4.0
SEND THE MESSAGE
@BOX 5.0
END
@BOX 1.1
PROC MONITOR (DEV.NO, ERROR);
INTEGER I, MESS.SIZE;
LOGICAL64 NAME;
INTEGER [4] MESS.DEST;
LOGICAL8 [80] ERROR.MSG;
SELECT IO.VARS [DEV.NO];
@BOX 3.1
SIZE (MONITOR.MSG [ERROR]) => MESS.SIZE;
FOR I < MESS.SIZE DO
   MONITOR.MSG [ERROR]^ [I] => ERROR.MSG [I];
OD
IF ERROR = 0 THEN
   VERSION.NO +> ERROR.MSG [28];
   DEV.NO / 10 +> ERROR.MSG [49];
   DEV.NO / 10 * 10 -: DEV.NO +> ERROR.MSG [50];
   SYS18.MACHINE.NAME => NAME;
   40 => I;
   WHILE NAME /= 0 DO
      NAME => ERROR.MSG [I];
      NAME ->> 8 => NAME;
      1 -> I;
   OD
   CH.NO / 10 +> ERROR.MSG [60];
   CH.NO / 10 * 10 -: CH.NO +> ERROR.MSG [61];
ELSE
   DEV.NO / 10 + "0" => ERROR.MSG [7];
   DEV.NO / 10 * 10 -> DEV.NO + "0" => ERROR.MSG [8];
FI
@BOX 4.1
CH.NO <<- 9 ! %100 ! V.MC.NO => MESS.DEST [0] => MESS.DEST [1];
8  => MESS.DEST [2];
0  => MESS.DEST [3];
SEND.MESSAGE (^ERROR.MSG, ^MESS.DEST, 0, 0, 0, 0);
@BOX 5.1
END
@END
@TITLE SYSTSK07.5(2,10)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
MAP SEG (SEG NO)
@BOX 2.0
READ STATUS OF SEGMENT
AND MAP IT IF NECESSARY
@BOX 3.0
END
@BOX 1.1
PROC MAP.SEG (SEG);
INTEGER SEG.SIZE;
@BOX 2.1
READ.SEGMENT.STATUS (SEG);
IF PW2 & %20 /= 0 THEN
   PW1 => SEG.SIZE;
ELSE
   PW1 ->> SYS14.PAGE.SHIFT => SEG.SIZE;
FI
IF PW2 & %40 /= 0 THEN
   IF PW2 & %20 /= 0 THEN
      COPY.BLOCK (SEG, 0, IO.BUF.SEG, IO.BUF.BLK);
      MAP (IO.BUF.SEG, IO.MSEG, 0);
      PW6 <<- SYS14.SEG.SHIFT => MAP.SEG;
      IO.BUF.BLK <<- SYS14.PAGE.SHIFT +> MAP.SEG;
   ELSE
      MAP (SEG, IO.MSEG, 0);
      PW6 <<- SYS14.SEG.SHIFT => MAP.SEG;
   FI
ELSE
   SEG <<- SYS14.SEG.SHIFT => MAP.SEG;
FI
SEG.SIZE => PW1;
@BOX 3.1
END
@END


@TITLE SYSTSK07.6(2,6)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
UPDATE SEGMENT (SEG.NO)
@BOX 2.0
WRITE UPDATED COPY OF SEGMENT
BACK TO MAIN SEGMENT
@BOX 3.0
END
@BOX 1.1
PROC UPDATE.SEG (SEG.NO);
@BOX 2.1
READ.SEGMENT.STATUS (SEG.NO);
IF PW2 & %60 = %60 THEN
   COPY.BLOCK (IO.BUF.SEG, IO.BUF.BLK, SEG.NO, 0);
FI
@BOX 3.1
END
@END
@TITLE SYSTSK07.7(2,10)
@COL 1S-2T-3T-4T-5R
@COL 6F
@ROW 3-6
@FLOW 1-2NO-3TALK-4NO-5-2
@FLOW 2YES-6
@FLOW 3BROADCAST-5
@FLOW 4YES-2
@BOX 1.0
TALK (TALK DESTINATION UID, BUFFER, SEGMENT) STATUS
@BOX 2.0
FIND AN INTERACTIVE OUTPUT DEVICE?
@BOX 3.0
TALK OR BROADCAST?
@BOX 4.0
INCORRECT USER?
@BOX 5.0
SEND THE MESSAGE TO THE USER
@BOX 6.0
END
@BOX 1.1
PROC TALK (TALK.DEST.UID, BUFFER, SEG.NO);
INTEGER DEV.NO;
INTEGER [4] T.DEST;
-1 => TALK => DEV.NO;
@BOX 2.1
WHILE 1 +> DEV.NO < SYS19.NO.OF.DEVICES AND
   IO.STATUS OF IO.VARS [DEV.NO] & (COMMS ! OUTPUT ! INTERACTIVE)
   /= (OUTPUT ! INTERACTIVE) DO
OD
IF DEV.NO = SYS19.NO.OF.DEVICES
@BOX 3.1
SELECT IO.VARS [DEV.NO];
IF TALK.DEST.UID = -1
@BOX 4.1
IF TALK.DEST.UID /= UID OR
   IO.STATUS OF IO.VARS [PAIR.NO] & LOGGED.IN = 0
@BOX 5.1
0 => TALK;
SYS15.SET.ID (DEST [0], DEST [1], UID);
CH.NO <<- 9 ! %100 ! V.MC.NO => T.DEST [0] => T.DEST [1];
8 => T.DEST [2];
0 => T.DEST [3];
SEND.MESSAGE (BUFFER, ^T.DEST, 8, 0, SEG.NO, %1E);
@BOX 6.1
END
@END
@TITLE SYSTSK07.8(2,10)
@COL 1S-2R-3T-4R-8F
@FLOW 1-2-3NO-4-8
@FLOW 3YES-8
@BOX 1.0
PROCESS NAME (NAME)
@BOX 2.0
SET NAMES INITIALLY
TO ZERO
@BOX3.0
CURRENT FILE/STREAM?
@BOX 4.0
COPY NAMES TO
PWW1 AND PWW2
@BOX 8.0
END
@BOX 1.1
PROC PROCESS.NAME (NAME);
INTEGER MAXCH, I;
@BOX 2.1
0 => PWW1 => PWW2;
@BOX 3.1
IF SIZE (NAME) = 0
@BOX 4.1
SIZE (NAME) => MAXCH;
-1 => I;
WHILE 1 +> I < MAXCH AND NAME^ [I] /= "/" DO
   PWW1 <<- 8 ! NAME^ [I] => PWW1;
OD
WHILE 1 +> I < MAXCH DO
   PWW2 <<- 8 ! NAME^ [I] => PWW2;
OD
@BOX 8.1
END
@END
@TITLE SYSTSK07.9(2,11)
@COL 1S-2T-14T-3T-15R-7R-4T-5R-13N-6F
@COL 10N-8R-9R-12N
@ROW 7-10
@ROW 5-8
@ROW 13-12
@FLOW 1-2***-14NO-3***T-15-7-4NO-5-13-6
@FLOW 2DATA-13
@FLOW 14YES-13
@FLOW 3***P-10-9-12-13-6
@FLOW 4YES-8-9
@BOX 1.0
PROCESS TALK COMMAND LINE (DEVICE NO, HEADER) STATUS
@BOX 2.0
ORDINARY DATA LINE?
@BOX 3.0
***T OR ***P?
@BOX 4.0
UNKNOWN DESTINATION MACHINE?
@BOX 5.0
SET UP TALK PARAMETERS
@BOX 6.0
END
@BOX 7.0
READ USERNAME AND MACHINE NAME
@BOX 8.0
OUTPUT TALK ERROR MESSAGE
@BOX 9.0
SET DEVICE TO THE OLD CLASS
@BOX 14.0
NOT ***T/***P COMMAND?
@BOX 15.0
OPEN OUTPUT DEVICE CHANNEL TO ALL
@BOX 1.1
PROC TALK.COMMAND.LINE (DEV.NO, HDR);
INTEGER I, J, B.COUNT;
INTEGER32 SPN.PID;
LOGICAL8 CH;
LOGICAL64 C.MC.NAME;
0 => TALK.COMMAND.LINE;
SELECT IO.VARS [DEV.NO];
@BOX 2.1
IF HDR^ [0] < 4 OR
   HDR^ [4] /= "*" OR
   HDR^ [5] /= "*" OR
   HDR^ [6] /= "*"
@BOX 3.1
IF CH = "P"
@BOX 4.1
PWW1 => TALK.DEST.UNAME;
LOOK.UP.PROCESS ("TALK", PWW2);
IF PW0 /= 0
@BOX 5.1
PW1 => TALK.DEST.SPN.PID;
SYS18.MACHINE.NAME => C.MC.NAME;
UID OF IO.VARS [PAIR.NO] => UID;
DATAVEC INIT.MESS (LOGICAL8)
   " TALKING FROM "
END
FOR J < 14 DO
   INIT.MESS [J] => HDR^ [J + 4];
OD
26 => I;
FOR 8 DO
   C.MC.NAME & %FF => HDR^ [1 -> I];
   C.MC.NAME ->> 8 => C.MC.NAME;
OD
"$L" => HDR^ [26];
23 => HDR^ [0];
@BOX 6.1
END
@BOX 7.1
FIND.NAME (HDR, 8);
@BOX 8.1
MONITOR (DEV.NO, 3);
@BOX 9.1
OLD.DEVICE.CLASS => DEVICE.CLASS;
IF IO.STATUS & DEDICATED /= 0 THEN
   SYS15.SET.PERI.CH.STATUS (CH.NO, 2,
      DEST [1] OF IO.VARS [PAIR.NO], 0);
FI
-1 => TALK.COMMAND.LINE;
"$L" => HDR^ [4];
75 => COUNT;
@BOX 14.1
IF HDR^ [7] => CH /= "T" /= "P"
@BOX 15.1
SYS15.SET.PERI.CH.STATUS (CH.NO, 1, 0, 0);
@END
@TITLE SYSTSK07.10(2,11)

@COL 1S-2R-3R-4R-5F
@FLOW 1-2-3-4-5

@BOX 1.0
FIND NAME (HEADER, START) TO
@BOX 2.0
FIND THE NAME
@BOX 3.0
EXTRACT THE NAME FROM HEADER
@BOX 4.0
PROCESS THE NAME
@BOX 5.0
END
@BOX 1.1
PROC FIND.NAME (HDR, STRT);
INTEGER J, B.COUNT;
ADDR [LOGICAL8] NAME;
@BOX 2.1
HDR^ [0] + 4 => B.COUNT;
WHILE HDR^ [STRT] /= "$L" =< " " AND
   STRT < B.COUNT DO
   1 +> STRT;
OD
STRT => J;
WHILE HDR^ [J] > " " AND
   J < B.COUNT DO
   1 +> J;
OD
@BOX 3.1
IF J => FIND.NAME > STRT THEN
   PART (HDR, STRT, J - 1) => NAME;
ELSE
   NIL.NAME => NAME;
FI
@BOX 4.1
PROCESS.NAME (NAME);
@BOX 5.1
END
@END

