1 /** $Log: stp_chrdev_gps.c $
4 * (1) Add GPS_DEBUG_TRACE_GPIO to disable GPIO debugging trace
5 * (2) Add GPS_DEBUG_DUMP to support GPS data dump
6 * (3) Add mtk_wcn_stp_is_ready() check in GPS_open()
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
14 #include <linux/cdev.h>
15 #include <linux/sched.h>
16 #include <asm/current.h>
17 #include <asm/uaccess.h>
18 #include <linux/skbuff.h>
19 #include <linux/device.h>
21 #include "osal_typedef.h"
25 MODULE_LICENSE("GPL");
27 #define GPS_DRIVER_NAME "mtk_stp_GPS_chrdev"
28 #define GPS_DEV_MAJOR 191 /* never used number */
29 #define GPS_DEBUG_TRACE_GPIO 0
30 #define GPS_DEBUG_DUMP 0
34 #define GPS_LOG_INFO 2
35 #define GPS_LOG_WARN 1
38 #define COMBO_IOC_GPS_HWVER 6
39 #define COMBO_IOC_GPS_IC_HW_VERSION 7
40 #define COMBO_IOC_GPS_IC_FW_VERSION 8
42 static UINT32 gDbgLevel
= GPS_LOG_DBG
;
44 #define GPS_DBG_FUNC(fmt, arg...) \
45 do { if (gDbgLevel >= GPS_LOG_DBG) \
46 pr_warn(PFX "%s: " fmt, __func__ , ##arg); \
48 #define GPS_INFO_FUNC(fmt, arg...) \
49 do { if (gDbgLevel >= GPS_LOG_INFO) \
50 pr_warn(PFX "%s: " fmt, __func__ , ##arg); \
52 #define GPS_WARN_FUNC(fmt, arg...) \
53 do { if (gDbgLevel >= GPS_LOG_WARN) \
54 pr_err(PFX "%s: " fmt, __func__ , ##arg); \
56 #define GPS_ERR_FUNC(fmt, arg...) \
57 do { if (gDbgLevel >= GPS_LOG_ERR) \
58 pr_err(PFX "%s: " fmt, __func__ , ##arg); \
60 #define GPS_TRC_FUNC(f) \
61 do { if (gDbgLevel >= GPS_LOG_DBG) \
62 pr_info(PFX "<%s> <%d>\n", __func__, __LINE__); \
66 static INT32 GPS_devs
= 1; /* device count */
67 static INT32 GPS_major
= GPS_DEV_MAJOR
; /* dynamic allocation */
68 module_param(GPS_major
, uint
, 0);
69 static struct cdev GPS_cdev
;
71 static UINT8 i_buf
[MTKSTP_BUFFER_SIZE
]; /* input buffer of read() */
72 static UINT8 o_buf
[MTKSTP_BUFFER_SIZE
]; /* output buffer of write() */
73 static struct semaphore wr_mtx
, rd_mtx
;
74 static DECLARE_WAIT_QUEUE_HEAD(GPS_wq
);
77 static VOID
GPS_event_cb(VOID
);
79 ssize_t
GPS_write(struct file
*filp
, const char __user
*buf
, size_t count
, loff_t
*f_pos
)
87 /*pr_warn("%s: count %d pos %lld\n", __func__, count, *f_pos); */
89 INT32 copy_size
= (count
< MTKSTP_BUFFER_SIZE
) ? count
: MTKSTP_BUFFER_SIZE
;
90 if (copy_from_user(&o_buf
[0], &buf
[0], copy_size
)) {
94 /* pr_warn("%02x ", val); */
95 #if GPS_DEBUG_TRACE_GPIO
96 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX
, DBG_TIE_LOW
);
98 written
= mtk_wcn_stp_send_data(&o_buf
[0], copy_size
, GPS_TASK_INDX
);
99 #if GPS_DEBUG_TRACE_GPIO
100 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX
, DBG_TIE_HIGH
);
105 PUINT8 buf_ptr
= &o_buf
[0];
107 pr_warn("--[GPS-WRITE]--");
108 for (k
= 0; k
< 10; k
++) {
111 pr_warn("0x%02x ", o_buf
[k
]);
117 If cannot send successfully, enqueue again
119 if (written != copy_size) {
120 // George: FIXME! Move GPS retry handling from app to driver
125 /*no windowspace in STP is available, native process should not call GPS_write with no delay at all */
127 ("target packet length:%zd, write success length:%d, retval = %d.\n",
128 count
, written
, retval
);
134 GPS_ERR_FUNC("target packet length:%zd is not allowed, retval = %d.\n", count
,
142 ssize_t
GPS_read(struct file
*filp
, char __user
*buf
, size_t count
, loff_t
*f_pos
)
149 /* pr_warn("GPS_read(): count %d pos %lld\n", count, *f_pos);*/
151 if (count
> MTKSTP_BUFFER_SIZE
) {
152 count
= MTKSTP_BUFFER_SIZE
;
154 #if GPS_DEBUG_TRACE_GPIO
155 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX
, DBG_TIE_LOW
);
157 retval
= mtk_wcn_stp_receive_data(i_buf
, count
, GPS_TASK_INDX
);
158 #if GPS_DEBUG_TRACE_GPIO
159 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX
, DBG_TIE_HIGH
);
162 while (retval
== 0) /* got nothing, wait for STP's signal */
164 /*wait_event(GPS_wq, flag != 0); *//* George: let signal wake up */
165 val
= wait_event_interruptible(GPS_wq
, flag
!= 0);
168 #if GPS_DEBUG_TRACE_GPIO
169 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX
, DBG_TIE_LOW
);
172 retval
= mtk_wcn_stp_receive_data(i_buf
, count
, GPS_TASK_INDX
);
174 #if GPS_DEBUG_TRACE_GPIO
175 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX
, DBG_TIE_HIGH
);
177 /* if we are signaled */
179 if (-ERESTARTSYS
== val
) {
180 GPS_INFO_FUNC("signaled by -ERESTARTSYS(%d)\n ", val
);
182 GPS_INFO_FUNC("signaled by %d\n ", val
);
190 PUINT8 buf_ptr
= &i_buf
[0];
192 pr_warn("--[GPS-READ]--");
193 for (k
= 0; k
< 10; k
++) {
196 pr_warn("0x%02x ", i_buf
[k
]);
203 /* we got something from STP driver */
204 if (copy_to_user(buf
, i_buf
, retval
)) {
211 /* we got nothing from STP driver, being signaled */
217 /* pr_warn("GPS_read(): retval = %d\n", retval);*/
221 /* int GPS_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */
222 long GPS_unlocked_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
225 ENUM_WMTHWVER_TYPE_T hw_ver_sym
= WMTHWVER_INVALID
;
226 UINT32 hw_version
= 0;
227 UINT32 fw_version
= 0;
228 pr_warn("GPS_ioctl(): cmd (%d)\n", cmd
);
231 case 0: /* enable/disable STP */
232 GPS_INFO_FUNC(KERN_INFO
"GPS_ioctl(): disable STP control from GPS dev\n");
236 /* George: STP is controlled by WMT only */
237 mtk_wcn_stp_enable(arg
);
241 case 1: /* send raw data */
242 GPS_INFO_FUNC(KERN_INFO
"GPS_ioctl(): disable raw data from GPS dev\n");
246 case COMBO_IOC_GPS_HWVER
:
247 /*get combo hw version */
248 hw_ver_sym
= mtk_wcn_wmt_hwver_get();
250 GPS_INFO_FUNC(KERN_INFO
251 "GPS_ioctl(): get hw version = %d, sizeof(hw_ver_sym) = %zd\n",
252 hw_ver_sym
, sizeof(hw_ver_sym
));
253 if (copy_to_user((int __user
*)arg
, &hw_ver_sym
, sizeof(hw_ver_sym
))) {
257 case COMBO_IOC_GPS_IC_HW_VERSION
:
258 /*get combo hw version from ic, without wmt mapping */
259 hw_version
= mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER
);
261 GPS_INFO_FUNC(KERN_INFO
"GPS_ioctl(): get hw version = 0x%x\n", hw_version
);
262 if (copy_to_user((int __user
*)arg
, &hw_version
, sizeof(hw_version
))) {
267 case COMBO_IOC_GPS_IC_FW_VERSION
:
268 /*get combo fw version from ic, without wmt mapping */
269 fw_version
= mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER
);
271 GPS_INFO_FUNC(KERN_INFO
"GPS_ioctl(): get fw version = 0x%x\n", fw_version
);
272 if (copy_to_user((int __user
*)arg
, &fw_version
, sizeof(fw_version
))) {
278 GPS_INFO_FUNC(KERN_INFO
"GPS_ioctl(): unknown cmd (%d)\n", cmd
);
286 long GPS_compat_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
289 pr_warn("%s: cmd (%d)\n", __func__
, cmd
);
290 ret
= GPS_unlocked_ioctl(filp
, cmd
, arg
);
291 pr_warn("%s: cmd (%d)\n", __func__
, cmd
);
295 static VOID
gps_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src
,
296 ENUM_WMTDRV_TYPE_T dst
,
297 ENUM_WMTMSG_TYPE_T type
, PVOID buf
, UINT32 sz
)
301 To handle reset procedure please
303 ENUM_WMTRSTMSG_TYPE_T rst_msg
;
305 GPS_INFO_FUNC("sizeof(ENUM_WMTRSTMSG_TYPE_T) = %zd\n", sizeof(ENUM_WMTRSTMSG_TYPE_T
));
306 if (sz
<= sizeof(ENUM_WMTRSTMSG_TYPE_T
)) {
307 memcpy((PINT8
)&rst_msg
, (PINT8
)buf
, sz
);
308 GPS_INFO_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src
,
309 dst
, type
, rst_msg
, sz
, WMTRSTMSG_RESET_MAX
);
310 if ((src
== WMTDRV_TYPE_WMT
) && (dst
== WMTDRV_TYPE_GPS
)
311 && (type
== WMTMSG_TYPE_RESET
)) {
312 if (rst_msg
== WMTRSTMSG_RESET_START
) {
313 GPS_INFO_FUNC("gps restart start!\n");
315 /*reset_start message handling */
317 } else if((rst_msg
== WMTRSTMSG_RESET_END
) || (rst_msg
== WMTRSTMSG_RESET_END_FAIL
)){
318 GPS_INFO_FUNC("gps restart end!\n");
320 /*reset_end message handling */
324 /*message format invalid */
328 static int GPS_open(struct inode
*inode
, struct file
*file
)
330 pr_warn("%s: major %d minor %d (pid %d)\n", __func__
,
331 imajor(inode
), iminor(inode
), current
->pid
);
332 if (current
->pid
== 1)
335 #if 1 /* GeorgeKuo: turn on function before check stp ready */
338 if (MTK_WCN_BOOL_FALSE
== mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS
)) {
339 GPS_WARN_FUNC("WMT turn on GPS fail!\n");
342 mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_GPS
, gps_cdev_rst_cb
);
343 GPS_INFO_FUNC("WMT turn on GPS OK!\n");
347 if (mtk_wcn_stp_is_ready()) {
349 if (MTK_WCN_BOOL_FALSE
== mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS
)) {
350 GPS_WARN_FUNC("WMT turn on GPS fail!\n");
353 GPS_INFO_FUNC("WMT turn on GPS OK!\n");
355 mtk_wcn_stp_register_event_cb(GPS_TASK_INDX
, GPS_event_cb
);
357 GPS_ERR_FUNC("STP is not ready, Cannot open GPS Devices\n\r");
359 /*return error code */
363 /* init_MUTEX(&wr_mtx); */
364 sema_init(&wr_mtx
, 1);
365 /* init_MUTEX(&rd_mtx); */
366 sema_init(&rd_mtx
, 1);
371 static int GPS_close(struct inode
*inode
, struct file
*file
)
373 pr_warn("%s: major %d minor %d (pid %d)\n", __func__
,
374 imajor(inode
), iminor(inode
), current
->pid
);
375 if (current
->pid
== 1)
379 mtk_wcn_stp_register_event_cb(GPS_TASK_INDX
, 0x0); /* unregister event callback function */
380 mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_GPS
);
382 if (MTK_WCN_BOOL_FALSE
== mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS
)) {
383 GPS_WARN_FUNC("WMT turn off GPS fail!\n");
384 return -EIO
; /* mostly, native programer does not care this return vlaue, but we still return error code. */
386 GPS_INFO_FUNC("WMT turn off GPS OK!\n");
392 struct file_operations GPS_fops
= {
394 .release
= GPS_close
,
397 /* .ioctl = GPS_ioctl */
398 .unlocked_ioctl
= GPS_unlocked_ioctl
,
399 .compat_ioctl
= GPS_compat_ioctl
,
402 VOID
GPS_event_cb(VOID
)
404 /* pr_warn("GPS_event_cb()\n");*/
413 struct class *stpgps_class
= NULL
;
416 static int GPS_init(void)
418 dev_t dev
= MKDEV(GPS_major
, 0);
422 struct device
*stpgps_dev
= NULL
;
425 /*static allocate chrdev */
426 alloc_ret
= register_chrdev_region(dev
, 1, GPS_DRIVER_NAME
);
428 pr_warn("fail to register chrdev\n");
432 cdev_init(&GPS_cdev
, &GPS_fops
);
433 GPS_cdev
.owner
= THIS_MODULE
;
435 cdev_err
= cdev_add(&GPS_cdev
, dev
, GPS_devs
);
440 stpgps_class
= class_create(THIS_MODULE
, "stpgps");
441 if (IS_ERR(stpgps_class
))
443 stpgps_dev
= device_create(stpgps_class
, NULL
, dev
, NULL
, "stpgps");
444 if (IS_ERR(stpgps_dev
))
447 pr_warn(KERN_ALERT
"%s driver(major %d) installed.\n", GPS_DRIVER_NAME
, GPS_major
);
454 if (!IS_ERR(stpgps_dev
))
455 device_destroy(stpgps_class
, dev
);
456 if (!IS_ERR(stpgps_class
)) {
457 class_destroy(stpgps_class
);
465 unregister_chrdev_region(dev
, GPS_devs
);
470 static void GPS_exit(void)
472 dev_t dev
= MKDEV(GPS_major
, 0);
474 device_destroy(stpgps_class
, dev
);
475 class_destroy(stpgps_class
);
480 unregister_chrdev_region(dev
, GPS_devs
);
482 pr_warn(KERN_ALERT
"%s driver removed.\n", GPS_DRIVER_NAME
);
486 #ifdef MTK_WCN_REMOVE_KERNEL_MODULE
488 INT32
mtk_wcn_stpgps_drv_init(VOID
)
493 VOID
mtk_wcn_stpgps_drv_exit(VOID
)
499 EXPORT_SYMBOL(mtk_wcn_stpgps_drv_init
);
500 EXPORT_SYMBOL(mtk_wcn_stpgps_drv_exit
);
503 module_init(GPS_init
);
504 module_exit(GPS_exit
);