]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Add GPS Proxy Driver
authorAnna Hanna Sedlak Grinbaum <asedla@codeaurora.org>
Sun, 10 Apr 2016 06:28:15 +0000 (09:28 +0300)
committerNicolas Dechesne <nicolas.dechesne@linaro.org>
Fri, 10 Jun 2016 07:59:38 +0000 (09:59 +0200)
The GPS Proxy Driver is a layer connecting between user space application and
GPSD service.

Change-Id: I8e4dd855839a1d9bc0b8f7431063fc200f8c2ebb
Signed-off-by: Anna Hanna Sedlak Grinbaum <asedla@codeaurora.org>
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/gps_proxy.c [new file with mode: 0644]
include/uapi/linux/gps_proxy.h [new file with mode: 0644]

index 9f244d633f3b7d474794e9ead629908ec8a0d1b9..4138de6da18b3724cc8a8b4aff236c88279c71e7 100644 (file)
@@ -83,6 +83,15 @@ config QCOM_WCNSS_CTRL
 config MSM_BUS_SCALING
        bool "Bus scaling driver"
        default n
 config MSM_BUS_SCALING
        bool "Bus scaling driver"
        default n
+
+config QTI_LNX_GPS_PROXY
+       tristate "User mode QTI_LNX_GPS_PROXY device driver support"
+       help
+         This supports user mode QTI_LNX_GPS_PROXY
+
+         Note that this application programming interface is EXPERIMENTAL
+         and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
+
        help
                This option enables bus scaling on MSM devices.  Bus scaling
                allows devices to request the clocks be set to rates sufficient
        help
                This option enables bus scaling on MSM devices.  Bus scaling
                allows devices to request the clocks be set to rates sufficient
index 49e0f7c3aeda0348b00978692e9bacd112b05da6..bf6f22a47a2b6db5520e2e56148606137aab60a2 100644 (file)
@@ -13,3 +13,5 @@ obj-$(CONFIG_MFD_QCOM_SMD_RPM) += rpm_log.o
 obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
 obj-$(CONFIG_BUS_TOPOLOGY_ADHOC) += msm_bus/
 obj-$(CONFIG_QCOM_IPCRTR_STUB) += ipcrtr_stub.o
 obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
 obj-$(CONFIG_BUS_TOPOLOGY_ADHOC) += msm_bus/
 obj-$(CONFIG_QCOM_IPCRTR_STUB) += ipcrtr_stub.o
