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