Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ Td(lib) — Sprite KS.390

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Td  —  C Library Procedures

NAME

Td_Create, Td_Delete, Td_PutRaw, Td_GetRaw, Td_ControlRaw, Td_Open, Td_Close, Td_PutCooked, Td_GetCooked, Td_ControlCooked, Td_CreatePdev, Td_DeletePdev − Terminal driver implementing 4.3 BSD operations. 

SYNOPSIS

#include <td.h>
Td_Terminal
Td_Create(bufferSize, cookedProc, cookedData, rawProc, rawData)
Td_Delete(terminal)
Td_PutRaw(terminal, numBytes, buffer)
int
Td_GetRaw(terminal, numBytes, buffer)
Td_ControlRaw(terminal, operation)
int
Td_Open(terminal, selectBitsPtr)
Td_Close(terminal)
int
Td_PutCooked(terminal, numBytesPtr, buffer, sigNumPtr, selectBitsPtr)
int
Td_GetCooked(terminal, pID, familyID, numBytesPtr, buffer, sigNumPtr, selectBitsPtr)
int
Td_ControlCooked(terminal, command, format, inputSize, input, outputSizePtr, output, sigNumPtr, selectBitsPtr)
Td_Pdev
Td_CreatePdev(name, realNamePtr, termPtr, rawProc, rawData)
Td_DeletePdev(ttyPdev)

ARGUMENTS

int bufferSize   (in) Size of output buffer to use for terminal.  This is not an exact specification, in that the terminal driver may actually allow more characters than this to be buffered, but it will always allow at least this many characters to be buffered. 

int (∗cookedProc)()   (in) Procedure to call for control operations on cooked side of driver. 

ClientData cookedData   (in) Additional value to pass to cookedProc. 

int (∗rawProc)()   (in) Procedure to call for control operations on raw side of driver. 

ClientData rawData   (in) Additional value to pass to rawProc. 

Td_Terminal terminal   (in) Token for terminal;  must have been returned by some previous call to Td_Create. 

int numBytes   (in) Total number of bytes to get or put for/from raw side of terminal. 

char ∗buffer   (in/out) Buffer containing characters to be written, or containing space in which to place characters being read. 

int operation   (in) Control operation being invoked from raw side of terminal.  Currently no operations are defined. 

int ∗selectBitsPtr   (in/out) Points to word whose bits (FS_READABLE and FS_WRITABLE) indicate whether read or write operations can complete successfully.  Different procedures may modify either or both of these bits. 

int ∗numBytesPtr   (in/out) Points to maximum number of bytes to read or write.  Gets overwritten with actual number of bytes read or written. 

int ∗sigNumPtr   (out) Overwritten with signal number to apply to invoking process.  Zero means no signal. 

int pID   (in) Identifier of process invoking operation. 

int familyID   (in) Process group that pID belongs to. 

int command   (in) Number of IOControl operation.  Note:  these are Sprite IOControl numbers, not UNIX ioctl numbers.  See <dev/tty.h> for definitions. 

Fmt_Format format   (in) Byte ordering and alignment format for the buffers used in an IOControl.  Usually the constant FMT_MY_FORMAT can be passed in for this parameter. 

int inputSize   (in) Number of bytes of information in input

char ∗input   (in) Input buffer for IOControl operation.  Its structure depends on the IOControl. 

int ∗outputSizePtr   (in/out) Points to word specifiying total number of bytes of output buffer space available at output.  Modified to hold the actual number of output bytes provided by the IOControl. 

char ∗output   (in) Output buffer for IOControl operation.  Its structure depends on the IOControl. 

char ∗name   (in) Name of file to use for terminal pseudo-device.  May be either full name or root. 

char ∗∗realNamePtr   (out) Where to store actual name of terminal pseudo-device used.  NULL means name is a root;  non-NULL means name is the full path name. 

