Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
- index 88c79b4..fa81d23 100644
- --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
- +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
- @@ -1020,8 +1020,6 @@
- qcom,halt-regs = <&tcsr 0x18000 0x19000 0x1a000>;
- - status = "disabled";
- -
- mba {
- memory-region = <&mba_mem>;
- };
- diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
- index b00bccd..d7e64cc 100644
- --- a/drivers/soc/qcom/Kconfig
- +++ b/drivers/soc/qcom/Kconfig
- @@ -86,4 +86,12 @@ config QCOM_WCNSS_CTRL
- Client driver for the WCNSS_CTRL SMD channel, used to download nv
- firmware to a newly booted WCNSS chip.
- +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
- +
- +
- endmenu
- diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
- index fab4466..3f33fc4 100644
- --- a/drivers/soc/qcom/Makefile
- +++ b/drivers/soc/qcom/Makefile
- @@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
- obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
- obj-$(CONFIG_QCOM_SMSM) += smsm.o
- obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.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
- index 0000000..d0b129c
- --- /dev/null
- +++ b/drivers/soc/qcom/gps_proxy.c
- @@ -0,0 +1,308 @@
- +/* 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 */
- + if (!down_killable(&g_port_sem)) {
- + /* UP to semaphore is necessary here for close or
- + next register handle (for parity) */
- + up(&g_port_sem);
- + rc = 0;
- + }
- + else {
- + rc = -EFAULT;
- + }
- + 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
- index 0000000..5ac7f6b
- --- /dev/null
- +++ b/include/uapi/linux/gps_proxy.h
- @@ -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__ */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement