add serial HOWTO doc
No binary (build failed)
—
(log yok)
| @@ -0,0 +1,424 @@ | |
| + | Downloaded from http://www.lafn.org/~dave/linux/Serial-Programming-HOWTO.txt |
| + | Seems to be somewhat old, but contains useful bits for getty.c hacking |
| + | ============================================================================ |
| + | |
| + | The Linux Serial Programming HOWTO, Part 1 of 2 |
| + | By Vernon C. Hoxie |
| + | v2.0 10 September 1999 |
| + | |
| + | This document describes how to program communications with devices |
| + | over a serial port on a Linux box. |
| + | ______________________________________________________________________ |
| + | |
| + | Table of Contents |
| + | |
| + | 1. Copyright |
| + | |
| + | 2. Introduction |
| + | |
| + | 3. Opening |
| + | |
| + | 4. Commands |
| + | |
| + | 5. Changing Baud Rates |
| + | |
| + | 6. Additional Control Calls |
| + | |
| + | 6.1 Sending a "break". |
| + | 6.2 Hardware flow control. |
| + | 6.3 Flushing I/O buffers. |
| + | |
| + | 7. Modem control |
| + | |
| + | 8. Process Groups |
| + | |
| + | 8.1 Sessions |
| + | 8.2 Process Groups |
| + | 8.3 Controlling Terminal |
| + | 8.3.1 Get the foreground group process id. |
| + | 8.3.2 Set the foreground process group id of a terminal. |
| + | 8.3.3 Get process group id. |
| + | |
| + | 9. Lockfiles |
| + | |
| + | 10. Additional Information |
| + | |
| + | 11. Feedback |
| + | |
| + | ______________________________________________________________________ |
| + | |
| + | 1. Copyright |
| + | |
| + | The Linux Serial-Programming-HOWTO is copyright (C) 1997 by Vernon |
| + | Hoxie. Linux HOWTO documents may be reproduced and distributed in |
| + | whole or in part, in any medium physical or electronic, as long as |
| + | this copyright notice is retained on all copies. Commercial |
| + | redistribution is allowed and encouraged; however, the author would |
| + | like to be notified of any such distributions. |
| + | |
| + | All translations, derivative works, or aggregate works incorporating |
| + | this Linux HOWTO document must be covered under this copyright notice. |
| + | That is, you may not produce a derivative work from this HOWTO and |
| + | impose additional restrictions on its distribution. |
| + | |
| + | This version is a complete rewrite of the previous Serial-Programming- |
| + | HOWTO by Peter H. Baumann, <mailto:[email protected]> |
| + | |
| + | 2. Introduction |
| + | |
| + | This HOWTO will attempt to give hints about how to write a program |
| + | which needs to access a serial port. Its principal focus will be on |
| + | the Linux implementation and what the meaning of the various library |
| + | functions available. |
| + | |
| + | Someone asked about which of several sequences of operations was |
| + | right. There is no absolute right way to accomplish an outcome. The |
| + | options available are too numerous. If your sequences produces the |
| + | desired results, then that is the right way for you. Another |
| + | programmer may select another set of options and get the same results. |
| + | His method is right for him. |
| + | |
| + | Neither of these methods may operate properly with some other |
| + | implementation of UNIX. It is strange that many of the concepts which |
| + | were implemented in the SYSV version have been dumped. Because UNIX |
| + | was developed by AT&T and much code has been generated on those |
| + | concepts, the AT&T version should be the standard to which others |
| + | should emulate. |
| + | |
| + | Now the standard is POSIX. |
| + | |
| + | It was once stated that the popularity of UNIX and C was that they |
| + | were created by programmers for programmers. Not by scholars who |
| + | insist on purity of style in deference to results and simplicity of |
| + | use. Not by committees with people who have diverse personal or |
| + | proprietary agenda. Now ANSI and POSIX have strayed from those |
| + | original clear and simply concepts. |
| + | |
| + | 3. Opening |
| + | |
| + | The various serial devices are opened just as any other file. |
| + | Although, the fopen(3) command may be used, the plain open(2) is |
| + | preferred. This call returns the file descriptor which is required |
| + | for the various commands that configure the interface. |
| + | |
| + | Open(2) has the format: |
| + | |
| + | #include <fcntl.h> |
| + | int open(char *path, int flags, [int mode]); |
| + | |
| + | In addition to the obvious O_RDWR, O_WRONLY and O_RDONLY, two |
| + | additional flags are available. These are O_NONBLOCK and O_NOCTTY. |
| + | Other flags listed in the open(2) manual page are not applicable to |
| + | serial devices. |
| + | |
| + | Normally, a serial device opens in "blocking" mode. This means that |
| + | the open() will not return until the Carrier Detect line from the port |
| + | is active, e.g. modem, is active. When opened with the O_NONBLOCK |
| + | flag set, the open() will return immediately regardless of the status |
| + | of the DCD line. The "blocking" mode also affects the read() call. |
| + | |
| + | The fcntl(2) command can be used to change the O_NONBLOCK flag anytime |
| + | after the device has been opened. |
| + | |
| + | The device driver and the data passing through it are controlled |
| + | according to settings in the struct termios. This structure is |
| + | defined in "/usr/include/termios.h". In the Linux tree, further |
| + | reference is made to "/usr/include/asm/termbits.h". |
| + | In blocking mode, a read(2) will block until data is available or a |
| + | signal is received. It is still subject to state of the ICANON flag. |
| + | |
| + | When the termios.c_lflag ICANON bit is set, input data is collected |
| + | into strings until a NL, EOF or EOL character is received. You can |
| + | define these in the termios.c_cc[] array. Also, ERASE and KILL |
| + | characters will operate on the incoming data before it is delivered to |
| + | the user. |
| + | |
| + | In non-canonical mode, incoming data is quanitified by use of the |
| + | c_cc[VMIN and c_cc[VTIME] values in termios.c_cc[]. |
| + | |
| + | Some programmers use the select() call to detect the completion of a |
| + | read(). This is not the best way of checking for incoming data. |
| + | Select() is part of the SOCKETS scheme and too complex for most |
| + | applications. |
| + | |
| + | A full explanation of the fields of the termios structure is contained |
| + | in termios(7) of the Users Manual. A version is included in Part 2 of |
| + | this HOWTO document. |
| + | |
| + | 4. Commands |
| + | |
| + | Changes to the struct termios are made by retrieving the current |
| + | settings, making the desired changes and transmitting the modified |
| + | structure back to the kernel. |
| + | |
| + | The historic means of communicating with the kernel was by use of the |
| + | ioctl(fd, COMMAND, arg) system call. Then the purists in the |
| + | computer industry decided that this was not genetically consistent. |
| + | Their argument was that the argument changed its stripes. Sometimes |
| + | it was an int, sometimes it was a pointer to int and other times it |
| + | was a pointer to struct termios. Then there were those times it was |
| + | empty or NULL. These variations are dependent upon the COMMAND. |
| + | |
| + | As a alternative, the tc* series of functions were concocted. |
| + | |
| + | These are: |
| + | |
| + | int tcgetattr(int filedes, struct termios *termios_p); |
| + | int tcsetattr(int filedes, int optional_actions, |
| + | const struct termios *termios_p); |
| + | |
| + | instead of: |
| + | |
| + | int ioctl(int filedes, int command, |
| + | struct termios *termios_p); |
| + | |
| + | where command is TCGETS or one of TCSETS, TCSETSW or TCSETSF. |
| + | |
| + | The TCSETS command is comparable to the TCSANOW optional_action for |
| + | the tc* version. These direct the kernel to adopt the changes |
| + | immediately. Other pairs are: |
| + | |
| + | command optional_action Meaning |
| + | TCSETSW TCSADRAIN Change after all output has drained. |
| + | TCSETSF TCSAFLUSH Change after all output has drained |
| + | then discard any input characters |
| + | not read. |
| + | |
| + | Since the return code from either the ioctl(2) or the tcsetattr(2) |
| + | commands only indicate that the command was processed by the kernel. |
| + | These do not indicate whether or not the changes were actually |
| + | accomplished. Either of these commands should be followed by a call |
| + | to: |
| + | |
| + | ioctl(fd, TCGETS, &new_termios); |
| + | |
| + | or: |
| + | |
| + | tcgetattr(fd, &new_termios); |
| + | |
| + | A user function which makes changes to the termios structure should |
| + | define two struct termios variables. One of these variables should |
| + | contain the desired configuration. The other should contain a copy of |
| + | the kernels version. Then after the desired configuration has been |
| + | sent to the kernel, another call should be made to retrieve the |
| + | kernels version. Then the two compared. |
| + | |
| + | Here is an example of how to add RTS/CTS flow control: |
| + | |
| + | struct termios my_termios; |
| + | struct termios new_termios; |
| + | |
| + | tcgetattr(fd, &my_termios); |
| + | my_termios.c_flag |= CRTSCTS; |
| + | tcsetattr(fd, TCSANOW, &my_termios); |
| + | tcgetattr(fd, &new_termios); |
| + | if (memcmp(my_termios, new_termios, |
| + | sizeof(my_termios)) != 0) { |
| + | /* do some error handling */ |
| + | } |
| + | |
| + | 5. Changing Baud Rates |
| + | |
| + | With Linux, the baud rate can be changed using a technique similar to |
| + | add/delete RTS/CTS. |
| + | |
| + | struct termios my_termios; |
| + | struct termios new_termios; |
| + | |
| + | tcgetattr(fd, &my_termios); |
| + | my_termios.c_flag &= ~CBAUD; |
| + | my_termios.c_flag |= B19200; |
| + | tcsetattr(fd, TCSANOW, &my_termios); |
| + | tcgetattr(fd, &new_termios); |
| + | if (memcmp(my_termios, new_termios, |
| + | sizeof(my_termios)) != 0) { |
| + | /* do some error handling */ |
| + | } |
| + | |
| + | POSIX adds another method. They define: |
| + | |
| + | speed_t cfgetispeed(const struct termios *termios_p); |
| + | speed_t cfgetospeed(const struct termios *termios_p); |
| + | |
| + | library calls to extract the current input or output speed from the |
| + | struct termios pointed to with *termio_p. This is a variable defined |
| + | in the calling process. In practice, the data contained in this |
| + | termios, should be obtained by the tcgetattr() call or an ioctl() call |
| + | using the TCGETS command. |
| + | |
| + | The companion library calls are: |
| + | |
| + | int cfsetispeed(struct termios *termios_p, speed_t speed); |
| + | int cfsetospeed(struct termios *termios_p, speed_t speed); |
| + | |
| + | which are used to change the value of the baud rate in the locally |
| + | defined *termios_p. Following either of these calls, either a call to |
| + | tcsetattr() or ioctl() with one of TCSETS, TCSETSW or TCSETSF as the |
| + | command to transmit the change to the kernel. |
| + | |
| + | The cf* commands are preferred for portability. Some weird Unices use |
| + | a considerably different format of termios. |
| + | |
| + | Most implementations of Linux use only the input speed for both input |
| + | and output. These functions are defined in the application program by |
| + | reference to <termios.h>. In reality, they are in |
| + | /usr/include/asm/termbits.h. |
| + | |
| + | 6. Additional Control Calls |
| + | |
| + | 6.1. Sending a "break". |
| + | |
| + | int ioctl(fd, TCSBRK, int arg); |
| + | int tcsendbreak(fd, int arg); |
| + | |
| + | Send a break: Here the action differs between the conventional |
| + | ioctl() call and the POSIX call. For the conventional call, an arg of |
| + | '0' sets the break control line of the UART for 0.25 seconds. For the |
| + | POSIX command, the break line is set for arg times 0.1 seconds. |
| + | |
| + | 6.2. Hardware flow control. |
| + | |
| + | int ioctl(fd, TCXONC, int action); |
| + | int tcflow(fd, int action); |
| + | |
| + | The action flags are: |
| + | |
| + | o TCOOFF 0 suspend output |
| + | |
| + | o TCOON 1 restart output |
| + | |
| + | o TCIOFF 2 transmit STOP character to suspend input |
| + | |
| + | o TCION 3 transmit START character to restart input |
| + | |
| + | 6.3. Flushing I/O buffers. |
| + | |
| + | int ioctl(fd, TCFLSH, queue_selector); |
| + | int tcflush(fd, queue_selector); |
| + | |
| + | The queue_selector flags are: |
| + | |
| + | o TCIFLUSH 0 flush any data not yet read from the input buffer |
| + | |
| + | o TCOFLUSH 1 flush any data written to the output buffer but not |
| + | yet transmitted |
| + | |
| + | o TCIOFLUSH 2 flush both buffers |
| + | |
| + | 7. Modem control |
| + | |
| + | The hardware modem control lines can be monitored or modified by the |
| + | ioctl(2) system call. A set of comparable tc* calls apparently do not |
| + | exist. The form of this call is: |
| + | |
| + | int ioctl(fd, COMMAND, (int *)flags); |
| + | |
| + | The COMMANDS and their action are: |
| + | |
| + | o TIOCMBIS turn on control lines depending upon which bits are set |
| + | in flags. |
| + | |
| + | o TIOCMBIC turn off control lines depending upon which bits are |
| + | unset in flags. |
| + | o TIOCMGET the appropriate bits are set in flags according to the |
| + | current status |
| + | |
| + | o TIOCMSET the state of the UART is changed according to which bits |
| + | are set/unset in 'flags' |
| + | |
| + | The bit pattern of flags refer to the following control lines: |
| + | |
| + | o TIOCM_LE Line enable |
| + | |
| + | o TIOCM_DTR Data Terminal Ready |
| + | |
| + | o TIOCM_RTS Request to send |
| + | |
| + | o TIOCM_ST Secondary transmit |
| + | |
| + | o TIOCM_SR Secondary receive |
| + | |
| + | o TIOCM_CTS Clear to send |
| + | |
| + | o TIOCM_CAR Carrier detect |
| + | |
| + | o TIOCM_RNG Ring |
| + | |
| + | o TIOCM_DSR Data set ready |
| + | |
| + | It should be noted that some of these bits are controlled by the modem |
| + | and the UART cannot change them but their status can be sensed by |
| + | TIOCMGET. Also, most Personal Computers do not provide hardware for |
| + | secondary transmit and receive. |
| + | |
| + | There are also a pair of ioctl() to monitor these lines. They are |
| + | undocumented as far as I have learned. The commands are TIOCMIWAIT |
| + | and TCIOGICOUNT. They also differ between versions of the Linux |
| + | kernel. |
| + | |
| + | See the lines.c file in my "serial_suite" for an example of how these |
| + | can be used see <ftp://scicom.alphacd.com/pub/linux/serial_suite> |
| + | |
| + | 8. Process Groups |
| + | |
| + | 8.1. Sessions |
| + | |
| + | 8.2. Process Groups |
| + | |
| + | Any newly created process inherits the Process Group of its creator. |
| + | The Process Group leader has the same PID as PGID. |
| + | |
| + | 8.3. Controlling Terminal |
| + | |
| + | There are a series of ioctl(2) and tc*(2) calls which can be used to |
| + | monitor or to change the process group to which the device is |
| + | attached. |
| + | |
| + | 8.3.1. Get the foreground group process id. |
| + | |
| + | If there is no foreground group, a number not representing an existing |
| + | process group is returned. On error, a -1 is returned and errno is |
| + | set. |
| + | |
| + | int ioctl(fd, TIOCGPGRP, (pid_t *)pid); |
| + | int tcgetpgrp(fd, (pid_t *)pid); |
| + | |
| + | 8.3.2. Set the foreground process group id of a terminal. |
| + | |
| + | The fd must be the controlling terminal and be associated with the |
| + | session of the calling process. |
| + | |
| + | int ioctl(fd, TIOCSPGRP, (pid_t *)pid); |
| + | int tcsetpgrp(fd, (pid_t *)pid); |
| + | |
| + | 8.3.3. Get process group id. |
| + | |
| + | int ioctl(fd, TIOCGPGRP, &(pid_t)pid); |
| + | int tcgetpgrp(fd, &(pid_t)pid); |
| + | |
| + | 9. Lockfiles |
| + | |
| + | Any process which accesses a serial device should first check for the |
| + | existence of lock file for the desired device. If such a lock lock |
| + | file exists, this means that the device may be in use by another |
| + | process. |
| + | |
| + | Check my "libdevlocks-x.x.tgz" at |
| + | <ftp://scicom.alphacdc.com/pub/linux> for an example of how these lock |
| + | files should be utilized. |
| + | |
| + | 10. Additional Information |
| + | |
| + | Check out my "serial_suite.tgz" for more information about programming |
| + | the serial ports at <mailto:[email protected]>. There some |
| + | examples and some blurbs about setting up modems and comments about |
| + | some general considerations. |
| + | |
| + | 11. Feedback |
| + | |
| + | Please send me any corrections, questions, comments, suggestions, or |
| + | additional material. I would like to improve this HOWTO! Tell me |
| + | exactly what you don't understand, or what could be clearer. You can |
| + | reach me at <mailto:[email protected]> via email. Please |
| + | include the version number of the Serial-Programming-HOWTO when |
| + | writing. |