Td_Terminal ∗termPtr   (out) If non-NULL, token for terminal gets stored in the word pointed to by termPtr. 

Td_Pdev ttyPdev   (in) Token for terminal-driven pseudo-device to destroy.  Must have been returned previously by Td_CreatePdev. 
 

INTRODUCTION

The Td library procedures implement a terminal driver with the same features as the terminal driver implemented in the 4.3 BSD kernel.  The data structures managed by the Td library are called Td_Terminals and have two interfaces:  cooked and raw.  The raw interface is used to communicate between the Td procedures and the low-level device corresponding to the terminal (usually a serial line device or a window on a screen).  The cooked interface is used to communicate with processes accessing the 4.3-BSD-like terminal.  In between, the Td library provides input and output character buffering, echoing and line editing, flow control, interrupt characters, and all the other features of the 4.3 BSD terminal driver. 

Each of the cooked and raw interfaces has at least four procedures associated with it.  Three of the procedures are provided by Td:  one to pass characters into the terminal driver (e.g. a character that was just typed on the keyboard, or a character that a user process wishes to ouput on the terminal), one to extract characters from the terminal driver (e.g. to pass them to a waiting user process, or to output them onto the terminal), and one to invoke control operations on the terminal.  The fourth procedure for each interface is provided by the program in which Td is embedded.  These procedures are called back by Td to notify the program of various events, for example, that characters are waiting in the terminal’s output buffer, or that a full line is present in the terminal’s input buffer. 

Most of the procedures in the Td library are generic in that they can be used in many different situations, including both user programs and the Sprite kernel.  Two additional procedures, Td_CreatePdev and Td_DeletePdev are provided to connect the cooked side of a Td_Terminal to a pseudo-device.  These procedures are used by user-level Sprite programs like rlogind and window-based terminal emulators. 
 

CREATING AND DELETING TERMINALS

The Td_Create procedure is used to create a Td_Terminal.  It returns a token that must be passed to most of the other Td procedures.  Several Td_Terminals may exist at the same time, each created by a separate call to Td_Create.  Each Td_Terminal corresponds to one logical terminal with its own input and output buffers.  The cookedProc and rawProc procedures, and their associated ClientData values, are used to invoke control operations on the two sides of the terminal.  The use of these two procedures is described in the sections below.  The bufferSize argument is described in the BUFFERING section below. 

Td_Delete simulates a hangup on a Td_Terminal, then destroys all of the state associated with the terminal.  After it is called, the terminal argument should never be used again by the caller. 
 

RAW INTERFACE

The raw interface is used to communicate between the terminal driver and the “dumb” terminal device.  It consists of the three procedures Td_PutRaw, Td_GetRaw, Td_ControlRaw, and the rawProc procedure passed to Td_Create. 

When characters are typed on the keyboard associated with the raw terminal, they should be passed to the temrinal driver by calling Td_PutRaw.  The Td library will then perform input processing such as echoing and line editing. 

The procedure Td_GetRaw should be invoked to remove characters from the terminal’s output buffer and copy them to buffer.  The return value indicates how many characters were actually copied, up to either numBytes or the total number of characters in the output buffer.  The return value is zero if the output buffer is empty.  The caller of Td_GetRaw should then pass the characters to the raw serial device, or display them on the screen if the terminal is being emulated in a window.  Note that it is up to the application in which Td is embedded to decide when to call Td_GetRaw.  However, Td calls rawProc to notify the application that the terminal’s output buffer contains characters;  see below for details. 

The procedure Td_ControlRaw should be called when certain interesting events occur on the raw terminal.  The operation argument identifies the event that occurred, and must be one of:

TD_BREAKMeans that a break just occurred on the raw device.  Td_ControlRaw should only be called when the break condition ends. 

TD_GOT_CARRIER
Means that there is now carrier present on the raw device (e.g. a modem connection was just made).

TD_LOST_CARRIER
Means that carrier just went away on the raw device (e.g. the party on the other end hung up the phone).

