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 #include <linux/init.h>
37 #include <linux/module.h>
38 #include <linux/types.h>
39 #include <linux/kernel.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>
52 MODULE_LICENSE("Dual BSD/GPL");
54 #define BT_DRIVER_NAME "mtk_stp_BT_chrdev"
55 #define BT_DEV_MAJOR 192 // never used number
57 #define PFX "[MTK-BT] "
63 #define COMBO_IOC_BT_HWVER 6
65 unsigned int gDbgLevel = BT_LOG_ERR;//BT_LOG_INFO; //Modify loglevel
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__);}
74 #define BT_NVRAM_CUSTOM_NAME "/data/BT_Addr"
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;
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);
87 volatile int retflag = 0;
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];
92 static int nvram_read(char *filename, char *buf, ssize_t len, int offset)
98 mm_segment_t old_fs = get_fs();
101 fd = filp_open(filename, O_WRONLY|O_CREAT, 0644);
104 BT_ERR_FUNC("failed to open!!\n");
108 if ((fd->f_op == NULL) || (fd->f_op->read == NULL))
110 BT_ERR_FUNC("file can not be read!!\n");
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");
125 retLen = fd->f_op->read(fd,
132 filp_close(fd, NULL);
140 int platform_load_nvram_data( char * filename, char * buf, int len)
143 BT_INFO_FUNC("platform_load_nvram_data ++ BDADDR\n");
145 return nvram_read( filename, buf, len, 0);
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,
156 To handle reset procedure please
158 ENUM_WMTRSTMSG_TYPE_T rst_msg;
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");
170 wake_up_interruptible(&inq);
171 /*reset_start message handling*/
173 } else if(rst_msg == WMTRSTMSG_RESET_END){
174 BT_INFO_FUNC("BT restart end!\n");
176 wake_up_interruptible(&inq);
177 /*reset_end message handling*/
181 /*message format invalid*/
182 BT_INFO_FUNC("message format invalid!\n");
186 void BT_event_cb(void)
188 BT_DBG_FUNC("BT_event_cb() \n");
193 /* finally, awake any reader */
194 wake_up_interruptible(&inq); /* blocked in read() and select() */
199 unsigned int BT_poll(struct file *filp, poll_table *wait)
201 unsigned int mask = 0;
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.
209 if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX))
211 poll_wait(filp, &inq, wait);
213 /* empty let select sleep */
214 if((!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) || retflag)
216 mask |= POLLIN | POLLRDNORM; /* readable */
221 mask |= POLLIN | POLLRDNORM; /* readable */
224 /* do we need condition? */
225 mask |= POLLOUT | POLLWRNORM; /* writable */
231 ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
237 BT_DBG_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos);
240 if (retflag == 1) //reset start
243 BT_INFO_FUNC("MT6620 reset Write: start\n");
245 else if (retflag == 2) // reset end
248 BT_INFO_FUNC("MT6620 reset Write: end\n");
255 int copy_size = (count < MTKSTP_BUFFER_SIZE) ? count : MTKSTP_BUFFER_SIZE;
256 if (copy_from_user(&o_buf[0], &buf[0], copy_size))
261 //printk("%02x ", val);
263 written = mtk_wcn_stp_send_data(&o_buf[0], copy_size, BT_TASK_INDX);
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);
278 BT_ERR_FUNC("target packet length:%d is not allowed, retval = %d.\n", count, retval);
286 ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
292 BT_DBG_FUNC("BT_read(): count %d pos %lld\n", count, *f_pos);
295 if (retflag == 1) //reset start
298 BT_INFO_FUNC("MT6620 reset Read: start\n");
300 else if (retflag == 2) // reset end
303 BT_INFO_FUNC("MT6620 reset Read: end\n");
308 if(count > MTKSTP_BUFFER_SIZE)
310 count = MTKSTP_BUFFER_SIZE;
312 retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX);
314 while(retval == 0) // got nothing, wait for STP's signal
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");
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");
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);
331 // we got something from STP driver
332 if (copy_to_user(buf, i_buf, retval))
340 BT_DBG_FUNC("BT_read(): retval = %d\n", retval);
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)
350 ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID;
351 BT_DBG_FUNC("BT_ioctl(): cmd (%d)\n", cmd);
356 case 0: // enable/disable STP
357 /* George: STP is controlled by WMT only */
358 /* mtk_wcn_stp_enable(arg); */
361 case 1: // send raw data
362 BT_DBG_FUNC("BT_ioctl(): disable raw data from BT dev \n");
365 case COMBO_IOC_BT_HWVER:
366 /*get combo hw version*/
367 hw_ver_sym = mtk_wcn_wmt_hwver_get();
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))){
376 BT_DBG_FUNC("BT_ioctl(): unknown cmd (%d)\n", cmd);
383 static int BT_open(struct inode *inode, struct file *file)
385 BT_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__,
391 #if 1 /* GeorgeKuo: turn on function before check stp ready */
393 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) {
394 BT_WARN_FUNC("WMT turn on BT fail!\n");
398 mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb);
399 BT_INFO_FUNC("WMT register BT rst cb!\n");
403 if (mtk_wcn_stp_is_ready()) {
404 #if 0 /* GeorgeKuo: turn on function before check stp ready */
406 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) {
407 BT_WARN_FUNC("WMT turn on BT fail!\n");
411 mtk_wcn_stp_set_bluez(0);
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));
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]);
424 mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb);
427 BT_ERR_FUNC("STP is not ready\n");
429 /*return error code*/
433 // init_MUTEX(&wr_mtx);
434 sema_init(&wr_mtx, 1);
435 // init_MUTEX(&rd_mtx);
436 sema_init(&rd_mtx, 1);
441 static int BT_close(struct inode *inode, struct file *file)
443 BT_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__,
449 mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT);
450 mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL);
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.
457 BT_INFO_FUNC("WMT turn off BT OK!\n");
463 struct file_operations BT_fops = {
468 // .ioctl = BT_ioctl,
469 .unlocked_ioctl = BT_unlocked_ioctl,
473 static int BT_init(void)
475 dev_t dev = MKDEV(BT_major, 0);
479 /*static allocate chrdev*/
480 alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME);
482 BT_ERR_FUNC("fail to register chrdev\n");
486 cdev_init(&BT_cdev, &BT_fops);
487 BT_cdev.owner = THIS_MODULE;
489 cdev_err = cdev_add(&BT_cdev, dev, BT_devs);
493 BT_INFO_FUNC("%s driver(major %d) installed.\n", BT_DRIVER_NAME, BT_major);
495 mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL);
497 /* init wait queue */
498 init_waitqueue_head(&(inq));
507 unregister_chrdev_region(dev, BT_devs);
512 static void BT_exit(void)
514 dev_t dev = MKDEV(BT_major, 0);
516 mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); // unregister event callback function
519 unregister_chrdev_region(dev, BT_devs);
521 BT_INFO_FUNC("%s driver removed.\n", BT_DRIVER_NAME);
524 module_init(BT_init);
525 module_exit(BT_exit);