/* 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;
}
Example #2
0
/* 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 fifo_avail_len;/* = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo);*/
    unsigned int how_much_put = 0;

#if 0
    {
        struct timeval now;
        do_gettimeofday(&now);
        printk("[+STP][  ][R] %4d --> sec = %lu, --> usec --> %lu\n",
            count, now.tv_sec, now.tv_usec);
    }
#endif

#if LDISC_RX_TASKLET_RWLOCK
    write_lock(&g_stp_uart_rx_handling_lock);
#endif

    if (count > 2000) {
        /*this is abnormal*/
        UART_ERR_FUNC("abnormal: buffer count = %d\n", count);
    }
    /*How much empty seat?*/
    fifo_avail_len = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo);
    if (fifo_avail_len > 0) {
        //UART_INFO_FUNC ("fifo left(%d), count(%d)\n", fifo_avail_len, count);
        #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
        how_much_put = kfifo_put(g_stp_uart_rx_fifo,(unsigned char *) data, count);
        #else
        how_much_put = kfifo_in(g_stp_uart_rx_fifo,(unsigned char *) data, count);
        #endif

#if LDISC_RX_TASKLET_RWLOCK
        /* George Test */
        write_unlock(&g_stp_uart_rx_handling_lock);
#endif

        /*schedule it!*/
        tasklet_schedule(&g_stp_uart_rx_fifo_tasklet);
    }
    else {
        UART_ERR_FUNC("stp_uart_tty_receive rxfifo is full!!\n");
    }

#if 0
    {
        struct timeval now;
        do_gettimeofday(&now);
        printk("[-STP][  ][R] %4d --> sec = %lu, --> usec --> %lu\n",
            count, now.tv_sec, now.tv_usec);
    }
#endif

#if LDISC_RX_TASKLET_RWLOCK
    /* George Test */
    //write_unlock(&g_stp_uart_rx_handling_lock);
#endif

}
static void mtk_wcn_stp_uart_exit(void)
{
    int err;

    mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL);    // unregister if_tx function

    /* Release tty registration of line discipline */
    if ((err = tty_unregister_ldisc(N_MTKSTP)))
    {
        UART_ERR_FUNC("Can't unregister MTK STP line discipline (%d)\n", err);
    }

#if (LDISC_RX == LDISC_RX_TASKLET)
    tasklet_kill(&g_stp_uart_rx_fifo_tasklet);
    stp_uart_fifo_deinit();
#elif (LDISC_RX == LDISC_RX_WORK)
	if (g_stp_uart_rx_work) {
		cancel_work_sync(g_stp_uart_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);
		g_stp_uart_rx_work = NULL;
	}
	stp_uart_fifo_deinit();

#endif
    return;
}
static void stp_uart_rx_worker (struct work_struct *work)
{
    unsigned int read;

    if (unlikely(!g_stp_uart_rx_fifo)) {
        UART_ERR_FUNC("NULL rx fifo!\n");
        return;
    }
    if (unlikely(!g_stp_uart_rx_buf)) {
        UART_ERR_FUNC("NULL rx buf!\n");
        return;
    }
	

    /* run until fifo becomes empty */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
    while (kfifo_len(g_stp_uart_rx_fifo)) {
        read = kfifo_get(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE);
        //UART_LOUD_FUNC("kfifo_get(%d)\n", read);
        if (likely(read)) {
            mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read);
        }
    }
#else
    while (!kfifo_is_empty(g_stp_uart_rx_fifo)) {
        read = kfifo_out(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE);
        UART_DBG_FUNC("kfifo_out(%d)\n", read);
		//printk("rx_work:%d\n\r",read);
        if (likely(read)) {
            //UART_LOUD_FUNC("->%d\n", read);
            mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read);
            //UART_LOUD_FUNC("<-\n", read);
        }
    }
