add MTK-combo-module,continue with commit 17f39ed917874e77e80411f33faba1b7ee8138c8
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_combo / common / linux / stp_uart.c
1 /* Copyright Statement:
2  *
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.
9  *
10  * MediaTek Inc. (C) 2010. All rights reserved.
11  *
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.
30  *
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.
34  */
35
36 /*******************************************************************************
37 *                         C O M P I L E R   F L A G S
38 ********************************************************************************
39 */
40
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)
44 */
45
46 /* ldisc rx and do stp data parsing context options:
47  *      LDISC_RX_TASKLET:
48  *          use rx tasklet to process rx data in bh
49  *          cons: can't sleep, priority too high.
50  *      LDISC_RX_TTY_CB:
51  *          process rx data directly in tty's recv callback context
52  *          (ldisc.receive_buf). Real context type depends on LDISC_LOW_LATENCY:
53  *              1:interrupt context
54  *              0: thread context.
55  *          cons: rx data may come too late.
56  *      LDISC_RX_WORK (default):
57  *          schedule another work_struct to handle
58  */
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)
64
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
69  * 0: use _NO_ rwlock
70 */
71 #elif (LDISC_RX == LDISC_RX_WORK)
72 /* enable low latency mechanism */
73 #undef LDISC_LOW_LATENCY
74 #define LDISC_LOW_LATENCY (1)
75 #endif
76
77 /* ldisc tx context options:
78  *      LDISC_TX_OLD:
79  *          Do uart tx in the caller thread (STP-CORE). Handle local tx buffer
80  *          in old way.
81  *      LDISC_TX_CALLER_THRD:
82  *          Do uart tx in the caller thread (STP-CORE). Handle tx using caller's
83  *          buffer directly.
84  */
85 #define LDISC_TX_OLD (0)
86 #define LDISC_TX_CALLER_THRD (1)
87
88 /* Select LDISC TX Method */
89 #define LDISC_TX (LDISC_TX_CALLER_THRD)
90
91 /*******************************************************************************
92 *                    E X T E R N A L   R E F E R E N C E S
93 ********************************************************************************
94 */
95 #include <linux/version.h>
96 #include <linux/module.h>
97
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>
105
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>
113
114 #include <linux/spinlock.h>
115
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 */
122
123 #include "stp_exp.h"
124
125 /*******************************************************************************
126 *                              C O N S T A N T S
127 ********************************************************************************
128 */
129 #define N_MTKSTP (15 + 1) /* refer to linux tty.h use N_HCI. */
130 #define HCIUARTSETPROTO (_IOW('U', 200, int))
131
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)
138
139 #define MAX_PACKET_ALLOWED (2000)
140
141 #if (LDISC_RX == LDISC_RX_TASKLET)
142 #define LDISC_RX_FIFO_SIZE (0x20000/*0x2000*/) /* 128K or 8K bytes? */
143
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 */
147
148 #endif
149
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? */
154
155 #elif (LDISC_TX == LDISC_TX_CALLER_THRD)
156
157 #define LDISC_TX_CALLER_THRD_RTY_LMT (10)
158 #define LDISC_TX_CALLER_THRD_RTY_MIN_DLY (3)
159 #endif
160
161 /*******************************************************************************
162 *                            P U B L I C   D A T A
163 ********************************************************************************
164 */
165
166 unsigned int gStpDbgLevel = UART_LOG_ERR;//UART_LOG_INFO;//modify loglevel
167
168 struct tty_struct *stp_tty = NULL;
169
170 /*******************************************************************************
171 *                           P R I V A T E   D A T A
172 ********************************************************************************
173 */
174
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);
181     #endif
182 #endif
183
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 */
190 #endif
191
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 */
200
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;
204
205 #else
206 #error "UNSUPPORTED LDISC_TX" LDISC_TX
207 #endif
208
209 //static unsigned int tx_count = 0; /* drop tx data test? */
210
211 /*******************************************************************************
212 *                             D A T A   T Y P E S
213 ********************************************************************************
214 */
215
216 /*******************************************************************************
217 *                                 M A C R O S
218 ********************************************************************************
219 */
220 //#define MAX(a,b) ((a) > (b) ? (a) : (b)) //unused
221 //#define MIN(a,b) ((a) < (b) ? (a) : (b)) //unused
222
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__);}
229
230 /*******************************************************************************
231 *                  F U N C T I O N   D E C L A R A T I O N S
232 ********************************************************************************
233 */
234 static INT32 mtk_wcn_uart_tx (
235     const UINT8 *data,
236     const UINT32 size,
237     UINT32 *written_size
238     );
239
240 /*******************************************************************************
241 *                              F U N C T I O N S
242 ********************************************************************************
243 */
244
245 #if (LDISC_TX == LDISC_TX_OLD)
246 static int stp_uart_tty_tx_init (void)
247 {
248     //init_MUTEX(&buf_mtx);
249     //spin_lock_init(&buf_lock);
250     rd_idx = wr_idx = 0;
251     return 0;
252 }
253
254 static int stp_uart_tty_tx_deinit (void)
255 {
256     rd_idx = wr_idx = 0;
257     return 0;
258 }
259
260 /* stp_uart_tty_open
261  *
262  * Arguments:
263  *     tty  pointer to tty info structure
264  *     data pointer to data buffer to be written
265  *     size data buffer length to be written
266  * Return Value:
267  *     > 0 if success, otherwise error code
268  */
269 static int stp_uart_tty_tx_write (
270     struct tty_struct *tty,
271     const UINT8 *data,
272     const UINT32 size
273     )
274 {
275     int ret;
276     int len;
277     int written;
278     int written_count;
279     int room;
280     unsigned old_wr;
281     unsigned old_rd;
282     //unsigned long flags;
283
284     UART_LOUD_FUNC("++\n");
285
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
289      */
290
291     //down(&buf_mtx);
292     /* [PatchNeed] spin_lock_irqsave is redundant */
293     //spin_lock_irqsave(&buf_lock, flags);
294     old_wr = wr_idx;
295     old_rd = rd_idx;
296
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);
303
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);
307         //up(&buf_mtx);
308         /* [PatchNeed] spin_lock_irqsave is redundant */
309         //spin_unlock_irqrestore(&buf_lock, flags);
310         return -1;
311     }
312     else {
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);
319     }
320     //up(&buf_mtx);
321     /* [PatchNeed] spin_lock_irqsave is redundant */
322     //spin_unlock_irqrestore(&buf_lock, flags);
323
324     /* Phase-II: get data from the buffer and send to tty UART.
325      * May be seperated into another context.
326     */
327
328     //down(&buf_mtx);
329     /* [PatchNeed] spin_lock_irqsave is redundant */
330     //spin_lock_irqsave(&buf_lock, flags);
331     written_count = 0;
332
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))
335     {
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!
338          */
339         //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
340
341         /*
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.
346         */
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);
351             ret = -2;
352             goto tx_write_out_unlock_old;
353         }
354         written_count = written;
355         rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE);
356
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)
360         {
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!
363              */
364             //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
365
366             written = tty->ops->write(tty, &tx_buf[rd_idx], len);
367             if (unlikely(written != len))
368             {
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);
371                 ret = -3;
372                 goto tx_write_out_unlock_old;
373             }
374             rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE);
375             written_count += written;
376         }
377         else if (unlikely(len < 0 || len >= MAX_PACKET_ALLOWED))
378         {
379             UART_ERR_FUNC("FAIL#4,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n",
380                 len, wr_idx, rd_idx,
381                 current->pid, current->comm);
382             ret = -4;
383             goto tx_write_out_unlock_old;
384         }
385     }
386     else
387     {
388         UART_ERR_FUNC("FAIL#5,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n",
389             len, wr_idx, rd_idx,
390             current->pid, current->comm);
391         ret = -5;
392         goto tx_write_out_unlock_old;
393     }
394
395     /* success case */
396     ret = written_count;
397
398
399 tx_write_out_unlock_old:
400     if (unlikely(ret < 0)) {
401         //reset read and write index of tx_buffer, is there any risk?
402         wr_idx = rd_idx = 0;
403         UART_ERR_FUNC("err(%d)reset fifo idx\n", ret);
404     }
405
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);
409
410    }
411     else {
412         UART_LOUD_FUNC("--wr(%d) rd(%d)\n", wr_idx, rd_idx);
413     }
414     //up(&buf_mtx);
415     //spin_unlock_irqrestore(&buf_lock, flags);
416
417     return ret;
418 }
419
420 /* end of (LDISC_TX == LDISC_TX_OLD) */
421
422 #elif (LDISC_TX == LDISC_TX_CALLER_THRD)
423 static inline int stp_uart_tty_tx_init (void)
424 {
425     /* nothing to be done */
426     return 0;
427 }
428
429 static inline int stp_uart_tty_tx_deinit (void)
430 {
431     /* nothing to be done */
432     return 0;
433 }
434
435 static int stp_uart_tty_tx_write (
436     struct tty_struct *tty,
437     const UINT8 *data,
438     const UINT32 size
439     )
440 {
441     int written;
442     int wr_count;
443     int retry_left;
444     int retry_delay_ms;
445
446     wr_count = tty->ops->write(tty, data, size);
447     if (likely(wr_count == size)) {
448         /* perfect case! */
449         return wr_count;
450     }
451
452     UART_DBG_FUNC("tty write FAIL#1,size(%d)wr(%d)pid[%d/%s]\n",
453         size, written, current->pid, current->comm);
454
455     /* error handling */
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
461          * , timer, etc).
462         */
463         msleep(retry_delay_ms);
464         // TODO: to be refined by considering wr_count, current baud rate, etc.
465         retry_delay_ms *= 2;
466         written = tty->ops->write(tty, data + wr_count, size - wr_count);
467         wr_count += written;
468     }
469
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);
473         /* workable case! */
474         return wr_count;
475     }
476
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);
480
481     return -wr_count;
482 }
483 #else
484 #error "unknown LDISC_TX" LDISC_TX
485 #endif
486
487 #if (LDISC_RX == LDISC_RX_TASKLET)
488 static int stp_uart_fifo_init(void)
489 {
490     int err = 0;
491
492     /*add rx fifo*/
493     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
494     {
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)
498         {
499             UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.33)\n");
500             err = -1;
501         }
502     }
503     #else
504     {
505         g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC);
506         if (NULL == g_stp_uart_rx_fifo)
507         {
508             err = -2;
509             UART_ERR_FUNC("kzalloc for g_stp_uart_rx_fifo failed (kernel version > 2.6.33)\n");
510         }
511         err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_ATOMIC);
512         if (0 != err)
513         {
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;
517             err = -3;
518         }
519     }
520     #endif
521
522     if (0 == err)
523     {
524         if (NULL != g_stp_uart_rx_fifo)
525         {
526             kfifo_reset(g_stp_uart_rx_fifo);
527             UART_ERR_FUNC("stp_uart_fifo_init() success.\n");
528         }
529         else
530         {
531             err = -4;
532             UART_ERR_FUNC("abnormal case, err = 0 but g_stp_uart_rx_fifo = NULL, set err to %d\n", err);
533         }
534     }
535     else
536     {
537         UART_ERR_FUNC("stp_uart_fifo_init() failed.\n");
538     }
539     return err;
540 }
541
542 static int stp_uart_fifo_deinit(void)
543 {
544     if (NULL != g_stp_uart_rx_fifo)
545     {
546         kfifo_free(g_stp_uart_rx_fifo);
547         #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
548                 //do nothing
549         #else
550         kfree(g_stp_uart_rx_fifo);
551         #endif
552         g_stp_uart_rx_fifo = NULL;
553     }
554     return 0;
555 }
556
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;
563
564 #if LDISC_RX_TASKLET_RWLOCK
565     read_lock(&g_stp_uart_rx_handling_lock);
566 #endif
567
568     how_much_to_get = kfifo_len(g_stp_uart_rx_fifo);
569
570     if (how_much_to_get >= LOCAL_BUFFER_LEN)
571     {
572         flag = 1;
573         UART_INFO_FUNC ("fifolen(%d)\n", how_much_to_get);
574     }
575
576     do {
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);
579         #else
580         how_much_get= kfifo_out(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN);
581         #endif
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);
586
587 #if LDISC_RX_TASKLET_RWLOCK
588     read_unlock(&g_stp_uart_rx_handling_lock);
589 #endif
590
591     if (1 == flag)
592     {
593         UART_INFO_FUNC ("finish, fifolen(%d)\n", kfifo_len(g_stp_uart_rx_fifo));
594     }
595 }
596
597 /* stp_uart_tty_receive()
598  *
599  *     Called by tty low level driver when receive data is
600  *     available.
601  *
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
606  *
607  * Return Value:    None
608  */
609 static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
610 {
611     unsigned int fifo_avail_len;/* = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo);*/
612     unsigned int how_much_put = 0;
613
614 #if 0
615     {
616         struct timeval now;
617         do_gettimeofday(&now);
618         printk("[+STP][  ][R] %4d --> sec = %lu, --> usec --> %lu\n",
619             count, now.tv_sec, now.tv_usec);
620     }
621 #endif
622
623 #if LDISC_RX_TASKLET_RWLOCK
624     write_lock(&g_stp_uart_rx_handling_lock);
625 #endif
626
627     if (count > 2000) {
628         /*this is abnormal*/
629         UART_ERR_FUNC("abnormal: buffer count = %d\n", count);
630     }
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);
637         #else
638         how_much_put = kfifo_in(g_stp_uart_rx_fifo,(unsigned char *) data, count);
639         #endif
640
641 #if LDISC_RX_TASKLET_RWLOCK
642         /* George Test */
643         write_unlock(&g_stp_uart_rx_handling_lock);
644 #endif
645
646         /*schedule it!*/
647         tasklet_schedule(&g_stp_uart_rx_fifo_tasklet);
648     }
649     else {
650         UART_ERR_FUNC("stp_uart_tty_receive rxfifo is full!!\n");
651     }
652
653 #if 0
654     {
655         struct timeval now;
656         do_gettimeofday(&now);
657         printk("[-STP][  ][R] %4d --> sec = %lu, --> usec --> %lu\n",
658             count, now.tv_sec, now.tv_usec);
659     }
660 #endif
661
662 #if LDISC_RX_TASKLET_RWLOCK
663     /* George Test */
664     //write_unlock(&g_stp_uart_rx_handling_lock);
665 #endif
666
667 }
668
669 #elif (LDISC_RX == LDISC_RX_TTY_CB)
670 /* stp_uart_tty_receive()
671  *
672  *     Called by tty low level driver when receive data is
673  *     available.
674  *
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
679  *
680  * Return Value:    None
681  */
682 static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
683 {
684     //UART_INFO_FUNC("count = %d\n", count);
685
686     if (count > 2000){
687         /*this is abnormal*/
688         UART_WARN_FUNC("count = %d\n", count);
689     }
690
691 #if 0
692     {
693         struct timeval now;
694
695         do_gettimeofday(&now);
696
697         printk("[+STP][  ][R] %4d --> sec = %d, --> usec --> %d\n",
698             count, now.tv_sec, now.tv_usec);
699     }
700 #endif
701
702
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);
706
707     /* George Test: useless? */
708     /*tty_unthrottle(tty);*/
709
710 #if 0
711     {
712         struct timeval now;
713
714         do_gettimeofday(&now);
715
716         printk("[-STP][  ][R] %4d --> sec = %d, --> usec --> %d\n",
717             count, now.tv_sec, now.tv_usec);
718     }
719 #endif
720     return;
721 }
722
723 #elif (LDISC_RX == LDISC_RX_WORK)
724 static int stp_uart_fifo_init(void)
725 {
726     int err = 0;
727
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");
732         err = -4;
733         goto fifo_init_end;
734     }
735     #else
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");
739         err = -4;
740         goto fifo_init_end;
741     }
742     memset(g_stp_uart_rx_buf, 0, LDISC_RX_BUF_SIZE);
743     #endif
744
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);
747
748     /*add rx fifo*/
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");
754         err = -1;
755         goto fifo_init_end;
756     }
757     #else
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) {
761         err = -2;
762         UART_ERR_FUNC("kzalloc struct kfifo failed (kernel version > 2.6.33)\n");
763         goto fifo_init_end;
764     }
765
766     /* allocate kfifo data buffer then */
767     err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_KERNEL);
768     if (0 != err) {
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;
772         err = -3;
773         goto fifo_init_end;
774     }
775     #endif
776     UART_LOUD_FUNC("g_stp_uart_rx_fifo alloc ok\n");
777
778 fifo_init_end:
779
780     if (0 == err) {
781         /* kfifo init ok */
782         kfifo_reset(g_stp_uart_rx_fifo);
783         UART_DBG_FUNC("g_stp_uart_rx_fifo init success\n");
784     }
785     else {
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;
791         }
792     }
793
794     return err;
795 }
796
797 static int stp_uart_fifo_deinit(void)
798 {
799     if (g_stp_uart_rx_buf) {
800         vfree(g_stp_uart_rx_buf);
801         g_stp_uart_rx_buf = NULL;
802     }
803
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))
807         //do nothing
808         #else
809         kfree(g_stp_uart_rx_fifo);
810         #endif
811         g_stp_uart_rx_fifo = NULL;
812     }
813     return 0;
814 }
815
816 static void stp_uart_rx_worker (struct work_struct *work)
817 {
818     unsigned int read;
819
820     if (unlikely(!g_stp_uart_rx_fifo)) {
821         UART_ERR_FUNC("NULL rx fifo!\n");
822         return;
823     }
824     if (unlikely(!g_stp_uart_rx_buf)) {
825         UART_ERR_FUNC("NULL rx buf!\n");
826         return;
827     }
828
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);
834         if (likely(read)) {
835             mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read);
836         }
837     }
838 #else
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);
842         if (likely(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);
846         }
847     }
848 #endif
849
850     return;
851 }
852
853 /* stp_uart_tty_receive()
854  *
855  *     Called by tty low level driver when receive data is
856  *     available.
857  *
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
862  *
863  * Return Value:    None
864  */
865 static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
866 {
867     unsigned int written;
868
869     //UART_LOUD_FUNC("URX:%d\n", count);
870     if (unlikely(count > 2000)) {
871         UART_WARN_FUNC("abnormal: buffer count = %d\n", count);
872     }
873
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);
877         return;
878     }
879
880     /* need to check available buffer size? skip! */
881
882     /* need to lock fifo? skip for single writer single reader! */
883
884 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
885     written = kfifo_put(g_stp_uart_rx_fifo, (unsigned char *) data, count);
886 #else
887     written = kfifo_in(g_stp_uart_rx_fifo, (unsigned char *) data, count);
888 #endif
889     queue_work(g_stp_uart_rx_wq, g_stp_uart_rx_work);
890
891     if (unlikely(written != count)) {
892         UART_ERR_FUNC("c(%d),w(%d) bytes dropped\n", count, written);
893     }
894
895     return;
896 }
897
898 #else
899 #error "unknown LDISC_RX!" LDISC_RX
900 #endif
901
902 /* ------ LDISC part ------ */
903 /* stp_uart_tty_open
904  *
905  *     Called when line discipline changed to HCI_UART.
906  *
907  * Arguments:
908  *     tty    pointer to tty info structure
909  * Return Value:
910  *     0 if success, otherwise error code
911  */
912 static int stp_uart_tty_open(struct tty_struct *tty)
913 {
914     UART_DBG_FUNC("original receive_room(%d) low_latency(%d) in tty(%p)\n",
915         tty->receive_room, tty->low_latency, tty);
916
917     tty->receive_room = 65536;
918 #if LDISC_LOW_LATENCY
919     tty->low_latency = 1;
920 #endif
921     UART_DBG_FUNC("set receive_room(%d) low_latency(%d) to tty(%p)\n",
922         tty->receive_room, tty->low_latency, tty);
923
924     /* Flush any pending characters in the driver and line discipline. */
925
926     /* FIXME: why is this needed. Note don't use ldisc_ref here as the
927        open path is before the ldisc is referencable */
928
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);
933     }
934 #else
935     if (tty->ldisc.ops->flush_buffer) {
936         tty->ldisc.ops->flush_buffer(tty);
937     }
938 #endif
939
940     tty_driver_flush_buffer(tty);
941
942     stp_uart_tty_tx_init();
943
944     stp_tty = tty;
945
946     /* Register to STP-CORE */
947     mtk_wcn_stp_register_if_tx(STP_UART_IF_TX,  mtk_wcn_uart_tx);
948
949     return 0;
950 }
951
952 /* stp_uart_tty_close()
953  *
954  *    Called when the line discipline is changed to something
955  *    else, the tty is closed, or the tty detects a hangup.
956  */
957 static void stp_uart_tty_close(struct tty_struct *tty)
958 {
959     UART_DBG_FUNC("stp_uart_tty_close(): tty %p\n", tty);
960     mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL);
961
962     stp_uart_tty_tx_deinit();
963
964     return;
965 }
966
967 /* stp_uart_tty_wakeup()
968  *
969  *    Callback for transmit wakeup. Called when low level
970  *    device driver can accept more send data.
971  *
972  * Arguments:        tty    pointer to associated tty instance data
973  * Return Value:    None
974  */
975 static void stp_uart_tty_wakeup(struct tty_struct *tty)
976 {
977     /*
978     UART_INFO_FUNC("in\n");
979     clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
980     stp_uart_tx_wakeup(tty);
981     */
982
983     return;
984 }
985
986 /* stp_uart_tty_ioctl()
987  *
988  *    Process IOCTL system call for the tty device.
989  *
990  * Arguments:
991  *
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)
996  *
997  * Return Value:    Command dependent
998  */
999 static int stp_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
1000                     unsigned int cmd, unsigned long arg)
1001 {
1002     int err = 0;
1003
1004     UART_LOUD_FUNC("++ ll(%d)\n", tty->low_latency);
1005
1006     switch (cmd) {
1007     case HCIUARTSETPROTO:
1008 #if LDISC_LOW_LATENCY
1009         UART_INFO_FUNC("set low_latency to 1\n");
1010         tty->low_latency = 1;
1011 #endif
1012         break;
1013     default:
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);
1017         break;
1018     };
1019
1020     UART_LOUD_FUNC("--\n");
1021     return err;
1022 }
1023
1024 /*
1025  * We don't provide read/write/poll interface for user space.
1026  */
1027 static ssize_t stp_uart_tty_read(struct tty_struct *tty, struct file *file,
1028                     unsigned char __user *buf, size_t nr)
1029 {
1030     return 0;
1031 }
1032
1033 static ssize_t stp_uart_tty_write(struct tty_struct *tty, struct file *file,
1034                     const unsigned char *data, size_t count)
1035 {
1036     return 0;
1037 }
1038
1039 static unsigned int stp_uart_tty_poll(struct tty_struct *tty,
1040                     struct file *filp, poll_table *wait)
1041 {
1042     return 0;
1043 }
1044
1045 static INT32 mtk_wcn_uart_tx (
1046     const UINT8 *data,
1047     const UINT32 size,
1048     UINT32 *written_size
1049     )
1050 {
1051     INT32 ret;
1052     int tx_len;
1053
1054     if (unlikely(0 == size)) {
1055         /* special case for STP-CORE, return ASAP. */
1056         if (likely(written_size)) {
1057             *written_size = 0;
1058         }
1059         return 0;
1060     }
1061
1062     UART_LOUD_FUNC("++\n");
1063
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);
1067         ret = -1;
1068         goto uart_tx_out;
1069     }
1070
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);
1074         ret = -2;
1075         goto uart_tx_out;
1076     }
1077
1078     *written_size = 0;
1079
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);
1084         dump_stack();
1085         ret = -3;
1086         goto uart_tx_out;
1087     }
1088
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);
1092         ++tx_count;
1093         return 0;
1094     }
1095 #endif
1096
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);
1100         *written_size = 0;
1101         ret = -4;
1102     }
1103     else {
1104         *written_size = tx_len;
1105         ret = 0;
1106     }
1107
1108 uart_tx_out:
1109     UART_LOUD_FUNC("--(%d, %d)\n", ret, *written_size);
1110
1111     return ret;
1112 }
1113
1114 static int __init mtk_wcn_stp_uart_init(void)
1115 {
1116     static struct tty_ldisc_ops stp_uart_ldisc;
1117     int err;
1118     int fifo_init_done;
1119
1120     UART_INFO_FUNC("MTK STP UART driver\n");
1121
1122     fifo_init_done = 0;
1123
1124 #if (LDISC_RX == LDISC_RX_TASKLET)
1125     err = stp_uart_fifo_init();
1126     if (err != 0) {
1127         UART_ERR_FUNC("stp_uart_fifo_init(TASKLET) error(%d)\n", err);
1128         err = -EFAULT;
1129         goto init_err;
1130     }
1131     fifo_init_done = 1;
1132
1133     /*init rx tasklet*/
1134     tasklet_init(&g_stp_uart_rx_fifo_tasklet, stp_uart_rx_handling, (unsigned long) 0);
1135
1136 #elif (LDISC_RX == LDISC_RX_WORK)
1137     err = stp_uart_fifo_init();
1138     if (err != 0) {
1139         UART_ERR_FUNC("stp_uart_fifo_init(WORK) error(%d)\n", err);
1140         err = -EFAULT;
1141         goto init_err;
1142     }
1143     fifo_init_done = 1;
1144
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));
1148         err = -ENOMEM;
1149         goto init_err;
1150     }
1151
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");
1155         err = -ENOMEM;
1156         goto init_err;
1157     }
1158
1159     /* init rx work */
1160     INIT_WORK(g_stp_uart_rx_work, stp_uart_rx_worker);
1161 #endif
1162
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;
1176
1177     err = tty_register_ldisc(N_MTKSTP, &stp_uart_ldisc);
1178     if (err) {
1179         UART_ERR_FUNC("MTK STP line discipline(%d) registration failed. (%d)\n", N_MTKSTP, err);
1180         goto init_err;
1181     }
1182
1183     /* init ok */
1184     return 0;
1185
1186 init_err:
1187
1188 #if (LDISC_RX == LDISC_RX_TASKLET)
1189     /* nothing */
1190     if (fifo_init_done) {
1191         stp_uart_fifo_deinit();
1192     }
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;
1197     }
1198     if (g_stp_uart_rx_work) {
1199         vfree(g_stp_uart_rx_work);
1200     }
1201     if (fifo_init_done) {
1202         stp_uart_fifo_deinit();
1203     }
1204 #endif
1205     UART_ERR_FUNC("init fail, return(%d)\n", err);
1206
1207     return err;
1208 }
1209
1210 static void __exit mtk_wcn_stp_uart_exit(void)
1211 {
1212     int err;
1213
1214     mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL);    // unregister if_tx function
1215
1216     /* Release tty registration of line discipline */
1217     if ((err = tty_unregister_ldisc(N_MTKSTP)))
1218     {
1219         UART_ERR_FUNC("Can't unregister MTK STP line discipline (%d)\n", err);
1220     }
1221
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);
1228     }
1229     if (g_stp_uart_rx_wq) {
1230         destroy_workqueue(g_stp_uart_rx_wq);
1231         g_stp_uart_rx_wq = NULL;
1232     }
1233     if (g_stp_uart_rx_work) {
1234         vfree(g_stp_uart_rx_work);
1235         g_stp_uart_rx_work = NULL;
1236     }
1237     stp_uart_fifo_deinit();
1238 #endif
1239
1240     return;
1241 }
1242
1243 module_init(mtk_wcn_stp_uart_init);
1244 module_exit(mtk_wcn_stp_uart_exit);
1245
1246 //MODULE_LICENSE("Proprietary");
1247 MODULE_LICENSE("GPL");
1248 MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3");
1249 MODULE_DESCRIPTION("STP-HIF UART Interface");
1250