You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
619 lines
16 KiB
619 lines
16 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2021. All rights reserved.
|
|
* Description: iapi_uart
|
|
* Author: Hisilicon
|
|
* Create: 2018-12-22
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stddef.h>
|
|
/* file operation interface */
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <termios.h> /* terminate interface */
|
|
#include <sys/mman.h>
|
|
#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;
|
|
}
|