+
+obj-$(CONFIG_QTI_LNX_GPS_PROXY) += gps_proxy.o
diff --git a/drivers/soc/qcom/gps_proxy.c b/drivers/soc/qcom/gps_proxy.c
new file mode 100644 (file)
index 0000000..6812962
--- /dev/null
@@ -0,0 +1,304 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <asm/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <uapi/linux/gps_proxy.h>
+
+/* Module information */
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL v2");
+
+#define LOC_SERVICE_SVC_ID     0x00000010
+#define LOC_SERVICE_V1                 2
+#define LOC_SERVICE_INS_ID     0
+
+#define DRIVER_VERSION                 "v1.0"
+#define DRIVER_DESC            "GPS TTY driver"
+#define MODULE_NAME            "gps_proxy"
+#define TTY_DRIVER_NAME        "gps_serial"
+#define TTY_DEV_NAME           "ttyGPS"
+#define MAX_TTY_BUFFER_SZ      0x10000
+#define GPS_TTY_MAJOR          100     /* experimental range */
+#define DEVICE_NAME            "gps_proxy_ch"
+#define CLASS_NAME             "gps_proxy_class"
+
+static struct tty_driver *gps_proxy_tty_driver;
+static struct tty_port gps_proxy_tty_port;
+static bool g_port_open = false;
+static struct semaphore g_port_sem;
+static int gps_proxy_ch_driver_major = 0;
+static struct class* gps_proxy_ch_class = 0;
+static struct device* gps_proxy_ch_dev = 0;
+
+static void serial_port_shutdown(struct tty_port *tport)
+{
+}
+
+static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
+{
+       return 0;
+}
+
+static struct tty_port_operations serial_port_ops = {
+       .activate = serial_port_activate,
+       .shutdown = serial_port_shutdown
+};
+
+static int gps_proxy_open(struct tty_struct *tty, struct file *file)
+{
+       int rc; 
+       rc = tty_port_open(&gps_proxy_tty_port, tty, file);
+       g_port_open = true;
+       up(&g_port_sem);
+       return rc;
+}
+
+static void gps_proxy_close(struct tty_struct *tty, struct file *file)
+{
+       tty_port_close(tty->port, tty, file);
+       g_port_open = false;
+       down(&g_port_sem);
+}
+
+static void gps_proxy_tty_hangup(struct tty_struct *tty)
+{
+       tty_port_hangup(tty->port);
+}
+
+static int gps_proxy_write(struct tty_struct *tty, 
+                     const unsigned char *buffer, int count)
+{
+       return count;
+}
+
+static int gps_proxy_write_room(struct tty_struct *tty) 
+{
+       return MAX_TTY_BUFFER_SZ;
+}
+
+static int gps_proxy_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+
+static int gps_proxy_tiocmget(struct tty_struct *tty)
+{
+       return 0;
+}
+
+static int gps_proxy_tiocmset(struct tty_struct *tty,
+                         unsigned int set, unsigned int clear)
+{
+       return 0;
+}
+
+static int gps_proxy_ioctl(struct tty_struct *tty,
+                      unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static struct tty_operations serial_ops = {
+       .open = gps_proxy_open,
+       .close = gps_proxy_close,
+       .hangup = gps_proxy_tty_hangup,
+       .write = gps_proxy_write,
+       .write_room = gps_proxy_write_room,
+       .chars_in_buffer = gps_proxy_tty_chars_in_buffer,
+       .tiocmget = gps_proxy_tiocmget,
+       .tiocmset = gps_proxy_tiocmset,
+       .ioctl = gps_proxy_ioctl,
+};
+
+int gps_proxy_ch_driver_open(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+int gps_proxy_ch_driver_close(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+long gps_proxy_chdev_ioctl(struct file *filp, unsigned int opt, unsigned long arg)
+{
+       int rc = 0;
+       struct gps_proxy_data buff;
+       switch (opt)
+       {
+               case QGPS_REGISTER_HANDLE:
+                       /* DOWN is necessary to make client wait till port is open */
+                       down(&g_port_sem);
+                       /* UP to semaphore is necessary here for close or
+                       next register handle (for parity) */
+                       up(&g_port_sem);
+                       rc = 0;
+                       break;
+               case QGPS_SEND_NMEA:
+                       pr_debug(KERN_INFO "Received string: %s\n", 
+                               ((struct gps_proxy_data*)arg)->nmea_string);
+                       rc = access_ok(struct gps_proxy_data, (struct gps_proxy_data*)arg,
+                                       sizeof(struct gps_proxy_data));
+                       if (!rc) {
+                               pr_err(KERN_ERR "Invalid argument was received\n");
+                               return rc;
+                       }
+                       rc = copy_from_user((void*)&buff, (void*)arg, sizeof(buff));
+                       if (rc) {
+                               pr_err(KERN_ERR "Number of bytes that \
+                                                couldn't be copied: %d", rc);
+                               return -EFAULT;
+                       }
+                       if (buff.nmea_length < QMI_LOC_NMEA_STRING_MAX_LENGTH_V02 + 1) {
+                               pr_debug(KERN_INFO "Received string: %s\n",
+                                       buff.nmea_string);
+                               rc = tty_insert_flip_string(&gps_proxy_tty_port, 
+                                               buff.nmea_string,
+                                               strnlen(buff.nmea_string,
+                                               QMI_LOC_NMEA_STRING_MAX_LENGTH_V02) + 1);
+                               if (rc < 0) {
+                                       pr_err(KERN_ERR "Error flipping string");
+                                       return rc;
+                               }
+                               tty_flip_buffer_push(&gps_proxy_tty_port);
+                       }
+                       else {
+                               pr_err(KERN_ERR "Illegal message size");
+                               rc = -EFAULT;
+                       }
+                       break;
+               case QGPS_IS_ACTIVE:
+                       if (g_port_open)
+                               rc = 0;
+                       else
+                               rc = -EFAULT;
+                       break;
+               default:
+                       rc = -EFAULT;
+                       break;
+       }
+       return rc;
+}
+
+struct file_operations gps_proxy_ch_driver_ops = {
+       open: gps_proxy_ch_driver_open,
+       unlocked_ioctl: gps_proxy_chdev_ioctl,
+       release: gps_proxy_ch_driver_close
+};
+
+static int __init gps_proxy_init(void)
+{
+       int rc;
+       struct device *ttydev;
+
+       sema_init(&g_port_sem,0);
+
+       gps_proxy_ch_driver_major = register_chrdev(0, "gps_proxy_ch_dev",
+                                                       &gps_proxy_ch_driver_ops);
+       if (gps_proxy_ch_driver_major < 0) {
+               pr_err(KERN_ERR "Failed to register char device\n");
+               return -EFAULT;
+       }
+       else {
+               pr_debug(KERN_INFO "char device registered with major %d\n",
+                       gps_proxy_ch_driver_major);
+       }
+
+       /* Register the device class */
+       gps_proxy_ch_class = class_create(THIS_MODULE, CLASS_NAME);
+       if (IS_ERR(gps_proxy_ch_class)){
+               unregister_chrdev(gps_proxy_ch_driver_major, DEVICE_NAME);
+               pr_debug(KERN_ALERT "Failed to register device class\n");
+               return -EFAULT;
+       }
+       pr_debug(KERN_INFO "EBBChar: device class registered correctly\n");
+
+       /* Register the device driver */
+       gps_proxy_ch_dev = device_create(gps_proxy_ch_class, NULL,
+                               MKDEV(gps_proxy_ch_driver_major, 0), NULL, DEVICE_NAME);
+       if (IS_ERR(gps_proxy_ch_dev)){
+               class_destroy(gps_proxy_ch_class);
+               unregister_chrdev(gps_proxy_ch_driver_major, DEVICE_NAME);
+               pr_debug(KERN_ALERT "Failed to create the device\n");
+               return -EFAULT;
+       }
+
+       /* allocate the tty driver */
+       gps_proxy_tty_driver = alloc_tty_driver(1);
+       if (!gps_proxy_tty_driver)
+               return -ENOMEM;
+
+       tty_port_init(&gps_proxy_tty_port);
+       gps_proxy_tty_port.ops = &serial_port_ops;
+
+       /* initialize the tty driver */
+       gps_proxy_tty_driver->driver_name = TTY_DRIVER_NAME;
+       gps_proxy_tty_driver->name = TTY_DEV_NAME;
+       gps_proxy_tty_driver->major = GPS_TTY_MAJOR;
+       gps_proxy_tty_driver->minor_start = 0;
+       gps_proxy_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       gps_proxy_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gps_proxy_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       gps_proxy_tty_driver->init_termios = tty_std_termios;
+
+       tty_set_operations(gps_proxy_tty_driver, &serial_ops);
+       /* register the tty driver */
+       rc = tty_register_driver(gps_proxy_tty_driver);
+       if (rc) {
+               pr_err("Failed to register gps_proxy tty driver\n");
+               put_tty_driver(gps_proxy_tty_driver);
+               return rc;
+       }
+
+       ttydev = tty_port_register_device(&gps_proxy_tty_port, gps_proxy_tty_driver, 0, 0);
+       if (IS_ERR(ttydev)) {
+               rc = PTR_ERR(ttydev);
+               pr_err("Failed to register gps_proxy tty proxy\n");
+               return rc;
+       }
+
+       pr_debug(KERN_INFO DRIVER_DESC " \n" DRIVER_VERSION);
+       return rc;
+}
+
+static void __exit gps_proxy_exit(void)
+{
+       tty_unregister_device(gps_proxy_tty_driver, 0);
+       tty_unregister_driver(gps_proxy_tty_driver);
+       unregister_chrdev(gps_proxy_ch_driver_major, "gps_proxy_ch_dev");
+       device_destroy(gps_proxy_ch_class, MKDEV(gps_proxy_ch_driver_major, 0));
+       class_unregister(gps_proxy_ch_class);
+       class_destroy(gps_proxy_ch_class);
+}
+
+late_initcall(gps_proxy_init);
+module_exit(gps_proxy_exit);
diff --git a/include/uapi/linux/gps_proxy.h b/include/uapi/linux/gps_proxy.h
new file mode 100644 (file)
index 0000000..5ac7f6b
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GPS_PROXY_H__
+#define __GPS_PROXY_H__
+
+#define QMI_LOC_NMEA_STRING_MAX_LENGTH_V02 201
+
+enum QGPS_TTY_IOCTL_CMDS {
+       QGPS_REGISTER_HANDLE_IOC = 0,
+       QGPS_SEND_NMEA_IOC,
+       QGPS_IS_ACTIVE_IOC,
+};
+
+#define QGPS_IOC_MAGIC                 'q'
+#define QGPS_REGISTER_HANDLE   _IO(QGPS_IOC_MAGIC, QGPS_REGISTER_HANDLE_IOC)
+#define QGPS_SEND_NMEA                 _IO(QGPS_IOC_MAGIC, QGPS_SEND_NMEA_IOC)
+#define QGPS_IS_ACTIVE                 _IO(QGPS_IOC_MAGIC, QGPS_IS_ACTIVE_IOC)
+
+struct gps_proxy_data {
+       size_t nmea_length;
+       char nmea_string[QMI_LOC_NMEA_STRING_MAX_LENGTH_V02];
+};
+
+#endif /* __GPS_PROXY_H__ */