diff options
-rw-r--r-- | loginutils/Serial-Programming-HOWTO.txt | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/loginutils/Serial-Programming-HOWTO.txt b/loginutils/Serial-Programming-HOWTO.txt new file mode 100644 index 000000000..0dfc8aa31 --- /dev/null +++ b/loginutils/Serial-Programming-HOWTO.txt @@ -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:Peter.Baumann@dlr.de> + + 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:vern@zebra.alphacdc.com>. 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:vern@zebra.alphacdc.com> via email. Please + include the version number of the Serial-Programming-HOWTO when + writing. |