The Td module will invoke the procedure rawProc, which was passed to Td_Create, to ask for special actions on the raw terminal device, or to provide additional information that may be useful in managing the raw terminal device.  RawProc must have the following structure: int rawProc(rawData, operation, inputSize, input, outputSize, output)
    ClientData rawData;
    int operation;
    int inputSize;
    char ∗input;
    int outputSize;
    char ∗output; {
 ... } The rawData argument will be the same as the rawData argument passed to Td_Create.  It usually refers to a data structure describing the raw device, which will be used by rawProc.  The operation parameter gives the reason for the call, the inputSize and input arguments describe an area of data that Td is making available to rawProc, and outputSize and output describe a buffer in which rawProc may place data that it wishes to return to Td.  The return value from rawProc indicates how many bytes of data were actually placed at output;  it must not be greater than ouptutSize.  At present, operation must be one of the following:

TD_RAW_START_BREAK
Initiate a break condition on the raw device, if the device supports it. There is no input data or output data for this operation.

TD_RAW_STOP_BREAKEnd a break condition on the raw device, if the device supports it.  There is no input data or output data for this operation. 

TD_RAW_SET_DTRSet the “data terminal ready” condition on the raw device, if it supports such an operation.  There is no input data or output data for this operation. 

TD_RAW_CLEAR_DTRClear the “data terminal ready” condition on the raw device, if it supports such an operation.  There is no input data or output data for this operation. 

TD_RAW_SHUTDOWNThe terminal has been closed and is being shut down.  The raw device should now be shut down too (e.g. hang up a modem).  There is no input data or output data for this operation. 

TD_RAW_OUTPUT_READY
This operation indicates that the output buffer for the terminal has just become non-empty.  At some point in the future, the application should invoke Td_GetRaw and output the characters to the device.  There is no input data or output data for this operation. 

TD_RAW_FLUSH_OUTPUT
If there are any characters buffered for output on the raw device but not yet output, they should be discarded without outputting them. There is no input data or output data for this operation.

TD_RAW_FLOW_CHARSThe flow-control characters for the terminal have just been modified.  The input argument points to a structure with the following format: typedef struct {
    char stop;
    char start; } Td_FlowChars;

Whenever stop is received from the raw terminal, output should be stopped until start is received.  Stop and start may be the same character.  This call is made so that the driver for the raw device may implement flow control directly in order to provide faster response to the start and stop characters.  The raw device driver may ignore these calls and simply pass the flow control characters to the terminal driver, in which case Td will implement flow control, albeit with slower response.  If either stop or start is -1, then the raw driver must not implement flow control.  There is no output data for this operation. 

TD_RAW_SET_BAUD_RATE
Someone has just asked to change the baud rate for the device.  Both the input and output arguments point to structures with the following format: typedef struct {
    char ispeed;
    char ospeed; } Td_BaudRate;

The ispeed and ospeed fields have the same values as they would in an sgttyb structure, such as B9600.  The input argument gives the requested baud rates.  RawProc may either accept these speeds or override them and return the actual speeds it used in the output area.  If the input speeds are accepted, then rawProc need not modify the output area;  it can simply return 0. 

TD_RAW_GET_BAUD_RATE
This operation is invoked to fetch the current input and output speeds for the raw device.  There is no input area, but output refers to a Td_BaudRate structure as described above for TD_RAW_SET_BAUD_RATE.  RawProc should fill in the current speeds for the device at ∗output and return sizeof(Td_BaudRate). 

 

COOKED INTERFACE

The cooked interface is used to communicate between the terminal driver and the processes wishing to access a device with full 4.3 BSD terminal semantics.  As with the raw interface, it consists of a collection of Td procedures that the enclosing application invokes, plus one procedure in the enclosing application that Td invokes. 

