lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20150114013350.GA11620@kroah.com>
Date:	Tue, 13 Jan 2015 17:33:50 -0800
From:	Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To:	"Felipe F. Tonello" <eu@...ipetonello.com>
Cc:	Jiri Slaby <jslaby@...e.cz>, linux-kernel@...r.kernel.org,
	linux-serial@...r.kernel.org
Subject: Re: [PATCH] char: Added support for u-blox 6 i2c gps driver

On Tue, Jan 13, 2015 at 05:16:42PM -0800, Felipe F. Tonello wrote:
> This driver will basically translate serial communication to i2c communication
> between the user-space and the GPS module.
> 
> It creates a /dev/ttyS device node.
> 
> There are specific tty termios flags in order to the tty line discipliner not
> to change the date it is pushed to user space.

I don't understand this sentance, what date?  What is pushed where?
What termios files?  What is a "discipliner"?

> That is necessary so the NMEA
> data is not corrupted.
> * iflags: added IGNCR: Ignore carriage return on input.
> * oflags: removed ONLCR: (XSI) Map NL to CR-NL on output.
> 
> Signed-off-by: Felipe F. Tonello <eu@...ipetonello.com>
> ---
>  drivers/tty/serial/Kconfig          |   9 ++
>  drivers/tty/serial/Makefile         |   1 +
>  drivers/tty/serial/ublox6-gps-i2c.c | 245 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 255 insertions(+)
>  create mode 100644 drivers/tty/serial/ublox6-gps-i2c.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 26cec64..49913eb 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1552,6 +1552,15 @@ config SERIAL_MEN_Z135
>  	  This driver can also be build as a module. If so, the module will be called
>  	  men_z135_uart.ko
>  
> +config SERIAL_UBLOX_GPS
> +	tristate "u-blox 6 I2C GPS support"
> +	depends on I2C
> +	default n
> +	help
> +	  This driver uses i2c to communicate with the u-blox 6 GPS module
> +	  and has a serial tty device interface to the user-space, making
> +	  it easy to read/write data from/to the GPS.
> +
>  endmenu
>  
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 0080cc3..cba2b5c 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
>  obj-$(CONFIG_SERIAL_RP2)	+= rp2.o
>  obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
> +obj-$(CONFIG_SERIAL_UBLOX_GPS) += ublox6-gps-i2c.o
>  
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/ublox6-gps-i2c.c b/drivers/tty/serial/ublox6-gps-i2c.c
> new file mode 100644
> index 0000000..16dd1cf
> --- /dev/null
> +++ b/drivers/tty/serial/ublox6-gps-i2c.c
> @@ -0,0 +1,245 @@
> +/* u-blox 6 I2C GPS driver
> + *
> + * Copyright (C) 2015 Felipe F. Tonello <eu@...ipetonello.com>
> + *
> + * Driver that translates a serial tty GPS device to a i2c GPS device

I don't think there is a "serial tty GPS device" here, right?


> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/i2c.h>
> +#include <linux/workqueue.h>
> +
> +/*
> + * Version Information
> + */
> +#define DRIVER_VERSION "v0.1"
> +#define DRIVER_DESC "u-blox 6 I2C GPS driver"
> +
> +#define UBLOX_GPS_MAJOR 0
> +#define UBLOX_GPS_NUM 1 /* Only support 1 GPS at a time */
> +
> +/* By default u-blox GPS fill its buffer every 1 second (1000 msecs) */
> +#define READ_TIME 1000
> +
> +static struct tty_port *ublox_gps_tty_port;
> +static struct i2c_client *ublox_gps_i2c_client;

Why only one device/client?  Why can't you have more than one in the
system?  Please don't make this work for only one device, these can all
be device-private.

> +static int ublox_gps_is_open;

Why do you need this?  And again, don't make it global for the whole
driver, but unique per-device

> +static struct file *ublox_gps_filp;

I don't understand why you even need this, what problem is this solving?

> +static void ublox_gps_read_worker(struct work_struct *private);
> +
> +static DECLARE_DELAYED_WORK(ublox_gps_wq, ublox_gps_read_worker);

Again, make device-specific.

