blob: 26cf59d749ffcaea6f52eac17a97cdae6143d3ce [file] [log] [blame]
Sylvain Munautfe28ded2011-09-02 22:18:24 +02001/*
2 * serial.c
3 *
4 * Utility functions to deal with serial ports
5 *
6 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25/*! \addtogroup serial
26 * @{
27 */
28
29/*! \file serial.c
30 * \file Osmocom serial port helpers
31 */
32
33#include <errno.h>
34#include <fcntl.h>
35#include <stdio.h>
36#include <termios.h>
37#include <unistd.h>
38#include <sys/ioctl.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <linux/serial.h>
42
43
44#include <osmocom/core/serial.h>
45
46
47#if 0
48# define dbg_perror(x) perror(x)
49#else
50# define dbg_perror(x) do { } while (0)
51#endif
52
53/*! \brief Open serial device and does base init
54 * \param[in] dev Path to the device node to open
55 * \param[in] baudrate Baudrate constant (speed_t: B9600, B...)
56 * \returns >=0 file descriptor in case of success or negative errno.
57 */
58int
59osmo_serial_init(const char *dev, speed_t baudrate)
60{
61 int rc, fd=0, v24;
62 struct termios tio;
63
64 /* Open device */
65 fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
66 if (fd < 0) {
67 dbg_perror("open");
68 return -errno;
69 }
70
71 /* Configure serial interface */
72 rc = tcgetattr(fd, &tio);
73 if (rc < 0) {
74 dbg_perror("tcgetattr()");
75 rc = -errno;
76 goto error;
77 }
78
79 cfsetispeed(&tio, baudrate);
80 cfsetospeed(&tio, baudrate);
81
82 tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
83 tio.c_cflag |= (CREAD | CLOCAL | CS8);
84 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
85 tio.c_iflag |= (INPCK | ISTRIP);
86 tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR);
87 tio.c_oflag &= ~(OPOST | ONLCR);
88
89 rc = tcsetattr(fd, TCSANOW, &tio);
90 if (rc < 0) {
91 dbg_perror("tcsetattr()");
92 rc = -errno;
93 goto error;
94 }
95
96 /* Set ready to read/write */
97 v24 = TIOCM_DTR | TIOCM_RTS;
98 rc = ioctl(fd, TIOCMBIS, &v24);
99 if (rc < 0) {
100 dbg_perror("ioctl(TIOCMBIS)");
101 rc = -errno;
102 goto error;
103 }
104
105 return fd;
106
107error:
108 if (fd)
109 close(fd);
110 return rc;
111}
112
113static int
114_osmo_serial_set_baudrate(int fd, speed_t baudrate)
115{
116 int rc;
117 struct termios tio;
118
119 rc = tcgetattr(fd, &tio);
120 if (rc < 0) {
121 dbg_perror("tcgetattr()");
122 return -errno;
123 }
124 cfsetispeed(&tio, baudrate);
125 cfsetospeed(&tio, baudrate);
126
127 rc = tcsetattr(fd, TCSANOW, &tio);
128 if (rc < 0) {
129 dbg_perror("tcgetattr()");
130 return -errno;
131 }
132
133 return 0;
134}
135
136/*! \brief Change current baudrate
137 * \param[in] fd File descriptor of the open device
138 * \param[in] baudrate Baudrate constant (speed_t: B9600, B...)
139 * \returns 0 for success or negative errno.
140 */
141int
142osmo_serial_set_baudrate(int fd, speed_t baudrate)
143{
144 osmo_serial_clear_custom_baudrate(fd);
145 return _osmo_serial_set_baudrate(fd, baudrate);
146}
147
148/*! \brief Change current baudrate to a custom one using OS specific method
149 * \param[in] fd File descriptor of the open device
150 * \param[in] baudrate Baudrate as integer
151 * \returns 0 for success or negative errno.
152 *
153 * This function might not work on all OS or with all type of serial adapters
154 */
155int
156osmo_serial_set_custom_baudrate(int fd, int baudrate)
157{
158 int rc;
159 struct serial_struct ser_info;
160
161 rc = ioctl(fd, TIOCGSERIAL, &ser_info);
162 if (rc < 0) {
163 dbg_perror("ioctl(TIOCGSERIAL)");
164 return -errno;
165 }
166
167 ser_info.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY;
168 ser_info.custom_divisor = ser_info.baud_base / baudrate;
169
170 rc = ioctl(fd, TIOCSSERIAL, &ser_info);
171 if (rc < 0) {
172 dbg_perror("ioctl(TIOCSSERIAL)");
173 return -errno;
174 }
175
176 return _osmo_serial_set_baudrate(fd, B38400); /* 38400 is a kind of magic ... */
177}
178
179/*! \brief Clear any custom baudrate
180 * \param[in] fd File descriptor of the open device
181 * \returns 0 for success or negative errno.
182 *
183 * This function might not work on all OS or with all type of serial adapters
184 */
185int
186osmo_serial_clear_custom_baudrate(int fd)
187{
188 int rc;
189 struct serial_struct ser_info;
190
191 rc = ioctl(fd, TIOCGSERIAL, &ser_info);
192 if (rc < 0) {
193 dbg_perror("ioctl(TIOCGSERIAL)");
194 return -errno;
195 }
196
197 ser_info.flags = ASYNC_LOW_LATENCY;
198 ser_info.custom_divisor = 0;
199
200 rc = ioctl(fd, TIOCSSERIAL, &ser_info);
201 if (rc < 0) {
202 dbg_perror("ioctl(TIOCSSERIAL)");
203 return -errno;
204 }
205
206 return 0;
207}
208
209/*! }@ */