Whenever a process attempts to open the terminal device, the procedure Td_Open should be called.  If the terminal is in “exclusive” mode (meaning opens are being refused), then a UNIX error number is returned.  Otherwise zero is returned and the FS_READABLE and FS_WRITABLE bits of ∗selectBitsPtr are set to indicate whether there are input characters or output buffer space available, respectively. 

When the terminal is closed, Td_Close should be invoked.  There should be exactly one Td_Close call for each Td_Open call:  if an open stream is dup-ed, Td_Close shouldn’t be called until the last dup-ed copy is closed. 

When a process writes data to the cooked terminal, Td_PutCooked should be invoked to pass the data to the terminal driver.  The characters will be added to the terminal’s output buffer after performing output processing on them.  The return value is always zero (meaning that the characters are always accepted).  The FS_WRITABLE bit in ∗selectBitsPtr will be updated to reflect whether the terminal’s output buffer is now “full” (see the BUFFERING section below for more on what this means).  If so, then no more calls should be made to Td_PutCooked until the terminal driver gives notice that there is more space in the output buffer (this is done by calling cookedProc as described below).  Td_PutCooked overwrites the value at ∗sigNumPtr;  if the value written is non-zero then it is a UNIX signal number that should be applied to the calling process. 

When a process wishes to read characters from the cooked terminal, Td_GetCooked should be called.  This procedure will remove characters from the terminal’s input buffer (up to ∗numBytesPtr of them) and copy them to buffer.  The value at ∗numBytesPtr will be updated to reflect the actual number of characters returned.  The return value from Td_GetCooked will normally be zero;  if an error occurred, then the return value will be a UNIX error number.  If the terminal’s input buffer is empty, then the return value will be EWOULDBLOCK and ∗numBytesPtr will be set to zero.  The FS_READABLE bit of ∗selectBitsPtr will be updated to reflect whether there are still more characters ready in the terminal’s input buffer.  Td_PutCooked overwrites the value at ∗sigNumPtr;  if the value written is non-zero then it is a UNIX signal number that should be applied to the calling process (this is used, for example, to generate SIGTTIN signals). 

When a process invokes an IOControl operation on the terminal, Td_ControlCooked should be called.  The arguments to Td_ControlCooked indicate the IOControl number (command), plus an input buffer (inputSize and input) and an output buffer (∗outputSizePtr and output).  The value at ∗outputSizePtr will be modified to reflect the actualy number of bytes of output data written at output (this will be no more than the original value of ∗outputSizePtr).  The contents of the input and output buffers are determined by the specific command being requested.  See the documentation on the 4.3 BSD terminal driver for details.  The byte ordering and structure alignment of the input and output buffers is specified by the format parameter.  The normal value to pass in is for format is FMT_MY_FORMAT, which is defined in “fmt.h”.  Td_ControlCooked will reformat the input and output buffers, if necessary, to match the byte ordering of a remote client process.  Td_ControlCooked will modify the FS_READABLE and FS_WRITABLE bits of ∗selectBitsPtr to reflect the state of the terminal’s input and output buffers when the IOControl completes.  Td_PutCooked overwrites the value at ∗sigNumPtr;  if the value written is non-zero then it is a UNIX signal number that should be applied to the calling process. 

The Td library will invoke the cookedProc, which was passed as an argument to Td_Create, when it wishes to give notice of interesting events related to the cooked side of the terminal.  CookedProc should have the following structure: int cookedProc(cookedData, operation, inputSize, input, outputSize, output)
    ClientData cookedData;
    int operation;
    int inputSize;
    char ∗input;
    int outputSize;
    char ∗output; {
 ... } The cookedData argument will be the same as the cookedData argument passed to Td_Create.  It usually refers to a data structure describing the interface to processes using the cooked terminal.  The other arguments to cookedProc and its result have the same meaning as the arguments and result for rawProc, except that  operation has different meanings.  The values currently defined for operation are:

