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