#endif

    return;
}
Example #5
0
static int stp_uart_tty_tx_write (
    struct tty_struct *tty,
    const UINT8 *data,
    const UINT32 size
    )
{
    int written;
    int wr_count;
    int retry_left;
    int retry_delay_ms;

    wr_count = tty->ops->write(tty, data, size);
    if (likely(wr_count == size)) {
        /* perfect case! */
        return wr_count;
    }

    UART_DBG_FUNC("tty write FAIL#1,size(%d)wr(%d)pid[%d/%s]\n",
        size, written, current->pid, current->comm);

    /* error handling */
    retry_left = tx_retry_limit;
    retry_delay_ms = tx_retry_delay_ms;
    while ( (retry_left--) && (wr_count < size)) {
        /* do msleep if and only if STP-CORE using process context (caller's or
         * any other task) instead of any irq context (hardirq, softirq, tasklet
         * , timer, etc).
        */
        msleep(retry_delay_ms);
        // TODO: to be refined by considering wr_count, current baud rate, etc.
        retry_delay_ms *= 2;
        written = tty->ops->write(tty, data + wr_count, size - wr_count);
        wr_count += written;
    }

    if (likely(wr_count == size)) {
        UART_DBG_FUNC("recovered,size(%d)retry_left(%d)delay(%d)\n",
            size, retry_left, retry_delay_ms);
        /* workable case! */
        return wr_count;
    }

    /* return -written_count as error code and let caller to further error handle */
    UART_ERR_FUNC("tty write FAIL#2,size(%d)wr(%d)retry_left(%d)pid[%d/%s]\n",
        size, wr_count, retry_left, current->pid, current->comm);

    return -wr_count;
}
Example #6
0
static int stp_uart_fifo_init(void)
{
    int err = 0;
    /*add rx fifo*/
        #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
        {
        spin_lock_init(&g_stp_uart_rx_fifo_spinlock);
        g_stp_uart_rx_fifo = kfifo_alloc(LDISC_RX_FIFO_SIZE, GFP_ATOMIC, &g_stp_uart_rx_fifo_spinlock);
        if (NULL == g_stp_uart_rx_fifo)
        {
            UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.35)\n");
            err = -1;
        }
        }
        #else
        {
            g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC);
            if (NULL == g_stp_uart_rx_fifo)
            {
                err = -2;
                UART_ERR_FUNC("kzalloc for g_stp_uart_rx_fifo failed (kernel version > 2.6.35)\n");
            }
            err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_ATOMIC);
            if (0 != err)
            {
                UART_ERR_FUNC("kfifo_alloc failed, errno(%d)(kernel version > 2.6.35)\n", err);
                kfree(g_stp_uart_rx_fifo);
                g_stp_uart_rx_fifo = NULL;
                err = -3;    
            }
        }
        #endif
    if (0 == err)
    {
        if (NULL != g_stp_uart_rx_fifo)
        {
            kfifo_reset(g_stp_uart_rx_fifo);
            UART_ERR_FUNC("stp_uart_fifo_init() success.\n");
        }
        else
        {
            err = -4;
            UART_ERR_FUNC("abnormal case, err = 0 but g_stp_uart_rx_fifo = NULL, set err to %d\n", err);
        }
    }
    else
    {
        UART_ERR_FUNC("stp_uart_fifo_init() failed.\n");
    }
#if 0    
	spin_lock_init(&g_stp_uart_rx_handling_lock);
