1 /* Copyright Statement:
3 * This software/firmware and related documentation ("MediaTek Software") are
4 * protected under relevant copyright laws. The information contained herein
5 * is confidential and proprietary to MediaTek Inc. and/or its licensors.
6 * Without the prior written permission of MediaTek inc. and/or its licensors,
7 * any reproduction, modification, use or disclosure of MediaTek Software,
8 * and information contained herein, in whole or in part, shall be strictly prohibited.
10 * MediaTek Inc. (C) 2010. All rights reserved.
12 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
13 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
14 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
15 * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
18 * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
19 * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
20 * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
21 * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
22 * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
23 * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
24 * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
25 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
26 * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
27 * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
28 * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
29 * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
31 * The following software/firmware and/or related documentation ("MediaTek Software")
32 * have been modified by MediaTek Inc. All revisions are subject to any receiver's
33 * applicable license agreements with MediaTek Inc.
36 /*******************************************************************************
37 * C O M P I L E R F L A G S
38 ********************************************************************************
41 #define LDISC_LOW_LATENCY (0)
42 /* 1: set low_latency to tty; rx may be called in hw_irq context;
43 * 0: rx may be called in kernel global workqueue context (kthread)
46 /* ldisc rx and do stp data parsing context options:
48 * use rx tasklet to process rx data in bh
49 * cons: can't sleep, priority too high.
51 * process rx data directly in tty's recv callback context
52 * (ldisc.receive_buf). Real context type depends on LDISC_LOW_LATENCY:
55 * cons: rx data may come too late.
56 * LDISC_RX_WORK (default):
57 * schedule another work_struct to handle
59 #define LDISC_RX_TASKLET (0)
60 #define LDISC_RX_TTY_CB (1)
61 #define LDISC_RX_WORK (2)
62 /* Select LDISC RX Method */
63 #define LDISC_RX (LDISC_RX_WORK)
65 /* More detailed options */
66 #if (LDISC_RX == LDISC_RX_TASKLET)
67 #define LDISC_RX_TASKLET_RWLOCK (0)
68 /* 1: use rwlock to protect rx kfifo (APEX default) for LDISC_RX_TASKLET
71 #elif (LDISC_RX == LDISC_RX_WORK)
72 /* enable low latency mechanism */
73 #undef LDISC_LOW_LATENCY
74 #define LDISC_LOW_LATENCY (1)
77 /* ldisc tx context options:
79 * Do uart tx in the caller thread (STP-CORE). Handle local tx buffer
81 * LDISC_TX_CALLER_THRD:
82 * Do uart tx in the caller thread (STP-CORE). Handle tx using caller's
85 #define LDISC_TX_OLD (0)
86 #define LDISC_TX_CALLER_THRD (1)
88 /* Select LDISC TX Method */
89 #define LDISC_TX (LDISC_TX_CALLER_THRD)
91 /*******************************************************************************
92 * E X T E R N A L R E F E R E N C E S
93 ********************************************************************************
95 #include <linux/version.h>
96 #include <linux/module.h>
98 #include <linux/kernel.h>
99 #include <linux/init.h>
100 #include <linux/types.h>
101 #include <linux/fcntl.h>
102 #include <linux/interrupt.h>
103 #include <linux/ptrace.h>
104 #include <linux/poll.h>
106 #include <linux/slab.h>
107 #include <linux/tty.h>
108 #include <linux/errno.h>
109 #include <linux/string.h>
110 #include <linux/signal.h>
111 #include <linux/ioctl.h>
112 #include <linux/skbuff.h>
114 #include <linux/spinlock.h>
116 #include <linux/time.h>
117 #include <linux/delay.h>
118 #include <linux/err.h>
119 #include <linux/kfifo.h>
120 #include <linux/vmalloc.h> /* vmalloc, vzalloc */
121 #include <linux/workqueue.h> /* INIT_WORK, schedule_work */
125 /*******************************************************************************
127 ********************************************************************************
129 #define N_MTKSTP (15 + 1) /* refer to linux tty.h use N_HCI. */
130 #define HCIUARTSETPROTO (_IOW('U', 200, int))
132 #define PFX "[STP-U]"
133 #define UART_LOG_LOUD (4)
134 #define UART_LOG_DBG (3)
135 #define UART_LOG_INFO (2)
136 #define UART_LOG_WARN (1)
137 #define UART_LOG_ERR (0)
139 #define MAX_PACKET_ALLOWED (2000)
141 #if (LDISC_RX == LDISC_RX_TASKLET)
142 #define LDISC_RX_FIFO_SIZE (0x20000/*0x2000*/) /* 128K or 8K bytes? */
144 #elif (LDISC_RX == LDISC_RX_WORK)
145 #define LDISC_RX_FIFO_SIZE (0x4000) /* 16K bytes shall be enough...... */
146 #define LDISC_RX_BUF_SIZE (2048) /* 2K bytes in one shot is enough */
150 #if (LDISC_TX == LDISC_TX_OLD)
151 /* no additional allocated for tx using caller's thread */
152 //#define STP_UART_TX_BUF_SIZE (MTKSTP_BUFFER_SIZE)
153 #define STP_UART_TX_BUF_SIZE (4096) /* 16K or 4K bytes is enough? */
155 #elif (LDISC_TX == LDISC_TX_CALLER_THRD)
157 #define LDISC_TX_CALLER_THRD_RTY_LMT (10)
158 #define LDISC_TX_CALLER_THRD_RTY_MIN_DLY (3)
161 /*******************************************************************************
162 * P U B L I C D A T A
163 ********************************************************************************
166 unsigned int gStpDbgLevel = UART_LOG_ERR;//UART_LOG_INFO;//modify loglevel
168 struct tty_struct *stp_tty = NULL;
170 /*******************************************************************************
171 * P R I V A T E D A T A
172 ********************************************************************************
175 #if (LDISC_RX == LDISC_RX_TASKLET)
176 struct kfifo *g_stp_uart_rx_fifo = NULL;
177 spinlock_t g_stp_uart_rx_fifo_spinlock;
178 struct tasklet_struct g_stp_uart_rx_fifo_tasklet;
179 #if LDISC_RX_TASKLET_RWLOCK
180 static DEFINE_RWLOCK(g_stp_uart_rx_handling_lock);
184 #if (LDISC_RX == LDISC_RX_WORK)
185 UINT8 *g_stp_uart_rx_buf; /* for stp rx data parsing */
186 struct kfifo *g_stp_uart_rx_fifo = NULL; /* for uart tty data receiving */
187 spinlock_t g_stp_uart_rx_fifo_spinlock; /* fifo spinlock */
188 struct workqueue_struct *g_stp_uart_rx_wq; /* rx work queue (do not use system_wq) */
189 struct work_struct *g_stp_uart_rx_work; /* rx work */
192 /* Private info for each Tx method */
193 #if (LDISC_TX == LDISC_TX_OLD)
194 static unsigned char tx_buf[STP_UART_TX_BUF_SIZE] = {0x0};
195 static unsigned int rd_idx = 0; /* the position next to read */
196 static unsigned int wr_idx = 0; /* the position next to write */
197 /* tx_buf in STP-UART is protected by caller(STP-CORE) locking mechanism. */
198 //struct semaphore buf_mtx; /* unused */
199 //static spinlock_t buf_lock; /* unused */
201 #elif (LDISC_TX == LDISC_TX_CALLER_THRD)
202 static int tx_retry_limit = LDISC_TX_CALLER_THRD_RTY_LMT;
203 static int tx_retry_delay_ms = LDISC_TX_CALLER_THRD_RTY_MIN_DLY;
206 #error "UNSUPPORTED LDISC_TX" LDISC_TX
209 //static unsigned int tx_count = 0; /* drop tx data test? */
211 /*******************************************************************************
213 ********************************************************************************
216 /*******************************************************************************
218 ********************************************************************************
220 //#define MAX(a,b) ((a) > (b) ? (a) : (b)) //unused
221 //#define MIN(a,b) ((a) < (b) ? (a) : (b)) //unused
223 #define UART_LOUD_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_LOUD){ printk(PFX "[L]%s:" fmt, __FUNCTION__ ,##arg);}
224 #define UART_DBG_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_DBG){ printk(PFX "[D]%s:" fmt, __FUNCTION__ ,##arg);}
225 #define UART_INFO_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_INFO){ printk(PFX "[I]%s:" fmt, __FUNCTION__ ,##arg);}
226 #define UART_WARN_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_WARN){ printk(PFX "[W]%s:" fmt, __FUNCTION__ ,##arg);}
227 #define UART_ERR_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_ERR){ printk(PFX "[E]%s:" fmt, __FUNCTION__ ,##arg);}
228 #define UART_TRC_FUNC(f) if(gStpDbgLevel >= UART_LOG_DBG){ printk(PFX "<%s/%d>\n", __FUNCTION__, __LINE__);}
230 /*******************************************************************************
231 * F U N C T I O N D E C L A R A T I O N S
232 ********************************************************************************
234 static INT32 mtk_wcn_uart_tx (
240 /*******************************************************************************
242 ********************************************************************************
245 #if (LDISC_TX == LDISC_TX_OLD)
246 static int stp_uart_tty_tx_init (void)
248 //init_MUTEX(&buf_mtx);
249 //spin_lock_init(&buf_lock);
254 static int stp_uart_tty_tx_deinit (void)
263 * tty pointer to tty info structure
264 * data pointer to data buffer to be written
265 * size data buffer length to be written
267 * > 0 if success, otherwise error code
269 static int stp_uart_tty_tx_write (
270 struct tty_struct *tty,
282 //unsigned long flags;
284 UART_LOUD_FUNC("++\n");
286 /* Phase-I: put data into STP-UART ring buffer "tx_buf" */
287 /* wr_idx : the position next to write
288 * rd_idx : the position next to read
292 /* [PatchNeed] spin_lock_irqsave is redundant */
293 //spin_lock_irqsave(&buf_lock, flags);
297 /* check left room size */
298 room = (wr_idx >= rd_idx)
299 ? (STP_UART_TX_BUF_SIZE - (wr_idx - rd_idx) - 1)
300 : (rd_idx - wr_idx - 1);
301 UART_DBG_FUNC("before data in:r(%d)s(%d)wr_i(%d)rd_i(%d)\n",
302 room, size, wr_idx, rd_idx);
304 if (unlikely(size > room)) {
305 UART_ERR_FUNC("buf unavailable FAIL#1,size(%d),wr_idx(%d),rd_idx(%d),room(%d),pid[%d/%s]\n",
306 size, wr_idx, rd_idx, room, current->pid, current->comm);
308 /* [PatchNeed] spin_lock_irqsave is redundant */
309 //spin_unlock_irqrestore(&buf_lock, flags);
313 len = min(size, STP_UART_TX_BUF_SIZE - (unsigned int)wr_idx);
314 memcpy(&tx_buf[wr_idx], &data[0], len);
315 memcpy(&tx_buf[0], &data[len], size - len);
316 wr_idx = (wr_idx + size) % STP_UART_TX_BUF_SIZE;
317 UART_DBG_FUNC("after data in: r(%d)s(%d)wr_i(%d)rd_i(%d)\n",
318 room, size, wr_idx, rd_idx);
321 /* [PatchNeed] spin_lock_irqsave is redundant */
322 //spin_unlock_irqrestore(&buf_lock, flags);
324 /* Phase-II: get data from the buffer and send to tty UART.
325 * May be seperated into another context.
329 /* [PatchNeed] spin_lock_irqsave is redundant */
330 //spin_lock_irqsave(&buf_lock, flags);
333 len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (STP_UART_TX_BUF_SIZE - rd_idx);
334 if (likely(len > 0 && len < MAX_PACKET_ALLOWED))
336 /* TTY_DO_WRITE_WAKEUP is used for "Call write_wakeup after queuing new"
337 * but stp_uart_tty_wakeup() is empty and unused now!
339 //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
342 * ops->write is called by the kernel to write a series of
343 * characters to the tty device. The characters may come from
344 * user space or kernel space. This routine will return the
345 * number of characters actually accepted for writing.
347 written = tty->ops->write(tty, &tx_buf[rd_idx], len);
348 if (written != len) {
349 UART_ERR_FUNC("tty-ops->write FAIL#2,len(%d)wr(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n",
350 len, written, wr_idx, rd_idx, current->pid, current->comm);
352 goto tx_write_out_unlock_old;
354 written_count = written;
355 rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE);
357 // all data is accepted by UART driver, check again in case roll over
358 len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (STP_UART_TX_BUF_SIZE - rd_idx);
359 if (len > 0 && len < MAX_PACKET_ALLOWED)
361 /* TTY_DO_WRITE_WAKEUP is used for "Call write_wakeup after queuing new"
362 * but stp_uart_tty_wakeup() is empty and unused now!
364 //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
366 written = tty->ops->write(tty, &tx_buf[rd_idx], len);
367 if (unlikely(written != len))
369 UART_ERR_FUNC("tty-ops->write FAIL#3,len(%d)wr(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n",
370 len, written, wr_idx, rd_idx, current->pid, current->comm);
372 goto tx_write_out_unlock_old;
374 rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE);
375 written_count += written;
377 else if (unlikely(len < 0 || len >= MAX_PACKET_ALLOWED))
379 UART_ERR_FUNC("FAIL#4,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n",
381 current->pid, current->comm);
383 goto tx_write_out_unlock_old;
388 UART_ERR_FUNC("FAIL#5,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n",
390 current->pid, current->comm);
392 goto tx_write_out_unlock_old;
399 tx_write_out_unlock_old:
400 if (unlikely(ret < 0)) {
401 //reset read and write index of tx_buffer, is there any risk?
403 UART_ERR_FUNC("err(%d)reset fifo idx\n", ret);
406 if (unlikely(wr_idx != rd_idx)) {
407 UART_WARN_FUNC("--wr(%d)rd(%d)size(%d)old wr(%d)rd(%d)\n",
408 wr_idx, rd_idx, size, old_wr, old_rd);
412 UART_LOUD_FUNC("--wr(%d) rd(%d)\n", wr_idx, rd_idx);
415 //spin_unlock_irqrestore(&buf_lock, flags);
420 /* end of (LDISC_TX == LDISC_TX_OLD) */
422 #elif (LDISC_TX == LDISC_TX_CALLER_THRD)
423 static inline int stp_uart_tty_tx_init (void)
425 /* nothing to be done */
429 static inline int stp_uart_tty_tx_deinit (void)
431 /* nothing to be done */
435 static int stp_uart_tty_tx_write (
436 struct tty_struct *tty,
446 wr_count = tty->ops->write(tty, data, size);
447 if (likely(wr_count == size)) {
452 UART_DBG_FUNC("tty write FAIL#1,size(%d)wr(%d)pid[%d/%s]\n",
453 size, written, current->pid, current->comm);
456 retry_left = tx_retry_limit;
457 retry_delay_ms = tx_retry_delay_ms;
458 while ( (retry_left--) && (wr_count < size)) {
459 /* do msleep if and only if STP-CORE using process context (caller's or
460 * any other task) instead of any irq context (hardirq, softirq, tasklet
463 msleep(retry_delay_ms);
464 // TODO: to be refined by considering wr_count, current baud rate, etc.
466 written = tty->ops->write(tty, data + wr_count, size - wr_count);
470 if (likely(wr_count == size)) {
471 UART_INFO_FUNC("recovered,size(%d)retry_left(%d)delay(%d)\n",
472 size, retry_left, retry_delay_ms);
477 /* return -written_count as error code and let caller to further error handle */
478 UART_ERR_FUNC("tty write FAIL#2,size(%d)wr(%d)retry_left(%d)pid[%d/%s]\n",
479 size, wr_count, retry_left, current->pid, current->comm);
484 #error "unknown LDISC_TX" LDISC_TX
487 #if (LDISC_RX == LDISC_RX_TASKLET)
488 static int stp_uart_fifo_init(void)
493 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
495 spin_lock_init(&g_stp_uart_rx_fifo_spinlock);
496 g_stp_uart_rx_fifo = kfifo_alloc(LDISC_RX_FIFO_SIZE, GFP_ATOMIC, &g_stp_uart_rx_fifo_spinlock);
497 if (NULL == g_stp_uart_rx_fifo)
499 UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.33)\n");
505 g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC);
506 if (NULL == g_stp_uart_rx_fifo)
509 UART_ERR_FUNC("kzalloc for g_stp_uart_rx_fifo failed (kernel version > 2.6.33)\n");
511 err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_ATOMIC);
514 UART_ERR_FUNC("kfifo_alloc failed, errno(%d)(kernel version > 2.6.33)\n", err);
515 kfree(g_stp_uart_rx_fifo);
516 g_stp_uart_rx_fifo = NULL;
524 if (NULL != g_stp_uart_rx_fifo)
526 kfifo_reset(g_stp_uart_rx_fifo);
527 UART_ERR_FUNC("stp_uart_fifo_init() success.\n");
532 UART_ERR_FUNC("abnormal case, err = 0 but g_stp_uart_rx_fifo = NULL, set err to %d\n", err);
537 UART_ERR_FUNC("stp_uart_fifo_init() failed.\n");
542 static int stp_uart_fifo_deinit(void)
544 if (NULL != g_stp_uart_rx_fifo)
546 kfifo_free(g_stp_uart_rx_fifo);
547 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
550 kfree(g_stp_uart_rx_fifo);
552 g_stp_uart_rx_fifo = NULL;
557 static void stp_uart_rx_handling(unsigned long func_data){
558 #define LOCAL_BUFFER_LEN 1024
559 unsigned char data[LOCAL_BUFFER_LEN];
560 unsigned int how_much_get = 0;
561 unsigned int how_much_to_get = 0;
562 unsigned int flag = 0;
564 #if LDISC_RX_TASKLET_RWLOCK
565 read_lock(&g_stp_uart_rx_handling_lock);
568 how_much_to_get = kfifo_len(g_stp_uart_rx_fifo);
570 if (how_much_to_get >= LOCAL_BUFFER_LEN)
573 UART_INFO_FUNC ("fifolen(%d)\n", how_much_to_get);
577 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
578 how_much_get= kfifo_get(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN);
580 how_much_get= kfifo_out(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN);
582 UART_INFO_FUNC ("fifoget(%d)\n", how_much_get);
583 mtk_wcn_stp_parser_data((UINT8 *)data, how_much_get);
584 how_much_to_get = kfifo_len(g_stp_uart_rx_fifo);
585 }while(how_much_to_get > 0);
587 #if LDISC_RX_TASKLET_RWLOCK
588 read_unlock(&g_stp_uart_rx_handling_lock);
593 UART_INFO_FUNC ("finish, fifolen(%d)\n", kfifo_len(g_stp_uart_rx_fifo));
597 /* stp_uart_tty_receive()
599 * Called by tty low level driver when receive data is
602 * Arguments: tty pointer to tty isntance data
603 * data pointer to received data
604 * flags pointer to flags for data
605 * count count of received data in bytes
609 static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
611 unsigned int fifo_avail_len;/* = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo);*/
612 unsigned int how_much_put = 0;
617 do_gettimeofday(&now);
618 printk("[+STP][ ][R] %4d --> sec = %lu, --> usec --> %lu\n",
619 count, now.tv_sec, now.tv_usec);
623 #if LDISC_RX_TASKLET_RWLOCK
624 write_lock(&g_stp_uart_rx_handling_lock);
629 UART_ERR_FUNC("abnormal: buffer count = %d\n", count);
631 /*How much empty seat?*/
632 fifo_avail_len = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo);
633 if (fifo_avail_len > 0) {
634 //UART_INFO_FUNC ("fifo left(%d), count(%d)\n", fifo_avail_len, count);
635 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
636 how_much_put = kfifo_put(g_stp_uart_rx_fifo,(unsigned char *) data, count);
638 how_much_put = kfifo_in(g_stp_uart_rx_fifo,(unsigned char *) data, count);
641 #if LDISC_RX_TASKLET_RWLOCK
643 write_unlock(&g_stp_uart_rx_handling_lock);
647 tasklet_schedule(&g_stp_uart_rx_fifo_tasklet);
650 UART_ERR_FUNC("stp_uart_tty_receive rxfifo is full!!\n");
656 do_gettimeofday(&now);
657 printk("[-STP][ ][R] %4d --> sec = %lu, --> usec --> %lu\n",
658 count, now.tv_sec, now.tv_usec);
662 #if LDISC_RX_TASKLET_RWLOCK
664 //write_unlock(&g_stp_uart_rx_handling_lock);
669 #elif (LDISC_RX == LDISC_RX_TTY_CB)
670 /* stp_uart_tty_receive()
672 * Called by tty low level driver when receive data is
675 * Arguments: tty pointer to tty isntance data
676 * data pointer to received data
677 * flags pointer to flags for data
678 * count count of received data in bytes
682 static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
684 //UART_INFO_FUNC("count = %d\n", count);
688 UART_WARN_FUNC("count = %d\n", count);
695 do_gettimeofday(&now);
697 printk("[+STP][ ][R] %4d --> sec = %d, --> usec --> %d\n",
698 count, now.tv_sec, now.tv_usec);
703 /*There are multi-context to access here? Need to spinlock?*/
704 /*Only one context: flush_to_ldisc in tty_buffer.c*/
705 mtk_wcn_stp_parser_data((UINT8 *)data, (UINT32)count);
707 /* George Test: useless? */
708 /*tty_unthrottle(tty);*/
714 do_gettimeofday(&now);
716 printk("[-STP][ ][R] %4d --> sec = %d, --> usec --> %d\n",
717 count, now.tv_sec, now.tv_usec);
723 #elif (LDISC_RX == LDISC_RX_WORK)
724 static int stp_uart_fifo_init(void)
728 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
729 g_stp_uart_rx_buf = vzalloc(LDISC_RX_BUF_SIZE);
730 if (!g_stp_uart_rx_buf) {
731 UART_ERR_FUNC("kfifo_alloc failed (kernel version >= 2.6.37)\n");
736 g_stp_uart_rx_buf = vmalloc(LDISC_RX_BUF_SIZE);
737 if (!g_stp_uart_rx_buf) {
738 UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.37)\n");
742 memset(g_stp_uart_rx_buf, 0, LDISC_RX_BUF_SIZE);
745 UART_LOUD_FUNC("g_stp_uart_rx_buf alloc ok(0x%p, %d)\n",
746 g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE);
749 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
750 spin_lock_init(&g_stp_uart_rx_fifo_spinlock);
751 g_stp_uart_rx_fifo = kfifo_alloc(LDISC_RX_FIFO_SIZE, GFP_KERNEL, &g_stp_uart_rx_fifo_spinlock);
752 if (NULL == g_stp_uart_rx_fifo) {
753 UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.33)\n");
758 /* allocate struct kfifo first */
759 g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_KERNEL);
760 if (NULL == g_stp_uart_rx_fifo) {
762 UART_ERR_FUNC("kzalloc struct kfifo failed (kernel version > 2.6.33)\n");
766 /* allocate kfifo data buffer then */
767 err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_KERNEL);
769 UART_ERR_FUNC("kfifo_alloc failed, err(%d)(kernel version > 2.6.33)\n", err);
770 kfree(g_stp_uart_rx_fifo);
771 g_stp_uart_rx_fifo = NULL;
776 UART_LOUD_FUNC("g_stp_uart_rx_fifo alloc ok\n");
782 kfifo_reset(g_stp_uart_rx_fifo);
783 UART_DBG_FUNC("g_stp_uart_rx_fifo init success\n");
786 UART_ERR_FUNC("stp_uart_fifo_init() fail(%d)\n", err);
787 if (g_stp_uart_rx_buf) {
788 UART_ERR_FUNC("free g_stp_uart_rx_buf\n");
789 vfree(g_stp_uart_rx_buf);
790 g_stp_uart_rx_buf = NULL;
797 static int stp_uart_fifo_deinit(void)
799 if (g_stp_uart_rx_buf) {
800 vfree(g_stp_uart_rx_buf);
801 g_stp_uart_rx_buf = NULL;
804 if (NULL != g_stp_uart_rx_fifo) {
805 kfifo_free(g_stp_uart_rx_fifo);
806 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
809 kfree(g_stp_uart_rx_fifo);
811 g_stp_uart_rx_fifo = NULL;
816 static void stp_uart_rx_worker (struct work_struct *work)
820 if (unlikely(!g_stp_uart_rx_fifo)) {
821 UART_ERR_FUNC("NULL rx fifo!\n");
824 if (unlikely(!g_stp_uart_rx_buf)) {
825 UART_ERR_FUNC("NULL rx buf!\n");
829 /* run until fifo becomes empty */
830 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
831 while (kfifo_len(g_stp_uart_rx_fifo)) {
832 read = kfifo_get(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE);
833 //UART_LOUD_FUNC("kfifo_get(%d)\n", read);
835 mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read);
839 while (!kfifo_is_empty(g_stp_uart_rx_fifo)) {
840 read = kfifo_out(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE);
841 UART_DBG_FUNC("kfifo_out(%d)\n", read);
843 //UART_LOUD_FUNC("->%d\n", read);
844 mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read);
845 //UART_LOUD_FUNC("<-\n", read);
853 /* stp_uart_tty_receive()
855 * Called by tty low level driver when receive data is
858 * Arguments: tty pointer to tty isntance data
859 * data pointer to received data
860 * flags pointer to flags for data
861 * count count of received data in bytes
865 static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
867 unsigned int written;
869 //UART_LOUD_FUNC("URX:%d\n", count);
870 if (unlikely(count > 2000)) {
871 UART_WARN_FUNC("abnormal: buffer count = %d\n", count);
874 if (unlikely(!g_stp_uart_rx_fifo || !g_stp_uart_rx_work || !g_stp_uart_rx_wq)) {
875 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",
876 g_stp_uart_rx_fifo, g_stp_uart_rx_work, g_stp_uart_rx_wq);
880 /* need to check available buffer size? skip! */
882 /* need to lock fifo? skip for single writer single reader! */
884 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
885 written = kfifo_put(g_stp_uart_rx_fifo, (unsigned char *) data, count);
887 written = kfifo_in(g_stp_uart_rx_fifo, (unsigned char *) data, count);
889 queue_work(g_stp_uart_rx_wq, g_stp_uart_rx_work);
891 if (unlikely(written != count)) {
892 UART_ERR_FUNC("c(%d),w(%d) bytes dropped\n", count, written);
899 #error "unknown LDISC_RX!" LDISC_RX
902 /* ------ LDISC part ------ */
905 * Called when line discipline changed to HCI_UART.
908 * tty pointer to tty info structure
910 * 0 if success, otherwise error code
912 static int stp_uart_tty_open(struct tty_struct *tty)
914 UART_DBG_FUNC("original receive_room(%d) low_latency(%d) in tty(%p)\n",
915 tty->receive_room, tty->low_latency, tty);
917 tty->receive_room = 65536;
918 #if LDISC_LOW_LATENCY
919 tty->low_latency = 1;
921 UART_DBG_FUNC("set receive_room(%d) low_latency(%d) to tty(%p)\n",
922 tty->receive_room, tty->low_latency, tty);
924 /* Flush any pending characters in the driver and line discipline. */
926 /* FIXME: why is this needed. Note don't use ldisc_ref here as the
927 open path is before the ldisc is referencable */
929 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
930 /* definition changed!! */
931 if (tty->ldisc->ops->flush_buffer) {
932 tty->ldisc->ops->flush_buffer(tty);
935 if (tty->ldisc.ops->flush_buffer) {
936 tty->ldisc.ops->flush_buffer(tty);
940 tty_driver_flush_buffer(tty);
942 stp_uart_tty_tx_init();
946 /* Register to STP-CORE */
947 mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, mtk_wcn_uart_tx);
952 /* stp_uart_tty_close()
954 * Called when the line discipline is changed to something
955 * else, the tty is closed, or the tty detects a hangup.
957 static void stp_uart_tty_close(struct tty_struct *tty)
959 UART_DBG_FUNC("stp_uart_tty_close(): tty %p\n", tty);
960 mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL);
962 stp_uart_tty_tx_deinit();
967 /* stp_uart_tty_wakeup()
969 * Callback for transmit wakeup. Called when low level
970 * device driver can accept more send data.
972 * Arguments: tty pointer to associated tty instance data
975 static void stp_uart_tty_wakeup(struct tty_struct *tty)
978 UART_INFO_FUNC("in\n");
979 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
980 stp_uart_tx_wakeup(tty);
986 /* stp_uart_tty_ioctl()
988 * Process IOCTL system call for the tty device.
992 * tty pointer to tty instance data
993 * file pointer to open file object for device
994 * cmd IOCTL command code
995 * arg argument for IOCTL call (cmd dependent)
997 * Return Value: Command dependent
999 static int stp_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
1000 unsigned int cmd, unsigned long arg)
1004 UART_LOUD_FUNC("++ ll(%d)\n", tty->low_latency);
1007 case HCIUARTSETPROTO:
1008 #if LDISC_LOW_LATENCY
1009 UART_INFO_FUNC("set low_latency to 1\n");
1010 tty->low_latency = 1;
1014 UART_LOUD_FUNC("redirect to n_tty_ioctl_helper\n");
1015 err = n_tty_ioctl_helper(tty, file, cmd, arg);
1016 UART_LOUD_FUNC("n_tty_ioctl_helper result(0x%x %d)\n", cmd, err);
1020 UART_LOUD_FUNC("--\n");
1025 * We don't provide read/write/poll interface for user space.
1027 static ssize_t stp_uart_tty_read(struct tty_struct *tty, struct file *file,
1028 unsigned char __user *buf, size_t nr)
1033 static ssize_t stp_uart_tty_write(struct tty_struct *tty, struct file *file,
1034 const unsigned char *data, size_t count)
1039 static unsigned int stp_uart_tty_poll(struct tty_struct *tty,
1040 struct file *filp, poll_table *wait)
1045 static INT32 mtk_wcn_uart_tx (
1048 UINT32 *written_size
1054 if (unlikely(0 == size)) {
1055 /* special case for STP-CORE, return ASAP. */
1056 if (likely(written_size)) {
1062 UART_LOUD_FUNC("++\n");
1064 /* input sanity checks */
1065 if (unlikely(stp_tty == NULL)) {
1066 UART_ERR_FUNC("NULL stp_tty,pid[%d/%s]\n", current->pid, current->comm);
1071 if (unlikely((data == NULL) || (written_size == NULL))) {
1072 UART_ERR_FUNC("NULL data(0x%p) or written(0x%p),pid[%d/%s]\n",
1073 data, written_size, current->pid, current->comm);
1080 /* Do size checking. Only 1~MAX_PACKET_ALLOWED-1 is allowed */
1081 if (unlikely(MAX_PACKET_ALLOWED <= size)) {
1082 UART_ERR_FUNC("abnormal size(%d),skip tx,pid[%d/%s]\n",
1083 size, current->pid, current->comm);
1089 #if 0 /* drop data test */
1090 if ((tx_count > 1000) && (tx_count % 5)== 0) {
1091 UART_INFO_FUNC("i=(%d), ****** drop data from uart******\n", i);
1097 tx_len = stp_uart_tty_tx_write(stp_tty, data, size);
1098 if (unlikely(tx_len < 0)) {
1099 UART_WARN_FUNC("stp_uart_tty_tx_write err(%d)\n", tx_len);
1104 *written_size = tx_len;
1109 UART_LOUD_FUNC("--(%d, %d)\n", ret, *written_size);
1114 static int __init mtk_wcn_stp_uart_init(void)
1116 static struct tty_ldisc_ops stp_uart_ldisc;
1120 UART_INFO_FUNC("MTK STP UART driver\n");
1124 #if (LDISC_RX == LDISC_RX_TASKLET)
1125 err = stp_uart_fifo_init();
1127 UART_ERR_FUNC("stp_uart_fifo_init(TASKLET) error(%d)\n", err);
1134 tasklet_init(&g_stp_uart_rx_fifo_tasklet, stp_uart_rx_handling, (unsigned long) 0);
1136 #elif (LDISC_RX == LDISC_RX_WORK)
1137 err = stp_uart_fifo_init();
1139 UART_ERR_FUNC("stp_uart_fifo_init(WORK) error(%d)\n", err);
1145 g_stp_uart_rx_work = vmalloc(sizeof(struct work_struct));
1146 if (!g_stp_uart_rx_work) {
1147 UART_ERR_FUNC("vmalloc work_struct(%d) fail\n", sizeof(struct work_struct));
1152 g_stp_uart_rx_wq = create_singlethread_workqueue("mtk_urxd");
1153 if (!g_stp_uart_rx_wq) {
1154 UART_ERR_FUNC("create_singlethread_workqueue fail\n");
1160 INIT_WORK(g_stp_uart_rx_work, stp_uart_rx_worker);
1163 /* Register the tty discipline */
1164 memset(&stp_uart_ldisc, 0, sizeof (stp_uart_ldisc));
1165 stp_uart_ldisc.magic = TTY_LDISC_MAGIC;
1166 stp_uart_ldisc.name = "n_mtkstp";
1167 stp_uart_ldisc.open = stp_uart_tty_open;
1168 stp_uart_ldisc.close = stp_uart_tty_close;
1169 stp_uart_ldisc.read = stp_uart_tty_read;
1170 stp_uart_ldisc.write = stp_uart_tty_write;
1171 stp_uart_ldisc.ioctl = stp_uart_tty_ioctl;
1172 stp_uart_ldisc.poll = stp_uart_tty_poll;
1173 stp_uart_ldisc.receive_buf = stp_uart_tty_receive;
1174 stp_uart_ldisc.write_wakeup = stp_uart_tty_wakeup;
1175 stp_uart_ldisc.owner = THIS_MODULE;
1177 err = tty_register_ldisc(N_MTKSTP, &stp_uart_ldisc);
1179 UART_ERR_FUNC("MTK STP line discipline(%d) registration failed. (%d)\n", N_MTKSTP, err);
1188 #if (LDISC_RX == LDISC_RX_TASKLET)
1190 if (fifo_init_done) {
1191 stp_uart_fifo_deinit();
1193 #elif (LDISC_RX == LDISC_RX_WORK)
1194 if (g_stp_uart_rx_wq) {
1195 destroy_workqueue(g_stp_uart_rx_wq);
1196 g_stp_uart_rx_wq = NULL;
1198 if (g_stp_uart_rx_work) {
1199 vfree(g_stp_uart_rx_work);
1201 if (fifo_init_done) {
1202 stp_uart_fifo_deinit();
1205 UART_ERR_FUNC("init fail, return(%d)\n", err);
1210 static void __exit mtk_wcn_stp_uart_exit(void)
1214 mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL); // unregister if_tx function
1216 /* Release tty registration of line discipline */
1217 if ((err = tty_unregister_ldisc(N_MTKSTP)))
1219 UART_ERR_FUNC("Can't unregister MTK STP line discipline (%d)\n", err);
1222 #if (LDISC_RX == LDISC_RX_TASKLET)
1223 tasklet_kill(&g_stp_uart_rx_fifo_tasklet);
1224 stp_uart_fifo_deinit();
1225 #elif (LDISC_RX == LDISC_RX_WORK)
1226 if (g_stp_uart_rx_work) {
1227 cancel_work_sync(g_stp_uart_rx_work);
1229 if (g_stp_uart_rx_wq) {
1230 destroy_workqueue(g_stp_uart_rx_wq);
1231 g_stp_uart_rx_wq = NULL;
1233 if (g_stp_uart_rx_work) {
1234 vfree(g_stp_uart_rx_work);
1235 g_stp_uart_rx_work = NULL;
1237 stp_uart_fifo_deinit();
1243 module_init(mtk_wcn_stp_uart_init);
1244 module_exit(mtk_wcn_stp_uart_exit);
1246 //MODULE_LICENSE("Proprietary");
1247 MODULE_LICENSE("GPL");
1248 MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3");
1249 MODULE_DESCRIPTION("STP-HIF UART Interface");