source: rtems/doc/bsp_howto/console.t @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 21.2 KB
Line 
1@c
2@c  COPYRIGHT (c) 1988-2008.
3@c  On-Line Applications Research Corporation (OAR).
4@c  All rights reserved.
5
6@chapter Console Driver
7
8@section Introduction
9
10This chapter describes the operation of a console driver using
11the RTEMS POSIX Termios support.  Traditionally RTEMS has referred
12to all serial device drivers as console device drivers.  A
13console driver can be used to do raw data processing in addition
14to the "normal" standard input and output device functions required
15of a console.
16
17The serial driver may be called as the consequence of a C Library
18call such as @code{printf} or @code{scanf} or directly via the
19@code{read} or @code{write} system calls.
20There are two main functioning modes:
21
22@itemize @bullet
23
24@item console: formatted input/output, with special characters (end of
25line, tabulations, etc.) recognition and processing,
26
27@item raw: permits raw data processing.
28
29@end itemize
30
31One may think that two serial drivers are needed to handle these two types
32of data, but Termios permits having only one driver.
33
34@section Termios
35
36Termios is a standard for terminal management, included in the POSIX
371003.1b standard.  As part of the POSIX and Open Group Single UNIX
38Specification, is commonly provided on UNIX implementations.  The
39Open Group has the termios portion of the POSIX standard online
40at @uref{http://opengroup.org/onlinepubs/007908775/xbd/termios.html
41,http://opengroup.org/onlinepubs/007908775/xbd/termios.html}.
42The requirements for the @code{<termios.h>} file are also provided
43and are at @uref{http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html,
44http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html}.
45
46Having RTEMS support for Termios is beneficial because:
47
48@itemize @bullet
49
50@item from the user's side because it provides standard primitive operations
51to access the terminal and change configuration settings.  These operations
52are the same under UNIX and RTEMS.
53
54@item from the BSP developer's side because it frees the
55developer from dealing with buffer states and mutual exclusions on them.
56Early RTEMS console device drivers also did their own special
57character processing.
58
59@item it is part of an internationally recognized standard.
60
61@item it makes porting code from other environments easier.
62
63@end itemize
64
65Termios support includes:
66
67@itemize @bullet
68
69@item raw and console handling,
70
71@item blocking or non-blocking characters receive, with or without
72Timeout.
73
74@end itemize
75
76At this time, RTEMS documentation does not include a thorough discussion
77of the Termios functionality.  For more information on Termios,
78type @code{man termios} on a Unix box or point a web browser
79at
80@uref{http://www.freebsd.org/cgi/man.cgi}.
81
82@section Driver Functioning Modes
83
84There are generally two main functioning modes for an UART (Universal
85Asynchronous Receiver-Transmitter, i.e. the serial chip):
86
87@itemize @bullet
88
89@item polled mode
90@item interrupt driven mode
91
92@end itemize
93
94In polled mode, the processor blocks on sending/receiving characters.
95This mode is not the most efficient way to utilize the UART. But
96polled mode is usually necessary when one wants to print an
97error message in the event of a fatal error such as a fatal error
98in the BSP.  This is also the simplest mode to
99program.  Polled mode is generally preferred if the serial port is
100to be used primarily as a debug console.  In a simple polled driver,
101the software will continuously check the status of the UART when
102it is reading or writing to the UART.  Termios improves on this
103by delaying the caller for 1 clock tick between successive checks
104of the UART on a read operation.
105
106In interrupt driven mode, the processor does not block on sending/receiving
107characters.  Data is buffered between the interrupt service routine
108and application code.  Two buffers are used to insulate the application
109from the relative slowness of the serial device.  One of the buffers is
110used for incoming characters, while the other is used for outgoing characters.
111
112An interrupt is raised when a character is received by the UART.
113The interrupt subroutine places the incoming character at the end
114of the input buffer.  When an application asks for input,
115the characters at the front of the buffer are returned.
116
117When the application prints to the serial device, the outgoing characters
118are placed at the end of the output buffer.  The driver will place
119one or more characters in the UART (the exact number depends on the UART)
120An interrupt will be raised when all the characters have been transmitted.
121The interrupt service routine has to send the characters
122remaining in the output buffer the same way.   When the transmitting side
123of the UART is idle, it is typically necessary to prime the transmitter
124before the first interrupt will occur.
125
126@section Serial Driver Functioning Overview
127
128The following Figure shows how a Termios driven serial driver works:
129
130@ifset use-ascii
131@center Figure not included in ASCII version
132@end ifset
133
134@ifset use-tex
135@sp1
136@center{@image{TERMIOSFlow,,6in}}
137@end ifset
138
139@ifset use-html
140@html
141<P ALIGN="center"><IMG SRC="TERMIOSFlow.png" ALT="Termios Flow"></P>
142@end html
143@end ifset
144
145The following list describes the basic flow.
146
147@itemize @bullet
148
149@item the application programmer uses standard C library call (printf,
150scanf, read, write, etc.),
151
152@item C library (e.g. RedHat (formerly Cygnus) Newlib) calls
153the RTEMS system call interface.  This code can be found in the
154@code{cpukit/libcsupport/src} directory.
155
156@item Glue code calls the serial driver entry routines.
157
158@end itemize
159
160@subsection Basics
161
162You need to include the following header files in your Termios device driver
163source file:
164@example
165@group
166#include <unistd.h>
167#include <termios.h>
168
169#include <rtems.h>
170#include <rtems/libio.h>
171#include <rtems/console.h>
172@end group
173@end example
174
175You need to provide a data structure for the Termios driver interface.  The
176functions are described later in this chapter.  The functions should return
177zero on succes and minus one in case of an error.  Currently the return value
178will be not checked from the Termios infrastructure in most cases.  One notable
179exception is the polled read function, here is the return value important.
180
181If you want to use polled IO it should look like the following.  You may also
182have a look at @code{c/src/lib/libbsp/shared/console-polled.c} for a shared
183implementation of the basic framework.  Termios must be told the addresses of
184the functions that are to be used for simple character IO, i.e. pointers to the
185@code{my_driver_poll_read} and @code{my_driver_poll_write} functions described
186later in @ref{Console Driver Termios and Polled IO}.
187
188@example
189@group
190static const rtems_termios_callbacks my_driver_callbacks_polled = @{
191    .firstOpen = my_driver_first_open,
192    .lastClose = my_driver_last_close,
193    .pollRead = my_driver_poll_read,
194    .write = my_driver_poll_write,
195    .setAttributes = my_driver_set_attributes,
196    .stopRemoteTx = NULL,
197    .startRemoteTx = NULL,
198    .outputUsesInterrupts = TERMIOS_POLLED
199@};
200@end group
201@end example
202
203For an interrupt driven implementation you need the following.  The driver
204functioning is quite different in this mode.  There is no device driver read
205function to be passed to Termios.  Indeed a @code{console_read} call returns
206the contents of Termios input buffer.  This buffer is filled in the driver
207interrupt subroutine, see also
208@ref{Console Driver Termios and Interrupt Driven IO}.
209The driver is responsible for providing a pointer to the
210@code{my_driver_interrupt_write} function.
211
212@example
213@group
214static const rtems_termios_callbacks my_driver_callbacks_interrupt = @{
215    .firstOpen = my_driver_first_open,
216    .lastClose = my_driver_last_close,
217    .pollRead = NULL,
218    .write = my_driver_interrupt_write,
219    .setAttributes = my_driver_set_attributes,
220    .stopRemoteTx = NULL,
221    .startRemoteTx = NULL,
222    .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
223@};
224@end group
225@end example
226
227You can also provide callback functions for remote transmission control.  This
228is not covered in this manual, so thay are set to @code{NULL} in the above
229examples.
230
231Normally the device specific data structures are stored in a table which is
232indexed by the minor number.  You may need an entry for the Termios handler
233pointer in your data structure.  For simplicity of the console initialization
234example the device name is also present.
235
236@example
237@group
238/* Driver specific data structure */
239typedef struct @{
240    const char *device_name;
241    struct rtems_termios_tty *tty;
242@} my_driver_entry;
243
244/*
245 * This table contains the driver specific data.  It is later
246 * indexed by the minor number.
247 */
248static my_driver_entry my_driver_table [MY_DRIVER_DEVICE_NUMBER];
249@end group
250@end example
251
252@subsection Termios and Polled IO
253
254The following functions are provided by the driver and invoked by
255Termios for simple character IO.
256
257The @code{my_driver_poll_write} routine is responsible for writing @code{n}
258characters from @code{buf} to the serial device specified by @code{minor}.
259
260On success, the number of bytes written is returned (zero indicates nothing
261was written).  On error, @code{-1} is returned.
262
263NOTE: Due to the current implementation of termios, any data passed into
264  the write function will be lost.
265
266@example
267@group
268static ssize_t my_driver_poll_write(int minor, const char *buf, size_t n)
269@{
270    my_driver_entry *e = &my_driver_table [minor];
271    int i = 0;
272   
273    /*
274     * There is no need to check the minor number since it is derived
275     * from a file descriptor.  The upper layer takes care that it is
276     * in a valid range.
277     */
278   
279    /* Write */
280    for (i = 0; i < n; ++i) @{
281        my_driver_write_char(e, buf [i]);
282    @}
283   
284    return n;
285@}
286@end group
287@end example
288
289The @code{my_driver_poll_read} routine is responsible for reading a single
290character from the serial device specified by @code{minor}.  If no character is
291available, then the routine should return minus one.
292
293@example
294@group
295static int my_driver_poll_read(int minor)
296@{
297    my_driver_entry *e = &my_driver_table [minor];
298   
299    /*
300     * There is no need to check the minor number since it is derived
301     * from a file descriptor.  The upper layer takes care that it is
302     * in a valid range.
303     */
304
305    /* Check if a character is available */
306    if (my_driver_can_read_char(e)) @{
307        /* Return the character */
308        return my_driver_read_char(e);
309    @} else @{
310        /* Return an error status */
311        return -1;
312    @}
313@}
314@end group
315@end example
316
317@subsection Termios and Interrupt Driven IO
318
319The UART generally generates interrupts when it is ready to accept or to emit a
320number of characters.  In this mode, the interrupt subroutine is the core of
321the driver.
322
323The @code{my_driver_interrupt_handler} is responsible for processing
324asynchronous interrupts from the UART.  There may be multiple interrupt
325handlers for a single UART.  Some UARTs can generate a unique interrupt vector
326for each interrupt source such as a character has been received or the
327transmitter is ready for another character.
328
329In the simplest case, the @code{my_driver_interrupt_handler} will have to check
330the status of the UART and determine what caused the interrupt.  The following
331describes the operation of an @code{my_driver_interrupt_handler} which has to
332do this:
333
334@example
335@group
336static void my_driver_interrupt_handler(
337    rtems_vector_number vector,
338    void *arg
339)
340@{
341    my_driver_entry *e = (my_driver_entry *) arg;
342    char buf [N];
343    int n = 0;
344
345    /*
346     * Check if we have received something.  The function reads the
347     * received characters from the device and stores them in the
348     * buffer.  It returns the number of read characters.
349     */
350    n = my_driver_read_received_chars(e, buf, N);
351    if (n > 0) @{
352        /* Hand the data over to the Termios infrastructure */
353        rtems_termios_enqueue_raw_characters(e->tty, buf, n);
354    @}
355
356    /*
357     * Check if we have something transmitted.  The functions returns
358     * the number of transmitted characters since the last write to the
359     * device.
360     */
361    n = my_driver_transmitted_chars(e);
362    if (n > 0) @{
363        /*
364         * Notify Termios that we have transmitted some characters.  It
365         * will call now the interrupt write function if more characters
366         * are ready for transmission.
367         */
368        rtems_termios_dequeue_characters(e->tty, n);
369    @}
370@}
371@end group
372@end example
373
374The @code{my_driver_interrupt_write} function is responsible for telling the
375device that the @code{n} characters at @code{buf} are to be transmitted.  The
376return value may be arbitrary since it is not checked from Termios.  It is
377guaranteed that @code{n} is greater than zero.  This routine is invoked either
378from task context with disabled interrupts to start a new transmission process
379with exactly one character in case of an idle output state or from the
380interrupt handler to refill the transmitter.  If the routine is invoked to
381start the transmit process the output state will become busy and Termios starts
382to fill the output buffer.  If the transmit interrupt arises before Termios was
383able to fill the transmit buffer you will end up with one interrupt per
384character.
385
386On error, the function should return @code{-1}. On success, it should return
387@code{0}, since it the interrupt handler will report the actual number of
388characters transmitted.
389 
390@example
391@group
392static ssize_t my_driver_interrupt_write(int minor, const char *buf, size_t n)
393@{
394    my_driver_entry *e = &my_driver_table [minor];
395   
396    /*
397     * There is no need to check the minor number since it is derived
398     * from a file descriptor.  The upper layer takes care that it is
399     * in a valid range.
400     */
401
402    /*
403     * Tell the device to transmit some characters from buf (less than
404     * or equal to n).  When the device is finished it should raise an
405     * interrupt.  The interrupt handler will notify Termios that these
406     * characters have been transmitted and this may trigger this write
407     * function again.  You may have to store the number of outstanding
408     * characters in the device data structure.
409     */
410
411    return 0;
412@}
413@end group
414@end example
415
416@subsection Initialization
417
418The driver initialization is called once during the RTEMS initialization
419process.
420
421The @code{console_initialize} function may look like this:
422
423@example
424@group
425rtems_device_driver console_initialize(
426    rtems_device_major_number major,
427    rtems_device_minor_number minor,
428    void *arg
429)
430@{
431    rtems_status_code sc = RTEMS_SUCCESSFUL;
432    rtems_device_minor_number i = 0;
433
434    /*
435     * Initialize the Termios infrastructure.  If Termios has already
436     * been initialized by another device driver, then this call will
437     * have no effect.
438     */
439    rtems_termios_initialize();
440   
441    /* Initialize each device */
442    for (i = 0; i < MY_DRIVER_DEVICE_NUMBER; ++i) @{
443        my_driver_entry *e = &my_driver_table [i];
444
445        /*
446         * Register this device in the file system.  In order to use the
447         * console (i.e. being able to do printf, scanf etc. on stdin,
448         * stdout and stderr), some device must be registered
449         * as "/dev/console" (CONSOLE_DEVICE_NAME).
450         */
451        sc = rtems_io_register_name (e->device_name, major, i);
452        RTEMS_CHECK_SC(sc, "Register IO device");
453
454        /*
455         * Initialize this device and install the interrupt handler if
456         * necessary.  You may also initialize the device in the first
457         * open call.
458         */
459    @}
460
461    return RTEMS_SUCCESSFUL;
462@}
463@end group
464@end example
465
466@subsection Opening a serial device
467
468The @code{console_open} function is called whenever a serial device is opened.
469The device registered as @code{"/dev/console"} (@code{CONSOLE_DEVICE_NAME}) is
470opened automatically during RTEMS initialization.  For instance, if UART
471channel 2 is registered as "/dev/tty1", the @code{console_open} entry point
472will be called as the result of an @code{fopen("/dev/tty1", mode)} in the
473application.
474
475The @code{console_open} function has to inform Termios of the low-level
476functions for serial line support.
477
478@example
479@group
480rtems_device_driver console_open(
481    rtems_device_major_number major,
482    rtems_device_minor_number minor,
483    void *arg
484)
485@{
486    struct rtems_termios_callbacks *callbacks =
487        &my_driver_callbacks_polled;
488
489    /*
490     * Check the minor number.  Termios does currently not check
491     * the return value of the first open call so the minor
492     * number must be checked here.
493     */
494    if (MY_DRIVER_IS_MINOR_INVALID(minor)) @{
495        return RTEMS_INVALID_NUMBER;
496    @}
497
498    /*
499     * Depending on the IO mode you need to pass a different set of
500     * callback functions to Termios.
501     */
502    if (MY_DRIVER_USES_INTERRUPTS(minor)) @{
503        callbacks = &my_driver_callbacks_interrupt;
504    @}
505
506    return rtems_termios_open(major, minor, arg, callbacks);
507@}
508@end group
509@end example
510
511During the first open of the device Termios will call @code{my_driver_first_open}.
512
513@example
514@group
515static int my_driver_first_open(int major, int minor, void *arg)
516@{
517    my_driver_entry *e = &my_driver_table [minor];
518    struct rtems_termios_tty *tty =
519        ((rtems_libio_open_close_args_t *) arg)->iop->data1;
520   
521    /* Check minor number */
522    if (MY_DRIVER_IS_MINOR_INVALID(minor)) @{
523        return -1;
524    @}
525
526    /* Connect the TTY data structure */
527    e->tty = tty;
528
529    /*
530     * You may add some initialization code here.
531     */
532
533    /*
534     * Sets the inital baud rate.  This should be set to the value of
535     * the boot loader.
536     */
537    return rtems_termios_set_initial_baud(e->tty, MY_DRIVER_BAUD_RATE);
538@}
539@end group
540@end example
541
542@subsection Closing a Serial Device
543
544The @code{console_close} is invoked when the serial device is to be closed.
545This entry point corresponds to the device driver close entry point.
546
547This routine is responsible for notifying Termios that the serial device was
548closed.  This is done with a call to @code{rtems_termios_close}.
549
550@example
551@group
552rtems_device_driver console_close(
553    rtems_device_major_number major,
554    rtems_device_minor_number minor,
555    void *arg
556)
557@{
558    return rtems_termios_close(arg);
559@}
560@end group
561@end example
562
563Termios will call the @code{my_driver_last_close} function if the last close
564happens on the device.
565@example
566@group
567static int my_driver_last_close(int major, int minor, void *arg)
568@{
569    my_driver_entry *e = &my_driver_table [minor];
570   
571    /*
572     * There is no need to check the minor number since it is derived
573     * from a file descriptor.  The upper layer takes care that it is
574     * in a valid range.
575     */
576
577    /* Disconnect the TTY data structure */
578    e->tty = NULL;
579
580    /*
581     * The driver may do some cleanup here.
582     */
583
584    return 0;
585@}
586@end group
587@end example
588
589@subsection Reading Characters from a Serial Device
590
591The @code{console_read} is invoked when the serial device is to be read from.
592This entry point corresponds to the device driver read entry point.
593
594This routine is responsible for returning the content of the Termios input
595buffer.  This is done by invoking the @code{rtems_termios_read} routine.
596
597@example
598@group
599rtems_device_driver console_read(
600    rtems_device_major_number major,
601    rtems_device_minor_number minor,
602    void *arg
603)
604@{
605    return rtems_termios_read(arg);
606@}
607@end group
608@end example
609
610@subsection Writing Characters to a Serial Device
611
612The @code{console_write} is invoked when the serial device is to be written to.
613This entry point corresponds to the device driver write entry point.
614
615This routine is responsible for adding the requested characters to the Termios
616output queue for this device.  This is done by calling the routine
617@code{rtems_termios_write} to add the characters at the end of the Termios
618output buffer.
619
620@example
621@group
622rtems_device_driver console_write(
623    rtems_device_major_number major,
624    rtems_device_minor_number minor,
625    void *arg
626)
627@{
628    return rtems_termios_write(arg);
629@}
630@end group
631@end example
632
633@subsection Changing Serial Line Parameters
634
635The @code{console_control} is invoked when the line parameters for a particular
636serial device are to be changed.  This entry point corresponds to the device
637driver io_control entry point.
638
639The application writer is able to control the serial line configuration with
640Termios calls (such as the @code{ioctl} command, see the Termios documentation
641for more details).  If the driver is to support dynamic configuration, then it
642must have the @code{console_control} piece of code.  Basically @code{ioctl}
643commands call @code{console_control} with the serial line configuration in a
644Termios defined data structure.
645
646@example
647@group
648rtems_device_driver console_control(
649    rtems_device_major_number major,
650    rtems_device_minor_number minor,
651    void *arg
652)
653@{
654    return rtems_termios_ioctl(arg);
655@}
656@end group
657@end example
658
659The driver is responsible for reinitializing the device with the correct
660settings.  For this purpuse Termios calls the @code{my_driver_set_attributes}
661function.
662
663@example
664@group
665static int my_driver_set_attributes(
666    int minor,
667    const struct termios *t
668)
669@{
670    my_driver_entry *e = &my_driver_table [minor];
671   
672    /*
673     * There is no need to check the minor number since it is derived
674     * from a file descriptor.  The upper layer takes care that it is
675     * in a valid range.
676     */
677
678    /*
679     * Inspect the termios data structure and configure the device
680     * appropriately.  The driver should only be concerned with the
681     * parts of the structure that specify hardware setting for the
682     * communications channel such as baud, character size, etc.
683     */
684
685    return 0;
686@}
687@end group
688@end example
Note: See TracBrowser for help on using the repository browser.