#endif
    return err;
}
static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{

#if 0
    mtk_wcn_stp_debug_gpio_assert(IDX_STP_RX_PROC, DBG_TIE_LOW);
#endif

    if(count > 2000){
        /*this is abnormal*/
        UART_ERR_FUNC("stp_uart_tty_receive buffer 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);

#if 0
    mtk_wcn_stp_debug_gpio_assert(IDX_STP_RX_PROC, DBG_TIE_HIGH);
#endif

    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;
}
Example #8
0
static void __exit mtk_wcn_stp_uart_exit(void)
{
    int err;

    mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL);    // unregister if_tx function

    /* Release tty registration of line discipline */
    if ((err = tty_unregister_ldisc(N_MTKSTP)))
    {
        UART_ERR_FUNC("Can't unregister MTK STP line discipline (%d)\n", err);
    }

#ifdef LDISC_RX_TASKLET
    tasklet_kill(&g_stp_uart_rx_fifo_tasklet);
    stp_uart_fifo_deinit();
#endif
    return;
}
Example #9
0
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;
}
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;

}
INT32  mtk_wcn_uart_tx(const UINT8 *data, const UINT32 size, UINT32 *written_size)
{
    int room;
    //int idx = 0;
    //unsigned long flags;
    unsigned int  len;
    //static int tmp=0;
    static int i = 0;
    if(stp_tty == NULL) return -1;
    UART_DBG_FUNC("++\n");
    (*written_size) = 0;

    // put data into ring buffer
    //down(&buf_mtx);


    /*
        [PatchNeed]
        spin_lock_irqsave is redundant
    */
    //spin_lock_irqsave(&buf_lock, flags);

    room = (wr_idx >= rd_idx) ? (MTKSTP_BUFFER_SIZE - (wr_idx - rd_idx) - 1) : (rd_idx - wr_idx - 1);
    UART_DBG_FUNC("r(%d)s(%d)wr_i(%d)rd_i(%d)\n\r", room, size, wr_idx, rd_idx);
    /*
        [PatchNeed]
        Block copy instead of byte copying
    */
    if(data == NULL){
        UART_ERR_FUNC("pid(%d)(%s): data is NULL\n", current->pid, current->comm);
        (*written_size) = 0;
        UART_DBG_FUNC("--\n");
        return -2;
    }

    #if 1
    if(unlikely(size > room)){
        UART_ERR_FUNC("pid(%d)(%s)room is not available, size needed(%d), wr_idx(%d), rd_idx(%d), room left(%d)\n", current->pid, current->comm, size, wr_idx, rd_idx, room);
        UART_DBG_FUNC("--\n");
        (*written_size) = 0;
        return -3;
    }
    else {
        /*
            wr_idx : the position next to write
            rd_idx : the position next to read
        */
        len = min(size, MTKSTP_BUFFER_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) % MTKSTP_BUFFER_SIZE;
        UART_DBG_FUNC("r(%d)s(%d)wr_i(%d)rd_i(%d)\n\r", room, size, wr_idx, rd_idx);
        i++;
        if (size < 0)
        {
            UART_ERR_FUNC("Error(i-%d):[pid(%d)(%s)]len(%d)size(%d)wr_i(%d)rd_i(%d)\n\r", i, current->pid, current->comm, len, size, wr_idx, rd_idx);
            (*written_size) = 0;
        }
        else if (size == 0)
        {
            (*written_size) = 0;
        }
        else if (size < MAX_PACKET_ALLOWED)
        {
            //only size ~(0, 2000) is allowed
            (*written_size) = stp_uart_tx_wakeup(stp_tty);
            if(*written_size < 0)
            {
                //reset read and write index of tx_buffer, is there any risk?
                wr_idx = rd_idx = 0;
                *written_size = 0;
            }
        }
        else
        {
            //we filter all packet with size > 2000
            UART_ERR_FUNC("Warnning(i-%d):[pid(%d)(%s)]len(%d)size(%d)wr_i(%d)rd_i(%d)\n\r", i, current->pid, current->comm, len, size,  wr_idx, rd_idx);
            (*written_size)= 0;
        }
    }
    #endif


    #if 0
    while((room > 0) && (size > 0))
    {
        tx_buf[wr_idx] = data[idx];
        wr_idx = ((wr_idx + 1) % MTKSTP_BUFFER_SIZE);
        idx++;
        room--;
        size--;
        (*written_size)++;
    }
    #endif
    //up(&buf_mtx);
    /*
        [PatchNeed]
        spin_lock_irqsave is redundant
    */
////    spin_lock_irqsave(&buf_lock, flags);

    /*[PatchNeed]To add a tasklet to shedule Uart Tx*/
    UART_DBG_FUNC("--\n");
    return 0;
}
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;
}
Example #14
0
/* 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;
}
Example #15
0
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;
}