ANDROID: gnss: Add command line test driver
This driver enables the "takeover" of a serdev bus device by the GNSS
subsystem. It can be used to test the GNSS subsystem without needing to
write a specific hardware backend.
The new module supports the following parameters:
gnss_cmdline.serdev=driver/port/serdev
gnss_cmdline.type=<protocol number>
An example which allows GNSS to wrap a platform serial8250 port and
advertise NMEA-0183 data is:
gnss_cmdline.serdev=serial8250/serial0/serial0-0
^ ^ ^
driver port serdev
gnss_cmdline.type=0
^
GNSS_TYPE_NMEA
Bug: 146517987
Change-Id: I421386ee4f2ba8f1f0832d9c56a067a600892d3c
Signed-off-by: Alistair Delva <adelva@google.com>
This commit is contained in:
@@ -54,4 +54,19 @@ config GNSS_UBX_SERIAL
|
|||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config GNSS_CMDLINE_SERIAL
|
||||||
|
tristate "Command line test driver for GNSS"
|
||||||
|
depends on SERIAL_DEV_BUS
|
||||||
|
select GNSS_SERIAL
|
||||||
|
---help---
|
||||||
|
Say Y here if you want to test the GNSS subsystem but do not have a
|
||||||
|
way to communicate a binding through firmware such as DT or ACPI.
|
||||||
|
The correct serdev device and protocol type must be specified on
|
||||||
|
the module command line.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module will
|
||||||
|
be called gnss-cmdline.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
endif # GNSS
|
endif # GNSS
|
||||||
|
|||||||
@@ -17,3 +17,6 @@ gnss-sirf-y := sirf.o
|
|||||||
|
|
||||||
obj-$(CONFIG_GNSS_UBX_SERIAL) += gnss-ubx.o
|
obj-$(CONFIG_GNSS_UBX_SERIAL) += gnss-ubx.o
|
||||||
gnss-ubx-y := ubx.o
|
gnss-ubx-y := ubx.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_GNSS_CMDLINE_SERIAL) += gnss-cmdline.o
|
||||||
|
gnss-cmdline-y := cmdline.o
|
||||||
|
|||||||
139
drivers/gnss/cmdline.c
Normal file
139
drivers/gnss/cmdline.c
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Test driver for GNSS. This driver requires the serdev binding and protocol
|
||||||
|
* type to be specified on the module command line.
|
||||||
|
*
|
||||||
|
* Copyright 2019 Google LLC
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/gnss.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/serdev.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
|
#define GNSS_CMDLINE_MODULE_NAME "gnss-cmdline"
|
||||||
|
|
||||||
|
#define gnss_cmdline_err(...) \
|
||||||
|
pr_err(GNSS_CMDLINE_MODULE_NAME ": " __VA_ARGS__)
|
||||||
|
|
||||||
|
static char *serdev;
|
||||||
|
module_param(serdev, charp, 0644);
|
||||||
|
MODULE_PARM_DESC(serdev, "serial device to wrap");
|
||||||
|
|
||||||
|
static int type;
|
||||||
|
module_param(type, int, 0644);
|
||||||
|
MODULE_PARM_DESC(serdev, "GNSS protocol type (see 'enum gnss_type')");
|
||||||
|
|
||||||
|
static struct serdev_device *serdev_device;
|
||||||
|
|
||||||
|
static int name_match(struct device *dev, void *data)
|
||||||
|
{
|
||||||
|
return strstr(dev_name(dev), data) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init gnss_cmdline_init(void)
|
||||||
|
{
|
||||||
|
struct device *serial_dev, *port_dev, *serdev_dev;
|
||||||
|
char *driver_name, *port_name, *serdev_name;
|
||||||
|
char *serdev_dup, *serdev_dup_sep;
|
||||||
|
struct gnss_serial *gserial;
|
||||||
|
int err = -ENODEV;
|
||||||
|
|
||||||
|
/* User did not set the serdev module parameter */
|
||||||
|
if (!serdev)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (type < 0 || type >= GNSS_TYPE_COUNT) {
|
||||||
|
gnss_cmdline_err("invalid gnss type '%d'\n", type);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
serdev_dup = serdev_dup_sep = kstrdup(serdev, GFP_KERNEL);
|
||||||
|
if (!serdev_dup)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
driver_name = strsep(&serdev_dup_sep, "/");
|
||||||
|
if (!driver_name) {
|
||||||
|
gnss_cmdline_err("driver name missing\n");
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
port_name = strsep(&serdev_dup_sep, "/");
|
||||||
|
if (!port_name) {
|
||||||
|
gnss_cmdline_err("port name missing\n");
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
serdev_name = strsep(&serdev_dup_sep, "/");
|
||||||
|
if (!serdev_name) {
|
||||||
|
gnss_cmdline_err("serdev name missing\n");
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the driver device instance (e.g. serial8250) */
|
||||||
|
serial_dev = bus_find_device_by_name(&platform_bus_type,
|
||||||
|
NULL, driver_name);
|
||||||
|
if (!serial_dev) {
|
||||||
|
gnss_cmdline_err("no device '%s'\n", driver_name);
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the port device instance (e.g. serial0) */
|
||||||
|
port_dev = device_find_child(serial_dev, port_name, name_match);
|
||||||
|
if (!port_dev) {
|
||||||
|
gnss_cmdline_err("no port '%s'\n", port_name);
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the serdev device instance (e.g. serial0-0) */
|
||||||
|
serdev_dev = device_find_child(port_dev, serdev_name, name_match);
|
||||||
|
if (!serdev_dev) {
|
||||||
|
gnss_cmdline_err("no serdev '%s'\n", serdev_name);
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
gserial = gnss_serial_allocate(to_serdev_device(serdev_dev), 0);
|
||||||
|
if (IS_ERR(gserial)) {
|
||||||
|
err = PTR_ERR(gserial);
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
gserial->gdev->type = type;
|
||||||
|
|
||||||
|
err = gnss_serial_register(gserial);
|
||||||
|
if (err) {
|
||||||
|
gnss_serial_free(gserial);
|
||||||
|
goto err_free_serdev_dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
serdev_device = to_serdev_device(serdev_dev);
|
||||||
|
err = 0;
|
||||||
|
err_free_serdev_dup:
|
||||||
|
kfree(serdev_dup);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit gnss_cmdline_exit(void)
|
||||||
|
{
|
||||||
|
struct gnss_serial *gserial;
|
||||||
|
|
||||||
|
if (!serdev_device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gserial = serdev_device_get_drvdata(serdev_device);
|
||||||
|
|
||||||
|
gnss_serial_deregister(gserial);
|
||||||
|
gnss_serial_free(gserial);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(gnss_cmdline_init);
|
||||||
|
module_exit(gnss_cmdline_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Alistair Delva <adelva@google.com>");
|
||||||
|
MODULE_DESCRIPTION("GNSS command line driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
Reference in New Issue
Block a user