/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2021. All rights reserved. * Description: iapi_uart * Author: Hisilicon * Create: 2018-12-22 */ #include #include #include #include /* file operation interface */ #include #include #include #include /* terminate interface */ #include #include "soc_log.h" #include "mpi_system_ext.h" #include "soc_errno.h" #include "uapi_uart.h" #define DEFAULT_BAUDRATE 115200 #define TIMEOUT_MAX (100 * TIMEOUT_MIN) #define TIMEOUT_MIN 100 #define EXT_UART_BUFLEN 1000 static struct { td_s32 fd; /* file description */ td_u32 in; /* receive position in buff */ td_u32 out; /* read position */ td_u32 cnt; /* receive data counter */ td_s32 tmout; /* read time out */ td_s32 close; /* ready to close uart */ pthread_t tid; /* receive thread id */ td_char buf[EXT_UART_BUFLEN]; /* receive buf */ } g_uart[1]; typedef enum { UART_CHIP_RESERVED13 = 0x0, UART_CHIP_RESERVED9 = 0x0, UART_CHIP_RESERVED5, UART_CHIP_MAX } uart_chip; static td_s32 uart_get_chipversion(uart_chip *chip_class) { td_s32 ret; ext_sys_version sys_version; if (chip_class == NULL) { return TD_FAILURE; } ret = ext_mpi_sys_init(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(ext_mpi_sys_init, ret); return ret; } ret = ext_mpi_sys_get_version(&sys_version); if (ret != TD_SUCCESS) { (td_void)ext_mpi_sys_deinit(); soc_fatal_print_call_fun_err(ext_mpi_sys_get_version, ret); return ret; } if (sys_version.chip_name_id == CHIP_NAME_HI3751V811) { *chip_class = UART_CHIP_RESERVED5; } else if (sys_version.chip_name_id <= CHIP_NAME_RESERVED19 && sys_version.chip_name_id >= CHIP_NAME_RESERVED5) { *chip_class = UART_CHIP_RESERVED5; } else if ((sys_version.chip_name_id == CHIP_NAME_RESERVED13) || (sys_version.chip_name_id == CHIP_NAME_RESERVED9)) { *chip_class = UART_CHIP_RESERVED13; } else { printf(" unkown chip type and chip version ...\n"); (td_void)ext_mpi_sys_deinit(); return TD_FAILURE; } ret = ext_mpi_sys_deinit(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(ext_mpi_sys_deinit, ret); return ret; } return TD_SUCCESS; } /* * Description: get current tty number * Calls: ext_mpi_sys_get_uart_num * Data Accessed: g_uart * Return: ttyAMA * !TD_SUCCESS */ td_s32 uapi_uart_get_number(td_void) { td_s32 ret; td_u32 val = 0; ret = ext_mpi_sys_init(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(ext_mpi_sys_init, ret); return ret; } ret = ext_mpi_sys_get_uart_num(&val); if (ret != TD_SUCCESS) { printf("uapi_uart_get_number failed\n"); return TD_FAILURE; } val &= 0x7; /* 0x7: bit0~bit2 is valid */ ret = ext_mpi_sys_deinit(); if (ret != TD_SUCCESS) { return ret; } return (td_s32)val; } /* * Description: switch to ttyAMA0/1 * Calls: uapi_uart_get_number * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_switch(td_s32 tty_ama) { td_s32 ret; uart_chip chip_tmp; ret = uart_get_chipversion(&chip_tmp); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(uart_get_chipversion, ret); return TD_FAILURE; } if (chip_tmp == UART_CHIP_RESERVED13 || chip_tmp == UART_CHIP_RESERVED9) { if (!(tty_ama >= 0 && tty_ama <= 5) || tty_ama == 1) { /* 0-5 mean switch num */ printf("invalid args %d for uapi_uart_switch\n", tty_ama); return SOC_ERR_UART_INVALID_PARA; } } if (chip_tmp == UART_CHIP_RESERVED5) { if (!(tty_ama == 0 || tty_ama == 1)) { printf("invalid args %d for uapi_uart_switch\n", tty_ama); return SOC_ERR_UART_INVALID_PARA; } } ret = ext_mpi_sys_init(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(ext_mpi_sys_init, ret); return ret; } ret = ext_mpi_sys_switch_uart((td_u32)tty_ama); if (ret != TD_SUCCESS) { (void)ext_mpi_sys_deinit(); printf("switch uart error\n"); soc_fatal_print_call_fun_err(ext_mpi_sys_switch_uart, ret); return TD_FAILURE; } ret = ext_mpi_sys_deinit(); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(ext_mpi_sys_deinit, ret); return ret; } return TD_SUCCESS; } /* * Description:get uart baud speed * Data Accessed:g_uart * Return:TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_get_speed(td_s32 *speed) { td_u32 i; td_u32 ispeed; td_u32 ospeed; struct termios option; if (speed == NULL) { printf("speed is null\n"); return SOC_ERR_UART_NULL_PTR; } /* baud speed reference table */ td_u32 speed_arr[] = { B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B600, B300, B110 }; td_s32 name_arr[] = { 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 600, 300, 110 }; if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } if (tcgetattr(g_uart[0].fd, &option) != 0) { printf("get speed is failed\n"); return SOC_ERR_UART_GET_ATTR; } ispeed = cfgetispeed(&option); ospeed = cfgetospeed(&option); if (ispeed != ospeed) { printf("ispeed=%u, ospeed=%u\n", ispeed, ospeed); return SOC_ERR_UART_IOSPEED; } for (i = 0; i < sizeof(speed_arr) / sizeof(td_s32); i++) { if (ispeed == speed_arr[i]) { *speed = name_arr[i]; return TD_SUCCESS; } } /* unsupport baud speed */ printf("only support speed of 230400 115200 57600 38400 19200 " "9600 4800 2400 1200 600 300 110 but [%d]\n", ispeed); return SOC_ERR_UART_SPEED; } /* Description: set uart baud speed */ td_s32 uapi_uart_set_speed(td_s32 speed) { td_u32 i; struct termios option; td_s32 temp_speed = speed; /* baud speed reference table */ speed_t speed_arr[] = { B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B600, B300, B110 }; td_s32 name_arr[] = { 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 600, 300, 110 }; if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } /* 0 means default setting 115200 */ if (temp_speed == 0) { temp_speed = DEFAULT_BAUDRATE; } if (tcgetattr(g_uart[0].fd, &option) != 0) { printf("get speed is failed\n"); return SOC_ERR_UART_GET_ATTR; } for (i = 0; i < sizeof(speed_arr) / sizeof(speed_t); i++) { if (temp_speed == name_arr[i]) { tcflush(g_uart[0].fd, TCIOFLUSH); cfsetispeed(&option, speed_arr[i]); cfsetospeed(&option, speed_arr[i]); if (tcsetattr(g_uart[0].fd, TCSANOW, &option) != 0) { printf("set speed is failed\n"); return SOC_ERR_UART_SET_ATTR; } return TD_SUCCESS; } } /* unsupport baud speed */ printf("only support speed of 230400 115200 57600 38400 19200 " "9600 4800 2400 1200 600 300 110 but [%d]\n", temp_speed); return SOC_ERR_UART_SPEED; } /* * Description: set uart data bits * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ static td_s32 ext_uart_set_data_bits(td_s32 databits, struct termios *option) { /* set data bits */ switch (databits) { case 7: /* mean data bits 7 */ option->c_cflag |= CS7; break; case 0: /* 0 means default setting */ case 8: /* mean data bits 8 */ option->c_cflag |= CS8; break; default: printf("only support data size of 7 or 8\n"); return SOC_ERR_UART_DATABITS; } return TD_SUCCESS; } /* * Description: set uart parity attribute * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ static td_s32 ext_uart_set_parity_attribute(td_char parity, struct termios *option) { /* set parity attribute */ switch (parity) { case 0: /* 0 means default setting */ case 'n': case 'N': option->c_cflag &= ~PARENB; /* Clear parity enable */ option->c_iflag &= ~INPCK; break; case 'o': case 'O': option->c_cflag |= (PARODD | PARENB); /* Enable odd parity */ option->c_iflag |= INPCK; /* enable parity checking */ break; case 'e': case 'E': option->c_cflag |= PARENB; option->c_cflag &= ~PARODD; /* Enable even parity */ option->c_iflag |= INPCK; /* enable parity checking */ break; default: printf("only support parity of n/N o/O e/E\n"); return SOC_ERR_UART_PARITY; } return TD_SUCCESS; } /* * Description: set uart stop bits * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ static td_s32 ext_uart_set_stop_bits(td_s32 stopbits, struct termios *option) { /* set stop bits */ switch (stopbits) { case 0: /* 0 means default setting */ case 1: /* stop bits 1 */ option->c_cflag &= ~CSTOPB; break; case 2: /* stop bits 2 */ option->c_cflag |= CSTOPB; break; default: printf("only support stop bits of 1 or 2\n"); return SOC_ERR_UART_STOPBITS; } return TD_SUCCESS; } /* * Description: set uart attribute * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_set_attr(td_s32 data_bits, td_s32 stop_bits, td_char parity) { struct termios option; td_s32 ret; if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } /* get old attribute */ if (tcgetattr(g_uart[0].fd, &option) != 0) { printf("get speed is failed\n"); return SOC_ERR_UART_GET_ATTR; } /* set general attribute */ option.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); option.c_oflag &= ~OPOST; /* Output */ option.c_iflag &= ~(ICRNL | IXON); /* ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) */ option.c_cflag &= ~CSIZE; /* set data bits */ ret = ext_uart_set_data_bits(data_bits, &option); if (ret != TD_SUCCESS) { return ret; } /* set parity attribute */ ret = ext_uart_set_parity_attribute(parity, &option); if (ret != TD_SUCCESS) { return ret; } /* set stop bits */ ret = ext_uart_set_stop_bits(stop_bits, &option); if (ret != TD_SUCCESS) { return ret; } option.c_cc[VTIME] = 5; /* time out value(500ms) */ option.c_cc[VMIN] = 0; /* each char */ tcflush(g_uart[0].fd, TCIOFLUSH); /* update the option and do it now */ if (tcsetattr(g_uart[0].fd, TCSANOW, &option) != 0) { printf("set speed is failed\n"); return SOC_ERR_UART_SET_ATTR; } return TD_SUCCESS; } /* * Description: get uart attribute * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_get_attr(td_s32 *data_bits, td_s32 *stop_bits, td_char *parity) { struct termios option; if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } if ((data_bits == NULL) || (stop_bits == NULL) || (parity == NULL)) { printf("input paramer is null\n"); return SOC_ERR_UART_NULL_PTR; } /* get current attribute */ if (tcgetattr(g_uart[0].fd, &option) != 0) { printf("get speed is failed\n"); return SOC_ERR_UART_GET_ATTR; } if ((option.c_cflag & CS8) == CS8) { *data_bits = 8; /* data bits 8 */ } else if ((option.c_cflag & CS7) == CS7) { *data_bits = 7; /* date bits 7 */ } else { printf("unknown data_bits[cflag=0%o]\n", option.c_cflag); } if ((option.c_cflag & CSTOPB) != 0) { *stop_bits = 2; /* stop bits 2 */ } else { *stop_bits = 1; /* stop bits 1 */ } if (((option.c_iflag & PARENB) != 0) && ((option.c_cflag & INPCK) != 0)) { if ((option.c_cflag & PARODD) != 0) { *parity = 'o'; return TD_SUCCESS; } *parity = 'e'; } else if (((option.c_cflag & PARENB) == 0) && ((option.c_iflag & INPCK) == 0)) { *parity = 'n'; } else { printf("unknown parity[cflag=0%o,iflag=0%o]\n", option.c_cflag, option.c_iflag); } return TD_SUCCESS; } /* * Description: timeout after receiving finished * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_set_timeout(td_s32 timeout) { (void)timeout; if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } return TD_SUCCESS; } /* * Description: read data from uart * Data Accessed: g_uart * Return: total * TD_SUCCESS */ td_s32 uapi_uart_read(td_char *buff, td_u32 len) { if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } if (buff == NULL) { printf("buff is null\n"); return SOC_ERR_UART_NULL_PTR; } td_s32 ret; ret = (td_s32)read(g_uart[0].fd, buff, len); if (ret < 0) { soc_fatal_print_call_fun_err(read, ret); return SOC_ERR_UART_READ; } g_uart[0].cnt += (td_u32)ret; return ret; } /* * Description: write data to uart * Data Accessed: g_uart * Return: ret * TD_SUCCESS */ td_s32 uapi_uart_write(td_char *buff, td_u32 len) { td_s32 ret; if (g_uart[0].fd <= 0) { return SOC_ERR_UART_NOT_OPEN; } if (buff == NULL) { printf("buff is null\n"); return SOC_ERR_UART_NULL_PTR; } ret = (td_s32)write(g_uart[0].fd, buff, len); if (ret == -1) { soc_fatal_print_call_fun_err(write, ret); return SOC_ERR_UART_WRITE; } return ret; } /* * Description: open uart device * Calls:Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_init(td_void) { td_s32 ret; uart_chip chip_tmp; td_u32 boardid = 0; /* already opened */ if (g_uart[0].fd > 0) { return TD_SUCCESS; } ret = uart_get_chipversion(&chip_tmp); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(uart_get_chipversion, ret); return TD_FAILURE; } ret = ext_mpi_sys_get_board_id(&boardid); if (ret != TD_SUCCESS) { soc_fatal_print_call_fun_err(uapi_sys_get_board_id, ret); return TD_FAILURE; } boardid &= 0x2000; if (chip_tmp == UART_CHIP_RESERVED13 || chip_tmp == UART_CHIP_RESERVED9) { if (boardid != 0x2000) { g_uart[0].fd = open("/dev/ttyAMA2", O_RDWR | O_NOCTTY); } else { g_uart[0].fd = open("/dev/ttyAMA5", O_RDWR | O_NOCTTY); } } else if (chip_tmp == UART_CHIP_RESERVED5) { printf("UART_CHIP_RESERVED5 open /dev/ttyAMA1 \n"); g_uart[0].fd = open("/dev/ttyAMA1", O_RDWR | O_NOCTTY); } if (g_uart[0].fd == -1) { soc_fatal_print_call_fun_err(open, g_uart[0].fd); return SOC_ERR_UART_OPEN; } g_uart[0].cnt = 0; return TD_SUCCESS; } /* * Description: close uart device * Data Accessed: g_uart * Return: TD_SUCCESS * !TD_SUCCESS */ td_s32 uapi_uart_deinit(td_void) { if (g_uart[0].fd <= 0) { return TD_SUCCESS; } if (close(g_uart[0].fd) != 0) { soc_fatal_print_call_fun_err(close, close(g_uart[0].fd)); return SOC_ERR_UART_CLOSE; } /* update fd */ g_uart[0].fd = 0; return TD_SUCCESS; }