static void stp_uart_rx_handling(unsigned long func_data){ unsigned int how_much_get = 0; unsigned int how_much_to_get = 0; unsigned int flag = 0; // read_lock(&g_stp_uart_rx_handling_lock); how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); if (how_much_to_get >= RX_BUFFER_LEN) { flag = 1; UART_INFO_FUNC ("fifolen(%d)\n", how_much_to_get); } do{ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) how_much_get= kfifo_get(g_stp_uart_rx_fifo, g_rx_data, RX_BUFFER_LEN); #else how_much_get= kfifo_out(g_stp_uart_rx_fifo, g_rx_data, RX_BUFFER_LEN); #endif //UART_INFO_FUNC ("fifoget(%d)\n", how_much_get); mtk_wcn_stp_parser_data((UINT8 *)g_rx_data, how_much_get); how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); }while(how_much_to_get > 0); // read_unlock(&g_stp_uart_rx_handling_lock); if (1 == flag) { UART_INFO_FUNC ("finish, fifolen(%d)\n", kfifo_len(g_stp_uart_rx_fifo)); } }
static void stp_uart_rx_handling(unsigned long func_data){ #define LOCAL_BUFFER_LEN 1024 unsigned char data[LOCAL_BUFFER_LEN]; unsigned int how_much_get = 0; unsigned int how_much_to_get = 0; unsigned int flag = 0; #if LDISC_RX_TASKLET_RWLOCK read_lock(&g_stp_uart_rx_handling_lock); #endif how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); if (how_much_to_get >= LOCAL_BUFFER_LEN) { flag = 1; UART_INFO_FUNC ("fifolen(%d)\n", how_much_to_get); } do { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) how_much_get= kfifo_get(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN); #else how_much_get= kfifo_out(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN); #endif UART_INFO_FUNC ("fifoget(%d)\n", how_much_get); mtk_wcn_stp_parser_data((UINT8 *)data, how_much_get); how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); }while(how_much_to_get > 0); #if LDISC_RX_TASKLET_RWLOCK read_unlock(&g_stp_uart_rx_handling_lock); #endif if (1 == flag) { UART_INFO_FUNC ("finish, fifolen(%d)\n", kfifo_len(g_stp_uart_rx_fifo)); } }
static int __init mtk_wcn_stp_uart_init(void) { static struct tty_ldisc_ops stp_uart_ldisc; int err; UART_INFO_FUNC("mtk_wcn_stp_uart_init(): MTK STP UART driver\n"); #ifdef LDISC_RX_TASKLET err = stp_uart_fifo_init(); if (err != 0) { return err; } /*init rx tasklet*/ tasklet_init(&g_stp_uart_rx_fifo_tasklet, stp_uart_rx_handling, (unsigned long) 0); #endif /* Register the tty discipline */ memset(&stp_uart_ldisc, 0, sizeof (stp_uart_ldisc)); stp_uart_ldisc.magic = TTY_LDISC_MAGIC; stp_uart_ldisc.name = "n_mtkstp"; stp_uart_ldisc.open = stp_uart_tty_open; stp_uart_ldisc.close = stp_uart_tty_close; stp_uart_ldisc.read = stp_uart_tty_read; stp_uart_ldisc.write = stp_uart_tty_write; stp_uart_ldisc.ioctl = stp_uart_tty_ioctl; stp_uart_ldisc.poll = stp_uart_tty_poll; stp_uart_ldisc.receive_buf = stp_uart_tty_receive; stp_uart_ldisc.write_wakeup = stp_uart_tty_wakeup; stp_uart_ldisc.owner = THIS_MODULE; if ((err = tty_register_ldisc(N_MTKSTP, &stp_uart_ldisc))) { UART_ERR_FUNC("MTK STP line discipline registration failed. (%d)\n", err); return err; } /* mtk_wcn_stp_register_if_tx( mtk_wcn_uart_tx); */ return 0; }
/* stp_uart_tty_ioctl() * * Process IOCTL system call for the tty device. * * Arguments: * * tty pointer to tty instance data * file pointer to open file object for device * cmd IOCTL command code * arg argument for IOCTL call (cmd dependent) * * Return Value: Command dependent */ static int stp_uart_tty_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { int err = 0; UART_LOUD_FUNC("++ ll(%d)\n", tty->low_latency); switch (cmd) { case HCIUARTSETPROTO: #if LDISC_LOW_LATENCY UART_INFO_FUNC("set low_latency to 1\n"); tty->low_latency = 1; #endif break; default: UART_LOUD_FUNC("redirect to n_tty_ioctl_helper\n"); err = n_tty_ioctl_helper(tty, file, cmd, arg); UART_LOUD_FUNC("n_tty_ioctl_helper result(0x%x %d)\n", cmd, err); break; }; UART_LOUD_FUNC("--\n"); return err; }
static inline int stp_uart_tx_wakeup(struct tty_struct *tty) { int len = 0; int written = 0; int written_count = 0; static int i = 0; //unsigned long flags; // get data from ring buffer // down(&buf_mtx); UART_DBG_FUNC("++\n"); //// spin_lock_irqsave(&buf_lock, flags); #if 0 if((i > 1000) && (i % 5)== 0) { UART_INFO_FUNC("i=(%d), ****** drop data from uart******\n", i); i++; return 0; } else { UART_INFO_FUNC("i=(%d)at stp uart **\n", i); } #endif len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (MTKSTP_BUFFER_SIZE - rd_idx); if(len > 0 && len < MAX_PACKET_ALLOWED) { i++; /* * 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. */ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); written = tty->ops->write(tty, &tx_buf[rd_idx], len); if(written != len) { UART_ERR_FUNC("Error(i-%d):[pid(%d)(%s)]tty-ops->write FAIL!len(%d)wr(%d)wr_i(%d)rd_i(%d)\n\r", i, current->pid, current->comm, len, written, wr_idx, rd_idx); return -1; } written_count = written; //printk("len = %d, written = %d\n", len, written); rd_idx = ((rd_idx + written) % MTKSTP_BUFFER_SIZE); // all data is accepted by UART driver, check again in case roll over len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (MTKSTP_BUFFER_SIZE - rd_idx); if(len > 0 && len < MAX_PACKET_ALLOWED) { set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); written = tty->ops->write(tty, &tx_buf[rd_idx], len); if (written != len) { UART_ERR_FUNC("Error(i-%d):[pid(%d)(%s)]len(%d)wr(%d)wr_i(%d)rd_i(%d)\n\r", i, current->pid, current->comm, len, written, wr_idx, rd_idx); return -1; } rd_idx = ((rd_idx + written) % MTKSTP_BUFFER_SIZE); written_count += written; } else if(len < 0 || len >= MAX_PACKET_ALLOWED) { UART_ERR_FUNC("Warnning(i-%d):[pid(%d)(%s)]length verfication(external) warnning,len(%d), wr_idx(%d), rd_idx(%d)!\n\r", i, current->pid, current->comm, len, wr_idx, rd_idx); return -1; } } else { UART_ERR_FUNC("Warnning(i-%d):[pid(%d)(%s)]length verfication(external) warnning,len(%d), wr_idx(%d), rd_idx(%d)!\n\r", i, current->pid, current->comm, len, wr_idx, rd_idx); return -1; } //up(&buf_mtx); //// spin_unlock_irqrestore(&buf_lock, flags); UART_DBG_FUNC("--\n"); return written_count; }
static int mtk_wcn_stp_uart_init(void) { static struct tty_ldisc_ops stp_uart_ldisc; int err; int fifo_init_done =0; UART_INFO_FUNC("mtk_wcn_stp_uart_init(): MTK STP UART driver\n"); #if (LDISC_RX == LDISC_RX_TASKLET) err = stp_uart_fifo_init(); if (err != 0) { goto init_err; } fifo_init_done = 1; /*init rx tasklet*/ tasklet_init(&g_stp_uart_rx_fifo_tasklet, stp_uart_rx_handling, (unsigned long) 0); #elif (LDISC_RX == LDISC_RX_WORK) err = stp_uart_fifo_init(); if (err != 0) { UART_ERR_FUNC("stp_uart_fifo_init(WORK) error(%d)\n", err); err = -EFAULT; goto init_err; } fifo_init_done = 1; g_stp_uart_rx_work = vmalloc(sizeof(struct work_struct)); if (!g_stp_uart_rx_work) { UART_ERR_FUNC("vmalloc work_struct(%d) fail\n", sizeof(struct work_struct)); err = -ENOMEM; goto init_err; } g_stp_uart_rx_wq = create_singlethread_workqueue("mtk_urxd"); if (!g_stp_uart_rx_wq) { UART_ERR_FUNC("create_singlethread_workqueue fail\n"); err = -ENOMEM; goto init_err; } /* init rx work */ INIT_WORK(g_stp_uart_rx_work, stp_uart_rx_worker); #endif /* Register the tty discipline */ memset(&stp_uart_ldisc, 0, sizeof (stp_uart_ldisc)); stp_uart_ldisc.magic = TTY_LDISC_MAGIC; stp_uart_ldisc.name = "n_mtkstp"; stp_uart_ldisc.open = stp_uart_tty_open; stp_uart_ldisc.close = stp_uart_tty_close; stp_uart_ldisc.read = stp_uart_tty_read; stp_uart_ldisc.write = stp_uart_tty_write; stp_uart_ldisc.ioctl = stp_uart_tty_ioctl; stp_uart_ldisc.poll = stp_uart_tty_poll; stp_uart_ldisc.receive_buf = stp_uart_tty_receive; stp_uart_ldisc.write_wakeup = stp_uart_tty_wakeup; stp_uart_ldisc.owner = THIS_MODULE; if ((err = tty_register_ldisc(N_MTKSTP, &stp_uart_ldisc))) { UART_ERR_FUNC("MTK STP line discipline registration failed. (%d)\n", err); goto init_err; } /* mtk_wcn_stp_register_if_tx( mtk_wcn_uart_tx); */ return 0; init_err: #if (LDISC_RX == LDISC_RX_TASKLET) /* nothing */ if (fifo_init_done) { stp_uart_fifo_deinit(); } #elif (LDISC_RX == LDISC_RX_WORK) if (g_stp_uart_rx_wq) { destroy_workqueue(g_stp_uart_rx_wq); g_stp_uart_rx_wq = NULL; } if (g_stp_uart_rx_work) { vfree(g_stp_uart_rx_work); } if (fifo_init_done) { stp_uart_fifo_deinit(); } #endif UART_ERR_FUNC("init fail, return(%d)\n", err); return err; }
static int stp_uart_fifo_init(void) { int err = 0; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) g_stp_uart_rx_buf = vzalloc(LDISC_RX_BUF_SIZE); if (!g_stp_uart_rx_buf) { UART_ERR_FUNC("kfifo_alloc failed (kernel version >= 2.6.37)\n"); err = -4; goto fifo_init_end; } #else g_stp_uart_rx_buf = vmalloc(LDISC_RX_BUF_SIZE); if (!g_stp_uart_rx_buf) { UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.37)\n"); err = -4; goto fifo_init_end; } memset(g_stp_uart_rx_buf, 0, LDISC_RX_BUF_SIZE); #endif UART_INFO_FUNC("g_stp_uart_rx_buf alloc ok(0x%p, %d)\n", g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE); /*add rx fifo*/ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) spin_lock_init(&g_stp_uart_rx_fifo_spinlock); g_stp_uart_rx_fifo = kfifo_alloc(LDISC_RX_FIFO_SIZE, GFP_KERNEL, &g_stp_uart_rx_fifo_spinlock); if (NULL == g_stp_uart_rx_fifo) { UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.33)\n"); err = -1; goto fifo_init_end; } #else /* allocate struct kfifo first */ g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_KERNEL); if (NULL == g_stp_uart_rx_fifo) { err = -2; UART_ERR_FUNC("kzalloc struct kfifo failed (kernel version > 2.6.33)\n"); goto fifo_init_end; } /* allocate kfifo data buffer then */ err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_KERNEL); if (0 != err) { UART_ERR_FUNC("kfifo_alloc failed, err(%d)(kernel version > 2.6.33)\n", err); kfree(g_stp_uart_rx_fifo); g_stp_uart_rx_fifo = NULL; err = -3; goto fifo_init_end; } #endif UART_INFO_FUNC("g_stp_uart_rx_fifo alloc ok\n"); fifo_init_end: if (0 == err) { /* kfifo init ok */ kfifo_reset(g_stp_uart_rx_fifo); UART_DBG_FUNC("g_stp_uart_rx_fifo init success\n"); } else { UART_ERR_FUNC("stp_uart_fifo_init() fail(%d)\n", err); if (g_stp_uart_rx_buf) { UART_ERR_FUNC("free g_stp_uart_rx_buf\n"); vfree(g_stp_uart_rx_buf); g_stp_uart_rx_buf = NULL; } } return err; }
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; }