• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params)
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