> +static void ublox_gps_read_worker(struct work_struct *private)
> +{
> +	s32 gps_buf_size, buf_size = 0;
> +	u8 *buf;
> +
> +	if (!ublox_gps_is_open)
> +		return;

How can this happen?

> +
> +	/* check if driver was removed */
> +	if (!ublox_gps_i2c_client)
> +		return;

How can this happen?

> +
> +	gps_buf_size = i2c_smbus_read_word_data(ublox_gps_i2c_client, 0xfd);
> +	if (gps_buf_size < 0) {
> +		dev_warn(&ublox_gps_i2c_client->dev, KBUILD_MODNAME ": couldn't read register(0xfd) from GPS.\n");

Something to be fixed for all of your dev_*() calls, don't put
KBUILD_MODNAME, it's not needed as dev_* handles everything properly to
point to the specific driver and device that created the message.


> +		/* try one more time */
> +		goto end;
> +	}
> +
> +	/* 0xfd is the MSB and 0xfe is the LSB */
> +	gps_buf_size = ((gps_buf_size & 0xf) << 8) | ((gps_buf_size & 0xf0) >> 8);

I don't understand the comment here.

> +
> +	if (gps_buf_size > 0) {
> +
> +		buf = kcalloc(gps_buf_size, sizeof(*buf), GFP_KERNEL);
> +		if (!buf) {
> +			dev_warn(&ublox_gps_i2c_client->dev, KBUILD_MODNAME ": couldn't allocate memory.\n");

No need to send any error if memory is gone, that already happened in
the syslog.

> +			/* try one more time */
> +			goto end;
> +		}
> +
> +		do {
> +			buf_size = i2c_master_recv(ublox_gps_i2c_client, (char *)buf, gps_buf_size);
> +			if (buf_size < 0) {
> +				dev_warn(&ublox_gps_i2c_client->dev, KBUILD_MODNAME ": couldn't read data from GPS.\n");
> +				kfree(buf);
> +				/* try one more time */
> +				goto end;
> +			}
> +
> +			tty_insert_flip_string(ublox_gps_tty_port, buf, buf_size);
> +
> +			gps_buf_size -= buf_size;
> +
> +			/* There is a small chance that we need to split the data over
> +			   several buffers. If this is the case we must loop */
> +		} while (unlikely(gps_buf_size > 0));
> +
> +		tty_flip_buffer_push(ublox_gps_tty_port);
> +
> +		kfree(buf);
> +	}
> +
> +end:
> +	/* resubmit the workqueue again */
> +	schedule_delayed_work(&ublox_gps_wq, msecs_to_jiffies(READ_TIME)); /* 1 sec delay */
> +}
> +
> +static int ublox_gps_serial_open(struct tty_struct *tty, struct file *filp)
> +{
> +	if (ublox_gps_is_open)
> +		return -EBUSY;
> +
> +	ublox_gps_filp = filp;
> +	ublox_gps_tty_port = tty->port;
> +	ublox_gps_tty_port->low_latency = true; /* make sure we push data immediately */
> +	ublox_gps_is_open = true;
> +
> +	schedule_delayed_work(&ublox_gps_wq, 0);
> +
> +	return 0;
> +}
> +
> +static void ublox_gps_serial_close(struct tty_struct *tty, struct file *filp)
> +{
> +	if (!ublox_gps_is_open)

How can this happen?

> +		return;
> +
> +	/* avoid stop when the denied (in open) file structure closes itself */
> +	if (ublox_gps_filp != filp)
> +		return;

I don't understand, how can something "close itself"?

> +
> +	ublox_gps_is_open = false;
> +	ublox_gps_filp = NULL;
> +	ublox_gps_tty_port = NULL;
> +}
> +
> +static int ublox_gps_serial_write(struct tty_struct *tty, const unsigned char *buf,
> +	int count)
> +{
> +	if (!ublox_gps_is_open)
> +		return 0;
> +
> +	/* check if driver was removed */
> +	if (!ublox_gps_i2c_client)
> +		return 0;
> +
> +	/* we don't write back to the GPS so just return same value here */
> +	return count;
> +}

So write does nothing, why even have it at all?

> +static int ublox_gps_write_room(struct tty_struct *tty)
> +{
> +	if (!ublox_gps_is_open)
> +		return 0;
> +
> +	/* check if driver was removed */
> +	if (!ublox_gps_i2c_client)
> +		return 0;
> +
> +	/* we don't write back to the GPS so just return some value here */
> +	return 1024;

Why have this function at all if it does nothing?


> +}
> +
> +static const struct tty_operations ublox_gps_serial_ops = {
> +	.open = ublox_gps_serial_open,
> +	.close = ublox_gps_serial_close,
> +	.write = ublox_gps_serial_write,
> +	.write_room = ublox_gps_write_room,
> +};
> +
> +static struct tty_driver *ublox_gps_tty_driver;
> +
> +static int ublox_gps_probe(struct i2c_client *client,
> +	const struct i2c_device_id *id)
> +{
> +	int result = 0;
> +
> +	ublox_gps_tty_driver = alloc_tty_driver(UBLOX_GPS_NUM);
> +	if (!ublox_gps_tty_driver)
> +		return -ENOMEM;
> +
> +	ublox_gps_tty_driver->owner = THIS_MODULE;
> +	ublox_gps_tty_driver->driver_name = "ublox_gps";
> +	ublox_gps_tty_driver->name = "ttyS";
> +	ublox_gps_tty_driver->major = UBLOX_GPS_MAJOR;
> +	ublox_gps_tty_driver->minor_start = 0;
> +	ublox_gps_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
> +	ublox_gps_tty_driver->subtype = SERIAL_TYPE_NORMAL;
> +	ublox_gps_tty_driver->flags = TTY_DRIVER_REAL_RAW;
> +	ublox_gps_tty_driver->init_termios = tty_std_termios;
> +	ublox_gps_tty_driver->init_termios.c_iflag = IGNCR | IXON;
> +	ublox_gps_tty_driver->init_termios.c_oflag = OPOST;
> +	ublox_gps_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
> +		HUPCL | CLOCAL;
> +	ublox_gps_tty_driver->init_termios.c_ispeed = 9600;
> +	ublox_gps_tty_driver->init_termios.c_ospeed = 9600;
> +	tty_set_operations(ublox_gps_tty_driver, &ublox_gps_serial_ops);
> +	result = tty_register_driver(ublox_gps_tty_driver);
> +	if (result) {
> +		dev_err(&ublox_gps_i2c_client->dev, KBUILD_MODNAME ": %s - tty_register_driver failed\n",
> +			__func__);
> +		goto err;
> +	}
> +
> +	ublox_gps_i2c_client = client;
> +	ublox_gps_filp = NULL;
> +	ublox_gps_tty_port = NULL;
> +	ublox_gps_is_open = false;
> +
> +	/* i2c_set_clientdata(client, NULL); */
> +
> +	dev_info(&ublox_gps_i2c_client->dev, KBUILD_MODNAME ": " DRIVER_VERSION ": "
> +		DRIVER_DESC "\n");

Be quiet for "normal" operations please, your driver should never send
anything to the kernel log unless some error happens.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