TD_COOKED_SIGNALA signal should be generated for the controlling process group associated with the terminal.  Input will point to a structure with the following format: typedef struct {
    int sigNum;
    int groupID; } Td_Signal;

The sigNum field gives a UNIX signal number (e.g. SIGINT), and groupID identifies the controlling process group for the terminal.  CookedProc is not expected to return any output data. 

TD_COOKED_READS_OK
There is now readable data in the input buffer associated with the terminal, so that the next call to Td_GetCooked will not return EWOULDBLOCK.  If there is a waiting process, it should probably be woken up.  There is no input data or output data for this operation. 

TD_COOKED_WRITES_OK
The output buffer for the terminal is now empty.  If there is a process waiting to do output, it should probably be woken up. There is no input data or output data for this operation.

 

PSEUDO-DEVICE INTERFACE

The Td library also contains routines to connect the cooked side of a terminal to a pseudo-device.  The pseudo-device routines use the facilities of the Pdev library, which in turn requires that the application use the Fs_Select library to manage I/O channels.  The non-pseudo-device portions of the Td library may be used without also using Fs_Select. 

Td_CreatePdev creates a pseudo-device file and arranges for the file to have terminal-like behavior by associating it with a terminal managed by the Td library.  Once Td_CreatePdev has been called, the pseudo-device and the cooked side of its terminal will be managed automatically.  However, it is up to Td_CreatePdev’s caller to manage the raw side of the pseudo-terminal.  The rawProc and rawData arguments to Td_CreatePdev are the same as the corresponding arguments to Td_Create (Td_CreatePdev passes them to Td_Create when it creates the terminal).  If the termPtr argument to Td_CreatePdev is not NULL, then Td_CreatePdev stores the Td_Terminal token for the pseudo-terminal at ∗termPtr; this allows the application to invoke procedures like Td_PutRaw. 

The name of the pseudo-device file created by Td_CreatePdev may be specified in either of two ways.  If the realNamePtr argument to Td_CreatePdev is NULL, then the name argument gives the complete name of the pseudo-device file.  If realNamePtr is not NULL, then the pseudo-device file will be created in a host-specific directory for the machine on which the program is running, and the file name will have the form nameXX, where XX is a small integer chosen to avoid conflict with other files that have the same name.  A pointer to the complete name will be stored in ∗realNamePtr;  the storage for the name is allocated by malloc and should eventually be freed by Td_CreatePdev’s caller. 

Td_CreatePdev normally returns a token for the pseudo-terminal.  If the pseudo-device couldn’t be opened, then NULL is returned and the variable pdev_ErrorMsg points to a string describing what went wrong. 

The only use for the token returned by Td_CreatePdev is to pass it to Td_DeletePdev.  When this happens, the pseudo-device is closed and the associated terminal is destroyed by calling Td_Delete. 
 

BUFFERING

The input buffer for a Td_Terminal grows automatically to accommodate as much data as is present:  there is no upper limit on its size.  The output buffer will also grow automatically:  Td_PutCooked always accepts all the data passed to it.  However, it is usually a bad idea to buffer a very large number of characters on output, since these characters will have to be output even if the process is killed with a control-C.  The bufferSize argument to Td_Create specifies a nominal output buffer size;  whenever more than this many characters are buffered, Td_PutCooked will turn off the FS_WRITABLE bit in ∗selectBitsPtr to indicate that the buffer is nominally full;  the enclosing application should then refuse to accept more characters for output (e.g., by suspending the process).  When the output buffer empties, cookedProc will be invoked with a TD_COOKED_WRITES_OK command. 
 

EXAMPLES

The best way to learn how to use the Td library is to look at examples in the Sprite source code.  The simplest example is the mktty program;  other examples are rlogind (the remote-login server) and tx (a window-based terminal emulator). 
 

KEYWORDS

4.3 BSD, pseudo-device, terminal driver

Sprite version 1.0  —  March 30, 1990

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026