/* stp_uart_tty_receive() * * Called by tty low level driver when receive data is * available. * * Arguments: tty pointer to tty isntance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes * * Return Value: None */ static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { unsigned int written; //UART_LOUD_FUNC("URX:%d\n", count); if (unlikely(count > 2000)) { UART_WARN_FUNC("abnormal: buffer count = %d\n", count); } if (unlikely(!g_stp_uart_rx_fifo || !g_stp_uart_rx_work || !g_stp_uart_rx_wq)) { UART_ERR_FUNC("abnormal g_stp_uart_rx_fifo(0x%p),g_stp_uart_rx_work(0x%p),g_stp_uart_rx_wq(0x%p)\n", g_stp_uart_rx_fifo, g_stp_uart_rx_work, g_stp_uart_rx_wq); return; } /* need to check available buffer size? skip! */ /* need to lock fifo? skip for single writer single reader! */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) written = kfifo_put(g_stp_uart_rx_fifo, (unsigned char *) data, count); #else written = kfifo_in(g_stp_uart_rx_fifo, (unsigned char *) data, count); #endif //printk("uart_rx:%d,wr:%d\n\r",count,written); queue_work(g_stp_uart_rx_wq, g_stp_uart_rx_work); if (unlikely(written != count)) { UART_ERR_FUNC("c(%d),w(%d) bytes dropped\n", count, written); } return; }
/* stp_uart_tty_receive() * * Called by tty low level driver when receive data is * available. * * Arguments: tty pointer to tty isntance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes * * Return Value: None */ static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { //UART_INFO_FUNC("count = %d\n", count); if (count > 2000){ /*this is abnormal*/ UART_WARN_FUNC("count = %d\n", count); } #if 0 { struct timeval now; do_gettimeofday(&now); printk("[+STP][ ][R] %4d --> sec = %d, --> usec --> %d\n", count, now.tv_sec, now.tv_usec); } #endif /*There are multi-context to access here? Need to spinlock?*/ /*Only one context: flush_to_ldisc in tty_buffer.c*/ mtk_wcn_stp_parser_data((UINT8 *)data, (UINT32)count); /* George Test: useless? */ /*tty_unthrottle(tty);*/ #if 0 { struct timeval now; do_gettimeofday(&now); printk("[-STP][ ][R] %4d --> sec = %d, --> usec --> %d\n", count, now.tv_sec, now.tv_usec); } #endif return; }
/* stp_uart_tty_open * * Arguments: * tty pointer to tty info structure * data pointer to data buffer to be written * size data buffer length to be written * Return Value: * > 0 if success, otherwise error code */ static int stp_uart_tty_tx_write ( struct tty_struct *tty, const UINT8 *data, const UINT32 size ) { int ret; int len; int written; int written_count; int room; unsigned old_wr; unsigned old_rd; //unsigned long flags; UART_LOUD_FUNC("++\n"); /* Phase-I: put data into STP-UART ring buffer "tx_buf" */ /* wr_idx : the position next to write * rd_idx : the position next to read */ //down(&buf_mtx); /* [PatchNeed] spin_lock_irqsave is redundant */ //spin_lock_irqsave(&buf_lock, flags); old_wr = wr_idx; old_rd = rd_idx; /* check left room size */ room = (wr_idx >= rd_idx) ? (STP_UART_TX_BUF_SIZE - (wr_idx - rd_idx) - 1) : (rd_idx - wr_idx - 1); UART_DBG_FUNC("before data in:r(%d)s(%d)wr_i(%d)rd_i(%d)\n", room, size, wr_idx, rd_idx); if (unlikely(size > room)) { UART_ERR_FUNC("buf unavailable FAIL#1,size(%d),wr_idx(%d),rd_idx(%d),room(%d),pid[%d/%s]\n", size, wr_idx, rd_idx, room, current->pid, current->comm); //up(&buf_mtx); /* [PatchNeed] spin_lock_irqsave is redundant */ //spin_unlock_irqrestore(&buf_lock, flags); return -1; } else { len = min(size, STP_UART_TX_BUF_SIZE - (unsigned int)wr_idx); memcpy(&tx_buf[wr_idx], &data[0], len); memcpy(&tx_buf[0], &data[len], size - len); wr_idx = (wr_idx + size) % STP_UART_TX_BUF_SIZE; UART_DBG_FUNC("after data in: r(%d)s(%d)wr_i(%d)rd_i(%d)\n", room, size, wr_idx, rd_idx); } //up(&buf_mtx); /* [PatchNeed] spin_lock_irqsave is redundant */ //spin_unlock_irqrestore(&buf_lock, flags); /* Phase-II: get data from the buffer and send to tty UART. * May be seperated into another context. */ //down(&buf_mtx); /* [PatchNeed] spin_lock_irqsave is redundant */ //spin_lock_irqsave(&buf_lock, flags); written_count = 0; len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (STP_UART_TX_BUF_SIZE - rd_idx); if (likely(len > 0 && len < MAX_PACKET_ALLOWED)) { /* TTY_DO_WRITE_WAKEUP is used for "Call write_wakeup after queuing new" * but stp_uart_tty_wakeup() is empty and unused now! */ //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); /* * ops->write is called by the kernel to write a series of * characters to the tty device. The characters may come from * user space or kernel space. This routine will return the * number of characters actually accepted for writing. */ written = tty->ops->write(tty, &tx_buf[rd_idx], len); if (written != len) { UART_ERR_FUNC("tty-ops->write FAIL#2,len(%d)wr(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", len, written, wr_idx, rd_idx, current->pid, current->comm); ret = -2; goto tx_write_out_unlock_old; } written_count = written; rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE); // all data is accepted by UART driver, check again in case roll over len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (STP_UART_TX_BUF_SIZE - rd_idx); if (len > 0 && len < MAX_PACKET_ALLOWED) { /* TTY_DO_WRITE_WAKEUP is used for "Call write_wakeup after queuing new" * but stp_uart_tty_wakeup() is empty and unused now! */ //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); written = tty->ops->write(tty, &tx_buf[rd_idx], len); if (unlikely(written != len)) { UART_ERR_FUNC("tty-ops->write FAIL#3,len(%d)wr(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", len, written, wr_idx, rd_idx, current->pid, current->comm); ret = -3; goto tx_write_out_unlock_old; } rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE); written_count += written; } else if (unlikely(len < 0 || len >= MAX_PACKET_ALLOWED)) { UART_ERR_FUNC("FAIL#4,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", len, wr_idx, rd_idx, current->pid, current->comm); ret = -4; goto tx_write_out_unlock_old; } } else { UART_ERR_FUNC("FAIL#5,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", len, wr_idx, rd_idx, current->pid, current->comm); ret = -5; goto tx_write_out_unlock_old; } /* success case */ ret = written_count; tx_write_out_unlock_old: if (unlikely(ret < 0)) { //reset read and write index of tx_buffer, is there any risk? wr_idx = rd_idx = 0; UART_ERR_FUNC("err(%d)reset fifo idx\n", ret); } if (unlikely(wr_idx != rd_idx)) { UART_WARN_FUNC("--wr(%d)rd(%d)size(%d)old wr(%d)rd(%d)\n", wr_idx, rd_idx, size, old_wr, old_rd); } else { UART_LOUD_FUNC("--wr(%d) rd(%d)\n", wr_idx, rd_idx); } //up(&buf_mtx); //spin_unlock_irqrestore(&buf_lock, flags); return ret; }
static INT32 mtk_wcn_uart_tx ( const UINT8 *data, const UINT32 size, UINT32 *written_size ) { INT32 ret; int tx_len; if (unlikely(0 == size)) { /* special case for STP-CORE, return ASAP. */ if (likely(written_size)) { *written_size = 0; } return 0; } UART_LOUD_FUNC("++\n"); /* input sanity checks */ if (unlikely(stp_tty == NULL)) { UART_ERR_FUNC("NULL stp_tty,pid[%d/%s]\n", current->pid, current->comm); ret = -1; goto uart_tx_out; } if (unlikely((data == NULL) || (written_size == NULL))) { UART_ERR_FUNC("NULL data(0x%p) or written(0x%p),pid[%d/%s]\n", data, written_size, current->pid, current->comm); ret = -2; goto uart_tx_out; } *written_size = 0; /* Do size checking. Only 1~MAX_PACKET_ALLOWED-1 is allowed */ if (unlikely(MAX_PACKET_ALLOWED <= size)) { UART_ERR_FUNC("abnormal size(%d),skip tx,pid[%d/%s]\n", size, current->pid, current->comm); dump_stack(); ret = -3; goto uart_tx_out; } #if 0 /* drop data test */ if ((tx_count > 1000) && (tx_count % 5)== 0) { UART_INFO_FUNC("i=(%d), ****** drop data from uart******\n", i); ++tx_count; return 0; } #endif tx_len = stp_uart_tty_tx_write(stp_tty, data, size); if (unlikely(tx_len < 0)) { UART_WARN_FUNC("stp_uart_tty_tx_write err(%d)\n", tx_len); *written_size = 0; ret = -4; } else { *written_size = tx_len; ret = 0; } uart_tx_out: UART_LOUD_FUNC("--(%d, %d)\n", ret, *written_size); return ret; }