Re: kernel PPS support for 4 wire serial ports (v2)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[Please CC me on replies, I'm not subscribed]

Here's a generic version that tries not to be intrusive.

1. sysfs interface that allows setting per port
2. recycled an unused member of struct uart_port

Attached patch is against linux-4.13.
-- 
Andreas Steinmetz                       SPAMmers use robotrap@xxxxxxxx
diff -rNup linux-4.13.orig/drivers/tty/serial/serial_core.c linux-4.13/drivers/tty/serial/serial_core.c
--- linux-4.13.orig/drivers/tty/serial/serial_core.c	2017-09-03 22:56:17.000000000 +0200
+++ linux-4.13/drivers/tty/serial/serial_core.c	2017-10-10 11:58:02.259478128 +0200
@@ -2664,6 +2664,56 @@ static ssize_t uart_get_attr_iomem_reg_s
 	return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift);
 }
 
+static ssize_t uart_get_attr_pps_4wire(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct tty_port *port = dev_get_drvdata(dev);
+	struct uart_state *state = container_of(port, struct uart_state, port);
+	struct uart_port *uport;
+	int mode = 0;
+
+	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
+	if (!uport)
+		goto out;
+
+	mode = uport->pps_4wire;
+
+out:
+	mutex_unlock(&port->mutex);
+	return snprintf(buf, PAGE_SIZE, mode ? "yes" : "no");
+}
+
+static ssize_t uart_set_attr_pps_4wire(struct device *dev,
+	struct device_attribute *attr, const char *buf,size_t count)
+{
+	struct tty_port *port = dev_get_drvdata(dev);
+	struct uart_state *state = container_of(port, struct uart_state, port);
+	struct uart_port *uport;
+	bool mode;
+	int ret;
+
+	if (!count)
+		return -EINVAL;
+
+	ret = kstrtobool(buf, &mode);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
+	if (!uport)
+		goto out;
+
+	spin_lock_irq(&uport->lock);
+	uport->pps_4wire = mode;
+	spin_unlock_irq(&uport->lock);
+
+out:
+	mutex_unlock(&port->mutex);
+	return count;
+}
+
 static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL);
 static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL);
 static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL);
@@ -2677,6 +2727,7 @@ static DEVICE_ATTR(custom_divisor, S_IRU
 static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL);
 static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL);
 static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL);
+static DEVICE_ATTR(pps_4wire, S_IRUSR | S_IWUSR | S_IRGRP, uart_get_attr_pps_4wire, uart_set_attr_pps_4wire);
 
 static struct attribute *tty_dev_attrs[] = {
 	&dev_attr_type.attr,
@@ -2692,6 +2743,7 @@ static struct attribute *tty_dev_attrs[]
 	&dev_attr_io_type.attr,
 	&dev_attr_iomem_base.attr,
 	&dev_attr_iomem_reg_shift.attr,
+	&dev_attr_pps_4wire.attr,
 	NULL,
 	};
 
@@ -2748,6 +2800,9 @@ int uart_add_one_port(struct uart_driver
 		goto out;
 	}
 
+	/* assert that pps handling is done via DCD as default */
+	uport->pps_4wire = 0;
+
 	/*
 	 * If this port is a console, then the spinlock is already
 	 * initialised.
@@ -2923,7 +2978,7 @@ void uart_handle_dcd_change(struct uart_
 
 	lockdep_assert_held_once(&uport->lock);
 
-	if (tty) {
+	if (tty && !uport->pps_4wire) {
 		ld = tty_ldisc_ref(tty);
 		if (ld) {
 			if (ld->ops->dcd_change)
@@ -2952,8 +3007,21 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change
  */
 void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
 {
+	struct tty_port *port = &uport->state->port;
+	struct tty_struct *tty = port->tty;
+	struct tty_ldisc *ld;
+
 	lockdep_assert_held_once(&uport->lock);
 
+	if (tty && uport->pps_4wire) {
+		ld = tty_ldisc_ref(tty);
+		if (ld) {
+			if (ld->ops->dcd_change)
+				ld->ops->dcd_change(tty, status);
+			tty_ldisc_deref(ld);
+		}
+	}
+
 	uport->icount.cts++;
 
 	if (uart_softcts_mode(uport)) {
diff -rNup linux-4.13.orig/include/linux/serial_core.h linux-4.13/include/linux/serial_core.h
--- linux-4.13.orig/include/linux/serial_core.h	2017-09-03 22:56:17.000000000 +0200
+++ linux-4.13/include/linux/serial_core.h	2017-10-10 11:58:02.257478108 +0200
@@ -144,7 +144,7 @@ struct uart_port {
 	unsigned char		x_char;			/* xon/xoff char */
 	unsigned char		regshift;		/* reg offset shift */
 	unsigned char		iotype;			/* io access style */
-	unsigned char		unused1;
+	unsigned char		pps_4wire;		/* CTS instead of DCD */
 
 #define UPIO_PORT		(SERIAL_IO_PORT)	/* 8b I/O port access */
 #define UPIO_HUB6		(SERIAL_IO_HUB6)	/* Hub6 ISA card */

[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux