• 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 #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