1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "usb_serial_linux_adapter.h"
17
18 #include <cerrno>
19 #include <cstdint>
20 #include <fcntl.h>
21 #include <hdf_base.h>
22 #include <hdf_log.h>
23 #include <cstdlib>
24 #include <cstring>
25 #include <sys/ioctl.h>
26 #include <termios.h>
27 #include <unistd.h>
28
29 #include "usbd_wrapper.h"
30
31 #define HDF_LOG_TAG usb_serial_linux_adapter
32
33 namespace OHOS {
34 namespace HDI {
35 namespace Usb {
36 namespace UsbSerialDdk {
37 namespace V1_0 {
38
39 static std::unordered_map<uint32_t, uint32_t> g_baudRateMap = {
40 {0, B0},
41 {50, B50},
42 {75, B75},
43 {110, B110},
44 {134, B134},
45 {150, B150},
46 {200, B200},
47 {300, B300},
48 {600, B600},
49 {1200, B1200},
50 {1800, B1800},
51 {2400, B2400},
52 {4800, B4800},
53 {9600, B9600},
54 {19200, B19200},
55 {38400, B38400},
56 {57600, B57600},
57 {115200, B115200},
58 {230400, B230400},
59 {460800, B460800},
60 {500000, B500000},
61 {576000, B576000},
62 {921600, B921600},
63 {1000000, B1000000},
64 {1152000, B1152000},
65 {1500000, B1500000},
66 {2000000, B2000000},
67 {2500000, B2500000},
68 {3000000, B3000000},
69 {3500000, B3500000},
70 {4000000, B4000000}
71 };
72
TransToStandardBaudRate(uint32_t baudRate)73 static uint32_t TransToStandardBaudRate(uint32_t baudRate)
74 {
75 auto it = g_baudRateMap.find(baudRate);
76 if (it != g_baudRateMap.end()) {
77 return it->second;
78 }
79 return baudRate;
80 }
81
SetDefaultTty(struct termios & tty)82 static void SetDefaultTty(struct termios &tty)
83 {
84 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
85 tty.c_iflag &= ~IGNBRK;
86 tty.c_lflag = 0;
87 tty.c_oflag = 0;
88
89 // read doesn't block
90 tty.c_cc[VMIN] = 0;
91 tty.c_cc[VTIME] = 0;
92
93 tty.c_iflag &= ~(IXON | IXOFF | IXANY);
94 tty.c_cflag &= ~CRTSCTS;
95
96 tty.c_cflag |= (CLOCAL | CREAD);
97 tty.c_cflag &= ~(PARENB | PARODD);
98 tty.c_cflag |= 0;
99 tty.c_cflag &= ~CSTOPB;
100 }
101
SetSpeed(struct termios & tty,uint32_t baudRate)102 static int SetSpeed(struct termios &tty, uint32_t baudRate)
103 {
104 tty.c_cflag &= ~CBAUD;
105 tty.c_cflag |= CBAUDEX;
106
107 // set baudRate
108 uint32_t baudRateConstant = 0;
109 baudRateConstant = TransToStandardBaudRate(baudRate);
110 if (cfsetospeed(&tty, baudRateConstant) != 0) {
111 HDF_LOGE("Cfsetospeed err.\n");
112 return USB_SERIAL_DDK_IO_ERROR;
113 }
114 if (cfsetispeed(&tty, baudRateConstant) != 0) {
115 HDF_LOGE("cfsetispeed err.\n");
116 return USB_SERIAL_DDK_IO_ERROR;
117 }
118 return HDF_SUCCESS;
119 }
120
SetDataBits(struct termios & tty,uint8_t dataBits)121 static int SetDataBits(struct termios &tty, uint8_t dataBits)
122 {
123 tty.c_cflag &= ~CSIZE;
124 switch (dataBits) {
125 case DATA_BITS_5:
126 tty.c_cflag |= CS5;
127 break;
128 case DATA_BITS_6:
129 tty.c_cflag |= CS6;
130 break;
131 case DATA_BITS_7:
132 tty.c_cflag |= CS7;
133 break;
134 case DATA_BITS_8:
135 tty.c_cflag |= CS8;
136 break;
137 default:
138 HDF_LOGE("Unsupported data bits %{public}d.\n", dataBits);
139 return USB_SERIAL_DDK_INVALID_PARAMETER;
140 }
141 return HDF_SUCCESS;
142 }
143
SetParity(struct termios & tty,uint8_t parity)144 static int SetParity(struct termios &tty, uint8_t parity)
145 {
146 tty.c_cflag &= ~(PARENB | PARODD);
147 switch (parity) {
148 case USB_SERIAL_PARITY_NONE:
149 tty.c_cflag |= 0;
150 break;
151 case USB_SERIAL_PARITY_ODD:
152 tty.c_cflag |= (PARODD | PARENB);
153 break;
154 case USB_SERIAL_PARITY_EVEN:
155 tty.c_cflag |= PARENB;
156 break;
157 default:
158 HDF_LOGE("Unsupported parity %{public}d.\n", parity);
159 return USB_SERIAL_DDK_INVALID_PARAMETER;
160 }
161 return HDF_SUCCESS;
162 }
163
SetBaudRate(int32_t fd,uint32_t baudRate)164 int32_t LinuxUsbSerialOsAdapter::SetBaudRate(int32_t fd, uint32_t baudRate)
165 {
166 HDF_LOGE("into SetBaudRate.\n");
167 struct termios tty;
168 if (tcgetattr(fd, &tty) != 0) {
169 HDF_LOGE("%{public}s: error tcgetattr %{public}s.\n", __func__, strerror(errno));
170 if (errno == EBADF) {
171 return USB_SERIAL_DDK_INVALID_OPERATION;
172 }
173 return USB_SERIAL_DDK_IO_ERROR;
174 }
175
176 int ret = SetSpeed(tty, baudRate);
177 if (ret != HDF_SUCCESS) {
178 return ret;
179 }
180 SetDefaultTty(tty);
181
182 if (tcsetattr(fd, TCSANOW, &tty) != 0) {
183 HDF_LOGE("error %d from tcsetattr\n", errno);
184 return USB_SERIAL_DDK_IO_ERROR;
185 }
186 return HDF_SUCCESS;
187 }
188
SetParams(int32_t fd,const UsbSerialParams & params)189 int32_t LinuxUsbSerialOsAdapter::SetParams(int32_t fd, const UsbSerialParams ¶ms)
190 {
191 struct termios tty;
192 if (tcgetattr(fd, &tty) != 0) {
193 HDF_LOGE("%{public}s: error tcgetattr fd %{public}d, %{public}s.\n", __func__, fd, strerror(errno));
194 if (errno == EBADF) {
195 return USB_SERIAL_DDK_INVALID_OPERATION;
196 }
197 return USB_SERIAL_DDK_IO_ERROR;
198 }
199
200 int ret = SetSpeed(tty, params.baudRate);
201 if (ret != HDF_SUCCESS) {
202 return ret;
203 }
204 SetDefaultTty(tty);
205
206 ret = SetDataBits(tty, params.nDataBits);
207 if (ret != HDF_SUCCESS) {
208 return ret;
209 }
210
211 if (params.nStopBits == STOP_ONE) {
212 tty.c_cflag &= ~CSTOPB;
213 } else if (params.nStopBits == STOP_TWO) {
214 tty.c_cflag |= CSTOPB;
215 } else {
216 HDF_LOGE("Unsupported stop bits %{public}d.\n", params.nStopBits);
217 return USB_SERIAL_DDK_INVALID_PARAMETER;
218 }
219
220 ret = SetParity(tty, params.parity);
221 if (ret != HDF_SUCCESS) {
222 return ret;
223 }
224
225 if (tcsetattr(fd, TCSANOW, &tty) != 0) {
226 HDF_LOGE("error %d from tcsetattr\n", errno);
227 return USB_SERIAL_DDK_IO_ERROR;
228 }
229 return HDF_SUCCESS;
230 }
231
SetTimeout(int32_t fd,int32_t timeout)232 int32_t LinuxUsbSerialOsAdapter::SetTimeout(int32_t fd, int32_t timeout)
233 {
234 struct termios tty;
235 if (tcgetattr(fd, &tty) != 0) {
236 HDF_LOGE("%{public}s: tcgetattr error %{public}s.\n", __func__, strerror(errno));
237 if (errno == EBADF) {
238 return USB_SERIAL_DDK_INVALID_OPERATION;
239 }
240 return USB_SERIAL_DDK_IO_ERROR;
241 }
242
243 if (timeout == -1) {
244 // block indefinitely
245 tty.c_cc[VTIME] = 0;
246 tty.c_cc[VMIN] = 1;
247 } else if (timeout == 0) {
248 // Setting both to 0 will give a non-blocking read
249 tty.c_cc[VTIME] = 0;
250 tty.c_cc[VMIN] = 0;
251 } else if (timeout > 0) {
252 tty.c_cc[VTIME] = (cc_t)(timeout / 100); // 100 ms
253 tty.c_cc[VMIN] = 0;
254 }
255
256 if (tcsetattr(fd, TCSANOW, &tty) != 0) {
257 HDF_LOGE("tcsetattr error %{public}s.\n", strerror(errno));
258 return USB_SERIAL_DDK_IO_ERROR;
259 }
260
261 return HDF_SUCCESS;
262 }
263
SetFlowControl(int32_t fd,int32_t flowControl)264 int32_t LinuxUsbSerialOsAdapter::SetFlowControl(int32_t fd, int32_t flowControl)
265 {
266 struct termios tty;
267 if (tcgetattr(fd, &tty) != 0) {
268 HDF_LOGE("%{public}s: error tcgetattr %{public}s.\n", __func__, strerror(errno));
269 if (errno == EBADF) {
270 return USB_SERIAL_DDK_INVALID_OPERATION;
271 }
272 return USB_SERIAL_DDK_IO_ERROR;
273 }
274 tty.c_iflag &= ~(IXON | IXOFF | IXANY);
275 tty.c_cflag &= ~CRTSCTS;
276 if (flowControl == USB_SERIAL_SOFTWARE_FLOW_CONTROL) {
277 tty.c_iflag |= (IXON | IXOFF | IXANY);
278 } else if (flowControl == USB_SERIAL_HARDWARE_FLOW_CONTROL) {
279 tty.c_cflag |= CRTSCTS;
280 }
281
282 if (tcsetattr(fd, TCSANOW, &tty) != 0) {
283 HDF_LOGE("error tcsetattr %{public}s.\n", strerror(errno));
284 return USB_SERIAL_DDK_IO_ERROR;
285 }
286 return HDF_SUCCESS;
287 }
288
IsDeviceDisconnect(int32_t fd)289 bool LinuxUsbSerialOsAdapter::IsDeviceDisconnect(int32_t fd)
290 {
291 struct termios term2;
292 int rv = ioctl(fd, TCGETS, &term2);
293 if (rv != 0) {
294 HDF_LOGE("device disconnection.\n");
295 return true;
296 }
297 return false;
298 }
299
Flush(int32_t fd)300 int32_t LinuxUsbSerialOsAdapter::Flush(int32_t fd)
301 {
302 int ret = tcdrain(fd);
303 if (ret != 0) {
304 HDF_LOGE("%{public}s: Failed to flush serial port %{public}s.\n", __func__, strerror(errno));
305 if (errno == EBADF) {
306 return USB_SERIAL_DDK_INVALID_OPERATION;
307 }
308 return USB_SERIAL_DDK_IO_ERROR;
309 }
310 return HDF_SUCCESS;
311 }
312
FlushInput(int32_t fd)313 int32_t LinuxUsbSerialOsAdapter::FlushInput(int32_t fd)
314 {
315 int ret = tcflush(fd, TCIFLUSH);
316 if (ret != 0) {
317 HDF_LOGE("%{public}s: Failed to flush input buffer: %{public}s.\n", __func__, strerror(errno));
318 if (errno == EBADF) {
319 return USB_SERIAL_DDK_INVALID_OPERATION;
320 }
321 return USB_SERIAL_DDK_IO_ERROR;
322 }
323 return HDF_SUCCESS;
324 }
325
FlushOutput(int32_t fd)326 int32_t LinuxUsbSerialOsAdapter::FlushOutput(int32_t fd)
327 {
328 int ret = tcflush(fd, TCOFLUSH);
329 if (ret != 0) {
330 HDF_LOGE("%{public}s: Failed to flush output buffer: %{public}s.\n", __func__, strerror(errno));
331 if (errno == EBADF) {
332 return USB_SERIAL_DDK_INVALID_OPERATION;
333 }
334 return USB_SERIAL_DDK_IO_ERROR;
335 }
336 return HDF_SUCCESS;
337 }
338
339 } // namespace V1_0
340 } // namespace UsbSerialDdk
341 } // namespace Usb
342 } // namespace HDI
343 } // namespace OHOS
344