This chapter includes:
The Character DDK currently includes the source code for the 8250 serial
driver. You may not have to change much:
- If your serial hardware is completely compatible with the 8250, you might
not have to change anything.
- If your hardware is almost compatible with the 8250, you might
have to change the register addresses.
See
“Registers,”
below.
- If compatibility is in question, you may have to change the source code.
See
“Source code,”
below.
You'll find the register addresses defined in
ddk_working_dir/ddk-char/src/hardware/devc/public/hw/8250.h.
The <8250.h> file defines:
- the register addresses, specified as offsets from the port address that
you set when you start the
devc-ser8250
driver
- bit definitions for the registers
See the documentation for your hardware for information about its registers
and bit definitions.
The source code for the 8250 serial driver is in
ddk_working_dir/ddk-char/src/hardware/devc/ser8250.
This directory includes:
- externs.c
- Defines the global data.
- externs.h
- Includes the required headers and declares the global data.
- init.c
- Initialization code.
- intr.c
- Interrupt handler routines.
- main.c
- The main part of the driver.
- options.c
- Parses the driver's command-line arguments.
- proto.h
- Prototypes for the driver's interface routines.
- query_defdev.c
- Queries the default devices.
Note that there's a special version of this routine for x86 desktop systems
in x86/query_defdev.c.
For other platforms, there aren't any default devices.
- tedit.c
- The tiny edit-mode routine.
- tto.c
- A routine to transmit up to the TX FIFO SIZE worth of data, called by io-char.
It also provides support to control and read hardware-control lines status, and
provides support for the stty utility. If there's no TX FIFO, tto() writes
only a single character.
- variant.h
- A header file that defines the two macros to read/write the 8250. This file can be
overwritten for different boards with their own read/write macros.
There are also platform-specific directories, each of which includes:
- <sys_ttyinit.c>
- Initialize the tty structure that the driver passes to io-char.
|
Change as little of the given source code as possible, because it's easy to
mess things up. |
The most important parts of the code are those associated with
output and interrupts.
Different chips use interrupts in different ways.
Typically, interrupts occurs when:
- the RX FIFO's receive level/threshold is reached
- the TX FIFO empties
- a change in the modem status lines occurs
The driver code adds characters only to the Input queue/buffer.
The Canonical buffer is handled by io-char and is manipulated
when the client read request is handled.
The ser8250 driver includes the following functions, defined
in proto.h:
The driver's main() routine (defined in main.c)
calls:
- ttc()
with an argument of TTC_INIT_PROC to allocate and configure
the resources shared by all devices, e.g. the resource manager
- ttc()
with an argument of TTC_INIT_START to allow the driver to
start accepting messages, i.e. work
- options()
to parse the driver's command-line options
This function is defined in init.c and is called by options().
The prototype is:
DEV_8250 *create_device(TTYINIT *dip,
unsigned unit);
This function gets a device entry and its input/output buffers and creates a new device
based on the options passed in.
This function is defined in init.c.
The prototype is:
int enable_device( DEV_8250 *dev)
This function enables all the serial ports.
You must call it for each port before returning from
options()
to complete the port initialization.
This function is defined in options.c.
The prototype is:
unsigned options( int argc,
char *argv[] )
This function parses the driver's command-line arguments.
For information about the arguments, see
devc-ser8250
in the Utilities Reference.
Depending on the options specified, this function may call:
- ttc()
with an argument of TTC_INIT_RAW to configure the terminal to RAW mode
- sys_ttyinit()
to initialize the tty as appropriate for the CPU platform
- ttc()
with an argument of TTC_SET_OPTION to pass standard terminal
configuration options to <libio-char.a> to be executed
- create_device()
to create a device
- query_default_device()
to query the default devices if none is specified on the command line
- enable_device()
to enable all the serial ports
The options() function returns the number of ports that are enabled.
This function is defined in query_defdev.c.
The prototype is:
void *query_default_device(TTYINIT *dip,
void *link )
This function returns a placeholder that's used for overwrites
in the platform directory.
This function is defined in intr.c.
The prototype is:
const struct sigevent *ser_intr( void *area,
int id )
The ser_attach_intr() function, which is called by
create_device(),
calls
InterruptAttach()
(see the QNX Neutrino Library Reference) to attach ser_intr()
to the first handler. If you don't want to transmit at interrupt time, then you can set the
EVENT_TTO event and return. This will trigger io-char's tte()
function to call into tto() at thread time rather then interrupt time.
The ser_intr() function calls:
- tti()
to pass a character of data received by the hardware to the io-char library
- tto() to transmit a character (or a number of characters if there is a TX FIFO)
by taking the next available byte in the io-char lib output buffer and writing it
to the hardware.
This function is defined in tto.c.
The prototype is:
void ser_stty( DEV_8250 *dev )
This function configures registers that can be changed dynamically at runtime (baud, parity, stop bits, etc.).
Don't use this function for any initialization that you need to do when first setting up the driver; use
create_device() instead.
This function is defined in <init.c>.
The prototype is:
void set_port( unsigned port,
unsigned mask,
unsigned data )
This function sets the specified bit(s) of the UART port to the given
value (0 or 1).
The arguments are:
- port
- The port you want to write the value to.
- mask
- The mask for the bit or bits that you want to set.
- data
- The value that you want to set.
This function is defined in <sys_ttyinit.c> in the
platform-specific directories under
ddk_working_dir/ddk-char/src/hardware/devc/ser8250.
The prototype is:
void sys_ttyinit( TTYINIT *dip )
This function initializes the TTYINIT clock and divisor default as
appropriate for the platform.
This function is defined in tto.c.
The prototype is:
int tto( TTYDEV *ttydev,
int action,
int arg1 )
This function takes data from io-char's output buffer and
gives it to the hardware.
It also deals with stty commands, by calling
ser_stty(), and provides line control and
line status information.
The arguments are:
- ttydev
- A pointer to the driver's
TTYDEV
structure.
- action
- One of:
- TTO_STTY — an stty command was
received. It's called by io-char when the stty
command is performed on the device. This action calls ser_stty(); the
argument is ignored.
- TTO_CTRL — set the characteristics of the port i.e. control
RS-232 modem lines.
- arg1 _SERCTL_BRK_CHG — called by io-char
when the application requests a break such as tcsendbreak() be sent
- arg1 _SERCTL_DTR_CHG — changes the DTR line
- arg1 _SERCTL_RTS_CHG — changes the RTS
line; io-char calls this to assert hardware flow control when the input
buffer is filling up (based on the high-water level)
- TTO_LINESTATUS — a request for line status. Returns the status of
the Modem Status and Modem Control registers when the user performs a devctl()
with DCMD_CHR_LINESTATUS; the argument is ignored.
- TTO_DATA — used if tto() is called directly from
the interrupt handler to transmit data or when io-char's write handler calls
down to initiate a transfer.
- TTO_EVENT — used to call into the tto() at thread
time to transmit data. The interrupt handler can return this event rather than calling tto() directly.
- arg1
- A data value which has different meanings for different actions. It's used to pass flags
that modify the action.