blob: 5a67cccef21554a3be88045fe4c396aed3285217 [file] [log] [blame]
/*****************************************************************************
* Copyright Statement:
* --------------------
* This software is protected by Copyright and the information contained
* herein is confidential. The software may not be copied and the information
* contained herein may not be used or disclosed except with the written
* permission of MediaTek Inc. (C) 2012
*
* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
*
* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
*
*****************************************************************************/
/*******************************************************************************
* Filename:
* ---------
* dcl_tty.c
*
* Project:
* --------
* MOLY
*
* Description:
* ------------
* Define how to access COM Port. Provide API for upper-layer applications to access COM Port
* It works with enabling compile flag __TTY_UT__.
*
* Author:
* -------
* -------
*
* ==========================================================================
* $Log$
*
* 11 03 2021 li-cheng.tsai
* [MOLY00629269] [FOCUS][VMOLYM][MT6298][Mercury][Pre-MP1][SQC][Dongle][MTBF][HQ][Lab][Ericsson][ErrorTimes:3][1][core0,vpe1,tc2(vpe1)] Fatal Error (0x1d, 0x0, 0x900072a8) - DHLHD
*
* [MD700.MP][MPD] patch back from VMOLYM, avoid race condition caused null callback function issue.
*
* 08 27 2021 li-cheng.tsai
* [MOLY00711608] [WIN] MiniDump is observed during ICT S4(Hibernate) stress.
*
* [MD700.MP][MPD] Solved race condition in assign rx ior
*
* 09 18 2020 li-cheng.tsai
* [MOLY00569647] [MP7.PRECHECKIN.DEV][Code sync] sync code from T700
* [R3.MP][MPD][CCCIDEV]code sync from T700
*
* 09 15 2020 li-cheng.tsai
* [MOLY00569647] [MP7.PRECHECKIN.DEV][Code sync] sync code from T700
* [MP7.PRECHECKIN.DEV][MPD][CCCIDEV]code sync from T700
*
* 09 14 2020 i-wei.tsai
* [MOLY00548843] [TITAN CRASH][Wingtech][TITAN][MT6765][N21][TFN][P200722-00292 ]S215DL-11 Device crashes into CP Crash upload mode
* .
*
* 08 10 2020 i-wei.tsai
* [MOLY00548843] [TITAN CRASH][Wingtech][TITAN][MT6765][N21][TFN][P200722-00292 ]S215DL-11 Device crashes into CP Crash upload mode
*
* . skip clear tx handling for ccci port
*
* 06 01 2020 li-cheng.tsai
* [MOLY00526500] [MODEM][ASSERT ][ASSERT] file:mcu/service/qmu_bm/src/qmu_bm.c line:512 p1:0x00000000 p2:0x00000000 p3:0x00000000
* CCCI TTY change to fix error handling
*
* 12 05 2019 i-wei.tsai
* [MOLY00463962] [Gen97] TTY DEV
*
* .
*
* 12 04 2019 amit.singh
* [MOLY00463020] [IPCORE] [TTY] VMOLY Patchback memory reduction by re-arranging member fields of structures
*
* TTY memory reduction by structure rearrange.
*
* 12 02 2019 amit.singh
* [MOLY00454015] [TTY] LG patchabck of MOLY00394195 to VMOLY.1001.DEV
*
* 1001.DEV to VMOLY TRUNK patchback TTY.
*
* 06 18 2019 i-wei.tsai
* [MOLY00413678] [MT6297][Apollo][Ericsson][IODT][NSA FullStack][Kista][5G][1][core0,vpe0,tc0(vpe0)] Assert fail dcl_tty.c 1063 - DR
*
* .remove un-used assertion
*
* 09 11 2018 i-wei.tsai
* [MOLY00349664] [ASSERT] file:mcu/common/driver/tty/src/dcl_tty.c line:1789
*
* .fix race condition issue in rx callback
*
* 07 24 2018 i-wei.tsai
* [MOLY00341790] [MT6295] UDC feature patch back
*
* .change spinlock to HWITC
*
* 06 04 2018 i-wei.tsai
* [MOLY00331344] [Gen95] TTYCore fix
*
* .
*
* 09 18 2017 i-wei.tsai
* [MOLY00278689] Performance improvement of INT_QueryExceptionStatus
*
* .
*
* 07 06 2017 i-wei.tsai
* [MOLY00262251] [Coverity defect fix] tty coverity fix
* .
*
* 05 09 2017 i-wei.tsai
* [MOLY00248066] [Gen93] [TTY] Log format refine
* .
* fix modis build error
*
* 05 09 2017 i-wei.tsai
* [MOLY00248066] [Gen93] [TTY] Log format refine
* .
* fix modis warning
*
* 05 09 2017 i-wei.tsai
* [MOLY00248066] [Gen93] [TTY] Log format refine
* .
* remove dummy character
*
* 05 09 2017 i-wei.tsai
* [MOLY00248066] [Gen93] [TTY] Log format refine
* .
* TTY log refine
*
* 06 22 2016 mt.tsai
* [MOLY00154662] Fix the tty build warning
* .delete unused variable in TTY
*
* 06 22 2016 mt.tsai
* [MOLY00177032] [Coverity Scanned Code Defect]CID:116560 code defect happened in /mcu/common/driver/tty/src/dcl_tty.c
* .
* [Coverity] add spinlock to full fill the protection of some variables
*
* 02 26 2016 mt.tsai
* [MOLY00166612] Remove violation include kal_debug.h
* The APIs in kal_debug.h is legacy and don't be provided for user
*
* 09 30 2015 mt.tsai
* [MOLY00143135] [UMOLY][LR11] TTYCore Unit Test
* .modified files for ttycore unit test
*
* 09 15 2015 i-wei.tsai
* [MOLY00141929] [UMOLY][ELBRUS][TTY] Add SMP support
* .
*
* 03 02 2015 i-wei.tsai
* [MOLY00097392] [UMOLY] [TTY] Timer tick macro modification
* .
*
* 12 10 2014 i-wei.tsai
* [MOLY00086663] [TK6291] [TTY] Add new uart port for MTAD
* .
*
* 11 14 2014 i-wei.tsai
* [MOLY00084437] [UMOLY] [TTY] rollback changes
* .
*
* 06 16 2014 i-wei.tsai
* [MOLY00068713] [MT6752] MD2 uart config setting (Buffer mode)
* .
*
* 04 25 2014 i-wei.tsai
* [MOLY00063770] [Rose][KK][Free Test][EE][VT Call]EE about [ASSERT] file:dcl_tty.c line:1367 will pop up after tap "Use touch tone keypad" to enter VT call screen.
* .
*
* 03 12 2014 i-wei.tsai
* [MOLY00059311] [TTY] New Feature for configurable indication mechanism
*
* 10 29 2013 i-wei.tsai
* [MOLY00044179] [TTY] Fixed 82LTE VT issue
* .
*
* 09 13 2013 shenghui.shi
* [MOLY00035078] [MT6290][PDN] Enable GDMA & HDMA related module PDN support
* move uart pdn_clr from dcl_tty.c to uart.c
*
* 08 26 2013 shenghui.shi
* [MOLY00035212] fix uart build modis error
* .
*
* 08 26 2013 shenghui.shi
* [MOLY00035078] [MT6290][PDN] Enable GDMA & HDMA related module PDN support
* add uart PDN feature
*
* 06 26 2013 i-wei.tsai
* [MOLY00027496] [TTYCore] Features check-in
* 1. add new TTY_CMD_MTU_SIZE support
* 2. add plug-in/plug-out indication
* 3. fix issue of flushing rx internal gpd
*
* 06 19 2013 i-wei.tsai
* [MOLY00026667] [TTYCore] Revise ttycore trace log in exception mode
*
* 05 29 2013 haoren.kao
* [MOLY00024108] Support New USB Core
* Replace with New USB Core.
* We sync with the following codes from HaoRen MOLY CBr w1322:
* 1. USB Core
* 2. USB Class - acm/rndis/mbim
* 3. ipcore
* 4. ttycore
* 5. ethercore
*
* 05 15 2013 i-wei.tsai
* [MOLY00021838] [MT6290 Bring-up] TTY DEV.
* Turn off aggressive log trace
*
* 05 10 2013 i-wei.tsai
* [MOLY00021838] [MT6290 Bring-up] TTY DEV
* sync from MT6290E1 First Call Branch
*
* 05 10 2013 i-wei.tsai
* [MOLY00021376] [MT6290 Bring-up] Basic load
* Check-in support
*
* 05 09 2013 i-wei.tsai
* [MOLY00021838] [MT6290 Bring-up] TTY DEV
* fix error for setting tx not rdy flag
*
* 05 09 2013 i-wei.tsai
* [MOLY00021838] [MT6290 Bring-up] TTY DEV
* add sending Ready2Write message when dirver attach
*
* 05 08 2013 i-wei.tsai
* [MOLY00021838] [MT6290 Bring-up] Revise ttycore trace log
* .
*
* 05 03 2013 i-wei.tsai
* [MOLY00021396] [MT6290 Bring-up] [Basic Load Support] [TTYCore] add option __MAUI_BASIC__
* basic load support
*
* 03 08 2013 i-wei.tsai
* [MOLY00011358] [TTYCore] TTYCore support
* Add CCIF UART device type and modify comments
*
* 03 01 2013 i-wei.tsai
* [MOLY00010632] add TTYCore new features
* fixed typo
*
* 02 21 2013 i-wei.tsai
* [MOLY00010632] add TTYCore new features
* checkin supporting buffer port features
*
* 11 08 2012 haoren.kao
* [MOLY00005322] TATAKA merge to MOLY
*
* MOLY Migration from TATAKA
****************************************************************************/
#include <stdio.h>
#include "dcl.h"
#include "qbm_config_num.h"
#include "qmu_bm.h"
#include "qmu_bm_util.h"
#include "kal_public_api.h"
#include "kal_general_types.h"
#include "stack_ltlcom.h"
#include "hif_ior.h"
#include "kal_internal_api.h"
#include "devdrv_ls.h"
#include "drv_msgid.h"
#include "md_drv_sap.h"
#include "drvpdn.h"
#include "drv_gdma.h"
#include <ex_public.h>
#include "kal_hrt_api.h"
#include "cccidev_qbm.h" /* macros for QBM_TYPE_CCCI_COMM */
//for reference the vp number
#include "cmux_vp_num.h"
#define TTY_CONSOLE_TRACE_ENABLED 0
#define TTY_AGGRESSIVE_TRACE 0
/*20120724 Ian Modify CCCI_COMM for TTYCore*/
// #if __HIF_CCCI_SUPPORT__
// /* using CCCI_COMM type to replace QBM_TYPE_TTY_INT/QBM_TYPE_TTY_TYPE1/QBM_TYPE_TTY_TYPE2 */
// #define TTY_QBM_DATA_LEN QBM_CCCI_COMM_DATA_LEN
// #define TTY_QBM_DATA_TYPE QBM_TYPE_CCCI_COMM
// #define TTY_QBM_DES_GET_DATAPTR CCCIDEV_GET_QBM_DATAPTR
// #define TTY_QBM_DES_GET_DATALEN CCCIDEV_GET_QBM_DATALEN
// #define TTY_QBM_DES_SET_DATALEN CCCICOMM_SET_QBM_DATALEN
// #else
// #define TTY_QBM_DATA_LEN QBM_TTY_XXX_DATA_LEN
// #define TTY_QBM_DATA_TYPE QBM_TYPE_TTY_INT
// #define TTY_QBM_DES_GET_DATAPTR QBM_DES_GET_DATAPTR
// #define TTY_QBM_DES_GET_DATALEN QBM_DES_GET_DATALEN
// #define TTY_QBM_DES_SET_DATALEN QBM_DES_SET_DATALEN
// #endif
extern void dbg_print(char *fmt,...);
#if TTY_CONSOLE_TRACE_ENABLED==1
/*
* Print indexed trace to console.
*/
#if defined(__MTK_TARGET__)
//#define tty_console_trace dbg_print
#define tty_console_trace dbg_print
#define TTY_NEW_LINE "\r\n"
#else
#define tty_console_trace dbg_print
#define TTY_NEW_LINE "\n"
#endif
/* #define tty_trace_error(...) tty_console_trace(__VA_ARGS__)*/
/* #define tty_trace_info(...) tty_console_trace(__VA_ARGS__)*/
#define BEGIN_TRACE_MAP(_mod)
#define TRC_MSG(_msg_index, _fmt) static const char _msg_index [] = _fmt TTY_NEW_LINE;
#define END_TRACE_MAP(_mod)
#else
/*
* Use DHL logging.
*/
#ifndef __MAUI_BASIC__
/* #define tty_trace_error(...) \
do{ \
if(INT_QueryExceptionStatus() == KAL_FALSE) \
{ \
dhl_trace(TRACE_ERROR, DHL_USER_FLAG_NONE, __VA_ARGS__); \
} \
}while(0)*/
/* #define tty_trace_info(...) \
do{ \
if(INT_QueryExceptionStatus() == KAL_FALSE) \
{ \
dhl_trace(TRACE_INFO, DHL_USER_FLAG_NONE, __VA_ARGS__); \
} \
}while(0)*/
/* #define tty_trace_func(...) \
do{ \
if(INT_QueryExceptionStatus() == KAL_FALSE) \
{ \
dhl_trace(TRACE_FUNC, DHL_USER_FLAG_NONE, __VA_ARGS__); \
} \
}while(0)*/
#else
/* #define tty_trace_error(...)*/
/* #define tty_trace_info(...)*/
/* #define tty_trace_func(...)*/
#endif
#endif /* TTY_CONSOLE_TRACE_ENABLED */
#ifndef __MAUI_BASIC__
#include "tty_trace.h"
#endif
/* Macros */
/* ==================================================================================================== */
#ifdef ATEST_SYS_TTYCORE
extern kal_bool ut_assert_flag;
#ifdef ASSERT
#undef ASSERT
#endif
//#define ASSERT(x) do{ if (x) ut_assert_flag = KAL_TRUE; }while(0)
void ASSERT(int x) {
if (!x) {
ut_assert_flag = KAL_TRUE;
}
}
#endif
#define VAR_MSG_ASSERT(var_msg) do{int var_msg=0; ASSERT(var_msg);} while(0)
#ifdef __TTY_DBG_MODE__
#define DBG_ASSERT(expr) ASSERT(expr)
#define TTY_CHECK_CONTEXT_ENABLED 1
#else
#define DBG_ASSERT(expr)
#define TTY_CHECK_CONTEXT_ENABLED 0
#endif
#define TTY_HWITC_ENABLE (1)
#if defined(TTY_HWITC_ENABLE)
#define TTY_SPIN_LOCK(_s) kal_hrt_take_itc_lock(KAL_ITC_TTY, KAL_INFINITE_WAIT)
#define TTY_SPIN_UNLOCK(_s) kal_hrt_give_itc_lock(KAL_ITC_TTY)
#else
#define TTY_SPIN_LOCK(_s) kal_take_spinlock(_s, KAL_INFINITE_WAIT)
#define TTY_SPIN_UNLOCK(_s) kal_give_spinlock(_s)
#endif
#define TTY_CHECK_HANDLE(handle) \
do{ \
if (handle == STATUS_INVALID_DEVICE) {return STATUS_FAIL;} \
if (!DCL_UART_IS_HANDLE_MAGIC(handle)) {if(INT_QueryExceptionStatus() == KAL_FALSE) \
MD_TRC(TTY_TR_INVALID_HANDLE,__LINE__, handle, kal_get_active_module_id());return STATUS_INVALID_DCL_HANDLE;} \
}while(0)
#define TTY_CHECK_DEV_IS_READY(dev) \
do{ \
/* Check if the driver callback is registered */ \
if (dev >= UART_DEV_CNT || dev < 0 || !tty_mgmt_info[dev].active) \
{ \
if(INT_QueryExceptionStatus() == KAL_FALSE) \
MD_TRC(TTY_TR_DEV_DRV_NOT_RDY,__LINE__, dev, kal_get_active_module_id()); \
return STATUS_DEVICE_NOT_EXIST; \
} \
}while(0)
#define TTY_CHECK_DEV_VALID(dev) \
do{ \
if (dev >= UART_DEV_CNT || dev < 0) {if(INT_QueryExceptionStatus() == KAL_FALSE) \
MD_TRC(TTY_TR_DEV_NOT_VALID,__LINE__, dev, kal_get_active_module_id());return STATUS_INVALID_DEVICE;} \
}while(0)
#if TTY_CHECK_CONTEXT_ENABLED==1
#define TTY_CHECK_RUN_IN_HISR(dev) do{if (tty_mgmt_info[dev].owner_id != MOD_DRV_DBG/*dbg_print is exception*/ && kal_if_hisr()){VAR_MSG_ASSERT(TTY_it_runs_in_hisr);}} while(0)
#define TTY_CHECK_ACTIVE_MOD(dev) \
do{ \
if (tty_mgmt_info[dev].owner_id != MOD_DRV_DBG/*dbg_print is exception*/ \
&& tty_mgmt_info[dev].owner_id != MOD_DHL \
&& tty_mgmt_info[dev].owner_id != MOD_DHL_READER \
&& tty_mgmt_info[dev].opened \
&& tty_mgmt_info[dev].owner_id != kal_get_active_module_id()) { \
VAR_MSG_ASSERT(TTY_Active_module_id_not_match); \
} \
}while(0)
#else
#define TTY_CHECK_RUN_IN_HISR(dev)
#define TTY_CHECK_ACTIVE_MOD(dev)
#endif
#define TTY_CONV_FLUSH_TX(cnt_thre) \
count = 0; \
if (TTY_IS_CONVENTIONAL_TX(device)) { \
while (1) { \
if (tty_mgmt_info[device].tx_gpd_num_used == 0) { \
break; \
} \
kal_sleep_task(KAL_TICKS_10_MSEC/2); \
if (++count > cnt_thre) { \
VAR_MSG_ASSERT(flush_tx_cmd_too_long); \
} \
} \
}
#define TTY_CONV_FLUSH_RX(cnt_thre) \
count = 0; \
if (TTY_IS_CONVENTIONAL_RX(device)) { \
while (1) { \
if (tty_mgmt_info[device].rx_gpd_num_assigned == 0) { \
break; \
} \
kal_sleep_task(KAL_TICKS_10_MSEC/2); \
if (++count > cnt_thre) { \
VAR_MSG_ASSERT(flush_rx_cmd_too_long); \
} \
} \
}
#define TTY_IS_CONVENTIONAL_TX(dev) (!(tty_mgmt_info[dev].flag & TTY_FLAG_NEW_TX))
#define TTY_IS_CONVENTIONAL_RX(dev) (!(tty_mgmt_info[dev].flag & TTY_FLAG_NEW_RX))
#define TTY_DRV_IS_ATTACHED(dev) (tty_mgmt_info[dev].drv_state == DRV_ST_ATTACHED)
#define DCL_UART_MAGIC_NUM 0x40000000
#define DCL_UART_IS_HANDLE_MAGIC(handl_) ((handl_)& DCL_UART_MAGIC_NUM)
#define DCL_UART_GET_DEV(handle_) ((DCL_DEV)((handle_) & (~DCL_UART_MAGIC_NUM)))
#define UART_DEV_CNT (uart_max_port - uart_port1 + 1) //subtract uart1, in case uart1 != 0 in future.
#define TTY_BC_TX_GPD_MAX_NUM 2 /* Tx Max GPD number for backward-compatible */
#define GPD_NUM_FOR_TTY 100
#if 0
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
#endif
#define TTY_IS_BUFF_PORT(dev) ((tty_mgmt_info[dev].drv_type == BUFF_DRV_TYPE))
#define TTY_MIN(_a, _b) (((_a) <= (_b)) ? (_a) : (_b))
#define TTY_CHK_DEV_OPEN(dev) (DCL_TRUE == tty_mgmt_info[dev].opened)
/* Structure define & Global variable */
/* ==================================================================================================== */
typedef struct _tty_port_mgmt
{
/* for buffer type driver*/
DCL_UINT32 drv_type;
kal_spinlockid spinLock; // each device has its own lock
DCL_UINT32 rx_allow_len; //Indicates downlink mtu size of HIF
qbm_gpd *rx_gpd;
DCL_UINT32 rx_gpd_num_assigned;
DCL_UINT32 tx_gpd_num_used;
/* for backward-compatible */
DCL_UART_TX_FUNC conv_tx_cb;
DCL_UART_RX_FUNC conv_rx_cb;
DCL_UINT32 dev_type; //record device type
DCL_UINT32 qbm_data_len; //supported GPD type length
DCL_UINT32 flag;
tty_drv_state_change_cb drv_state_change_cb;
DCL_UINT32 qbm_data_type; //supported GPD type
tty_rx_cb rx_cb;
tty_txdone_cb tx_done_cb;
SeriPort_HANLDER_CB sp_handler_cb;
module_type pending_owner;
DCL_UINT16 rx_buf_offset; // it indicates the buffer offset of rx_gpd (data in rx_gpd before offset has been received)
DCL_UINT16 chunk_size;
module_type owner_id;
tty_drv_state_e drv_state; // 1: driver attach; 0: driver detach
/* For legacy USBcore solution: driver attach event may be later than user traffic*/
DCL_BOOL tx_not_rdy;
DCL_BOOL opened; // opened by upper module
DCL_BOOL init_by_new_mod;
DCL_BOOL rx_up_mod_wait; //add for buffer device
DCL_BOOL tx_up_mod_wait;
DCL_BOOL flush_rx;
DCL_BOOL flush_tx;
DCL_BOOL no_indication; //User can set attribute to disable receiving ILM through SIO_SET_INDICATION
DCL_BOOL active; // registered uart handler callback by driver
/*store flag if user send SIO_CMD_OPEN or register callback before driver register CB*/
DCL_BOOL early_tx_done_cb_req;
DCL_BOOL early_open_req;
} tty_port_mgmt;
typedef enum
{
GPD_DRV_TYPE,
BUFF_DRV_TYPE,
}tty_driver_type;
typedef struct _tty_dev_info
{
SIO_TYPE_T dev_type;
DCL_UINT32 buff_type;
DCL_UINT32 buff_data_len;
tty_driver_type drv_type;
}tty_dev_info;
#define NOT_DEFINED_TYPE 0xFFFFFFFF
#define NOT_DEFINED_LENGTH 0xFFFFFFFF
static tty_dev_info tty_dev_info_tbl[DCL_UART_DEV_TYPE_MAX] = {
#if defined(MT6752) && defined(__MD2__)
{DCL_UART_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //6752 MD2 uart only support buffer mode
#else
{DCL_UART_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , GPD_DRV_TYPE},
#endif
{DCL_UART_USB_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , GPD_DRV_TYPE},
{DCL_UART_BLUETOOTH_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_SPPA_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_CMUX_TYPE, NOT_DEFINED_TYPE , NOT_DEFINED_LENGTH , BUFF_DRV_TYPE},
{DCL_UART_CCCI_TYPE, QBM_TYPE_CCCI_COMM, QBM_CCCI_COMM_DATA_LEN , GPD_DRV_TYPE},
{DCL_UART_CCIF_TYPE, NOT_DEFINED_TYPE, NOT_DEFINED_LENGTH , BUFF_DRV_TYPE},
{DCL_UART_DCC_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_LOGACC_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_LMU_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_SP_USB_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_MINI_LOG_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , BUFF_DRV_TYPE}, //not checked
{DCL_UART_MTAD_TYPE, QBM_TYPE_TTY_INT , QBM_TTY_XXX_DATA_LEN , GPD_DRV_TYPE},
};
static tty_port_mgmt tty_mgmt_info[UART_DEV_CNT];
/* Internal used API declaration */
/* ==================================================================================================== */
static DCL_STATUS _DclSerialPort_UpModuleReinit(DCL_DEV device, module_type module_id, int flag);
static DCL_STATUS _DclSerialPort_UpModuleRegisterCb(DCL_DEV device, tty_rx_cb rx_cb, tty_txdone_cb tx_done_cb, tty_drv_state_change_cb drv_state_change_cb);
/* Internal used API */
/* ==================================================================================================== */
static void DEVDRV_LS_DRAM_EX_ROCODE
TTY_QBM_DES_SET_DATALEN(void* gpd, kal_uint32 data_len)
{
void* bd = NULL;
ASSERT(NULL != gpd);
if(0 != QBM_DES_GET_BDP(gpd))
{
//4 <case> GPD->BD->BUFF
bd = QBM_DES_GET_DATAPTR(gpd);
ASSERT(NULL!=bd);
QBM_DES_SET_DATALEN(bd, data_len);
qbm_cal_set_checksum((kal_uint8 *)bd);
}
QBM_DES_SET_DATALEN(gpd, data_len);
qbm_cal_set_checksum((kal_uint8 *)gpd);
}
static DCL_UINT32 DEVDRV_LS_DRAM_EX_ROCODE
TTY_QBM_DES_GET_DATALEN(void* gpd)
{
void* bd = NULL;
DCL_UINT32 data_len = 0;
ASSERT(NULL!=gpd);
if(0 != QBM_DES_GET_BDP(gpd)){
//4 <case 1> GPD->BD->BUFF
bd = QBM_DES_GET_DATAPTR(gpd);
ASSERT(NULL!=bd);
data_len = QBM_DES_GET_DATALEN(bd);
}else{
//4 <case 2> GPD->BUFF
data_len = QBM_DES_GET_DATALEN(gpd);
}
return data_len;
}
static void* DEVDRV_LS_DRAM_EX_ROCODE
TTY_QBM_DES_GET_DATAPTR(void* gpd)
{
void* bd = NULL;
void* data_ptr = NULL;
ASSERT(NULL!=gpd);
if(0 != QBM_DES_GET_BDP(gpd)){
//4 <case 1> GPD->BD->BUFF
bd = QBM_DES_GET_DATAPTR(gpd);
ASSERT(NULL!=bd);
data_ptr = QBM_DES_GET_DATAPTR(bd);
}else{
//4 <case 2> GPD->BUFF
data_ptr = QBM_DES_GET_DATAPTR(gpd);
}
ASSERT(NULL!=data_ptr);
return data_ptr;
}
static void DEVDRV_LS_DRAM_EX_ROCODE
_tty_update_buff_info_from_port(DCL_DEV device, SIO_TYPE_T dev_type)
{
DCL_UINT8 i;
for( i = 0; i < DCL_UART_DEV_TYPE_MAX; i++)
{
if(tty_dev_info_tbl[i].dev_type == dev_type)
{
tty_mgmt_info[device].qbm_data_type = tty_dev_info_tbl[i].buff_type;
tty_mgmt_info[device].qbm_data_len = tty_dev_info_tbl[i].buff_data_len;
tty_mgmt_info[device].drv_type = tty_dev_info_tbl[i].drv_type;
return;
}
}
ASSERT(i < DCL_UART_DEV_TYPE_MAX);
return;
}
void DEVDRV_LS_DRAM_EX_ROCODE
_tty_send_ilm(
DCL_DEV device,
module_type source_id,
msg_type msg_id)
{
void *port_ptr = 0;
/*New feature: some ports may not need ilm indication*/
if(tty_mgmt_info[device].no_indication == 1)
{
return;
}
switch(msg_id)
{
case MSG_ID_UART_READY_TO_READ_IND:
{
uart_ready_to_read_ind_struct *tmp;
tmp = (uart_ready_to_read_ind_struct *)
construct_local_para(sizeof(uart_ready_to_read_ind_struct),TD_UL);
tmp->port = device;
port_ptr = tmp;
}
break;
case MSG_ID_UART_READY_TO_WRITE_IND:
{
uart_ready_to_write_ind_struct *tmp;
tmp = (uart_ready_to_write_ind_struct *)
construct_local_para(sizeof(uart_ready_to_write_ind_struct),TD_UL);
tmp->port = device;
port_ptr = tmp;
}
break;
case MSG_ID_UART_DSR_CHANGE_IND:
{
uart_dsr_change_ind_struct *tmp;
tmp = (uart_dsr_change_ind_struct *)
construct_local_para(sizeof(uart_dsr_change_ind_struct),TD_UL);
tmp->port = device;
port_ptr = tmp;
}
break;
case MSG_ID_UART_ESCAPE_DETECTED_IND:
{
uart_escape_detected_ind_struct *tmp;
tmp = (uart_escape_detected_ind_struct *)
construct_local_para(sizeof(uart_escape_detected_ind_struct),TD_UL);
tmp->port = device;
port_ptr = tmp;
}
break;
case MSG_ID_UART_PLUGOUT_IND:
{
uart_plugout_ind_struct *tmp;
tmp = (uart_plugout_ind_struct *)
construct_local_para(sizeof(uart_plugout_ind_struct),TD_RESET);
tmp->port = device;
port_ptr = tmp;
}
break;
case MSG_ID_UART_PLUGIN_IND:
{
uart_plugin_ind_struct *tmp;
tmp = (uart_plugin_ind_struct *)
construct_local_para(sizeof(uart_plugin_ind_struct),TD_RESET);
tmp->port = device;
port_ptr = tmp;
}
break;
default:
{
/* Print error log */
return;
}
}
msg_send5(source_id, // source module ID
tty_mgmt_info[device].owner_id, // destination module ID
DRIVER_PS_SAP, // sap ID
msg_id, // msg ID
port_ptr // local_para_struct *
);
}
#ifdef __TTY_DBG_MODE__
/**
* @brief Check if any gpd length is zero
* @result none
*/
static void DEVDRV_LS_DRAM_EX_ROCODE
_tty_gpd_zero_len_check(
tty_io_request_t *ior)
{
tty_io_request_t *ior_tmp = ior;
do {
void *gpd = ior_tmp->first_gpd;
while (gpd != ior_tmp->last_gpd) {
ASSERT(TTY_QBM_DES_GET_DATALEN(gpd));
gpd = QBM_DES_GET_NEXT(gpd);
}
ASSERT(TTY_QBM_DES_GET_DATALEN(gpd));
} while ((ior_tmp = ior_tmp->next_request) != NULL);
}
#endif
/**
* @brief Free all gpds of ior
* @result total number of free gpd
*/
static DCL_UINT32 DEVDRV_LS_DRAM_EX_ROCODE
_tty_free_ior(
tty_io_request_t *ior)
{
DCL_UINT32 number = 0;
if (ior) {
do {
number += qbmt_dest_q(ior->first_gpd, ior->last_gpd);
} while ((ior = ior->next_request) != NULL);
}
return number;
}
/*
_tty_rx_cb is used for backward-compatible.
In TTY Core design, only one rx ior is prepared for Rx receiving in conventional Rx mode.
If rx_gpd is callbacked and when conventional upper module send SIO_CMD_GET_BYTES command to receive data, _tty_rx_cb won't be called until the only
one rx_gpd is re-assigned to driver.
Thus rx_gpd don't need mutex protection.
*/
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_tty_rx_cb(
DCL_HANDLE handle,
module_type source_id,
tty_io_request_t *rx_ior)
{
DCL_DEV device;
void *gpd_tmp;
tty_io_request_t *ior_tmp;
device = DCL_UART_GET_DEV(handle);
if (!tty_mgmt_info[device].flush_rx) {
/* global rx gpd must be NULL when rx callback of non-flush command is called */
ASSERT(!tty_mgmt_info[device].rx_gpd);
}
/*
The rx callback is called by flush done :
<1> there is a next request of rx_ior
<2> there are 2 gpd of rx_ior
*/
if (rx_ior->next_request)
{
ASSERT(tty_mgmt_info[device].flush_rx);
ASSERT(rx_ior->first_gpd == rx_ior->last_gpd);
ASSERT(rx_ior->next_request->first_gpd == rx_ior->next_request->last_gpd);
ior_tmp = rx_ior->next_request;
rx_ior->next_request = NULL;
QBM_FREE_ONE(ior_tmp->first_gpd);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
ASSERT(tty_mgmt_info[device].rx_gpd_num_assigned >= 1);
tty_mgmt_info[device].rx_gpd_num_assigned --;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
} else if (rx_ior->first_gpd != rx_ior->last_gpd)
{
ASSERT(tty_mgmt_info[device].flush_rx);
// tj.chang, 2011/12/27: We should not promise the length of last_gpd is 0.
// ASSERT(TTY_QBM_DES_GET_DATALEN(rx_ior->last_gpd) == 0);
ASSERT(QBM_DES_GET_NEXT(rx_ior->first_gpd) == rx_ior->last_gpd);
gpd_tmp = rx_ior->last_gpd;
rx_ior->last_gpd = rx_ior->first_gpd;
QBM_FREE_ONE(gpd_tmp);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
ASSERT(tty_mgmt_info[device].rx_gpd_num_assigned >= 1);
tty_mgmt_info[device].rx_gpd_num_assigned --;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
if (!tty_mgmt_info[device].flush_rx && TTY_QBM_DES_GET_DATALEN(rx_ior->first_gpd) > 0)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_gpd = rx_ior->first_gpd;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
//change start for ALPS04065656
//handling race condition between UL data gpd and clr rx buff.
if(tty_mgmt_info[device].flush_rx) {
void *rx_gpd;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if(tty_mgmt_info[device].rx_gpd) {
rx_gpd = tty_mgmt_info[device].rx_gpd;
tty_mgmt_info[device].rx_gpd = NULL;
tty_mgmt_info[device].rx_buf_offset = 0;
tty_mgmt_info[device].rx_gpd_num_assigned--;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
QBM_FREE_ONE(rx_gpd);
} else {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
} else {
//change end for ALPS04065656
/* Inform upper layer module readyToRead */
if (tty_mgmt_info[device].conv_rx_cb) {
tty_mgmt_info[device].conv_rx_cb(device);
} else {
_tty_send_ilm(device, source_id, MSG_ID_UART_READY_TO_READ_IND);
}
}
} else
{ /* The rx callback is called by clear tx/rx buffer (flush) command */
QBM_FREE_ONE(rx_ior->first_gpd);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
ASSERT(tty_mgmt_info[device].rx_gpd_num_assigned >= 1);
tty_mgmt_info[device].rx_gpd_num_assigned --;
if (tty_mgmt_info[device].rx_gpd_num_assigned == 0) {
/* clear flush_rx flag if all rx_gpd are free */
tty_mgmt_info[device].flush_rx = 0;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
return STATUS_OK;
}
/*
_tty_rx_buff_cb is used for backward-compatible buffer mode driver.
This callback is only used for conventional user on buffer mode port.
The main task of this callback is sending ILM to tty user.
(Flush RX shall not go there.)
*/
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_tty_rx_buff_cb(
DCL_HANDLE handle,
module_type source_id,
tty_io_request_t *rx_ior)
{
DCL_DEV device;
device = DCL_UART_GET_DEV(handle);
/*Current design does not return data through callback*/
ASSERT(rx_ior == NULL);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].rx_up_mod_wait)
{
tty_mgmt_info[device].rx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].conv_rx_cb) {
tty_mgmt_info[device].conv_rx_cb(device);
} else {
_tty_send_ilm(device, source_id, MSG_ID_UART_READY_TO_READ_IND);
}
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_tty_tx_done_cb(
DCL_HANDLE handle,
module_type source_id,
tty_io_request_t *tx_ior)
{
DCL_DEV device;
DCL_UINT32 number;
device = DCL_UART_GET_DEV(handle);
if (tx_ior) {
number = _tty_free_ior(tx_ior);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
ASSERT(tty_mgmt_info[device].tx_gpd_num_used >= number);
tty_mgmt_info[device].tx_gpd_num_used -= number;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].flush_tx)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].tx_up_mod_wait)
{
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].conv_tx_cb) {
tty_mgmt_info[device].conv_tx_cb(device);
} else {
_tty_send_ilm(device, source_id, MSG_ID_UART_READY_TO_WRITE_IND);
}
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
} else {
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].tx_gpd_num_used == 0) {
/* clear flush_tx flag if all tx_gpd are free */
tty_mgmt_info[device].flush_tx = 0;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
} else {
/* print error log - tx_ior can't be null */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_TX_IOR_IS_NULL,device, source_id);
ASSERT(tx_ior);
return STATUS_FAIL;
}
return STATUS_OK;
}
/*
_tty_tx_buff_done_cb is used for backward-compatible buffer mode driver.
This callback is only used for conventional user on buffer mode port.
The main task of this callback is sending ILM to tty user.
(Flush TX shall not go there.)
*/
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_tty_tx_buff_done_cb(
DCL_HANDLE handle,
module_type source_id,
tty_io_request_t *tx_ior)
{
DCL_DEV device;
device = DCL_UART_GET_DEV(handle);
/*Current design does not return data through callback*/
ASSERT(tx_ior == NULL);
/*
* This function is invoked when lower driver finish the TX.
* check up_mod_wait to send the indication message
*/
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].tx_up_mod_wait)
{
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].conv_tx_cb) {
tty_mgmt_info[device].conv_tx_cb(device);
} else {
_tty_send_ilm(device, source_id, MSG_ID_UART_READY_TO_WRITE_IND);
}
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
return STATUS_OK;
}
void DEVDRV_LS_DRAM_EX_ROCODE
_cal_and_set_rx_allow_len(
DCL_DEV device,
DCL_UINT16 chunk_size)
{
DCL_HANDLE handle;
UART_CTRL_GET_MTU_SIZE_T ur_ctrl_get_mtu_size;
handle = DclSerialPort_Open(device, 0);
if(chunk_size == 1) //no chunk size restriction
{
DclSerialPort_Control(handle, TTY_CMD_GET_MTU_SIZE, (DCL_CTRL_DATA_T*)&ur_ctrl_get_mtu_size);
tty_mgmt_info[device].rx_allow_len = TTY_MIN(ur_ctrl_get_mtu_size.ulmtu_sz, tty_mgmt_info[device].qbm_data_len);
}
else
{
tty_mgmt_info[device].rx_allow_len = chunk_size;
}
ASSERT(tty_mgmt_info[device].rx_allow_len >= chunk_size);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_RX_ALLOW_LEN,device, tty_mgmt_info[device].rx_allow_len);
return;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_tty_conv_assign_rx_gpd_to_drv(
DCL_DEV device)
{
DCL_STATUS result;
UART_CTRL_ASSIGN_RX_IOR_T ur_ctrl_assign_rxior;
tty_io_request_t *rx_ior;
void *rx_gpd_first, *rx_gpd_last;
DCL_UINT32 remain_rx_gpd_num;
DCL_UINT32 alloc_num;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].flush_rx && tty_mgmt_info[device].rx_gpd_num_assigned < 2 /*one for tailed gpd, another for real data receiving*/)
{
remain_rx_gpd_num = 2 - tty_mgmt_info[device].rx_gpd_num_assigned;
/** Add assigned gpd first to avoid conventional assign_rx_ior race condition , one is triggered in DclSerialPort_DrvAttach, the other is SIO_CMD_OPEN post-command*/
tty_mgmt_info[device].rx_gpd_num_assigned += remain_rx_gpd_num;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
//alloc_num = qbmt_alloc_q_no_tail(TTY_QBM_DATA_TYPE, remain_rx_gpd_num, &rx_gpd_first, &rx_gpd_last);
alloc_num = qbmt_alloc_q_no_tail(tty_mgmt_info[device].qbm_data_type, remain_rx_gpd_num, &rx_gpd_first, &rx_gpd_last);
if (alloc_num != remain_rx_gpd_num)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
/** Minus assigned gpd when cannot get gpds */
tty_mgmt_info[device].rx_gpd_num_assigned -= remain_rx_gpd_num;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_GPD_EXHAUST,device, kal_get_active_module_id());
VAR_MSG_ASSERT(tty_internal_qbm_exhaust);
return STATUS_FAIL;
}
//ASSERT(TTY_QBM_DATA_LEN >= tty_mgmt_info[device].chunk_size);
ASSERT(tty_mgmt_info[device].qbm_data_len >= tty_mgmt_info[device].chunk_size);
/* First gpd */
QBM_DES_SET_HWO(rx_gpd_first);
QBM_DES_SET_ALLOW_LEN(rx_gpd_first, tty_mgmt_info[device].rx_allow_len);
qbm_cal_set_checksum(rx_gpd_first);
QBM_CACHE_FLUSH(rx_gpd_first, sizeof(qbm_gpd));
/* Last gpd */
if (alloc_num == 2) {
QBM_DES_SET_HWO(rx_gpd_last);
QBM_DES_SET_ALLOW_LEN(rx_gpd_last, tty_mgmt_info[device].rx_allow_len);
qbm_cal_set_checksum(rx_gpd_last);
QBM_CACHE_FLUSH(rx_gpd_last, sizeof(qbm_gpd));
}
rx_ior = (tty_io_request_t*)QBM_DES_GET_SW_CTRL_FIELD(rx_gpd_first);
rx_ior->first_gpd = rx_gpd_first;
rx_ior->last_gpd = rx_gpd_last;
rx_ior->next_request = NULL;
ur_ctrl_assign_rxior.u4OwnerId = tty_mgmt_info[device].owner_id;
ur_ctrl_assign_rxior.ior = rx_ior;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
_tty_free_ior(rx_ior);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_ASSIGN_RX_IOR, (DCL_CTRL_DATA_T *)&ur_ctrl_assign_rxior);
if (result != STATUS_OK) {
/* command failed */
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
/** Minus assigned gpd when driver return fail */
tty_mgmt_info[device].rx_gpd_num_assigned -= remain_rx_gpd_num;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
_tty_free_ior(rx_ior);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_ASSIGN_RX_IOR,device, result, kal_get_active_module_id());
return result;
}
} else {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_tty_conv_drv_state_change_cb(
DCL_HANDLE handle,
tty_drv_state_e state)
{
DCL_DEV device;
device = DCL_UART_GET_DEV(handle);
switch(state)
{
case DRV_ST_DETACHED:
{
_tty_send_ilm(device, MOD_TTY, MSG_ID_UART_PLUGOUT_IND);
break;
}
case DRV_ST_ATTACHED:
{
_tty_send_ilm(device, MOD_TTY, MSG_ID_UART_PLUGIN_IND);
break;
}
default:
{
ASSERT(0);
break;
}
}
return STATUS_OK;
}
/* External used API */
/* ==================================================================================================== */
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_Initialize(void)
{
#if !defined(TTY_HWITC_ENABLE)
kal_uint32 i;
kal_char tty_lock_name[50];
#endif
/* QBM number for TTY internal used must be larger than or equal to max possible gpd number for rx data path use */
/* we dont need to reserve GPD buffer for virtual port, because the driver mode of virtual port is buffer mode*/
//ASSERT(QBM_NUM_TTY_INT >= ((UART_DEV_CNT-CMUX_VP_NUM)*2/*2 buffer for Rx*/+(UART_DEV_CNT-CMUX_VP_NUM)*TTY_BC_TX_GPD_MAX_NUM/*Tx*/));
ASSERT(QBM_NUM_TTY_INT >= ((UART_DEV_CNT-CMUX_VP_NUM-CCCI_TTY_DEV_NUM)*2/*2 buffer for Rx*/));
#if defined(__HIF_CCCI_SUPPORT__)
ASSERT(QBM_NUM_CCCI_COMM >= (CCCI_TTY_DEV_NUM*2/*2 buffer for Rx*/));
#endif
/*Init tty_mgmt_info instance*/
kal_mem_set(tty_mgmt_info, 0, sizeof(tty_port_mgmt)*UART_DEV_CNT);
/* Init lock resource */
#if !defined(TTY_HWITC_ENABLE)
/* HW ITC don't need create process, but spinlock needs */
for(i = 0; i < UART_DEV_CNT; i++)
{
sprintf(tty_lock_name, "TTYSPINLOCK_%d", i);
tty_mgmt_info[i].spinLock = kal_create_spinlock(tty_lock_name);
if(tty_mgmt_info[i].spinLock == NULL) ASSERT(0);
}
#endif
return STATUS_OK;
}
DCL_HANDLE DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_Open(
DCL_DEV dev,
DCL_FLAGS flags)
{
if ((dev<uart_port1) ||(dev>uart_max_port)) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_OPEN_ERR,dev, kal_get_active_module_id());
return STATUS_INVALID_DEVICE;
}
if (uart_port_null == dev) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_OPEN_ERR,dev, kal_get_active_module_id());
return STATUS_INVALID_DEVICE;
}
return (DCL_UART_MAGIC_NUM | dev);
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_Close(
DCL_HANDLE handle)
{
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_Configure(
DCL_HANDLE handle,
DCL_CONFIGURE_T *configure)
{
return STATUS_OK;
}
/*!
* @brief If upper layer module execute DclSerialPort_UpModuleInit
* ---> New Module Init
* ---> In DclSerialPort_UpModuleInit, it will help send SIO_CMD_OPEN command
* If upper layer module execute DclSerialPort_Control with SIO_CMD_OPEN command without calling DclSerialPort_UpModuleInit
* ---> Old module init (for backward compatible)
*/
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_Control(
DCL_HANDLE handle,
DCL_CTRL_CMD cmd,
DCL_CTRL_DATA_T *data)
{
DCL_STATUS result;
DCL_DEV device;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
/*20130313:SIO_CMD_OPEN will not check device exist*/
if (cmd == SIO_CMD_OPEN)
{
TTY_CHECK_DEV_VALID(device);
/*If driver has not register yet, store the request*/
if(!tty_mgmt_info[device].active)
{
UART_CTRL_OPEN_T *ur_ctrl_open = &(data->rUARTCtrlOPEN);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].early_open_req) {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_OPEN_ALREADY_OPENED,device, kal_get_active_module_id());
return STATUS_ALREADY_OPENED;
}
tty_mgmt_info[device].early_open_req = 1;
tty_mgmt_info[device].pending_owner = (module_type) ur_ctrl_open->u4OwenrId;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_OK;
}
}
else if(cmd == SIO_CMD_CLOSE)
{
TTY_CHECK_DEV_VALID(device);
/*If driver has not register yet, store the request*/
if(!tty_mgmt_info[device].active)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].early_open_req) {
tty_mgmt_info[device].early_open_req = 0;
tty_mgmt_info[device].pending_owner = MOD_NIL;
if (tty_mgmt_info[device].early_tx_done_cb_req)
{
tty_mgmt_info[device].early_tx_done_cb_req = 0;
}
//clean info set by UpmoduleInit
if(tty_mgmt_info[device].init_by_new_mod)
{
tty_mgmt_info[device].init_by_new_mod = 0;
tty_mgmt_info[device].owner_id = MOD_NIL;
tty_mgmt_info[device].flag = 0;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DEV_IS_NOT_OPENED,device, kal_get_active_module_id());
return STATUS_NOT_OPENED;
}
return STATUS_OK;
}
}
else
{
TTY_CHECK_DEV_IS_READY(device);
}
#if TTY_AGGRESSIVE_TRACE
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_DCL_CONTROL,device, cmd, kal_get_active_module_id());
#endif
/* Pre-command Process */
switch (cmd)
{
case SIO_CMD_OPEN:
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].opened) {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_OPEN_ALREADY_OPENED,device, kal_get_active_module_id());
return STATUS_ALREADY_OPENED;
}
tty_mgmt_info[device].opened = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
break;
case SIO_CMD_GET_BYTES:
case SIO_CMD_GET_UART_BYTE:
{
UART_CTRL_GET_BYTES_T ur_ctrl_getbytes;
UART_CTRL_GET_BYTES_T *p_ur_ctrl_getbytes;
DCL_UINT16 real_data_len;
DCL_UINT8 *real_data;
void *rx_gpd;
if (!TTY_IS_CONVENTIONAL_RX(device)) {
return STATUS_INVALID_OPERATION;
}
/* If device is buffer port, bypass cmd to driver*/
if(TTY_IS_BUFF_PORT(device))
{
// TODO:add support for SIO_CMD_GET_UART_BYTE, which is blocking read.
ASSERT(cmd == SIO_CMD_GET_BYTES);
break;
}
/*
This area is for conventional RX - backward compatible
*/
if (cmd == SIO_CMD_GET_UART_BYTE) {
UART_CTRL_GET_UART_BYTE_T *p_ur_ctrl_get_uart_byte;
p_ur_ctrl_get_uart_byte = &(data->rUARTCtrlGETUARTBYTE);
ur_ctrl_getbytes.puBuffaddr = &p_ur_ctrl_get_uart_byte->uByte;
ur_ctrl_getbytes.u2Length = 1;
p_ur_ctrl_getbytes = &ur_ctrl_getbytes;
} else {
p_ur_ctrl_getbytes = &(data->rUARTCtrlGETBYTES);
}
if (TTY_DRV_IS_ATTACHED(device) && ! tty_mgmt_info[device].flush_rx) {
_tty_conv_assign_rx_gpd_to_drv(device);
} else {
p_ur_ctrl_getbytes->u2RetSize = 0;
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_WRONG_STATE,device, kal_get_active_module_id());
return STATUS_ERROR_WRONG_STATE;
}
rx_gpd = tty_mgmt_info[device].rx_gpd;
if (!rx_gpd) {
p_ur_ctrl_getbytes->u2RetSize = 0;
#if TTY_AGGRESSIVE_TRACE
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_CONV_RX_NOT_RDY,device, kal_get_active_module_id());
#endif
} else {
real_data = (DCL_UINT8*)TTY_QBM_DES_GET_DATAPTR(rx_gpd) + tty_mgmt_info[device].rx_buf_offset;
real_data_len = TTY_QBM_DES_GET_DATALEN(rx_gpd) - tty_mgmt_info[device].rx_buf_offset;
if (real_data_len > p_ur_ctrl_getbytes->u2Length) {
kal_mem_cpy(p_ur_ctrl_getbytes->puBuffaddr, real_data, p_ur_ctrl_getbytes->u2Length);
p_ur_ctrl_getbytes->u2RetSize = p_ur_ctrl_getbytes->u2Length;
tty_mgmt_info[device].rx_buf_offset += p_ur_ctrl_getbytes->u2Length;
} else {
kal_mem_cpy(p_ur_ctrl_getbytes->puBuffaddr, real_data, real_data_len);
p_ur_ctrl_getbytes->u2RetSize = real_data_len;
tty_mgmt_info[device].rx_buf_offset = 0;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_gpd = NULL;
ASSERT(tty_mgmt_info[device].rx_gpd_num_assigned >= 1);
tty_mgmt_info[device].rx_gpd_num_assigned --;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
QBM_FREE_ONE(rx_gpd);
/* Re-aasign rx gpd to driver for data receiveing */
_tty_conv_assign_rx_gpd_to_drv(device);
}
}
#if TTY_AGGRESSIVE_TRACE
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_CONV_RX,device, p_ur_ctrl_getbytes->u2RetSize);
#endif
return STATUS_OK;
}
break;
case SIO_CMD_PUT_UART_BYTE:
case SIO_CMD_PUT_UART_BYTES:
case SIO_CMD_PUT_BYTES:
case SIO_CMD_PUT_ISR_BYTES:
{
UART_CTRL_PUT_BYTES_T ur_ctrl_putbytes;
UART_CTRL_PUT_BYTES_T *p_ur_ctrl_putbytes;
DCL_UINT8 *buf_ptr;
void *tx_gpd;
hif_io_request_t *tx_ior;
UART_CTRL_PUT_BYTES_IOR_T ur_ctrl_putbytes_ior;
if (!TTY_IS_CONVENTIONAL_TX(device)) {
return STATUS_INVALID_OPERATION;
}
/* If device is buffer port, bypass cmd to driver*/
if(TTY_IS_BUFF_PORT(device))
{
// TODO:add support for SIO_CMD_PUT_UART_BYTE(S), which are blocking write.
ASSERT(cmd == SIO_CMD_PUT_BYTES);
break;
}
/*
This area is for conventional TX
*/
if (cmd == SIO_CMD_PUT_UART_BYTE) {
UART_CTRL_PUT_UART_BYTE_T *p_ur_ctrl_put_uart_byte;
p_ur_ctrl_put_uart_byte = &(data->rUARTCtrlPUTUARTBYTE);
ur_ctrl_putbytes.puBuffaddr = &p_ur_ctrl_put_uart_byte->uData;
ur_ctrl_putbytes.u2Length = 1;
p_ur_ctrl_putbytes = &ur_ctrl_putbytes;
} else if (cmd == SIO_CMD_PUT_UART_BYTES) {
UART_CTRL_PUT_UART_BYTES_T *p_ur_ctrl_put_uart_bytes;
p_ur_ctrl_put_uart_bytes = &(data->rUARTCtrlPUTUARTBYTES);
ur_ctrl_putbytes.puBuffaddr = p_ur_ctrl_put_uart_bytes->puBuffaddr;
ur_ctrl_putbytes.u2Length = p_ur_ctrl_put_uart_bytes->u2Length;
p_ur_ctrl_putbytes = &ur_ctrl_putbytes;
} else {
p_ur_ctrl_putbytes = &(data->rUARTCtrlPUTBYTES);
}
ASSERT(p_ur_ctrl_putbytes->u2Length);
if (!TTY_DRV_IS_ATTACHED(device) || tty_mgmt_info[device].flush_tx) {
p_ur_ctrl_putbytes->u2RetSize = 0;
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_WRONG_STATE,device, kal_get_active_module_id());
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_not_rdy = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_ERROR_WRONG_STATE;
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if(!TTY_CHK_DEV_OPEN(device)){
p_ur_ctrl_putbytes->u2RetSize = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_NOT_OPENED;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].tx_gpd_num_used >= TTY_BC_TX_GPD_MAX_NUM) {
/* tx ior is not yet retrieved, still in driver */
p_ur_ctrl_putbytes->u2RetSize = 0;
if (cmd != SIO_CMD_PUT_ISR_BYTES) {
tty_mgmt_info[device].tx_up_mod_wait = 1;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
#if TTY_AGGRESSIVE_TRACE
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_CONV_TX_NOT_RDY,device, tty_mgmt_info[device].tx_gpd_num_used, kal_get_active_module_id());
#endif
} else {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
//tx_gpd = QBM_ALLOC_ONE(TTY_QBM_DATA_TYPE);
tx_gpd = QBM_ALLOC_ONE(tty_mgmt_info[device].qbm_data_type);
if (tx_gpd)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_gpd_num_used ++;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tx_ior = (hif_io_request_t*)QBM_DES_GET_SW_CTRL_FIELD(tx_gpd);
tx_ior->next_request = NULL;
tx_ior->first_gpd = tx_gpd;
tx_ior->last_gpd = tx_gpd;
ur_ctrl_putbytes_ior.u4OwnerId = tty_mgmt_info[device].owner_id;
ur_ctrl_putbytes_ior.putIor = (void*)tx_ior;
buf_ptr = TTY_QBM_DES_GET_DATAPTR(tx_gpd);
//if (TTY_QBM_DATA_LEN >= p_ur_ctrl_putbytes->u2Length) {
if (tty_mgmt_info[device].qbm_data_len >= p_ur_ctrl_putbytes->u2Length) {
kal_mem_cpy(buf_ptr, p_ur_ctrl_putbytes->puBuffaddr, p_ur_ctrl_putbytes->u2Length);
p_ur_ctrl_putbytes->u2RetSize = p_ur_ctrl_putbytes->u2Length;
if (cmd != SIO_CMD_PUT_ISR_BYTES) {
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
} else {
//kal_mem_cpy(buf_ptr, p_ur_ctrl_putbytes->puBuffaddr, TTY_QBM_DATA_LEN);
//p_ur_ctrl_putbytes->u2RetSize = TTY_QBM_DATA_LEN;
kal_mem_cpy(buf_ptr, p_ur_ctrl_putbytes->puBuffaddr, tty_mgmt_info[device].qbm_data_len);
p_ur_ctrl_putbytes->u2RetSize = tty_mgmt_info[device].qbm_data_len;
if (cmd != SIO_CMD_PUT_ISR_BYTES) {
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_up_mod_wait = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
TTY_QBM_DES_SET_DATALEN(tx_gpd, p_ur_ctrl_putbytes->u2RetSize); // Set data length
//QBM_CACHE_FLUSH(buf_ptr, p_ur_ctrl_putbytes->u2RetSize); // khr debug, flush data
#if TTY_AGGRESSIVE_TRACE
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_CONV_TX,device, p_ur_ctrl_putbytes->u2RetSize);
#endif
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
tty_mgmt_info[device].tx_gpd_num_used --;
if (cmd != SIO_CMD_PUT_ISR_BYTES) {
tty_mgmt_info[device].tx_up_mod_wait = 1;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
QBM_FREE_ONE(tx_gpd);
p_ur_ctrl_putbytes->u2RetSize = 0;
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_PUT_BYTES_IOR, (DCL_CTRL_DATA_T *)&ur_ctrl_putbytes_ior);
if (result != STATUS_OK) {
/* command failed */
QBM_FREE_ONE(tx_gpd);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_gpd_num_used --;
if (cmd != SIO_CMD_PUT_ISR_BYTES) {
tty_mgmt_info[device].tx_up_mod_wait = 1;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
p_ur_ctrl_putbytes->u2RetSize = 0;
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_PUT_BYTES_IOR,device, result, kal_get_active_module_id());
return result;
}
} else {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_GPD_EXHAUST,device, kal_get_active_module_id());
//This case has error handling, so remove assert check here.
//VAR_MSG_ASSERT(tty_internal_gpd_exhaust);
p_ur_ctrl_putbytes->u2RetSize = 0;
if (cmd != SIO_CMD_PUT_ISR_BYTES) {
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_up_mod_wait = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
}
return STATUS_OK;
}
break;
case SIO_CMD_GET_RX_AVAIL:
{
UART_CTRL_RX_AVAIL_T *ur_ctrl_rx_avail;
ur_ctrl_rx_avail = &(data->rUARTCtrlRXAVAIL);
/* If device is buffer port, bypass cmd to driver*/
if(TTY_IS_BUFF_PORT(device) && TTY_IS_CONVENTIONAL_RX(device))
{
break;
}
if (TTY_IS_CONVENTIONAL_RX(device))
{
if (tty_mgmt_info[device].rx_gpd) {
ur_ctrl_rx_avail->u2RetSize = TTY_QBM_DES_GET_DATALEN(tty_mgmt_info[device].rx_gpd) - tty_mgmt_info[device].rx_buf_offset;
} else {
ur_ctrl_rx_avail->u2RetSize = 0;
}
return STATUS_OK;
} else
{
return STATUS_FAIL; // This command doesn't be suported in NEW TTY Rx path
}
}
break;
case SIO_CMD_GET_TX_AVAIL:
case SIO_CMD_GET_ISR_TX_AVAIL:
{
UART_CTRL_TX_AVAIL_T *ur_ctrl_tx_avail;
ur_ctrl_tx_avail = &(data->rUARTCtrlTXAVAIL);
/* If device is buffer port, bypass cmd to driver*/
if(TTY_IS_BUFF_PORT(device) && TTY_IS_CONVENTIONAL_TX(device))
{
break;
}
if (TTY_IS_CONVENTIONAL_TX(device))
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].tx_gpd_num_used >= TTY_BC_TX_GPD_MAX_NUM) {
/* If Tx ior is in driver, return Tx available room = 0 byte */
ur_ctrl_tx_avail->u2RetSize = 0;
} else {
/* If Tx ior is retrieved and available, return Tx available room = TTY_QBM_DATA_LEN byte */
//ur_ctrl_tx_avail->u2RetSize = TTY_QBM_DATA_LEN;
ur_ctrl_tx_avail->u2RetSize = tty_mgmt_info[device].qbm_data_len;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_OK;
} else
{
return STATUS_FAIL; // This command doesn't be suported in NEW TTY Tx path
}
}
break;
case TTY_CMD_GET_DRV_STATE:
{
UART_CTRL_GET_DRV_STATE_T *ur_ctrl_get_drv_st;
ur_ctrl_get_drv_st = &(data->rUARTCtrlGetDrvState);
ur_ctrl_get_drv_st->drv_state = tty_mgmt_info[device].drv_state;
return STATUS_OK;
}
break;
case SIO_CMD_REG_TX_CB:
{
UART_CTRL_REG_TX_CB_T *ur_ctrl_reg_tx_cb;
ur_ctrl_reg_tx_cb = &(data->rUARTCtrlREGTXCB);
if (!TTY_IS_CONVENTIONAL_TX(device)) {
return STATUS_INVALID_OPERATION;
}
tty_mgmt_info[device].conv_tx_cb = ur_ctrl_reg_tx_cb->func;
return STATUS_OK;
}
break;
case SIO_CMD_REG_RX_CB:
{
UART_CTRL_REG_RX_CB_T *ur_ctrl_reg_rx_cb;
ur_ctrl_reg_rx_cb = &(data->rUARTCtrlREGRXCB);
if (!TTY_IS_CONVENTIONAL_RX(device)) {
return STATUS_INVALID_OPERATION;
}
tty_mgmt_info[device].conv_rx_cb = ur_ctrl_reg_rx_cb->func;
return STATUS_OK;
}
break;
case SIO_CMD_SET_OWNER:
case SIO_CMD_CLOSE:
{
/* Only GPD port will reference this flag*/
if(!TTY_IS_BUFF_PORT(device))
{
tty_mgmt_info[device].flush_tx = 1;
tty_mgmt_info[device].flush_rx = 1;
}
/* Check if there is any rx buff store in tty*/
if(TTY_IS_CONVENTIONAL_RX(device))
{
void *rx_gpd;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].rx_gpd) {
rx_gpd = tty_mgmt_info[device].rx_gpd;
tty_mgmt_info[device].rx_gpd = NULL;
tty_mgmt_info[device].rx_buf_offset = 0;
tty_mgmt_info[device].rx_gpd_num_assigned--;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
QBM_FREE_ONE(rx_gpd);
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
}
break;
case SIO_CMD_CLR_TX_BUF:
{
/* CCCI driver doesn't support TX flush command
* beacause some port share the same HW queue.
*/
if(DCL_UART_CCCI_TYPE != tty_mgmt_info[device].dev_type){
/*Buffer port need to clear tx_up_mod_wait_flag*/
if(TTY_IS_BUFF_PORT(device)){
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_up_mod_wait = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
else {
/* Only GPD port will reference this flag*/
tty_mgmt_info[device].flush_tx = 1;
}
}
}
break;
case SIO_CMD_CLR_RX_BUF:
{
void *rx_gpd;
/* Only GPD port will reference this flag*/
if(!TTY_IS_BUFF_PORT(device))
{
tty_mgmt_info[device].flush_rx = 1;
}
/* Check if there is any rx buff store in tty*/
if (TTY_IS_CONVENTIONAL_RX(device))
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].rx_gpd) {
rx_gpd = tty_mgmt_info[device].rx_gpd;
tty_mgmt_info[device].rx_gpd = NULL;
tty_mgmt_info[device].rx_buf_offset = 0;
tty_mgmt_info[device].rx_gpd_num_assigned--;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
QBM_FREE_ONE(rx_gpd);
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
/*Buffer port need to clear rx_up_mod_wait_flag*/
if(TTY_IS_BUFF_PORT(device))
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_up_mod_wait = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
break;
case SIO_CMD_SEND_ISR_DATA:
case SIO_CMD_SEND_DATA:
{
VAR_MSG_ASSERT(not_support_sio_command);
}
break;
case TTY_CMD_SET_INDICATION:
{
UART_CTRL_SET_INDICATION_T *ur_ctrl_set_indication;
ur_ctrl_set_indication = &(data->rUARTCtrlSETINDICATION);
if(ur_ctrl_set_indication->need_indication == 0)
{
tty_mgmt_info[device].no_indication = 1;
}
}
break;
default:
break;
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
if (cmd == SIO_CMD_OPEN) {
tty_mgmt_info[device].opened = 0;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, cmd, data);
if (result != STATUS_OK) {
if (cmd == SIO_CMD_OPEN) {
/* open failed */
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].opened = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DCL_CMD_NG,device, cmd, result);
return result;
}
/* Post-command Process */
switch (cmd)
{
case SIO_CMD_OPEN:
{
if (!tty_mgmt_info[device].init_by_new_mod)
{ /* Conventional Module Init */
UART_CTRL_OPEN_T *ur_ctrl_open;
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CONV_INIT,device, kal_get_active_module_id());
tty_mgmt_info[device].rx_gpd = NULL;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_gpd_num_assigned = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_buf_offset = 0;
tty_mgmt_info[device].flag = 0;
tty_mgmt_info[device].no_indication = 0;
ur_ctrl_open = &(data->rUARTCtrlOPEN);
tty_mgmt_info[device].owner_id = (module_type)ur_ctrl_open->u4OwenrId;
/* buffer port shall register different callback*/
if(TTY_IS_BUFF_PORT(device))
{
_DclSerialPort_UpModuleRegisterCb(device, _tty_rx_buff_cb, _tty_tx_buff_done_cb, NULL);
}
else
{
/* 20130617: Add drv_state_change callback for supporting plug-in/plug-out indication*/
_DclSerialPort_UpModuleRegisterCb(device, _tty_rx_cb, _tty_tx_done_cb, _tty_conv_drv_state_change_cb);
}
}
/* Init rx_up_mod_wait for buffer port*/
if(TTY_IS_BUFF_PORT(device))
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_up_mod_wait = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
/* If upper module firstly send SIO_CMD_OPEN command & use conventional Rx path, tty will help send TTY_CMD_ASSIGN_RX_IOR to assign RX IOR to driver */
/* Only takes when GPD ports*/
if(!TTY_IS_BUFF_PORT(device))
{
if (TTY_IS_CONVENTIONAL_RX(device) && TTY_DRV_IS_ATTACHED(device))
{
_tty_conv_assign_rx_gpd_to_drv(device);
}
}
}
break;
case SIO_CMD_SET_OWNER:
{
UART_CTRL_OWNER_T *ur_ctrl_owner;
DCL_UINT32 count;
ur_ctrl_owner = &(data->rUARTCtrlOWNER);
/* Only GPD port needs to check if all GPDs of previous user are returned*/
if(!TTY_IS_BUFF_PORT(device))
{
TTY_CONV_FLUSH_TX(10);
TTY_CONV_FLUSH_RX(10);
}
/* Reset parameters */
tty_mgmt_info[device].flag = 0;
tty_mgmt_info[device].rx_gpd = NULL;
tty_mgmt_info[device].rx_buf_offset = 0;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].conv_tx_cb = NULL;
tty_mgmt_info[device].conv_rx_cb = NULL;
tty_mgmt_info[device].flush_tx = 0;
tty_mgmt_info[device].flush_rx = 0;
tty_mgmt_info[device].owner_id = (module_type)ur_ctrl_owner->u4OwenrId;
tty_mgmt_info[device].no_indication= 0;
if(!TTY_IS_BUFF_PORT(device))
{
/* Pre-assign Rx gpd if conventional Rx path is used */
if (TTY_DRV_IS_ATTACHED(device) && TTY_IS_CONVENTIONAL_RX(device))
{
_tty_conv_assign_rx_gpd_to_drv(device);
}
/* By default set all callback functions with tty internal handler */
_DclSerialPort_UpModuleRegisterCb(device, _tty_rx_cb, _tty_tx_done_cb, NULL);
}
else
{
/* buffer port, just register buff port callback*/
_DclSerialPort_UpModuleRegisterCb(device, _tty_rx_buff_cb, _tty_tx_buff_done_cb, NULL);
}
}
break;
case SIO_CMD_CLR_TX_BUF:
{
DCL_UINT32 count;
if(DCL_UART_CCCI_TYPE != tty_mgmt_info[device].dev_type){
/* Only GPD port needs to check if all GPDs of previous user are returned*/
if(!TTY_IS_BUFF_PORT(device)){
TTY_CONV_FLUSH_TX(10);
tty_mgmt_info[device].flush_tx = 0;
}
}
}
break;
case SIO_CMD_CLR_RX_BUF:
{
DCL_UINT32 count;
/* Only GPD port needs to check if all GPDs of previous user are returned*/
if(!TTY_IS_BUFF_PORT(device))
{
TTY_CONV_FLUSH_RX(10);
tty_mgmt_info[device].flush_rx = 0;
if (TTY_DRV_IS_ATTACHED(device) && TTY_IS_CONVENTIONAL_RX(device))
{
_tty_conv_assign_rx_gpd_to_drv(device);
}
}
}
break;
case SIO_CMD_CLOSE:
{
DCL_UINT32 count;
/* Only GPD port needs to check if all GPDs of previous user are returned*/
if(!TTY_IS_BUFF_PORT(device))
{
TTY_CONV_FLUSH_TX(10);
TTY_CONV_FLUSH_RX(10);
}
tty_mgmt_info[device].flush_tx = 0;
tty_mgmt_info[device].flush_rx = 0;
tty_mgmt_info[device].flag = 0;
tty_mgmt_info[device].init_by_new_mod = 0;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].opened = 0;
tty_mgmt_info[device].rx_gpd_num_assigned = 0;
tty_mgmt_info[device].tx_gpd_num_used = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_buf_offset = 0;
tty_mgmt_info[device].conv_tx_cb = NULL;
tty_mgmt_info[device].conv_rx_cb = NULL;
tty_mgmt_info[device].no_indication= 0;
}
break;
//case SIO_CMD_PUT_UART_BYTE: //not support in buffer port currently
//case SIO_CMD_PUT_UART_BYTES: //not support in buffer port currently
//case SIO_CMD_PUT_ISR_BYTES: //not support in buffer port currently
case SIO_CMD_PUT_BYTES:
{
UART_CTRL_PUT_BYTES_T *p_ur_ctrl_putbytes;
UART_CTRL_TX_AVAIL_T ur_ctrl_tx_avail;
//GPD port shall not go here.
ASSERT(TTY_IS_BUFF_PORT(device));
/*
Only SIO_CMD_PUT_BYTES will return length of transmitted data
*/
if(cmd == SIO_CMD_PUT_BYTES)
{
p_ur_ctrl_putbytes = &(data->rUARTCtrlPUTBYTES);
if(p_ur_ctrl_putbytes->u2Length != p_ur_ctrl_putbytes->u2RetSize)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_up_mod_wait = 1;
/*
Ready to write message may lost before setting tx_up_mod_wait as 1.
(Due to user task priority may be lower than HIF task priority)
so we need to double confirmed with HIF driver if it is really no space to write
*/
ur_ctrl_tx_avail.u2RetSize = 0;
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
sp_handler_cb(device, SIO_CMD_GET_TX_AVAIL, (DCL_CTRL_DATA_T *)&ur_ctrl_tx_avail);
if(ur_ctrl_tx_avail.u2RetSize > 0)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if( tty_mgmt_info[device].tx_up_mod_wait == 1)
{
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
_tty_send_ilm(device, MOD_TTY, MSG_ID_UART_READY_TO_WRITE_IND);
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
}
}
}
break;
case SIO_CMD_GET_BYTES:
//case SIO_CMD_GET_UART_BYTE: //not support in buffer port currently
{
UART_CTRL_GET_BYTES_T *p_ur_ctrl_getbytes;
UART_CTRL_RX_AVAIL_T ur_ctrl_rx_avail;
//GPD port shall not go here.
ASSERT(TTY_IS_BUFF_PORT(device));
if(cmd == SIO_CMD_GET_BYTES)
{
p_ur_ctrl_getbytes = &(data->rUARTCtrlGETBYTES);
//Last read
if(p_ur_ctrl_getbytes->u2Length > p_ur_ctrl_getbytes->u2RetSize)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_up_mod_wait = 1;
/*
Ready to read message may lost before setting rx_up_mod_wait as 1.
(Due to user task priority may be lower than HIF task priority)
so we need to double confirmed with HIF driver if it is really no data ready to read
*/
ur_ctrl_rx_avail.u2RetSize = 0;
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
sp_handler_cb(device, SIO_CMD_GET_RX_AVAIL, (DCL_CTRL_DATA_T *)&ur_ctrl_rx_avail);
if(ur_ctrl_rx_avail.u2RetSize > 0)
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if( tty_mgmt_info[device].rx_up_mod_wait == 1)
{
tty_mgmt_info[device].rx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
_tty_send_ilm(device, MOD_TTY, MSG_ID_UART_READY_TO_READ_IND);
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
}
}
}
break;
default:
break;
}
return result;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleInit(
DCL_HANDLE handle,
module_type module_id,
int flag)
{
DCL_STATUS status = STATUS_FAIL;
DCL_DEV device;
UART_CTRL_OPEN_T uCtlOpen;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
/*20130313:remove driver active check, because user may do initial flow before driver in active state*/
TTY_CHECK_DEV_VALID(device);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_NEW_INIT,device,module_id);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (tty_mgmt_info[device].opened || tty_mgmt_info[device].early_open_req) {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_OPEN_ALREADY_OPENED,device, module_id);
return STATUS_ALREADY_OPENED;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].owner_id = module_id;
tty_mgmt_info[device].flag = flag;
tty_mgmt_info[device].init_by_new_mod = 1;
tty_mgmt_info[device].rx_gpd = NULL;
tty_mgmt_info[device].rx_buf_offset = 0;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].rx_gpd_num_assigned = 0;
tty_mgmt_info[device].tx_gpd_num_used = 0;
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].conv_tx_cb = NULL;
tty_mgmt_info[device].conv_rx_cb = NULL;
tty_mgmt_info[device].flush_tx = 0;
tty_mgmt_info[device].flush_rx = 0;
tty_mgmt_info[device].no_indication = 0;
if (TTY_IS_CONVENTIONAL_TX(device) && TTY_IS_CONVENTIONAL_RX(device)) {
tty_mgmt_info[device].init_by_new_mod = 0;
}
/* Send SIO_CMD_OPEN command */
/* 20130313: If driver is not active, store SIO_CMD_OPEN and then return */
if(tty_mgmt_info[device].active)
{
uCtlOpen.u4OwenrId = module_id;
status = DclSerialPort_Control(handle, SIO_CMD_OPEN, (DCL_CTRL_DATA_T*)&uCtlOpen);
if (STATUS_OK != status) {
return status;
}
}
else
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].early_open_req = 1;
tty_mgmt_info[device].pending_owner = module_id;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_OK;
}
return STATUS_OK;
}
static DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_DclSerialPort_UpModuleReinit(
DCL_DEV device,
module_type module_id,
int flag)
{
DCL_STATUS result;
UART_CTRL_CLR_BUFFER_T ur_ctrl_clr_buf;
DCL_UINT32 count;
SeriPort_HANLDER_CB sp_handler_cb;
/*
* Notes: if device is buffer port, just reset the ttycore internal flag,
* because it is impossible to use gpd buffer on buffer port
*/
if(TTY_IS_BUFF_PORT(device))
{
goto _RESET_FLAG;
}
/* If primary module uses conventional Rx and new module uses new rx path, flush Rx data path */
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (TTY_IS_CONVENTIONAL_RX(device) &&
tty_mgmt_info[device].rx_gpd_num_assigned > 0 &&
(flag & TTY_FLAG_NEW_RX)
)
{
/* -- 1. Send clear rx buffer command -- */
ur_ctrl_clr_buf.u4OwenrId = tty_mgmt_info[device].owner_id;
tty_mgmt_info[device].flush_rx = 1;
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, SIO_CMD_CLR_RX_BUF, (DCL_CTRL_DATA_T*)&ur_ctrl_clr_buf);
if (result != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_CLR_RX_BUF,device, result, kal_get_active_module_id());
return result;
}
/* -- 2. Wait until all rx gpds are returned back -- */
TTY_CONV_FLUSH_RX(10);
} else {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
_RESET_FLAG:
tty_mgmt_info[device].owner_id = module_id;
tty_mgmt_info[device].flag = flag;
tty_mgmt_info[device].rx_gpd = NULL;
tty_mgmt_info[device].rx_buf_offset = 0;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].tx_gpd_num_used = 0;
tty_mgmt_info[device].tx_up_mod_wait = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].conv_tx_cb = NULL;
tty_mgmt_info[device].conv_rx_cb = NULL;
tty_mgmt_info[device].flush_tx = 0;
tty_mgmt_info[device].flush_rx = 0;
tty_mgmt_info[device].no_indication = 0;
if (TTY_IS_CONVENTIONAL_TX(device) && TTY_IS_CONVENTIONAL_RX(device)) {
tty_mgmt_info[device].init_by_new_mod = 0;
} else {
tty_mgmt_info[device].init_by_new_mod = 1;
}
return STATUS_OK;
}
/* Re-init API is invoked when New upper module change owner -> it need re-set flag and re-register related callback function */
/* This API must be called after SIO_CMD_SET_OWNER command */
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleReinit(
DCL_HANDLE handle,
module_type module_id,
int flag)
{
DCL_DEV device;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
TTY_CHECK_DEV_IS_READY(device);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_REINIT,device, module_id);
if (!tty_mgmt_info[device].opened) {
return STATUS_NOT_OPENED;
}
return _DclSerialPort_UpModuleReinit(device, module_id, flag);
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleDeinit(
DCL_HANDLE handle)
{
DCL_STATUS status = STATUS_FAIL;
DCL_DEV device;
UART_CTRL_CLOSE_T data;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
/*20130313:remove driver active check, because user may do initial flow before driver in active state*/
TTY_CHECK_DEV_VALID(device);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DEINIT,device, kal_get_active_module_id());
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].opened && !tty_mgmt_info[device].early_open_req) {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DEV_IS_NOT_OPENED,device, kal_get_active_module_id());
return STATUS_NOT_OPENED;
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
/* Send SIO_CMD_CLOSE command */
data.u4OwenrId = tty_mgmt_info[device].owner_id;
status = DclSerialPort_Control(handle, SIO_CMD_CLOSE, (DCL_CTRL_DATA_T*)&data);
return status;
}
static DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
_DclSerialPort_UpModuleRegisterCb(
DCL_DEV device,
tty_rx_cb rx_cb,
tty_txdone_cb tx_done_cb,
tty_drv_state_change_cb drv_state_change_cb)
{
DCL_STATUS result;
SeriPort_HANLDER_CB sp_handler_cb;
tty_mgmt_info[device].rx_cb = rx_cb;
tty_mgmt_info[device].tx_done_cb = tx_done_cb;
tty_mgmt_info[device].drv_state_change_cb = drv_state_change_cb;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if(!tty_mgmt_info[device].active && tx_done_cb)
{
tty_mgmt_info[device].early_tx_done_cb_req = 1;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_OK;
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
/* Send TTY_CMD_TX_INFO command */
if (tx_done_cb)
{
UART_CTRL_NEED_TX_DONE_CB_T ur_ctrl_need_tx_done_cb;
ur_ctrl_need_tx_done_cb.u4OwnerId = tty_mgmt_info[device].owner_id;
ur_ctrl_need_tx_done_cb.needTxDoneCb = 1;
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_NEED_TX_DONE_CB, (DCL_CTRL_DATA_T*)&ur_ctrl_need_tx_done_cb);
if (result != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_NEED_TX_DONE_CB,device, result, kal_get_active_module_id());
return result;
}
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleRegisterCb(
DCL_HANDLE handle,
tty_rx_cb rx_cb,
tty_txdone_cb tx_done_cb,
tty_drv_state_change_cb drv_state_change_cb)
{
DCL_DEV device;
DCL_STATUS result;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
/*20130313:remove driver active check, because user may do initial flow before driver in active state*/
TTY_CHECK_DEV_VALID(device);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_REG_CB,device, kal_get_active_module_id());
/* Check flag & callback correctness */
if (!TTY_IS_CONVENTIONAL_RX(device) && !rx_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_NEW_RX_CB_IS_NULL,device, kal_get_active_module_id());
VAR_MSG_ASSERT(use_new_rx_but_not_register_cb);
}
if (TTY_IS_CONVENTIONAL_RX(device)) {
ASSERT(!rx_cb);
/* Buffer port use different internal callback*/
if(TTY_IS_BUFF_PORT(device))
{
rx_cb = _tty_rx_buff_cb;
}
else
{
rx_cb = _tty_rx_cb;
}
}
if (TTY_IS_CONVENTIONAL_TX(device)) {
ASSERT(!tx_done_cb);
/* Buffer port use different internal callback*/
if(TTY_IS_BUFF_PORT(device))
{
tx_done_cb = _tty_tx_buff_done_cb;
}
else
{
tx_done_cb = _tty_tx_done_cb;
}
}
if (TTY_IS_CONVENTIONAL_RX(device) && TTY_IS_CONVENTIONAL_TX(device)) {
ASSERT(!drv_state_change_cb);
} else {
ASSERT(drv_state_change_cb);
}
result = _DclSerialPort_UpModuleRegisterCb(device, rx_cb, tx_done_cb, drv_state_change_cb);
if (result != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_REG_CB_FAIL,device, result, kal_get_active_module_id());
return result;
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleTransmit(
DCL_HANDLE handle,
tty_io_request_t *ior)
{
DCL_DEV device;
UART_CTRL_PUT_BYTES_IOR_T ur_ctrl_putbytes_ior;
DCL_STATUS result;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
DBG_ASSERT(ior);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
if (!TTY_CHK_DEV_OPEN(device)){
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_NOT_OPENED;
}
ur_ctrl_putbytes_ior.u4OwnerId = tty_mgmt_info[device].owner_id;
ur_ctrl_putbytes_ior.putIor = (void*)ior;
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_PUT_BYTES_IOR, (DCL_CTRL_DATA_T*)&ur_ctrl_putbytes_ior);
#ifdef __TTY_DBG_MODE__
_tty_gpd_zero_len_check(ior);
#endif
return result;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleTransmitLight(
DCL_HANDLE handle,
tty_io_request_t *ior)
{
DCL_DEV device;
UART_CTRL_PUT_BYTES_IOR_T ur_ctrl_putbytes_ior;
DCL_STATUS result;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
DBG_ASSERT(ior);
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
ur_ctrl_putbytes_ior.u4OwnerId = tty_mgmt_info[device].owner_id;
ur_ctrl_putbytes_ior.putIor = (void*)ior;
#ifdef __TTY_DBG_MODE__
_tty_gpd_zero_len_check(ior);
#endif
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_PUT_BYTES_IOR_LIGHT, (DCL_CTRL_DATA_T*)&ur_ctrl_putbytes_ior);
return result;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_UpModuleAssignRxIor(
DCL_HANDLE handle,
tty_io_request_t *rx_ior)
{
DCL_DEV device;
UART_CTRL_ASSIGN_RX_IOR_T uartCtlAsnRxIor;
DCL_STATUS result;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
DBG_ASSERT(rx_ior);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ASSIGN_RX_IOR,device, kal_get_active_module_id());
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
uartCtlAsnRxIor.u4OwnerId = tty_mgmt_info[device].owner_id;
uartCtlAsnRxIor.ior = (void*)rx_ior;
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_ASSIGN_RX_IOR, (DCL_CTRL_DATA_T*)&uartCtlAsnRxIor);
return result;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_DrvRegisterCb(
DCL_HANDLE handle,
Seriport_HANDLER_T* seriport_handler)
{
DCL_DEV device;
UART_CTRL_OPEN_T uCtlOpen;
UART_CTRL_NEED_TX_DONE_CB_T ur_ctrl_need_tx_done_cb;
DCL_STATUS status;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_REGISTER_CB,device, seriport_handler, kal_get_active_module_id());
if (!seriport_handler->SeriportHandlerCb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
ASSERT(seriport_handler->SeriportHandlerCb);
return STATUS_INVALID_ARGUMENT;
}
if (tty_mgmt_info[device].active) {
return STATUS_ALREADY_OPENED;
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].sp_handler_cb = seriport_handler->SeriportHandlerCb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
tty_mgmt_info[device].dev_type = seriport_handler->DevType;
_tty_update_buff_info_from_port(device, seriport_handler->DevType);
//Must to put at the end of function.
tty_mgmt_info[device].active = 1;
//------------------------------------------------------------------//
//check if user has opened the port before driver register callback //
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if(tty_mgmt_info[device].early_open_req)
{
tty_mgmt_info[device].early_open_req = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
uCtlOpen.u4OwenrId = tty_mgmt_info[device].pending_owner;
//temp for uart
//DclSerialPort_Control(handle,SIO_CMD_INIT,(DCL_CTRL_DATA_T*)&uCtlOpen);
status = DclSerialPort_Control(handle, SIO_CMD_OPEN, (DCL_CTRL_DATA_T*)&uCtlOpen);
if (STATUS_OK != status) {
//ASSERT(0);
return status;
}
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if(tty_mgmt_info[device].early_tx_done_cb_req)
{
tty_mgmt_info[device].early_tx_done_cb_req = 0;
ur_ctrl_need_tx_done_cb.u4OwnerId = tty_mgmt_info[device].owner_id;
ur_ctrl_need_tx_done_cb.needTxDoneCb = 1;
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
status = sp_handler_cb(device, TTY_CMD_NEED_TX_DONE_CB, (DCL_CTRL_DATA_T*)&ur_ctrl_need_tx_done_cb);
if (status != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_NEED_TX_DONE_CB,device, status, kal_get_active_module_id());
return status;
}
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_DrvDeRegisterCb(
DCL_HANDLE handle)
{
DCL_DEV device;
//TTY_THREAD_DECLARE(thread_lock);
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_DEREGISTER_CB,device, kal_get_active_module_id());
if(tty_mgmt_info[device].drv_state == DRV_ST_ATTACHED)
{
return STATUS_INVALID_OPERATION;
}
if (!tty_mgmt_info[device].active) {
return STATUS_INVALID_OPERATION;
}
/*Enlarge spinlock in order to protect the handler pointer */
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
/* Clear flags */
tty_mgmt_info[device].active = 0;
tty_mgmt_info[device].sp_handler_cb = NULL;
/***** Add for USB CV test *****/
/* Check device state */
/* Here we slient clear opened flag if the device is opened
After driver registered the device, tty will re-open the device
*/
if(tty_mgmt_info[device].opened)
{
tty_mgmt_info[device].opened = 0;
tty_mgmt_info[device].early_open_req = 1;
tty_mgmt_info[device].pending_owner = tty_mgmt_info[device].owner_id;
if(tty_mgmt_info[device].tx_done_cb)
{
tty_mgmt_info[device].early_tx_done_cb_req = 1;
}
}
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
/***** Add for USB CV test *****/
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_DrvAttach(
DCL_HANDLE handle)
{
DCL_DEV device;
DCL_STATUS result;
UART_CTRL_GET_CHUNK_SIZE_T ur_ctrl_get_chunk_size;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
TTY_CHECK_DEV_IS_READY(device);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_ATTACH,device, kal_get_active_module_id());
tty_mgmt_info[device].drv_state = DRV_ST_ATTACHED;
if(TTY_IS_BUFF_PORT(device))
{
/* Set default value align with USB, although buffer port does not reference this value*/
tty_mgmt_info[device].chunk_size = 512;
goto _RETURN;
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, TTY_CMD_GET_CHUNK_SIZE, (DCL_CTRL_DATA_T*)&ur_ctrl_get_chunk_size);
if (result != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_GET_CHUNK_SIZE,device, result, kal_get_active_module_id());
ASSERT(0);
return result;
}
tty_mgmt_info[device].chunk_size = (DCL_UINT16)ur_ctrl_get_chunk_size.chunkSize;
//set rx allow len
_cal_and_set_rx_allow_len(device, tty_mgmt_info[device].chunk_size);
if (tty_mgmt_info[device].opened)
{
/* Notify upper layer the driver status is attached */
if (tty_mgmt_info[device].drv_state_change_cb) {
tty_mgmt_info[device].drv_state_change_cb(handle, DRV_ST_ATTACHED);
}
if (TTY_IS_CONVENTIONAL_RX(device)) {
_tty_conv_assign_rx_gpd_to_drv(device);
}
if (TTY_IS_CONVENTIONAL_TX(device))
{
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if(tty_mgmt_info[device].tx_not_rdy == 1)
{
tty_mgmt_info[device].tx_not_rdy = 0;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
_tty_send_ilm(device, MOD_TTY, MSG_ID_UART_READY_TO_WRITE_IND);
}
else
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
}
_RETURN:
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_DrvDetach(
DCL_HANDLE handle)
{
DCL_DEV device;
DCL_STATUS result;
UART_CTRL_CLR_BUFFER_T ur_ctrl_clr_buf;
SeriPort_HANLDER_CB sp_handler_cb;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
TTY_CHECK_DEV_IS_READY(device);
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_DETACH,device, kal_get_active_module_id());
tty_mgmt_info[device].drv_state = DRV_ST_DETACHED;
/* Notify upper layer the driver status is detached */
if (tty_mgmt_info[device].opened)
{
if (tty_mgmt_info[device].drv_state_change_cb) {
tty_mgmt_info[device].drv_state_change_cb(handle, DRV_ST_DETACHED);
}
/* Send clear tx/rx buffer command */
ur_ctrl_clr_buf.u4OwenrId = tty_mgmt_info[device].owner_id;
/* Buffer port also needs to do flush when detached */
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if ((tty_mgmt_info[device].tx_gpd_num_used != 0 && TTY_IS_CONVENTIONAL_TX(device))
|| TTY_IS_BUFF_PORT(device) )
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
/* Only GPD driver needs to toggle this flag*/
if(!TTY_IS_BUFF_PORT(device))
{
tty_mgmt_info[device].flush_tx = 1;
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, SIO_CMD_CLR_TX_BUF, (DCL_CTRL_DATA_T*)&ur_ctrl_clr_buf);
if (result != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_CLR_TX_BUF,device, result, kal_get_active_module_id());
return result;
}
} else {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
/* Buffer port also needs to do flush when detached */
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if ((tty_mgmt_info[device].rx_gpd_num_assigned != 0 && TTY_IS_CONVENTIONAL_RX(device))
|| TTY_IS_BUFF_PORT(device) )
{
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
/* Only GPD driver needs to toggle this flag*/
if(!TTY_IS_BUFF_PORT(device))
{
tty_mgmt_info[device].flush_rx = 1;
}
TTY_SPIN_LOCK(tty_mgmt_info[device].spinLock);
if (!tty_mgmt_info[device].sp_handler_cb) {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_CB_IS_NULL,device, kal_get_active_module_id());
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
return STATUS_FAIL;
}
sp_handler_cb = tty_mgmt_info[device].sp_handler_cb;
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
result = sp_handler_cb(device, SIO_CMD_CLR_RX_BUF, (DCL_CTRL_DATA_T*)&ur_ctrl_clr_buf);
if (result != STATUS_OK) {
/* command failed */
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_CMD_ERR_CLR_RX_BUF,device, result, kal_get_active_module_id());
return result;
}
} else {
TTY_SPIN_UNLOCK(tty_mgmt_info[device].spinLock);
}
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_DrvRx(
DCL_HANDLE handle,
module_type source_id,
void *rx_ior)
{
DCL_DEV device;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
if (tty_mgmt_info[device].opened && tty_mgmt_info[device].rx_cb) {
tty_mgmt_info[device].rx_cb(handle, source_id, (tty_io_request_t*)rx_ior);
} else {
if(INT_QueryExceptionStatus() == KAL_FALSE)
MD_TRC(TTY_TR_DRV_RX_NG,device, tty_mgmt_info[device].opened, tty_mgmt_info[device].rx_cb);
/* Free ior when the device is closed */
if(!TTY_IS_BUFF_PORT(device))
{
_tty_free_ior(rx_ior);
}
}
return STATUS_OK;
}
DCL_STATUS DEVDRV_LS_DRAM_EX_ROCODE
DclSerialPort_DrvTxDone(
DCL_HANDLE handle,
module_type source_id,
void *tx_ior)
{
DCL_DEV device;
TTY_CHECK_HANDLE(handle);
device = DCL_UART_GET_DEV(handle);
if (tty_mgmt_info[device].opened && tty_mgmt_info[device].tx_done_cb) {
tty_mgmt_info[device].tx_done_cb(handle, source_id, (tty_io_request_t*)tx_ior);
} else {
/* Free ior when the device is closed */
if(!TTY_IS_BUFF_PORT(device))
{
_tty_free_ior(tx_ior);
}
}
return STATUS_OK;
}