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 #include "linux_serial.h"
16 #include <hdf_base.h>
17 #include <hdf_log.h>
18 #include <unistd.h>
19 #include <cstdlib>
20 #include <fcntl.h>
21 #include <cstring>
22 #include <filesystem>
23 #include <cerrno>
24 #include <cstdio>
25 #include <cctype>
26 #include <sys/un.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <sys/select.h>
31 #include "usbd_wrapper.h"
32 #include "securec.h"
33
34 #define _BSD_SOURCE
35
36 #define UEVENT_BUFFER_SIZE 2048
37 #define CMSPAR 010000000000
38 #define BUFF_SIZE 50
39 #define SYSFS_PATH_LEN 128
40 #define RETRY_NUM 5
41 #define MAX_TRANS_DATA_SIZE 8192
42
43
44 #define ERR_CODE_IOEXCEPTION (-5)
45 #define ERR_CODE_DEVICENOTOPEN (-6)
46 #define ERR_CODE_TIMEOUT (-7)
47
48 namespace OHOS {
49 namespace HDI {
50 namespace Usb {
51 namespace Serial {
52 namespace V1_0 {
53
54 static const std::string SERIAL_TYPE_NAME = "ttyUSB";
55 static const int32_t ERR_NO = -1;
56 static const uint8_t DATABITS_FIVE = 5;
57 static const uint8_t DATABITS_SIX = 6;
58 static const uint8_t DATABITS_SEVEN = 7;
59 static const uint8_t DATABITS_EIGHT = 8;
60 static const int32_t THOUSAND = 1000;
61
62 namespace fs = std::filesystem;
63
64 typedef std::pair<int32_t, int32_t> BaudratePair;
65
66 BaudratePair g_baudratePairs[] = {
67 {BAUDRATE_50, B50},
68 {BAUDRATE_75, B75},
69 {BAUDRATE_110, B110},
70 {BAUDRATE_134, B134},
71 {BAUDRATE_150, B150},
72 {BAUDRATE_200, B200},
73 {BAUDRATE_300, B300},
74 {BAUDRATE_600, B600},
75 {BAUDRATE_1200, B1200},
76 {BAUDRATE_1800, B1800},
77 {BAUDRATE_2400, B2400},
78 {BAUDRATE_4800, B4800},
79 {BAUDRATE_9600, B9600},
80 {BAUDRATE_19200, B19200},
81 {BAUDRATE_38400, B38400},
82 {BAUDRATE_57600, B57600},
83 {BAUDRATE_115200, B115200},
84 {BAUDRATE_230400, B230400},
85 {BAUDRATE_460800, B460800},
86 {BAUDRATE_500000, B500000},
87 {BAUDRATE_576000, B576000},
88 {BAUDRATE_921600, B921600},
89 {BAUDRATE_1000000, B1000000},
90 {BAUDRATE_1152000, B1152000},
91 {BAUDRATE_1500000, B1500000},
92 {BAUDRATE_2000000, B2000000},
93 {BAUDRATE_2500000, B2500000},
94 {BAUDRATE_3000000, B3000000},
95 {BAUDRATE_3500000, B3500000},
96 {BAUDRATE_4000000, B4000000},
97 };
98
LinuxSerial()99 LinuxSerial::LinuxSerial()
100 {
101 HDF_LOGI("%{public}s: enter SerialUSBWrapper initialization.", __func__);
102 }
103
~LinuxSerial()104 LinuxSerial::~LinuxSerial()
105 {
106 HDF_LOGI("%{public}s: enter Destroying SerialUSBWrapper.", __func__);
107 }
108
GetInstance()109 LinuxSerial &LinuxSerial::GetInstance()
110 {
111 static LinuxSerial instance;
112 return instance;
113 }
114
GetBaudrate(unsigned int baudrate)115 int32_t LinuxSerial::GetBaudrate(unsigned int baudrate)
116 {
117 for (const auto& pair : g_baudratePairs) {
118 if (static_cast<unsigned int>(pair.first) == baudrate) {
119 return pair.second;
120 }
121 }
122 return HDF_FAILURE;
123 }
124
GetDatabits(unsigned char dataBits,tcflag_t & cflag)125 int32_t LinuxSerial::GetDatabits(unsigned char dataBits, tcflag_t& cflag)
126 {
127 switch (dataBits) {
128 case DATABITS_FIVE:
129 cflag |= CS5;
130 break;
131 case DATABITS_SIX:
132 cflag |= CS6;
133 break;
134 case DATABITS_SEVEN:
135 cflag |= CS7;
136 break;
137 case DATABITS_EIGHT:
138 cflag |= CS8;
139 break;
140 default:
141 return HDF_FAILURE;
142 }
143 return HDF_SUCCESS;
144 }
145
GetParity(tcflag_t & cflag,unsigned char parity)146 int32_t LinuxSerial::GetParity(tcflag_t& cflag, unsigned char parity)
147 {
148 cflag &= ~(PARENB | PARODD | CMSPAR);
149 switch (parity) {
150 case USB_ATTR_PARITY_NONE:
151 break;
152 case USB_ATTR_PARITY_ODD:
153 cflag |= PARENB | PARODD;
154 break;
155 case USB_ATTR_PARITY_EVEN:
156 cflag |= PARENB;
157 break;
158 case USB_ATTR_PARITY_MARK:
159 cflag |= PARENB | PARODD | CMSPAR;
160 break;
161 case USB_ATTR_PARITY_SPACE:
162 cflag |= PARENB | CMSPAR;
163 break;
164 default:
165 HDF_LOGE("%{public}s: Parity not exist!", __func__);
166 return HDF_FAILURE;
167 }
168 return HDF_SUCCESS;
169 }
170
GetStopbits(tcflag_t & cflag,unsigned char stopBits)171 int32_t LinuxSerial::GetStopbits(tcflag_t& cflag, unsigned char stopBits)
172 {
173 if (stopBits == USB_ATTR_STOPBIT_1) {
174 cflag &= ~CSTOPB;
175 } else if (stopBits == USB_ATTR_STOPBIT_2) {
176 cflag |= CSTOPB;
177 } else {
178 return HDF_FAILURE;
179 }
180 return HDF_SUCCESS;
181 }
182
GetFdByPortId(int32_t portId)183 int32_t LinuxSerial::GetFdByPortId(int32_t portId)
184 {
185 size_t index = 0;
186 bool isFound = false;
187 std::lock_guard<std::mutex> lock(portMutex_);
188 for (index = 0; index < serialPortList_.size(); index++) {
189 if (portId == serialPortList_[index].portId) {
190 isFound = true;
191 break;
192 }
193 }
194 if (!isFound) {
195 HDF_LOGE("%{public}s: not find portId.", __func__);
196 return HDF_FAILURE;
197 }
198 if (ERR_NO == serialPortList_[index].fd) {
199 HDF_LOGE("%{public}s: fd not exist.", __func__);
200 return HDF_FAILURE;
201 }
202 return serialPortList_[index].fd;
203 }
204
SerialOpen(int32_t portId)205 int32_t LinuxSerial::SerialOpen(int32_t portId)
206 {
207 std::lock_guard<std::mutex> lock(portMutex_);
208 size_t index = 0;
209 bool isFound = false;
210 char path[BUFF_SIZE] = {'\0'};
211 for (index = 0; index < serialPortList_.size(); index++) {
212 if (portId == serialPortList_[index].portId) {
213 isFound = true;
214 break;
215 }
216 }
217 if (!isFound) {
218 HDF_LOGE("%{public}s: not find portId.", __func__);
219 return HDF_FAILURE;
220 }
221 if (ERR_NO != serialPortList_[index].fd) {
222 HDF_LOGE("%{public}s: device has been opened,fd=%{public}d", __func__, serialPortList_[index].fd);
223 return HDF_FAILURE;
224 }
225 int32_t ret = 0;
226 ret = snprintf_s(path, sizeof(path), sizeof(path)-1, "/dev/ttyUSB%d", portId);
227 if (ret < 0) {
228 HDF_LOGE("%{public}s: sprintf_s path failed, ret:%{public}d", __func__, ret);
229 return HDF_FAILURE;
230 }
231 serialPortList_[index].fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
232 if (serialPortList_[index].fd <= 0) {
233 HDF_LOGE("%{public}s: Unable to open serial port.", __func__);
234 return HDF_FAILURE;
235 }
236 fdsan_exchange_owner_tag(serialPortList_[index].fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN));
237
238 if (tcgetattr(serialPortList_[index].fd, &options_) == -1) {
239 fdsan_close_with_tag(serialPortList_[index].fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN));
240 HDF_LOGE("%{public}s: get attribute failed %{public}d.", __func__, errno);
241 serialPortList_.erase(serialPortList_.begin() + index);
242 return HDF_FAILURE;
243 }
244 options_.c_lflag &= ~ICANON;
245 options_.c_lflag &= ~ECHO;
246 if (tcsetattr(serialPortList_[index].fd, TCSANOW, &options_) == -1) {
247 fdsan_close_with_tag(serialPortList_[index].fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN));
248 HDF_LOGE("%{public}s: set attribute failed %{public}d.", __func__, errno);
249 serialPortList_.erase(serialPortList_.begin() + index);
250 return HDF_FAILURE;
251 }
252 return HDF_SUCCESS;
253 }
254
SerialClose(int32_t portId)255 int32_t LinuxSerial::SerialClose(int32_t portId)
256 {
257 std::lock_guard<std::mutex> lock(portMutex_);
258 size_t index = 0;
259 bool isFound = false;
260 for (index = 0; index < serialPortList_.size(); index++) {
261 if (portId == serialPortList_[index].portId) {
262 isFound = true;
263 break;
264 }
265 }
266 if (!isFound) {
267 HDF_LOGE("%{public}s: not find portId.", __func__);
268 return HDF_FAILURE;
269 }
270 if (ERR_NO == serialPortList_[index].fd) {
271 HDF_LOGE("%{public}s: fd not exist.", __func__);
272 return HDF_FAILURE;
273 }
274 fdsan_close_with_tag(serialPortList_[index].fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN));
275 serialPortList_[index].fd = -1;
276 return HDF_SUCCESS;
277 }
278
SerialRead(int32_t portId,std::vector<uint8_t> & data,uint32_t size,uint32_t timeout)279 int32_t LinuxSerial::SerialRead(int32_t portId, std::vector<uint8_t>& data, uint32_t size, uint32_t timeout)
280 {
281 int32_t fd = -1;
282 if (size <= 0) {
283 return HDF_FAILURE;
284 }
285 fd = GetFdByPortId(portId);
286 if (fd < 0) {
287 return ERR_CODE_IOEXCEPTION;
288 }
289
290 uint8_t dataIn[MAX_TRANS_DATA_SIZE] = {0};
291 fd_set readfds;
292 FD_ZERO(&readfds);
293 FD_SET(fd, &readfds);
294
295 struct timeval readTimeout;
296 readTimeout.tv_sec = 0;
297 readTimeout.tv_usec = timeout * THOUSAND;
298
299 int32_t bytesRead;
300 int32_t status = select(fd + 1, &readfds, nullptr, nullptr, &readTimeout);
301 if (status == -1) {
302 return HDF_FAILURE;
303 } else if (status == 0) {
304 return ERR_CODE_TIMEOUT;
305 } else {
306 bytesRead = read(fd, dataIn, size);
307 if (bytesRead < 0) {
308 HDF_LOGE("%{public}s: read fail. %{public}d", __func__, errno);
309 return ERR_CODE_IOEXCEPTION;
310 }
311 }
312 std::vector<uint8_t> vec(dataIn, dataIn + bytesRead);
313 data.insert(data.end(), vec.begin(), vec.end());
314 HDF_LOGI("%{public}s: read success. %{public}s", __func__, data.data());
315 return bytesRead;
316 }
317
SerialWrite(int32_t portId,const std::vector<uint8_t> & data,uint32_t size,uint32_t timeout)318 int32_t LinuxSerial::SerialWrite(int32_t portId, const std::vector<uint8_t>& data, uint32_t size, uint32_t timeout)
319 {
320 int32_t fd;
321 int32_t bytesWritten;
322 fd = GetFdByPortId(portId);
323 if (fd < 0) {
324 return ERR_CODE_IOEXCEPTION;
325 }
326 if (data.empty()) {
327 HDF_LOGE("%{public}s: data is empty!", __func__);
328 return HDF_FAILURE;
329 }
330 fd_set writefd;
331 FD_ZERO(&writefd);
332 FD_SET(fd, &writefd);
333
334 struct timeval writeTimeout;
335 writeTimeout.tv_sec = 0;
336 writeTimeout.tv_usec = timeout * THOUSAND;
337
338 int32_t status = select(fd + 1, nullptr, &writefd, nullptr, &writeTimeout);
339 if (status == -1) {
340 return HDF_FAILURE;
341 } else if (status == 0) {
342 HDF_LOGE("%{public}s: write timed out. %{public}d", __func__, errno);
343 return ERR_CODE_TIMEOUT;
344 } else {
345 bytesWritten = write(fd, data.data(), data.size());
346 if (bytesWritten == ERR_NO) {
347 HDF_LOGE("%{public}s: write fail.", __func__);
348 return ERR_CODE_IOEXCEPTION;
349 }
350 }
351 return bytesWritten;
352 }
353
TranslateParity(tcflag_t parity,SerialAttribute & attribute)354 void TranslateParity(tcflag_t parity, SerialAttribute& attribute)
355 {
356 if ((parity & PARENB) && (parity & CMSPAR)) {
357 if (parity & PARODD) {
358 attribute.parity = USB_ATTR_PARITY_MARK;
359 } else {
360 attribute.parity = USB_ATTR_PARITY_SPACE;
361 }
362 } else {
363 if (parity & PARODD) {
364 attribute.parity = USB_ATTR_PARITY_ODD;
365 } else {
366 attribute.parity = USB_ATTR_PARITY_EVEN;
367 }
368 }
369 }
370
SerialGetAttribute(int32_t portId,SerialAttribute & attribute)371 int32_t LinuxSerial::SerialGetAttribute(int32_t portId, SerialAttribute& attribute)
372 {
373 HDF_LOGI("%{public}s: enter get attribute.", __func__);
374 int32_t fd = GetFdByPortId(portId);
375 if (fd < 0) {
376 return ERR_CODE_IOEXCEPTION;
377 }
378 if (tcgetattr(fd, &options_) == -1) {
379 HDF_LOGE("%{public}s: get attribute failed %{public}d.", __func__, errno);
380 return HDF_FAILURE;
381 }
382
383 for (const auto& pair : g_baudratePairs) {
384 if (static_cast<unsigned int>(pair.second) == cfgetispeed(&options_)) {
385 attribute.baudrate = static_cast<unsigned int>(pair.first);
386 }
387 }
388
389 auto databits = options_.c_cflag & CSIZE;
390
391 switch (databits) {
392 case CS5:
393 attribute.dataBits = DATABITS_FIVE;
394 break;
395 case CS6:
396 attribute.dataBits = DATABITS_SIX;
397 break;
398 case CS7:
399 attribute.dataBits = DATABITS_SEVEN;
400 break;
401 case CS8:
402 attribute.dataBits = DATABITS_EIGHT;
403 break;
404 default:
405 HDF_LOGE("%{public}s: Unknown data bits setting", __func__);
406 return HDF_FAILURE;
407 }
408
409 if (options_.c_cflag & PARENB) {
410 TranslateParity(options_.c_cflag, attribute);
411 } else {
412 attribute.parity = USB_ATTR_PARITY_NONE;
413 }
414
415 attribute.stopBits = (options_.c_cflag & CSTOPB) ? USB_ATTR_STOPBIT_2 : USB_ATTR_STOPBIT_1;
416 return HDF_SUCCESS;
417 }
418
SerialSetAttribute(int32_t portId,const SerialAttribute & attribute)419 int32_t LinuxSerial::SerialSetAttribute(int32_t portId, const SerialAttribute& attribute)
420 {
421 HDF_LOGI("%{public}s: enter set attribute.", __func__);
422 int32_t fd;
423 int retry = RETRY_NUM;
424 fd = GetFdByPortId(portId);
425 if (fd < 0) {
426 return ERR_CODE_IOEXCEPTION;
427 }
428
429 if (tcgetattr(fd, &options_) == -1) {
430 HDF_LOGE("%{public}s: get attribute failed %{public}d.", __func__, errno);
431 return HDF_FAILURE;
432 }
433
434 int ret = GetStopbits(options_.c_cflag, attribute.stopBits);
435 if (ret < 0) {
436 HDF_LOGE("%{public}s: stopBits set fail.", __func__);
437 return HDF_FAILURE;
438 }
439
440 ret = GetParity(options_.c_cflag, attribute.parity);
441 if (ret < 0) {
442 HDF_LOGE("%{public}s:parity set fail.", __func__);
443 return ret;
444 }
445
446 options_.c_cflag &= ~CSIZE;
447 if (GetDatabits(attribute.dataBits, options_.c_cflag) < 0) {
448 HDF_LOGE("%{public}s: dataBits set fail.", __func__);
449 return HDF_FAILURE;
450 }
451
452 options_.c_cflag |= (CLOCAL | CREAD);
453 if (GetBaudrate(attribute.baudrate) < 0) {
454 HDF_LOGE("%{public}s: baudrate set fail.", __func__);
455 return HDF_FAILURE;
456 }
457
458 cfsetispeed(&options_, GetBaudrate(attribute.baudrate));
459 cfsetospeed(&options_, GetBaudrate(attribute.baudrate));
460 while (retry-- > 0) {
461 //dev/ttyUSB0
462 if (tcsetattr(fd, TCSANOW, &options_) == 0) {
463 break;
464 } else {
465 HDF_LOGE("%{public}s: tcsetattr failed.", __func__);
466 }
467 }
468 if (retry <= 0) {
469 HDF_LOGE("%{public}s: Failed to set attributes after multiple attempts.", __func__);
470 return ERR_CODE_IOEXCEPTION;
471 }
472 return HDF_SUCCESS;
473 }
474
HandleDevListEntry(struct UsbPnpNotifyMatchInfoTable * device,std::vector<SerialPort> & portIds,std::string targetPath)475 void LinuxSerial::HandleDevListEntry(struct UsbPnpNotifyMatchInfoTable *device, std::vector<SerialPort>& portIds,
476 std::string targetPath)
477 {
478 SerialPort serialPort;
479 Serialfd serialPortId;
480 struct UsbPnpNotifyDeviceInfo *devInfo = &device->deviceInfo;
481 HDF_LOGI("%{public}s: device: devNum = %{public}d, busNum = %{public}d, numInfos = %{public}d",
482 __func__, device->devNum, device->busNum, device->numInfos);
483 HDF_LOGI("%{public}s: device info: vendorId = %{public}d, productId = %{public}d, deviceClass = %{public}d",
484 __func__, devInfo->vendorId, devInfo->productId, devInfo->deviceClass);
485 HDF_LOGI("%{public}s: device: serialNo: %{public}s", __func__, devInfo->serialNo.c_str());
486
487 std::string devnameStr(targetPath);
488 size_t pos = devnameStr.find(SERIAL_TYPE_NAME);
489 if (pos != std::string::npos) {
490 std::string numStr = devnameStr.substr(pos + SERIAL_TYPE_NAME.length());
491 int num = atoi(numStr.c_str());
492 serialPort.portId = num;
493 serialPortId.portId = num;
494 serialPortId.fd = -1;
495 }
496 serialPort.deviceInfo.busNum = static_cast<uint8_t>(device->busNum);
497 serialPort.deviceInfo.devAddr = static_cast<uint8_t>(device->devNum);
498 serialPort.deviceInfo.vid = static_cast<int32_t>(devInfo->vendorId);
499 serialPort.deviceInfo.pid = static_cast<int32_t>(devInfo->productId);
500 serialPort.deviceInfo.serialNum = devInfo->serialNo;
501 auto it = std::find_if(serialPortList_.begin(), serialPortList_.end(), [&](const Serialfd& tempSerial) {
502 return tempSerial.portId == serialPortId.portId;
503 });
504 if (it == serialPortList_.end()) {
505 serialPortList_.push_back(serialPortId);
506 }
507 portIds.push_back(serialPort);
508 }
509
DevMgrInitDevice(struct UsbDdkDeviceInfo * deviceInfo)510 static int32_t DevMgrInitDevice(struct UsbDdkDeviceInfo *deviceInfo)
511 {
512 (void)memset_s(deviceInfo, sizeof(struct UsbDdkDeviceInfo), 0, sizeof(struct UsbDdkDeviceInfo));
513 int32_t ret = OsalMutexInit(&deviceInfo->deviceMutex);
514 if (ret != HDF_SUCCESS) {
515 HDF_LOGE("%{public}s: init mutex failed", __func__);
516 return HDF_FAILURE;
517 }
518 DListHeadInit(&deviceInfo->list);
519
520 return HDF_SUCCESS;
521 }
522
SerialGetPortList(std::vector<SerialPort> & portIds)523 int32_t LinuxSerial::SerialGetPortList(std::vector<SerialPort>& portIds)
524 {
525 DIR *dir = opendir(SYSFS_DEVICES_DIR);
526 if (dir == NULL) {
527 HDF_LOGE("%{public}s: opendir failed sysfsDevDir:%{public}s", __func__, SYSFS_DEVICES_DIR);
528 return HDF_FAILURE;
529 }
530
531 struct UsbDdkDeviceInfo *device = (struct UsbDdkDeviceInfo *)OsalMemCalloc(sizeof(struct UsbDdkDeviceInfo));
532 if (device == NULL) {
533 HDF_LOGE("%{public}s: init device failed", __func__);
534 closedir(dir);
535 return HDF_FAILURE;
536 }
537 int32_t status = HDF_SUCCESS;
538 struct dirent *devHandle;
539 while ((devHandle = readdir(dir))) {
540 std::string ttyPathStr(devHandle->d_name);
541 if (ttyPathStr == "." || ttyPathStr == "..") {
542 continue;
543 }
544 fs::path ttyPath(SYSFS_DEVICES_DIR + ttyPathStr);
545 if (!fs::exists(ttyPath) || !fs::is_symlink(ttyPath)) {
546 HDF_LOGE("%{public}s: path %{public}s not exist", __func__, ttyPath.string().c_str());
547 continue;
548 }
549 fs::path realPath = fs::read_symlink(ttyPath);
550 std::string tempPath = ttyPath.parent_path().string() + "/" + realPath.string();
551 realPath = fs::weakly_canonical(fs::path(tempPath));
552 std::string targetPath = realPath.parent_path().parent_path().string();
553 status = DevMgrInitDevice(device);
554 if (status != HDF_SUCCESS) {
555 HDF_LOGE("%{public}s: init device failed:%{public}d", __func__, status);
556 break;
557 }
558 status = SerialGetDevice(targetPath.c_str(), &device->info);
559 if (status != HDF_SUCCESS) {
560 HDF_LOGE("%{public}s: sysfs get device failed:%{public}d", __func__, status);
561 break;
562 }
563 HandleDevListEntry(&device->info, portIds, ttyPath.string());
564 }
565
566 OsalMemFree(device);
567 closedir(dir);
568 return HDF_SUCCESS;
569 }
570 } // V1_0
571 } // Serial
572 } // Usb
573 } // HDI
574 } // OHOS
575