source: rtems/doc/bsp_howto/console.t @ 8d50380

4.104.115
Last change on this file since 8d50380 was 8d50380, checked in by Joel Sherrill <joel.sherrill@…>, on 01/29/09 at 14:57:22

2009-01-29 Sebastian Huber <sebastian.huber@…>

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