import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / common / linux / stp_chrdev_gps.c
1 /** $Log: stp_chrdev_gps.c $
2 *
3 * 12 13 2010 Sean.Wang
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()
7 */
8
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/fs.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>
20
21 #include "osal_typedef.h"
22 #include "stp_exp.h"
23 #include "wmt_exp.h"
24
25 MODULE_LICENSE("GPL");
26
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
31
32 #define PFX "[GPS] "
33 #define GPS_LOG_DBG 3
34 #define GPS_LOG_INFO 2
35 #define GPS_LOG_WARN 1
36 #define GPS_LOG_ERR 0
37
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
41
42 static UINT32 gDbgLevel = GPS_LOG_DBG;
43
44 #define GPS_DBG_FUNC(fmt, arg...) \
45 do { if (gDbgLevel >= GPS_LOG_DBG) \
46 pr_warn(PFX "%s: " fmt, __func__ , ##arg); \
47 } while (0)
48 #define GPS_INFO_FUNC(fmt, arg...) \
49 do { if (gDbgLevel >= GPS_LOG_INFO) \
50 pr_warn(PFX "%s: " fmt, __func__ , ##arg); \
51 } while (0)
52 #define GPS_WARN_FUNC(fmt, arg...) \
53 do { if (gDbgLevel >= GPS_LOG_WARN) \
54 pr_err(PFX "%s: " fmt, __func__ , ##arg); \
55 } while (0)
56 #define GPS_ERR_FUNC(fmt, arg...) \
57 do { if (gDbgLevel >= GPS_LOG_ERR) \
58 pr_err(PFX "%s: " fmt, __func__ , ##arg); \
59 } while (0)
60 #define GPS_TRC_FUNC(f) \
61 do { if (gDbgLevel >= GPS_LOG_DBG) \
62 pr_info(PFX "<%s> <%d>\n", __func__, __LINE__); \
63 } while (0)
64
65
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;
70
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);
75 static INT32 flag;
76
77 static VOID GPS_event_cb(VOID);
78
79 ssize_t GPS_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
80 {
81 INT32 retval = 0;
82 INT32 written = 0;
83 down(&wr_mtx);
84
85 /* GPS_TRC_FUNC(); */
86
87 /*pr_warn("%s: count %d pos %lld\n", __func__, count, *f_pos); */
88 if (count > 0) {
89 INT32 copy_size = (count < MTKSTP_BUFFER_SIZE) ? count : MTKSTP_BUFFER_SIZE;
90 if (copy_from_user(&o_buf[0], &buf[0], copy_size)) {
91 retval = -EFAULT;
92 goto out;
93 }
94 /* pr_warn("%02x ", val); */
95 #if GPS_DEBUG_TRACE_GPIO
96 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_LOW);
97 #endif
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);
101 #endif
102
103 #if GPS_DEBUG_DUMP
104 {
105 PUINT8 buf_ptr = &o_buf[0];
106 INT32 k = 0;
107 pr_warn("--[GPS-WRITE]--");
108 for (k = 0; k < 10; k++) {
109 if (k % 16 == 0)
110 pr_warn("\n");
111 pr_warn("0x%02x ", o_buf[k]);
112 }
113 pr_warn("\n");
114 }
115 #endif
116 /*
117 If cannot send successfully, enqueue again
118
119 if (written != copy_size) {
120 // George: FIXME! Move GPS retry handling from app to driver
121 }
122 */
123 if (0 == written) {
124 retval = -ENOSPC;
125 /*no windowspace in STP is available, native process should not call GPS_write with no delay at all */
126 GPS_ERR_FUNC
127 ("target packet length:%zd, write success length:%d, retval = %d.\n",
128 count, written, retval);
129 } else {
130 retval = written;
131 }
132 } else {
133 retval = -EFAULT;
134 GPS_ERR_FUNC("target packet length:%zd is not allowed, retval = %d.\n", count,
135 retval);
136 }
137 out:
138 up(&wr_mtx);
139 return (retval);
140 }
141
142 ssize_t GPS_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
143 {
144 INT32 val = 0;
145 INT32 retval;
146
147 down(&rd_mtx);
148
149 /* pr_warn("GPS_read(): count %d pos %lld\n", count, *f_pos);*/
150
151 if (count > MTKSTP_BUFFER_SIZE) {
152 count = MTKSTP_BUFFER_SIZE;
153 }
154 #if GPS_DEBUG_TRACE_GPIO
155 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW);
156 #endif
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);
160 #endif
161
162 while (retval == 0) /* got nothing, wait for STP's signal */
163 {
164 /*wait_event(GPS_wq, flag != 0); *//* George: let signal wake up */
165 val = wait_event_interruptible(GPS_wq, flag != 0);
166 flag = 0;
167
168 #if GPS_DEBUG_TRACE_GPIO
169 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW);
170 #endif
171
172 retval = mtk_wcn_stp_receive_data(i_buf, count, GPS_TASK_INDX);
173
174 #if GPS_DEBUG_TRACE_GPIO
175 mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH);
176 #endif
177 /* if we are signaled */
178 if (val) {
179 if (-ERESTARTSYS == val) {
180 GPS_INFO_FUNC("signaled by -ERESTARTSYS(%d)\n ", val);
181 } else {
182 GPS_INFO_FUNC("signaled by %d\n ", val);
183 }
184 break;
185 }
186 }
187
188 #if GPS_DEBUG_DUMP
189 {
190 PUINT8 buf_ptr = &i_buf[0];
191 INT32 k = 0;
192 pr_warn("--[GPS-READ]--");
193 for (k = 0; k < 10; k++) {
194 if (k % 16 == 0)
195 pr_warn("\n");
196 pr_warn("0x%02x ", i_buf[k]);
197 }
198 pr_warn("--\n");
199 }
200 #endif
201
202 if (retval) {
203 /* we got something from STP driver */
204 if (copy_to_user(buf, i_buf, retval)) {
205 retval = -EFAULT;
206 goto OUT;
207 } else {
208 /* success */
209 }
210 } else {
211 /* we got nothing from STP driver, being signaled */
212 retval = val;
213 }
214
215 OUT:
216 up(&rd_mtx);
217 /* pr_warn("GPS_read(): retval = %d\n", retval);*/
218 return (retval);
219 }
220
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)
223 {
224 INT32 retval = 0;
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);
229
230 switch (cmd) {
231 case 0: /* enable/disable STP */
232 GPS_INFO_FUNC(KERN_INFO "GPS_ioctl(): disable STP control from GPS dev\n");
233 retval = -EINVAL;
234 #if 1
235 #else
236 /* George: STP is controlled by WMT only */
237 mtk_wcn_stp_enable(arg);
238 #endif
239 break;
240
241 case 1: /* send raw data */
242 GPS_INFO_FUNC(KERN_INFO "GPS_ioctl(): disable raw data from GPS dev\n");
243 retval = -EINVAL;
244 break;
245
246 case COMBO_IOC_GPS_HWVER:
247 /*get combo hw version */
248 hw_ver_sym = mtk_wcn_wmt_hwver_get();
249
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))) {
254 retval = -EFAULT;
255 }
256 break;
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);
260
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))) {
263 retval = -EFAULT;
264 }
265 break;
266
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);
270
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))) {
273 retval = -EFAULT;
274 }
275 break;
276 default:
277 retval = -EFAULT;
278 GPS_INFO_FUNC(KERN_INFO "GPS_ioctl(): unknown cmd (%d)\n", cmd);
279 break;
280 }
281
282 /*OUT:*/
283 return retval;
284 }
285
286 long GPS_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
287 {
288 long ret;
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);
292 return ret;
293 }
294
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)
298 {
299
300 /*
301 To handle reset procedure please
302 */
303 ENUM_WMTRSTMSG_TYPE_T rst_msg;
304
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");
314
315 /*reset_start message handling */
316
317 } else if((rst_msg == WMTRSTMSG_RESET_END) || (rst_msg == WMTRSTMSG_RESET_END_FAIL)){
318 GPS_INFO_FUNC("gps restart end!\n");
319
320 /*reset_end message handling */
321 }
322 }
323 } else {
324 /*message format invalid */
325 }
326 }
327
328 static int GPS_open(struct inode *inode, struct file *file)
329 {
330 pr_warn("%s: major %d minor %d (pid %d)\n", __func__,
331 imajor(inode), iminor(inode), current->pid);
332 if (current->pid == 1)
333 return 0;
334
335 #if 1 /* GeorgeKuo: turn on function before check stp ready */
336 /* turn on BT */
337
338 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS)) {
339 GPS_WARN_FUNC("WMT turn on GPS fail!\n");
340 return -ENODEV;
341 } else {
342 mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_GPS, gps_cdev_rst_cb);
343 GPS_INFO_FUNC("WMT turn on GPS OK!\n");
344 }
345 #endif
346
347 if (mtk_wcn_stp_is_ready()) {
348 #if 0
349 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS)) {
350 GPS_WARN_FUNC("WMT turn on GPS fail!\n");
351 return -ENODEV;
352 }
353 GPS_INFO_FUNC("WMT turn on GPS OK!\n");
354 #endif
355 mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, GPS_event_cb);
356 } else {
357 GPS_ERR_FUNC("STP is not ready, Cannot open GPS Devices\n\r");
358
359 /*return error code */
360 return -ENODEV;
361 }
362
363 /* init_MUTEX(&wr_mtx); */
364 sema_init(&wr_mtx, 1);
365 /* init_MUTEX(&rd_mtx); */
366 sema_init(&rd_mtx, 1);
367
368 return 0;
369 }
370
371 static int GPS_close(struct inode *inode, struct file *file)
372 {
373 pr_warn("%s: major %d minor %d (pid %d)\n", __func__,
374 imajor(inode), iminor(inode), current->pid);
375 if (current->pid == 1)
376 return 0;
377
378 /*Flush Rx Queue */
379 mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, 0x0); /* unregister event callback function */
380 mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_GPS);
381
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. */
385 } else {
386 GPS_INFO_FUNC("WMT turn off GPS OK!\n");
387 }
388
389 return 0;
390 }
391
392 struct file_operations GPS_fops = {
393 .open = GPS_open,
394 .release = GPS_close,
395 .read = GPS_read,
396 .write = GPS_write,
397 /* .ioctl = GPS_ioctl */
398 .unlocked_ioctl = GPS_unlocked_ioctl,
399 .compat_ioctl = GPS_compat_ioctl,
400 };
401
402 VOID GPS_event_cb(VOID)
403 {
404 /* pr_warn("GPS_event_cb()\n");*/
405
406 flag = 1;
407 wake_up(&GPS_wq);
408
409 return;
410 }
411
412 #if REMOVE_MK_NODE
413 struct class *stpgps_class = NULL;
414 #endif
415
416 static int GPS_init(void)
417 {
418 dev_t dev = MKDEV(GPS_major, 0);
419 INT32 alloc_ret = 0;
420 INT32 cdev_err = 0;
421 #if REMOVE_MK_NODE
422 struct device *stpgps_dev = NULL;
423 #endif
424
425 /*static allocate chrdev */
426 alloc_ret = register_chrdev_region(dev, 1, GPS_DRIVER_NAME);
427 if (alloc_ret) {
428 pr_warn("fail to register chrdev\n");
429 return alloc_ret;
430 }
431
432 cdev_init(&GPS_cdev, &GPS_fops);
433 GPS_cdev.owner = THIS_MODULE;
434
435 cdev_err = cdev_add(&GPS_cdev, dev, GPS_devs);
436 if (cdev_err)
437 goto error;
438 #if REMOVE_MK_NODE
439
440 stpgps_class = class_create(THIS_MODULE, "stpgps");
441 if (IS_ERR(stpgps_class))
442 goto error;
443 stpgps_dev = device_create(stpgps_class, NULL, dev, NULL, "stpgps");
444 if (IS_ERR(stpgps_dev))
445 goto error;
446 #endif
447 pr_warn(KERN_ALERT "%s driver(major %d) installed.\n", GPS_DRIVER_NAME, GPS_major);
448
449 return 0;
450
451 error:
452
453 #if REMOVE_MK_NODE
454 if (!IS_ERR(stpgps_dev))
455 device_destroy(stpgps_class, dev);
456 if (!IS_ERR(stpgps_class)) {
457 class_destroy(stpgps_class);
458 stpgps_class = NULL;
459 }
460 #endif
461 if (cdev_err == 0)
462 cdev_del(&GPS_cdev);
463
464 if (alloc_ret == 0)
465 unregister_chrdev_region(dev, GPS_devs);
466
467 return -1;
468 }
469
470 static void GPS_exit(void)
471 {
472 dev_t dev = MKDEV(GPS_major, 0);
473 #if REMOVE_MK_NODE
474 device_destroy(stpgps_class, dev);
475 class_destroy(stpgps_class);
476 stpgps_class = NULL;
477 #endif
478
479 cdev_del(&GPS_cdev);
480 unregister_chrdev_region(dev, GPS_devs);
481
482 pr_warn(KERN_ALERT "%s driver removed.\n", GPS_DRIVER_NAME);
483 }
484
485
486 #ifdef MTK_WCN_REMOVE_KERNEL_MODULE
487
488 INT32 mtk_wcn_stpgps_drv_init(VOID)
489 {
490 return GPS_init();
491 }
492
493 VOID mtk_wcn_stpgps_drv_exit(VOID)
494 {
495 return GPS_exit();
496 }
497
498
499 EXPORT_SYMBOL(mtk_wcn_stpgps_drv_init);
500 EXPORT_SYMBOL(mtk_wcn_stpgps_drv_exit);
501 #else
502
503 module_init(GPS_init);
504 module_exit(GPS_exit);
505
506 #endif