2 * @copyright Copyright (c) 2017-2020 TOYOTA MOTOR CORPORATION.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 * This source code is a sample source code .
20 * Implementation of the function must be performed by the vendor.
24 #include "usb_hal_internal.h"
25 #include "usb_hal_debug.h"
26 #include <sys/types.h>
35 * USB role switch information table
37 const UsbRoleSwitchInfo kUsbRoleSwitchTable = {USB_ROLE_FILE, USB_HOST_STRING, USB_FUNCTION_STRING};
40 * Read content of USB role switch file, then determine HOST/FUNCTION role
41 * according to the specified HOST/FUNCTION value.
43 static EFrameworkunifiedStatus GetUsbRoleType(const char* file_path, const char* usb_host_value, const char* usb_function_value,
44 UsbRoleType* usb_role) {
45 if (!file_path || !usb_host_value || !usb_function_value || !usb_role) {
46 USB_ERROR_LOG("parameter is NULL.");
47 return eFrameworkunifiedStatusFail;
50 // 1. open role switch file
51 int fd = open(file_path, O_RDONLY);
53 USB_ERROR_LOG("open [%s] failed.(%d, %s)", file_path, errno, strerror(errno));
54 return eFrameworkunifiedStatusFail;
57 // 2. read file content
58 char file_content[FILE_CONTENT_LENGTH];
59 memset(file_content, 0, sizeof(file_content));
60 ssize_t ret = read(fd, file_content, sizeof(file_content) - 1);
61 int read_error = errno;
67 USB_ERROR_LOG("read failed.(%d, %s)", read_error, strerror(read_error));
68 return eFrameworkunifiedStatusFail;
71 // 4. compare file content to HOST/FUNCTION value
72 if (!strcmp(usb_host_value, file_content)) {
73 *usb_role = USB_ROLE_HOST;
74 } else if (!strcmp(usb_function_value, file_content)) {
75 *usb_role = USB_ROLE_FUNCTION;
77 USB_ERROR_LOG("content error.[%s]", file_content);
78 return eFrameworkunifiedStatusFail;
81 return eFrameworkunifiedStatusOK;
85 * Write the specified role value to USB role switch file.
87 static EFrameworkunifiedStatus SetUsbRoleValue(const char* file_path, const char* role_value) {
88 if (!file_path || !role_value) {
89 USB_ERROR_LOG("parameter is NULL.");
90 return eFrameworkunifiedStatusFail;
93 // 1. open role switch file
94 int fd = open(file_path, O_WRONLY | O_TRUNC);
96 USB_ERROR_LOG("open [%s] failed.(%d, %s)", file_path, errno, strerror(errno));
97 return eFrameworkunifiedStatusFail;
100 // 2. write role file
101 ssize_t ret = write(fd, role_value, strlen(role_value));
102 int write_error = errno;
107 // 4. check write result
108 if (static_cast<ssize_t>(strlen(role_value)) != ret) {
109 USB_ERROR_LOG("write [%s] failed, ret=%zd.(%d, %s)", role_value, ret, write_error, strerror(write_error));
110 return eFrameworkunifiedStatusFail;
112 return eFrameworkunifiedStatusOK;
117 * Check whether the specified USB port supports power control.
119 static bool CheckSupportPowerControl(UsbPortNumber usb_port_no) {
120 if (USB_PORT_NUMBER_MAX <= usb_port_no) {
128 * Check whether the specified gpio port is available.
130 static bool CheckGpioPortAvailable(UsbGpioPort gpio_port) {
131 if (USB_GPIO_PORT_MAX <= gpio_port) {
132 USB_ERROR_LOG("port %d is invalid.", gpio_port);
136 if (!kUsbGpioInfo[gpio_port].port_name || (0 == strlen(kUsbGpioInfo[gpio_port].port_name))) {
137 USB_ERROR_LOG("port %d is not available.", gpio_port);
145 * Open gpio export file.
147 static int OpenExportFile() {
148 return open(kUsbGpioExportFile, O_WRONLY);
152 * Open the direction file of the specified gpio port.
154 static int OpenDirectionFile(const char* port_name) {
155 if (!port_name || (0 == strlen(port_name))) {
156 USB_ERROR_LOG("port name is invalid.");
160 char dir_file[FILE_PATH_LENGTH];
161 // /sys/class/gpio/gpio123/direction
162 snprintf(dir_file, sizeof(dir_file), "%s%s%s", kUsbGpioFilePrefix, port_name, kUsbGpioDirectionFile);
163 return open(dir_file, O_RDWR);
167 * Open the value file of the specified gpio port.
169 static int OpenValueFile(const char* port_name, bool ro) {
170 if (!port_name || (0 == strlen(port_name))) {
171 USB_ERROR_LOG("port name is invalid.");
175 char value_file[FILE_PATH_LENGTH];
176 // /sys/class/gpio/gpio123/value
177 snprintf(value_file, sizeof(value_file), "%s%s%s", kUsbGpioFilePrefix, port_name, kUsbGpioValueFile);
178 return open(value_file, ro ? O_RDONLY : O_RDWR);
182 * Initialize gpio port value.
184 static EFrameworkunifiedStatus InitializeGpioPort(UsbGpioPort gpio_port) {
185 if (!CheckGpioPortAvailable(gpio_port)) {
186 return eFrameworkunifiedStatusFail;
189 char port_file[FILE_PATH_LENGTH];
190 snprintf(port_file, sizeof(port_file), "%s%s", kUsbGpioFilePrefix, kUsbGpioInfo[gpio_port].port_name);
192 // check if port is exported already
193 if (0 == access(port_file, F_OK)) {
194 return eFrameworkunifiedStatusOK;
197 // open the export file
198 int export_fd = OpenExportFile();
199 if (-1 == export_fd) {
200 USB_ERROR_LOG("open [%s] failed.(%d, %s)", "export", errno, strerror(errno));
201 return eFrameworkunifiedStatusFail;
204 // do export by writing the export file
205 ssize_t ret = write(export_fd, kUsbGpioInfo[gpio_port].port_name, strlen(kUsbGpioInfo[gpio_port].port_name));
206 int write_error = errno;
208 // close the export file
211 // check write result
212 if (static_cast<ssize_t>(strlen(kUsbGpioInfo[gpio_port].port_name)) != ret) {
213 USB_ERROR_LOG("write [%s] failed, ret=%zd.(%d, %s)", kUsbGpioInfo[gpio_port].port_name, ret, write_error,
214 strerror(write_error));
215 return eFrameworkunifiedStatusFail;
218 // open the direction file
219 int direction_fd = OpenDirectionFile(kUsbGpioInfo[gpio_port].port_name);
220 if (-1 == direction_fd) {
221 USB_ERROR_LOG("open direction file failed.(%d, %s)", errno, strerror(errno));
222 return eFrameworkunifiedStatusFail;
226 const char* direction_value;
227 if (!kUsbGpioInfo[gpio_port].is_output) {
228 // for input port, set direction as "in"
229 direction_value = kUsbGpioDirectionIn;
231 if (kUsbGpioHighValue == kUsbGpioInfo[gpio_port].default_value) {
232 // for output port, if default value is high, set direction as "high"
233 direction_value = kUsbGpioDirectionHigh;
234 } else if (kUsbGpioLowValue == kUsbGpioInfo[gpio_port].default_value) {
235 // for output port, if default value is low, set direction as "low"
236 direction_value = kUsbGpioDirectionLow;
238 USB_ERROR_LOG("unknown default value[%c]", kUsbGpioInfo[gpio_port].default_value);
239 return eFrameworkunifiedStatusFail;
243 ret = write(direction_fd, direction_value, strlen(direction_value));
246 if (static_cast<ssize_t>(strlen(direction_value)) != ret) {
247 USB_ERROR_LOG("write direction %s failed, ret=%zd.(%d, %s)", direction_value, ret, write_error,
248 strerror(write_error));
249 return eFrameworkunifiedStatusFail;
252 return eFrameworkunifiedStatusOK;
256 * Get gpio port value.
258 static EFrameworkunifiedStatus GetGpioPortValue(UsbGpioPort port_name, bool* port_value) {
259 if ((USB_GPIO_PORT_MAX <= port_name) || !port_value) {
260 USB_ERROR_LOG("parameter is invalid.");
261 return eFrameworkunifiedStatusFail;
264 // initialize gpio port
265 EFrameworkunifiedStatus result = InitializeGpioPort(port_name);
266 if (eFrameworkunifiedStatusOK != result) {
270 // open port value file
271 int fd = OpenValueFile(kUsbGpioInfo[port_name].port_name, true);
273 USB_ERROR_LOG("open value file failed.(%d, %s)", errno, strerror(errno));
274 return eFrameworkunifiedStatusFail;
278 char file_content = '\0';
279 ssize_t ret = read(fd, &file_content, sizeof(file_content));
280 int read_error = errno;
285 if (sizeof(file_content) != ret) {
286 USB_ERROR_LOG("read failed.(%d, %s)", read_error, strerror(read_error));
287 return eFrameworkunifiedStatusFail;
290 // compare file content to high/low value
291 if (kUsbGpioHighValue == file_content) {
292 *port_value = (kUsbGpioInfo[port_name].active_low ? false : true);
293 } else if (kUsbGpioLowValue == file_content) {
294 *port_value = (kUsbGpioInfo[port_name].active_low ? true : false);
296 USB_ERROR_LOG("content error.[%c]", file_content);
297 return eFrameworkunifiedStatusFail;
300 return eFrameworkunifiedStatusOK;
304 * Set gpio port value.
306 static EFrameworkunifiedStatus SetGpioPortValue(UsbGpioPort port_name, GpioPortValue port_value) {
307 if (USB_GPIO_PORT_MAX <= port_name) {
308 USB_ERROR_LOG("parameter is invalid.");
309 return eFrameworkunifiedStatusFail;
312 // initialize gpio port
313 EFrameworkunifiedStatus result = InitializeGpioPort(port_name);
314 if (eFrameworkunifiedStatusOK != result) {
318 // check direction is output
319 if (!kUsbGpioInfo[port_name].is_output) {
320 USB_ERROR_LOG("%d not an output port.", port_name);
321 return eFrameworkunifiedStatusFail;
324 // open port value file
325 int fd = OpenValueFile(kUsbGpioInfo[port_name].port_name, false);
327 USB_ERROR_LOG("open value file failed.(%d, %s)", errno, strerror(errno));
328 return eFrameworkunifiedStatusFail;
332 bool port_active = (GPIO_PORT_ON == port_value ? true : false);
333 bool write_low = (kUsbGpioInfo[port_name].active_low ? port_active : !port_active);
334 char write_value = (write_low ? kUsbGpioLowValue : kUsbGpioHighValue);
335 ssize_t ret = write(fd, &write_value, sizeof(write_value));
336 int write_error = errno;
341 // check write result
342 if (sizeof(write_value) != ret) {
343 USB_ERROR_LOG("write [%c] failed, ret=%zd.(%d, %s)", write_value, ret, write_error, strerror(write_error));
344 return eFrameworkunifiedStatusFail;
346 return eFrameworkunifiedStatusOK;
353 static EFrameworkunifiedStatus CheckUsbOvercurrent(UsbPortNumber usb_port_no, bool* is_ovc) {
354 if ((USB_PORT_NUMBER_MAX <= usb_port_no) || !is_ovc) {
355 return eFrameworkunifiedStatusFail;
358 return GetGpioPortValue(kUsbOvercurrentGpio[usb_port_no], is_ovc);
361 EFrameworkunifiedStatus GetUsbRoleSwitch(UsbRoleType* usb_role) {
362 // check NULL pointer
364 USB_ERROR_LOG("parameter is NULL.");
365 return eFrameworkunifiedStatusNullPointer;
368 return GetUsbRoleType(kUsbRoleSwitchTable.file_path, kUsbRoleSwitchTable.usb_host_value,
369 kUsbRoleSwitchTable.usb_function_value, usb_role);
372 EFrameworkunifiedStatus SetUsbRoleSwitch(UsbRoleType usb_role) {
373 if ((USB_ROLE_HOST != usb_role) && (USB_ROLE_FUNCTION != usb_role)) {
374 USB_ERROR_LOG("parameter error.[%d]", usb_role);
375 return eFrameworkunifiedStatusInvldParam;
378 // check current usb role:
379 // allow to switch only when usb_role is different from current usb role.
380 UsbRoleType current_role;
381 if (eFrameworkunifiedStatusOK != GetUsbRoleSwitch(¤t_role)) {
382 return eFrameworkunifiedStatusFail;
385 if (current_role == usb_role) {
386 return eFrameworkunifiedStatusOK;
389 // check usb role type
390 // - HOST: write HOST value to role file
391 // - FUNCTION: write FUNCTION value to role file
392 return SetUsbRoleValue(kUsbRoleSwitchTable.file_path, (USB_ROLE_HOST == usb_role)
393 ? kUsbRoleSwitchTable.usb_host_value
394 : kUsbRoleSwitchTable.usb_function_value);
397 EFrameworkunifiedStatus CheckUsbAuthenticationError(UsbAuthenticationError* usb_auth_error) {
398 // check NULL pointer
399 if (!usb_auth_error) {
400 USB_ERROR_LOG("parameter is NULL.");
401 return eFrameworkunifiedStatusNullPointer;
404 // Empty Stub implementations
405 *usb_auth_error = USB_AUTHENTICATION_ERROR_NONE;
406 return eFrameworkunifiedStatusOK;
409 EFrameworkunifiedStatus ResetUsbVbus(UsbPortNumber usb_port_no) {
410 // check support power control
411 if (!CheckSupportPowerControl(usb_port_no)) {
412 return eFrameworkunifiedStatusInvldParam;
415 // step 1: power off USB port
416 EFrameworkunifiedStatus result = SetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], GPIO_PORT_OFF);
417 if (eFrameworkunifiedStatusOK != result) {
418 USB_ERROR_LOG("power off USB%d failed.", usb_port_no);
422 // step 2: sleep 1.1 sec
425 // step 3: power on USB port
426 result = SetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], GPIO_PORT_ON);
427 if (eFrameworkunifiedStatusOK != result) {
428 USB_ERROR_LOG("power on USB%d failed.", usb_port_no);
433 EFrameworkunifiedStatus IsUsbPortPowered(UsbPortNumber usb_port_no, bool* is_powered) {
435 return eFrameworkunifiedStatusNullPointer;
438 // check support power control
439 if (!CheckSupportPowerControl(usb_port_no)) {
440 return eFrameworkunifiedStatusInvldParam;
443 return GetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], is_powered);
446 EFrameworkunifiedStatus PowerOnUsbPort(UsbPortNumber usb_port_no) {
447 // check support power control
448 if (!CheckSupportPowerControl(usb_port_no)) {
449 return eFrameworkunifiedStatusInvldParam;
451 bool current_power = false;
452 if (eFrameworkunifiedStatusOK != GetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], ¤t_power)) {
453 return eFrameworkunifiedStatusFail;
457 return eFrameworkunifiedStatusOK;
459 return SetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], GPIO_PORT_ON);
462 EFrameworkunifiedStatus PowerOffUsbPort(UsbPortNumber usb_port_no) {
463 // check support power control
464 if (!CheckSupportPowerControl(usb_port_no)) {
465 return eFrameworkunifiedStatusInvldParam;
467 bool current_power = false;
468 if (eFrameworkunifiedStatusOK != GetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], ¤t_power)) {
469 return eFrameworkunifiedStatusFail;
472 if (!current_power) {
473 return eFrameworkunifiedStatusOK;
476 return SetGpioPortValue(kUsbPowerEnableGpio[usb_port_no], GPIO_PORT_OFF);
479 EFrameworkunifiedStatus CheckUsbAbnormalStatus(UsbPortNumber usb_port_no, UsbAbnormalStatus* usb_abnormal_status) {
480 if (USB_PORT_NUMBER_MAX <= usb_port_no) {
481 return eFrameworkunifiedStatusInvldParam;
484 // check NULL pointer
485 if (!usb_abnormal_status) {
486 return eFrameworkunifiedStatusNullPointer;
491 EFrameworkunifiedStatus result = CheckUsbOvercurrent(usb_port_no, &is_ovc);
492 if (eFrameworkunifiedStatusOK == result) {
494 *usb_abnormal_status = USB_ABNORMAL_STATUS_OVERCURRENT;
496 *usb_abnormal_status = USB_ABNORMAL_STATUS_NONE;