add MTK-combo-module,continue with commit 17f39ed917874e77e80411f33faba1b7ee8138c8
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_combo / common / linux / stp_chrdev_bt.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 #include <linux/init.h>
37 #include <linux/module.h>
38 #include <linux/types.h>
39 #include <linux/kernel.h>
40 #include <linux/fs.h>
41 #include <linux/cdev.h>
42 #include <linux/sched.h>
43 #include <asm/current.h>
44 #include <asm/uaccess.h>
45 #include <linux/fcntl.h>
46 #include <linux/poll.h>
47 #include <linux/time.h>
48 #include <linux/delay.h>
49 #include "stp_exp.h"
50 #include "wmt_exp.h"
51
52 MODULE_LICENSE("Dual BSD/GPL");
53
54 #define BT_DRIVER_NAME "mtk_stp_BT_chrdev"
55 #define BT_DEV_MAJOR 192 // never used number
56
57 #define PFX                         "[MTK-BT] "
58 #define BT_LOG_DBG                  3
59 #define BT_LOG_INFO                 2
60 #define BT_LOG_WARN                 1
61 #define BT_LOG_ERR                  0
62
63 #define COMBO_IOC_BT_HWVER           6
64
65 unsigned int gDbgLevel = BT_LOG_ERR;//BT_LOG_INFO; //Modify loglevel
66
67 #define BT_DBG_FUNC(fmt, arg...)    if(gDbgLevel >= BT_LOG_DBG){ printk(PFX "%s: "  fmt, __FUNCTION__ ,##arg);}
68 #define BT_INFO_FUNC(fmt, arg...)   if(gDbgLevel >= BT_LOG_INFO){ printk(PFX "%s: "  fmt, __FUNCTION__ ,##arg);}
69 #define BT_WARN_FUNC(fmt, arg...)   if(gDbgLevel >= BT_LOG_WARN){ printk(PFX "%s: "  fmt, __FUNCTION__ ,##arg);}
70 #define BT_ERR_FUNC(fmt, arg...)    if(gDbgLevel >= BT_LOG_ERR){ printk(PFX "%s: "   fmt, __FUNCTION__ ,##arg);}
71 #define BT_TRC_FUNC(f)              if(gDbgLevel >= BT_LOG_DBG){printk(PFX "<%s> <%d>\n", __FUNCTION__, __LINE__);}
72
73 #define VERSION "1.0"
74 #define BT_NVRAM_CUSTOM_NAME "/data/BT_Addr"
75
76 static int BT_devs = 1;        /* device count */
77 static int BT_major = BT_DEV_MAJOR;       /* dynamic allocation */
78 module_param(BT_major, uint, 0);
79 static struct cdev BT_cdev;
80
81 static unsigned char i_buf[MTKSTP_BUFFER_SIZE];    // input buffer of read()
82 static unsigned char o_buf[MTKSTP_BUFFER_SIZE];    // output buffer of write()
83 static struct semaphore wr_mtx, rd_mtx;
84 static wait_queue_head_t inq;    /* read queues */
85 static DECLARE_WAIT_QUEUE_HEAD(BT_wq);
86 static int flag = 0;
87 volatile int retflag = 0;
88
89 unsigned char g_bt_bd_addr[10]={0x01,0x1a,0xfc,0x06,0x00,0x55,0x66,0x77,0x88,0x00};
90 unsigned char g_nvram_btdata[8];
91
92 static int nvram_read(char *filename, char *buf, ssize_t len, int offset)
93 {
94     struct file *fd;
95     //ssize_t ret;
96     int retLen = -1;
97
98     mm_segment_t old_fs = get_fs();
99     set_fs(KERNEL_DS);
100
101     fd = filp_open(filename, O_WRONLY|O_CREAT, 0644);
102
103     if(IS_ERR(fd)) {
104         BT_ERR_FUNC("failed to open!!\n");
105         return -1;
106     }
107     do{
108         if ((fd->f_op == NULL) || (fd->f_op->read == NULL))
109             {
110             BT_ERR_FUNC("file can not be read!!\n");
111             break;
112             }
113
114         if (fd->f_pos != offset) {
115             if (fd->f_op->llseek) {
116                     if(fd->f_op->llseek(fd, offset, 0) != offset) {
117                         BT_ERR_FUNC("[nvram_read] : failed to seek!!\n");
118                         break;
119                     }
120               } else {
121                     fd->f_pos = offset;
122               }
123         }
124
125             retLen = fd->f_op->read(fd,
126                                           buf,
127                                           len,
128                                           &fd->f_pos);
129
130     }while(false);
131
132     filp_close(fd, NULL);
133
134     set_fs(old_fs);
135
136     return retLen;
137 }
138
139
140 int platform_load_nvram_data( char * filename, char * buf, int len)
141 {
142     //int ret;
143     BT_INFO_FUNC("platform_load_nvram_data ++ BDADDR\n");
144
145     return nvram_read( filename, buf, len, 0);
146 }
147
148 static void bt_cdev_rst_cb(
149     ENUM_WMTDRV_TYPE_T src,
150     ENUM_WMTDRV_TYPE_T dst,
151     ENUM_WMTMSG_TYPE_T type,
152     void *buf,
153     unsigned int sz){
154
155     /*
156         To handle reset procedure please
157     */
158     ENUM_WMTRSTMSG_TYPE_T rst_msg;
159
160     BT_INFO_FUNC("sizeof(ENUM_WMTRSTMSG_TYPE_T) = %d\n", sizeof(ENUM_WMTRSTMSG_TYPE_T));
161     if(sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)){
162         memcpy((char *)&rst_msg, (char *)buf, sz);
163         BT_INFO_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX);
164         if((src == WMTDRV_TYPE_WMT) &&
165             (dst == WMTDRV_TYPE_BT) &&
166                 (type == WMTMSG_TYPE_RESET)){
167                     if(rst_msg == WMTRSTMSG_RESET_START){
168                         BT_INFO_FUNC("BT restart start!\n");
169                         retflag = 1;
170                         wake_up_interruptible(&inq);
171                         /*reset_start message handling*/
172
173                     } else if(rst_msg == WMTRSTMSG_RESET_END){
174                         BT_INFO_FUNC("BT restart end!\n");
175                         retflag = 2;
176                         wake_up_interruptible(&inq);
177                         /*reset_end message handling*/
178                     }
179         }
180     } else {
181         /*message format invalid*/
182     BT_INFO_FUNC("message format invalid!\n");
183     }
184 }
185
186 void BT_event_cb(void)
187 {
188     BT_DBG_FUNC("BT_event_cb() \n");
189
190     flag = 1;
191     wake_up(&BT_wq);
192
193     /* finally, awake any reader */
194     wake_up_interruptible(&inq);  /* blocked in read() and select() */
195
196     return;
197 }
198
199 unsigned int BT_poll(struct file *filp, poll_table *wait)
200 {
201     unsigned int mask = 0;
202
203 //    down(&wr_mtx);
204     /*
205      * The buffer is circular; it is considered full
206      * if "wp" is right behind "rp". "left" is 0 if the
207      * buffer is empty, and it is "1" if it is completely full.
208      */
209     if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX))
210     {
211         poll_wait(filp, &inq,  wait);
212
213         /* empty let select sleep */
214         if((!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) || retflag)
215         {
216             mask |= POLLIN | POLLRDNORM;  /* readable */
217         }
218     }
219     else
220     {
221         mask |= POLLIN | POLLRDNORM;  /* readable */
222     }
223
224     /* do we need condition? */
225     mask |= POLLOUT | POLLWRNORM; /* writable */
226 //    up(&wr_mtx);
227     return mask;
228 }
229
230
231 ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
232 {
233     int retval = 0;
234     int written = 0;
235     down(&wr_mtx);
236
237     BT_DBG_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos);
238     if(retflag)
239     {
240         if (retflag == 1) //reset start
241         {
242             retval = -88;
243             BT_INFO_FUNC("MT6620 reset Write: start\n");
244         }
245         else if (retflag == 2) // reset end
246         {
247           retval = -99;
248             BT_INFO_FUNC("MT6620 reset Write: end\n");
249         }
250     goto OUT;
251     }
252
253     if (count > 0)
254     {
255         int copy_size = (count < MTKSTP_BUFFER_SIZE) ? count : MTKSTP_BUFFER_SIZE;
256         if (copy_from_user(&o_buf[0], &buf[0], copy_size))
257         {
258             retval = -EFAULT;
259             goto OUT;
260         }
261         //printk("%02x ", val);
262
263         written = mtk_wcn_stp_send_data(&o_buf[0], copy_size, BT_TASK_INDX);
264         if(0 == written)
265         {
266             retval = -ENOSPC;
267             /*no windowspace in STP is available, native process should not call BT_write with no delay at all*/
268             BT_ERR_FUNC("target packet length:%d, write success length:%d, retval = %d.\n", count, written, retval);
269         }
270         else
271         {
272             retval = written;
273         }
274
275     }else
276     {
277         retval = -EFAULT;
278         BT_ERR_FUNC("target packet length:%d is not allowed, retval = %d.\n", count, retval);
279     }
280
281 OUT:
282     up(&wr_mtx);
283     return (retval);
284 }
285
286 ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
287 {
288     int retval = 0;
289
290     down(&rd_mtx);
291
292     BT_DBG_FUNC("BT_read(): count %d pos %lld\n", count, *f_pos);
293     if(retflag)
294     {
295         if (retflag == 1) //reset start
296         {
297             retval = -88;
298             BT_INFO_FUNC("MT6620 reset Read: start\n");
299         }
300         else if (retflag == 2) // reset end
301         {
302           retval = -99;
303       BT_INFO_FUNC("MT6620 reset Read: end\n");
304         }
305     goto OUT;
306     }
307
308     if(count > MTKSTP_BUFFER_SIZE)
309     {
310         count = MTKSTP_BUFFER_SIZE;
311     }
312     retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX);
313
314     while(retval == 0) // got nothing, wait for STP's signal
315     {
316         /*If nonblocking mode, return directly O_NONBLOCK is specified during open() */
317         if (filp->f_flags & O_NONBLOCK){
318             BT_DBG_FUNC("Non-blocking BT_read() \n");
319             retval = -EAGAIN;
320             goto OUT;
321         }
322
323         BT_DBG_FUNC("BT_read(): wait_event 1\n");
324         wait_event(BT_wq, flag != 0);
325         BT_DBG_FUNC("BT_read(): wait_event 2\n");
326         flag = 0;
327         retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX);
328         BT_DBG_FUNC("BT_read(): mtk_wcn_stp_receive_data() = %d\n", retval);
329     }
330
331     // we got something from STP driver
332     if (copy_to_user(buf, i_buf, retval))
333     {
334         retval = -EFAULT;
335         goto OUT;
336     }
337
338 OUT:
339     up(&rd_mtx);
340     BT_DBG_FUNC("BT_read(): retval = %d\n", retval);
341     return (retval);
342 }
343
344 //int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
345 long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
346 {
347     int retval = 0;
348
349
350     ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID;
351     BT_DBG_FUNC("BT_ioctl(): cmd (%d)\n", cmd);
352
353     switch(cmd)
354     {
355 #if 0
356         case 0: // enable/disable STP
357             /* George: STP is controlled by WMT only */
358             /* mtk_wcn_stp_enable(arg); */
359             break;
360 #endif
361         case 1: // send raw data
362             BT_DBG_FUNC("BT_ioctl(): disable raw data from BT dev \n");
363             retval = -EINVAL;
364             break;
365         case COMBO_IOC_BT_HWVER:
366             /*get combo hw version*/
367             hw_ver_sym = mtk_wcn_wmt_hwver_get();
368
369             BT_INFO_FUNC("BT_ioctl(): get hw version = %d, sizeof(hw_ver_sym) = %d\n", hw_ver_sym, sizeof(hw_ver_sym));
370             if(copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))){
371                retval = -EFAULT;
372             }
373             break;
374         default:
375             retval = -EFAULT;
376             BT_DBG_FUNC("BT_ioctl(): unknown cmd (%d)\n", cmd);
377             break;
378     }
379
380     return retval;
381 }
382
383 static int BT_open(struct inode *inode, struct file *file)
384 {
385     BT_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__,
386         imajor(inode),
387         iminor(inode),
388         current->pid
389         );
390
391 #if 1 /* GeorgeKuo: turn on function before check stp ready */
392      /* turn on BT */
393     if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) {
394         BT_WARN_FUNC("WMT turn on BT fail!\n");
395         return -ENODEV;
396     }else{
397         retflag = 0;
398         mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb);
399         BT_INFO_FUNC("WMT register BT rst cb!\n");
400     }
401 #endif
402
403     if (mtk_wcn_stp_is_ready()) {
404 #if 0 /* GeorgeKuo: turn on function before check stp ready */
405          /* turn on BT */
406         if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) {
407             BT_WARN_FUNC("WMT turn on BT fail!\n");
408             return -ENODEV;
409         }
410 #endif
411         mtk_wcn_stp_set_bluez(0);
412
413         BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n");
414         BT_INFO_FUNC("WMT turn on BT OK!\n");
415         BT_INFO_FUNC("STP is ready!\n");
416         platform_load_nvram_data(BT_NVRAM_CUSTOM_NAME,
417             (char *)&g_nvram_btdata, sizeof(g_nvram_btdata));
418
419         BT_INFO_FUNC("Read NVRAM : BD address %02x%02x%02x%02x%02x%02x Cap 0x%02x Codec 0x%02x\n",
420             g_nvram_btdata[0], g_nvram_btdata[1], g_nvram_btdata[2],
421             g_nvram_btdata[3], g_nvram_btdata[4], g_nvram_btdata[5],
422             g_nvram_btdata[6], g_nvram_btdata[7]);
423
424         mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb);
425     }
426     else {
427         BT_ERR_FUNC("STP is not ready\n");
428
429         /*return error code*/
430         return -ENODEV;
431     }
432
433 //    init_MUTEX(&wr_mtx);
434     sema_init(&wr_mtx, 1);
435 //    init_MUTEX(&rd_mtx);
436     sema_init(&rd_mtx, 1);
437
438     return 0;
439 }
440
441 static int BT_close(struct inode *inode, struct file *file)
442 {
443     BT_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__,
444         imajor(inode),
445         iminor(inode),
446         current->pid
447         );
448     retflag = 0;
449     mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT);
450     mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL);
451
452     if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) {
453         BT_INFO_FUNC("WMT turn off BT fail!\n");
454         return -EIO;    //mostly, native programmer will not check this return value.
455     }
456     else {
457         BT_INFO_FUNC("WMT turn off BT OK!\n");
458     }
459
460     return 0;
461 }
462
463 struct file_operations BT_fops = {
464     .open = BT_open,
465     .release = BT_close,
466     .read = BT_read,
467     .write = BT_write,
468 //    .ioctl = BT_ioctl,
469     .unlocked_ioctl = BT_unlocked_ioctl,
470     .poll = BT_poll
471 };
472
473 static int BT_init(void)
474 {
475     dev_t dev = MKDEV(BT_major, 0);
476     int alloc_ret = 0;
477     int cdev_err = 0;
478
479     /*static allocate chrdev*/
480     alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME);
481     if (alloc_ret) {
482         BT_ERR_FUNC("fail to register chrdev\n");
483         return alloc_ret;
484     }
485
486     cdev_init(&BT_cdev, &BT_fops);
487     BT_cdev.owner = THIS_MODULE;
488
489     cdev_err = cdev_add(&BT_cdev, dev, BT_devs);
490     if (cdev_err)
491         goto error;
492
493     BT_INFO_FUNC("%s driver(major %d) installed.\n", BT_DRIVER_NAME, BT_major);
494     retflag = 0;
495     mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL);
496
497     /* init wait queue */
498     init_waitqueue_head(&(inq));
499
500     return 0;
501
502 error:
503     if (cdev_err == 0)
504         cdev_del(&BT_cdev);
505
506     if (alloc_ret == 0)
507         unregister_chrdev_region(dev, BT_devs);
508
509     return -1;
510 }
511
512 static void BT_exit(void)
513 {
514     dev_t dev = MKDEV(BT_major, 0);
515     retflag = 0;
516     mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL);  // unregister event callback function
517
518     cdev_del(&BT_cdev);
519     unregister_chrdev_region(dev, BT_devs);
520
521     BT_INFO_FUNC("%s driver removed.\n", BT_DRIVER_NAME);
522 }
523
524 module_init(BT_init);
525 module_exit(BT_exit);
526
527