Skip to contentSkip to conversation

Add virtual serial null modem emulation driver

PATCH Superseded Rishi Gupta 5 participants 18 messages Jan 6, 2020 – Feb 12, 2020

Subsystems (2)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover Add virtual serial null modem emulation driver

The driver named ttyvs creates virtual tty/serial device which emulates behaviour of a real serial port device. Serial port events like parity, frame, overflow errors, ring indications, break assertions, flow controls are also emulated.

It supports both device-tree and non device-tree platforms. And works in both built-in and loadable driver methods.

Use cases
~~~~~~~~~~~~~~~~~
This driver saves time to market and have following use cases including but not limited to; automated testing, GPS and other data simulation, data injection for corner case testing, scaleability testing, data sniffing, robotics emulator/simulator, application development when hardware, firmware and driver is still not available, identifying hardware issues from software bugs quickly during development, development cost reduction across team, product demo where data from hardware needs to be sent to the GUI application, data forwarding, serial port redirection etc.

Basic idea
~~~~~~~~~~~~~~~~~

This driver implements a virtual multi-port serial card in such a way that the virtual card can have 0 to N number of virtual serial ports (tty devices). The devices created in this card are used in exactly the same way as the real tty devices using standard termios and Linux/Posix APIs.

/dev/ttyvs_card
+~~~~~~~~~~~~~~~~~~~~~+

   |   +-------------+   |
   |   | /dev/ttyvs0 |   |
   |   +-------------+   |
   |   .                 |
   |   .                 |
   |   +-------------+   |
   |   | /dev/ttyvsN |   |
   |   +-------------+   |

+~~~~~~~~~~~~~~~~~~~~~+

Creating devices
~~~~~~~~~~~~~~~~~

Devices can be created/deleted by writing to /dev/ttyvs_card node.

# Create a loop back device using given number (for ex; ttyvs8):
echo "genlb#00008#xxxxx#7-8,x,x,x#4-1,6,x,x#x-x,x,x,x#x-x,x,x,x#y#x" > /dev/ttyvs_card

# Create a null modem pair using given numbers (for ex; ttyvs5/6):
echo "gennm#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#7-8,x,x,x#4-1,6,x,x#y#y" > /dev/ttyvs_card

# Create null modem pair using next free number (index)
echo "gennm#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#7-8,x,x,x#4-1,6,x,x#y#y" > /dev/ttyvs_card

# Create loopback devices using next free number (index)
echo "genlb#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#x-x,x,x,x#x-x,x,x,x#y#x" > /dev/ttyvs_card

Devices can also be created through DT. This patch describes this in detail:
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings

Deleting devices
~~~~~~~~~~~~~~~~~

Devices can be deleted by writing pre-formatted string only. Driver returns negative error code if invalid, out of range values or syntactically invalid values are supplied.

# To delete all devices in one shot write 'xxxxx' as shown below:
echo "del#xxxxx#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" > /dev/ttyvs_card

# To delete a device by number specify its number for ex; to delete 5th device:
echo "del#00005#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" > /dev/ttyvs_card

Device tree bindings
~~~~~~~~~~~~~~~~~~~~

Devices can also be created and configured through DT. Following patch describes how to do it in detail.
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings

Module parameters
~~~~~~~~~~~~~~~~~

The ttyvs driver can be passd 3 optional parameters.

max_num_vs_devs: specifies how may virtyal tty devices this driver should support. By default driver supports upto 64 devices. This can also be specified through DT property.

init_num_nm_pairs: specifies how many standard type null modem pairs should be created when driver is loaded. If this parameter is used and devices are also created through DT, then all of these devices will be deleted. DT is given more preference in all cases.

init_num_lb_devs: specifies how many standard type loop-back devices should be created when driver is loaded. If this parameter is used and devices are also created through DT, then all of these devices will be deleted. DT is given more preference in all cases.

Udev rules example
~~~~~~~~~~~~~~~~~~

# Set permissions on card node to manage devices ACTION=="add", SUBSYSTEM=="misc", KERNEL=="ttyvs_card", MODE="0666"

# Set permissions of sysfs files for event emulation ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyvs[0-9]*", MODE="0666",\
RUN+="/bin/chmod 0666 %S%p/event %S%p/faultycable"

Emulating events
~~~~~~~~~~~~~~~~~

Event emulation is through per-device sysfs file.

1. Emulate framing error (insert TTY_FRAME in data buffer):

$ echo "1" > /sys/devices/virtual/tty/ttyvsN/event

2. Emulate parity error (insert TTY_PARITY in data buffer):

$ echo "2" > /sys/devices/virtual/tty/ttyvsN/event

3. Emulate overrun error (insert TTY_OVERRUN in data buffer):

$ echo "3" > /sys/devices/virtual/tty/ttyvsN/event

4. Emulate ring indicator (set RI signal):

$ echo "4" > /sys/devices/virtual/tty/ttyvsN/event

5. Emulate ring indicator (unset RI signal):

$ echo "5" > /sys/devices/virtual/tty/ttyvsN/event

6. Emulate break received (insert TTY_BREAK in data buffer):

$ echo "6" > /sys/devices/virtual/tty/ttyvsN/event

7. Emulate cable is faulty (data sent is not received):

$ echo "1" > /sys/devices/virtual/tty/ttyvsN/faultycable

8. Emulate cable is not faulty (default):

$ echo "0" > /sys/devices/virtual/tty/ttyvsN/faultycable

There are 3 patches in this submission:
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings [PATCH 2/3] tty/serial: ttvys: add null modem driver emulating serial port [PATCH 3/3] tty: documentation: abi: add ttyvs null modem driver sysfs nodes

Rishi Gupta (3):
dt-bindings: ttyvs: document serial null modem driver dt bindings tty/serial: ttvys: add null modem driver emulating serial port
tty: documentation: abi: add ttyvs null modem driver sysfs nodes

 .../ABI/testing/sysfs-devices-virtual-tty_ttyvs    |   18 +
 .../devicetree/bindings/serial/ttyvs.yaml          |  175 ++
 MAINTAINERS                                        |    8 +
 drivers/tty/Kconfig                                |   16 +
 drivers/tty/Makefile                               |    1 +
 drivers/tty/ttyvs.c                                | 2429 ++++++++++++++++++++
 6 files changed, 2647 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs
 create mode 100644 Documentation/devicetree/bindings/serial/ttyvs.yaml
 create mode 100644 drivers/tty/ttyvs.c
Signature · 1 line
2.7.4
#1 lore raw

PATCH 1/3 dt-bindings: ttyvs: document serial null modem driver dt bindings

The ttyvs driver creates virtual tty devices. These devices can also be created through device tree. This commit document this.

---
 .../devicetree/bindings/serial/ttyvs.yaml          | 175 +++++++++++++++++++++
 1 file changed, 175 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/ttyvs.yaml
Documentation/devicetree/bindings/serial/ttyvs.yaml new file +175 -0
new file mode 100644
index 0000000..d37c237
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/ttyvs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Virtual multi-port serial card DT bindings
+
+maintainers:
+  - Rishi Gupta <[email protected]>
+
+description: |
+  The ttyvs driver creates a virtual card accessible through node
+  /dev/ttyvs_card. This card can have 0 to 65535 virtual tty devices.
+  The card is modeled as a node with zero or more child nodes each
+  representing a virtual tty device. These devices can be configured
+  to be a loop-back type device or it can be part of a null-modem pair.
+
+  Devices can be created through DT (see examples Ex1/2/3 at the end)
+  or by writing pre-formatted string to card node.
+
+  If the driver is built as loadable module, standard null modem pairs
+  can be created by passing 'init_num_nm_pairs' parameter. Similarly,
+  standard loopback devices can be created by passing 'init_num_lb_devs'
+  parameter. When DT is used and device nodes are defined, all devices
+  created due to module parameters will be deleted first and then
+  devices specified by DT will be created.
+
+  Devices can be deleted only by writing pre-formatted string to card node,
+  irrespective of whether they were created using DT or through string.
+
+properties:
+  compatible:
+    const: ttyvs,virtual-uart-card
+
+  max-num-vs-devs:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 0xffff
+    maxItems: 1
+    description:
+      By default, the driver can create upto 64 devices. This number can
+      be changed by passing 'max_num_vs_devs' parameter to the driver or
+      by defining 'max-num-vs-devs' DT property. If both are used then
+      first all devices created during module loading are deleted, then
+      driver updates itself to support total number of devices as defined
+      by max-num-vs-devs property.
+
+patternProperties:
+  "^ttyvs@[0-9]+$":
+    type: object
+    description:
+      A node representing one virtual tty device. This node optionally,
+      describes, device number and its configuration.
+
+    properties:
+      dev-num:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - minimum: 0
+          - maximum: 0xffff
+        maxItems: 1
+        description:
+          Specifies index (N in /dev/ttyvsN) to use for creating device.
+          If this property is not specified then next lowest free index
+          is used by driver. Valid value for N is 0 to 65535.
+
+      rtsmap:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+        items:
+          - enum: [1, 6, 8, 9]
+        maxItems: 1
+        description:
+          Specifies to which pin(s) RTS pin of this device should be
+          connected. Valid values are pin 1 (DCD), pin 6 (DSR), pin 8
+          (CTS) and pin 9 (RI). If this is not used then RTS pin is
+          left unconnected.
+
+      dtrmap:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+        items:
+          - enum: [1, 6, 8, 9]
+        maxItems: 1
+        description:
+          Specifies to which pin(s) DTR pin of this device should be
+          connected. Valid values are pin 1 (DCD), pin 6 (DSR), pin 8
+          (CTS) and pin 9 (RI). If this is not used then DTR pin is
+          left unconnected.
+
+      set-dtr-at-open:
+        type: boolean
+        description:
+          If used, DTR signal will be asserted by driver when device
+          node is opened by user space application.
+
+      peer-dev:
+        $ref: /schemas/types.yaml#definitions/phandle
+        description:
+          Phandle to the peer DT node if this node is part of a null
+          modem pair.
+
+required:
+  - compatible
+
+examples:
+  - |
+    # Ex1; Null-modem pair only TX/RX connected
+    # /dev/ttvs0  <---> /dev/ttyvs1
+    #      TX (3) ----> (2) RX
+    #      RX (2) <---- (3) TX
+
+    ttyvs-card@0 {
+        compatible = "ttyvs,virtual-uart-card";
+
+        ttyvs0: ttyvs0 {
+            dev-num = <0>;
+            peer-dev = <&ttyvs1>;
+        };
+
+        ttyvs1: ttyvs1 {
+            dev-num = <1>;
+            peer-dev = <&ttyvs0>;
+        };
+    };
+
+  - |
+    # Ex2; Standard loop-back device
+    # TX (3) -->|
+    # RX (2) <--|
+
+    ttyvs-card@0 {
+        compatible = "ttyvs,virtual-uart-card";
+        ttyvs2 {
+            dev-num = <2>;
+            rtsmap = <8>;
+            dtrmap = <1 6>;
+            set-dtr-at-open;
+        };
+    };
+
+  - |
+    # Ex3; Standard null-modem pair for hardware flow control
+    # TX  (3) ----> (2) RX
+    # RX  (2) <---- (3) TX
+    # RTS (7) ----> (8) CTS
+    # DTR (4) --+-> (1) DCD
+    #           +-> (6) DSR
+    # CTS (8) <---- (7) RTS
+    # DCD (1) <-+-- (4) DTR
+    # DSR (6) <-+
+
+    ttyvs-card@0 {
+        compatible = "ttyvs,virtual-uart-card";
+        max-num-vs-devs = <128>;
+
+        ttyvs3: ttyvs3 {
+            dev-num = <3>;
+            rtsmap = <8>;
+            dtrmap = <1 6>;
+            set-dtr-at-open;
+            peer-dev = <&ttyvs4>;
+        };
+
+        ttyvs4: ttyvs4 {
+            dev-num = <4>;
+            rtsmap = <8>;
+            dtrmap = <1 6>;
+            set-dtr-at-open;
+            peer-dev = <&ttyvs3>;
+        };
+    };
+...
Signature · 1 line
2.7.4
#2 lore raw

PATCH 2/3 tty/serial: ttvys: add null modem driver emulating serial port

In reply to Rishi Gupta

This commit adds driver that can create virtual tty devices. This is useful in software testing and gps data simulation.

Devices are created either through DT or by writing to device node. Serial port events like frame, parity, overflow errors are also emulated by writing to sysfs files.

---
 MAINTAINERS          |    8 +
 drivers/tty/Kconfig  |   16 +
 drivers/tty/Makefile |    1 +
 drivers/tty/ttyvs.c  | 2429 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2454 insertions(+)
 create mode 100644 drivers/tty/ttyvs.c
MAINTAINERS +8 -0
index c6b893f..350fb36 100644
@@ -16794,6 +16794,14 @@ F:	include/uapi/linux/serial_core.h
 F:	include/uapi/linux/serial.h
 F:	include/uapi/linux/tty.h
 
+TTYVS VIRTUAL SERIAL DRIVER
+M:	Rishi Gupta <[email protected]>
+L:	[email protected]
+L:	[email protected]
+S:	Maintained
+F:	Documentation/devicetree/bindings/serial/ttyvs.yaml
+F:	drivers/tty/ttyvs.c
+
 TUA9001 MEDIA DRIVER
 M:	Antti Palosaari <[email protected]>
 L:	[email protected]
drivers/tty/Kconfig +16 -0
index a312cb3..1e843f9 100644
@@ -477,4 +477,20 @@ config LDISC_AUTOLOAD
 	  dev.tty.ldisc_autoload sysctl, this configuration option will
 	  only set the default value of this functionality.
 
+config TTY_VS
+	tristate "Virtual serial null modem emulation"
+	help
+	  This driver creates virtual serial port devices (loopback and
+	  null modem style) that can be used in the same way as real serial
+	  port devices. Parity, frame, overflow, ring indicator, baudrate
+	  mismatch, hardware and software flow control can be emulated.
+
+	  For information about how to create/delete devices, exchange data
+	  and emulate events, please read:
+	  <file:Documentation/devicetree/bindings/serial/ttyvs.yaml>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ttyvs.ko. If you want to compile this driver
+	  into the kernel, say Y here.
+
 endif # TTY
drivers/tty/Makefile +1 -0
index 020b1cd..c5f2b4c 100644
@@ -34,5 +34,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
 obj-$(CONFIG_GOLDFISH_TTY)	+= goldfish.o
 obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
 obj-$(CONFIG_VCC)		+= vcc.o
+obj-$(CONFIG_TTY_VS)	+= ttyvs.o
 
 obj-y += ipwireless/
drivers/tty/ttyvs.c new file +2429 -0

2,429 lines not on this page · raw message

Signature · 1 line
2.7.4
maintainer
#3 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

Quoted 153 lines · Rishi Gupta

This commit adds driver that can create virtual tty devices. This is useful in software testing and gps data simulation.

Devices are created either through DT or by writing to device node. Serial port events like frame, parity, overflow errors are also emulated by writing to sysfs files.

---
 MAINTAINERS          |    8 +
 drivers/tty/Kconfig  |   16 +
 drivers/tty/Makefile |    1 +
 drivers/tty/ttyvs.c  | 2429 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2454 insertions(+)
 create mode 100644 drivers/tty/ttyvs.c
MAINTAINERS +8 -0
index c6b893f..350fb36 100644
@@ -16794,6 +16794,14 @@ F:	include/uapi/linux/serial_core.h
 F:	include/uapi/linux/serial.h
 F:	include/uapi/linux/tty.h
 
+TTYVS VIRTUAL SERIAL DRIVER
+M:	Rishi Gupta <[email protected]>
+L:	[email protected]
+L:	[email protected]
+S:	Maintained
+F:	Documentation/devicetree/bindings/serial/ttyvs.yaml
+F:	drivers/tty/ttyvs.c
+
 TUA9001 MEDIA DRIVER
 M:	Antti Palosaari <[email protected]>
 L:	[email protected]
drivers/tty/Kconfig +16 -0
index a312cb3..1e843f9 100644
@@ -477,4 +477,20 @@ config LDISC_AUTOLOAD
 	  dev.tty.ldisc_autoload sysctl, this configuration option will
 	  only set the default value of this functionality.
 
+config TTY_VS
+	tristate "Virtual serial null modem emulation"
+	help
+	  This driver creates virtual serial port devices (loopback and
+	  null modem style) that can be used in the same way as real serial
+	  port devices. Parity, frame, overflow, ring indicator, baudrate
+	  mismatch, hardware and software flow control can be emulated.
+
+	  For information about how to create/delete devices, exchange data
+	  and emulate events, please read:
+	  <file:Documentation/devicetree/bindings/serial/ttyvs.yaml>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ttyvs.ko. If you want to compile this driver
+	  into the kernel, say Y here.
+
 endif # TTY
drivers/tty/Makefile +1 -0
index 020b1cd..c5f2b4c 100644
@@ -34,5 +34,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
 obj-$(CONFIG_GOLDFISH_TTY)	+= goldfish.o
 obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
 obj-$(CONFIG_VCC)		+= vcc.o
+obj-$(CONFIG_TTY_VS)	+= ttyvs.o
 
 obj-y += ipwireless/
drivers/tty/ttyvs.c new file +76 -0
new file mode 100644
index 0000000..894346c
@@ -0,0 +1,2429 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Serial port null modem emulation driver
+ *
+ * Copyright (c) 2020, Rishi Gupta <[email protected]>
+ */
+
+/*
+ * Virtual multi-port serial card:
+ *
+ * This driver implements a virtual multi-port serial card in such a
+ * way that the virtual card can have 0 to N number of virtual serial
+ * ports (tty devices). The devices created in this card are used in
+ * exactly the same way as the real tty devices using standard termios
+ * and Linux/Posix APIs.
+ *
+ *    /dev/ttyvs_card
+ *  +~~~~~~~~~~~~~~~~~~~~~+
+ *  |   +-------------+   |
+ *  |   | /dev/ttyvs0 |   |
+ *  |   +-------------+   |
+ *  |   .                 |
+ *  |   .                 |
+ *  |   +-------------+   |
+ *  |   | /dev/ttyvsN |   |
+ *  |   +-------------+   |
+ *  +~~~~~~~~~~~~~~~~~~~~~+
+ *
+ * DT bindings: Documentation/devicetree/bindings/serial/ttyvs.yaml
+ *
+ * Example udev rules:
+ * 1. Permissions on card's node to create/destroy and query information:
+ *    ACTION=="add", SUBSYSTEM=="misc", KERNEL=="ttyvs_card", MODE="0666"
+ *
+ * 2. Permission on tty device nodes and event sysfs files (%S is sysfs
+ *    mount point and %p is DEVPATH /devices/virtual/tty/ttyvsNUM):
+ *    ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyvs[0-9]*",\
+ *    MODE="0666", RUN+="/bin/chmod 0666 %S%p/event %S%p/faultycable"
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.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 <linux/sched.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* Pin out configurations definitions */
+#define VS_CON_CTS    0x0001
+#define VS_CON_DCD    0x0002
+#define VS_CON_DSR    0x0004
+#define VS_CON_RI     0x0008
+
+/* Modem control register definitions */
+#define VS_MCR_DTR    0x0001
+#define VS_MCR_RTS    0x0002
+#define VS_MCR_LOOP   0x0004
+
+/* Modem status register definitions */
+#define VS_MSR_CTS    0x0008
+#define VS_MSR_DCD    0x0010
+#define VS_MSR_RI     0x0020

drivers/tty/ttyvs.c line 86

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+#define VS_MSR_DSR    0x0040
+
+/* UART frame structure definitions */
+#define VS_CRTSCTS       0x0001
+#define VS_XON           0x0002
+#define VS_NONE          0X0004
+#define VS_DATA_5        0X0008
+#define VS_DATA_6        0X0010
+#define VS_DATA_7        0X0020
+#define VS_DATA_8        0X0040

Why the "X"?

Quoted 52 lines
drivers/tty/ttyvs.c new file +52 -0
+#define VS_PARITY_NONE   0x0080
+#define VS_PARITY_ODD    0x0100
+#define VS_PARITY_EVEN   0x0200
+#define VS_PARITY_MARK   0x0400
+#define VS_PARITY_SPACE  0x0800
+#define VS_STOP_1        0x1000
+#define VS_STOP_2        0x2000
+
+/* Constants for the device type (odevtyp) */
+#define VS_SNM 0x0001
+#define VS_CNM 0x0002
+#define VS_SLB 0x0003
+#define VS_CLB 0x0004
+
+/* Represents a virtual tty device in this virtual card */
+struct vs_dev {
+	/* index for this device in tty core */
+	unsigned int own_index;
+	/* index of the device to which this device is connected */
+	unsigned int peer_index;
+	/* shadow modem status register */
+	int msr_reg;
+	/* shadow modem control register */
+	int mcr_reg;
+	/* rts line connections for this device */
+	int rts_mappings;
+	/* dtr line connections for this device */
+	int dtr_mappings;
+	int set_odtr_at_open;
+	int set_pdtr_at_open;
+	int odevtyp;
+	/* mutual exclusion at device level */
+	struct mutex lock;
+	int is_break_on;
+	/* currently active baudrate */
+	int baud;
+	int uart_frame;
+	int waiting_msr_chg;
+	int tx_paused;
+	int faulty_cable;
+	struct tty_struct *own_tty;
+	struct tty_struct *peer_tty;
+	struct serial_struct serial;
+	struct async_icount icount;
+	struct device *device;
+};
+
+/*
+ * Associates index of the device as managed by index manager
+ * to its device specific data.
+ */
+struct vs_info {

drivers/tty/ttyvs.c line 148

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+	int index;
+	struct vs_dev *vsdev;
+};
+
+/*
+ * Root of database of all devices managed by this driver. Devices
+ * are referenced using this root. For ex; to retreive struct vs_dev
+ * of 3rd device use db[3].vsdev.
+ */
+static struct vs_info *db;

No, please create these dynamically, no need to have this, right?

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+
+/*
+ * This is used to create and destroy devices atomically.
+ */
+static DEFINE_MUTEX(card_lock);
+
+/* Describes this driver */
+static struct tty_driver *ttyvs_driver;
+
+/* Module params / device-tree properties */

drivers/tty/ttyvs.c line 168

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+#define VS_DEFAULT_MAX_DEV 64
+static ushort max_num_vs_devs = VS_DEFAULT_MAX_DEV;
+static ushort init_num_nm_pairs;
+static ushort init_num_lb_devs;
+
+/* Gives how many null modem pairs exist at present */
+static ushort total_nm_pair;
+
+/* Gives how many loop back devices exist at present */
+static ushort total_lb_devs;

u16 for all of these?

Quoted 5 lines
drivers/tty/ttyvs.c new file +5 -0
+static struct attribute *vs_info_attrs[] = {
+	&dev_attr_event.attr,
+	&dev_attr_faultycable.attr,
+	&dev_attr_ownidx.attr,
+	&dev_attr_peeridx.attr,

drivers/tty/ttyvs.c line 506

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+	&dev_attr_ortsmap.attr,
+	&dev_attr_odtrmap.attr,
+	&dev_attr_prtsmap.attr,
+	&dev_attr_pdtrmap.attr,
+	&dev_attr_odevtyp.attr,
+	&dev_attr_odtropn.attr,
+	&dev_attr_pdtropn.attr,
+	&dev_attr_ostats.attr,
+	NULL,
+};

There are a _LOT_ of sysfs files here that are not documented anywhere in your Documentation/ABI/ entry. Why are these all needed?

drivers/tty/ttyvs.c line 510

Quoted 4 lines
drivers/tty/ttyvs.c new file +4 -0
+
+static const struct attribute_group vs_info_attr_grp = {
+	.attrs = vs_info_attrs,
+};

ATTRIBUTE_GROUPS()?

Quoted 12 lines
drivers/tty/ttyvs.c new file +12 -0
+/*
+ * Returns next minor number (index) free to be used for
+ * next tty device otherwise -ENOMEM. If a particular index
+ * is to be excluded it is provided by the caller in 'exclude'.
+ */
+static int vs_get_free_idx(unsigned int *idx, int exclude)
+{
+	int x;
+
+	for (x = 0; x < max_num_vs_devs; x++) {
+		if (db[x].index == -1) {
+			if (x == exclude) {

drivers/tty/ttyvs.c line 1521

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+				continue;
+			} else {
+				*idx = x;
+				return 0;
+			}
+		}
+	}
+
+	return -ENOMEM;
+}

Use an idr please. Or is it an 'ida'? Either way, NEVER open-code this type of logic anymore, you will get it wrong :(

Quoted 28 lines
drivers/tty/ttyvs.c new file +28 -0
+static int vs_alloc_reg_one_dev(int oidx, int pidx, int rtsmap,
+			int dtrmap, int dtropn)
+{
+	int ret;
+	struct vs_dev *vsdev;
+	struct device *dev;
+
+	/* Allocate and init virtual tty device private data */
+	vsdev = kcalloc(1, sizeof(struct vs_dev), GFP_KERNEL);
+	if (!vsdev)
+		return -ENOMEM;
+
+	vsdev->own_tty = NULL;
+	vsdev->peer_tty = NULL;
+	vsdev->own_index = oidx;
+	vsdev->peer_index =  pidx;
+	vsdev->rts_mappings = rtsmap;
+	vsdev->dtr_mappings = dtrmap;
+	vsdev->set_odtr_at_open = dtropn;
+	vsdev->msr_reg = 0;
+	vsdev->mcr_reg = 0;
+	vsdev->waiting_msr_chg = 0;
+	vsdev->tx_paused = 0;
+	vsdev->faulty_cable = 0;
+	mutex_init(&vsdev->lock);
+
+	/* Register with tty core with specific minor number */
+	dev = tty_register_device(ttyvs_driver, oidx, NULL);

drivers/tty/ttyvs.c line 1674

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+	if (!dev) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	vsdev->device = dev;
+	dev_set_drvdata(dev, vsdev);
+
+	/* Create custom sysfs files for this device for events */
+	ret = sysfs_create_group(&dev->kobj, &vs_info_attr_grp);

Please no. You just raced with userspace and lost (i.e. userspace has no idea these files are present.)

Please use the correct apis for this, if you _REALLY_ want special sysfs files for a tty device.

greg k-h

#4 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

Thanks Greg for the review, please find my replies inline.

Quoted 159 lines · Greg KH
Quoted 157 lines · Rishi Gupta

This commit adds driver that can create virtual tty devices. This is useful in software testing and gps data simulation.

Devices are created either through DT or by writing to device node. Serial port events like frame, parity, overflow errors are also emulated by writing to sysfs files.

---
 MAINTAINERS          |    8 +
 drivers/tty/Kconfig  |   16 +
 drivers/tty/Makefile |    1 +
 drivers/tty/ttyvs.c  | 2429 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2454 insertions(+)
 create mode 100644 drivers/tty/ttyvs.c
MAINTAINERS +8 -0
index c6b893f..350fb36 100644
@@ -16794,6 +16794,14 @@ F:   include/uapi/linux/serial_core.h
 F:   include/uapi/linux/serial.h
 F:   include/uapi/linux/tty.h
 
+TTYVS VIRTUAL SERIAL DRIVER
+M:   Rishi Gupta <[email protected]>
+L:   [email protected]
+L:   [email protected]
+S:   Maintained
+F:   Documentation/devicetree/bindings/serial/ttyvs.yaml
+F:   drivers/tty/ttyvs.c
+
 TUA9001 MEDIA DRIVER
 M:   Antti Palosaari <[email protected]>
 L:   [email protected]
drivers/tty/Kconfig +16 -0
index a312cb3..1e843f9 100644
@@ -477,4 +477,20 @@ config LDISC_AUTOLOAD
        dev.tty.ldisc_autoload sysctl, this configuration option will
        only set the default value of this functionality.
 
+config TTY_VS
+     tristate "Virtual serial null modem emulation"
+     help
+       This driver creates virtual serial port devices (loopback and
+       null modem style) that can be used in the same way as real serial
+       port devices. Parity, frame, overflow, ring indicator, baudrate
+       mismatch, hardware and software flow control can be emulated.
+
+       For information about how to create/delete devices, exchange data
+       and emulate events, please read:
+       <file:Documentation/devicetree/bindings/serial/ttyvs.yaml>.
+
+       To compile this driver as a module, choose M here: the
+       module will be called ttyvs.ko. If you want to compile this driver
+       into the kernel, say Y here.
+
 endif # TTY
drivers/tty/Makefile +1 -0
index 020b1cd..c5f2b4c 100644
@@ -34,5 +34,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
 obj-$(CONFIG_GOLDFISH_TTY)   += goldfish.o
 obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
 obj-$(CONFIG_VCC)            += vcc.o
+obj-$(CONFIG_TTY_VS) += ttyvs.o
 
 obj-y += ipwireless/
drivers/tty/ttyvs.c new file +80 -0
new file mode 100644
index 0000000..894346c
@@ -0,0 +1,2429 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Serial port null modem emulation driver
+ *
+ * Copyright (c) 2020, Rishi Gupta <[email protected]>
+ */
+
+/*
+ * Virtual multi-port serial card:
+ *
+ * This driver implements a virtual multi-port serial card in such a
+ * way that the virtual card can have 0 to N number of virtual serial
+ * ports (tty devices). The devices created in this card are used in
+ * exactly the same way as the real tty devices using standard termios
+ * and Linux/Posix APIs.
+ *
+ *    /dev/ttyvs_card
+ *  +~~~~~~~~~~~~~~~~~~~~~+
+ *  |   +-------------+   |
+ *  |   | /dev/ttyvs0 |   |
+ *  |   +-------------+   |
+ *  |   .                 |
+ *  |   .                 |
+ *  |   +-------------+   |
+ *  |   | /dev/ttyvsN |   |
+ *  |   +-------------+   |
+ *  +~~~~~~~~~~~~~~~~~~~~~+
+ *
+ * DT bindings: Documentation/devicetree/bindings/serial/ttyvs.yaml
+ *
+ * Example udev rules:
+ * 1. Permissions on card's node to create/destroy and query information:
+ *    ACTION=="add", SUBSYSTEM=="misc", KERNEL=="ttyvs_card", MODE="0666"
+ *
+ * 2. Permission on tty device nodes and event sysfs files (%S is sysfs
+ *    mount point and %p is DEVPATH /devices/virtual/tty/ttyvsNUM):
+ *    ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyvs[0-9]*",\
+ *    MODE="0666", RUN+="/bin/chmod 0666 %S%p/event %S%p/faultycable"
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.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 <linux/sched.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* Pin out configurations definitions */
+#define VS_CON_CTS    0x0001
+#define VS_CON_DCD    0x0002
+#define VS_CON_DSR    0x0004
+#define VS_CON_RI     0x0008
+
+/* Modem control register definitions */
+#define VS_MCR_DTR    0x0001
+#define VS_MCR_RTS    0x0002
+#define VS_MCR_LOOP   0x0004
+
+/* Modem status register definitions */
+#define VS_MSR_CTS    0x0008
+#define VS_MSR_DCD    0x0010
+#define VS_MSR_RI     0x0020
+#define VS_MSR_DSR    0x0040
+
+/* UART frame structure definitions */
+#define VS_CRTSCTS       0x0001
Quoted 8 lines

drivers/tty/ttyvs.c line 86

Quoted 6 lines
drivers/tty/ttyvs.c new file +6 -0
+#define VS_XON           0x0002
+#define VS_NONE          0X0004
+#define VS_DATA_5        0X0008
+#define VS_DATA_6        0X0010
+#define VS_DATA_7        0X0020
+#define VS_DATA_8        0X0040

Why the "X"?

Sorry I did not understand, do you mean why VS_XON.

Quoted 58 lines
Quoted 58 lines
drivers/tty/ttyvs.c new file +56 -0
+#define VS_PARITY_NONE   0x0080
+#define VS_PARITY_ODD    0x0100
+#define VS_PARITY_EVEN   0x0200
+#define VS_PARITY_MARK   0x0400
+#define VS_PARITY_SPACE  0x0800
+#define VS_STOP_1        0x1000
+#define VS_STOP_2        0x2000
+
+/* Constants for the device type (odevtyp) */
+#define VS_SNM 0x0001
+#define VS_CNM 0x0002
+#define VS_SLB 0x0003
+#define VS_CLB 0x0004
+
+/* Represents a virtual tty device in this virtual card */
+struct vs_dev {
+     /* index for this device in tty core */
+     unsigned int own_index;
+     /* index of the device to which this device is connected */
+     unsigned int peer_index;
+     /* shadow modem status register */
+     int msr_reg;
+     /* shadow modem control register */
+     int mcr_reg;
+     /* rts line connections for this device */
+     int rts_mappings;
+     /* dtr line connections for this device */
+     int dtr_mappings;
+     int set_odtr_at_open;
+     int set_pdtr_at_open;
+     int odevtyp;
+     /* mutual exclusion at device level */
+     struct mutex lock;
+     int is_break_on;
+     /* currently active baudrate */
+     int baud;
+     int uart_frame;
+     int waiting_msr_chg;
+     int tx_paused;
+     int faulty_cable;
+     struct tty_struct *own_tty;
+     struct tty_struct *peer_tty;
+     struct serial_struct serial;
+     struct async_icount icount;
+     struct device *device;
+};
+
+/*
+ * Associates index of the device as managed by index manager
+ * to its device specific data.
+ */
+struct vs_info {
+     int index;
+     struct vs_dev *vsdev;
+};
+
Quoted 8 lines

drivers/tty/ttyvs.c line 148

Quoted 6 lines
drivers/tty/ttyvs.c new file +6 -0
+/*
+ * Root of database of all devices managed by this driver. Devices
+ * are referenced using this root. For ex; to retreive struct vs_dev
+ * of 3rd device use db[3].vsdev.
+ */
+static struct vs_info *db;

No, please create these dynamically, no need to have this, right?

Okay, I have replaced this with index radix tree. I will send v2 soon.

Quoted 15 lines
Quoted 15 lines
drivers/tty/ttyvs.c new file +14 -0
+
+/*
+ * This is used to create and destroy devices atomically.
+ */
+static DEFINE_MUTEX(card_lock);
+
+/* Describes this driver */
+static struct tty_driver *ttyvs_driver;
+
+/* Module params / device-tree properties */
+#define VS_DEFAULT_MAX_DEV 64
+static ushort max_num_vs_devs = VS_DEFAULT_MAX_DEV;
+static ushort init_num_nm_pairs;
+static ushort init_num_lb_devs;
Quoted 8 lines

drivers/tty/ttyvs.c line 168

Quoted 6 lines
drivers/tty/ttyvs.c new file +6 -0
+
+/* Gives how many null modem pairs exist at present */
+static ushort total_nm_pair;
+
+/* Gives how many loop back devices exist at present */
+static ushort total_lb_devs;

u16 for all of these?

Okay, I will update in v2.

Quoted 12 lines
Quoted 12 lines
drivers/tty/ttyvs.c new file +10 -0
+static struct attribute *vs_info_attrs[] = {
+     &dev_attr_event.attr,
+     &dev_attr_faultycable.attr,
+     &dev_attr_ownidx.attr,
+     &dev_attr_peeridx.attr,
+     &dev_attr_ortsmap.attr,
+     &dev_attr_odtrmap.attr,
+     &dev_attr_prtsmap.attr,
+     &dev_attr_pdtrmap.attr,
+     &dev_attr_odevtyp.attr,
Quoted 8 lines

drivers/tty/ttyvs.c line 506

Quoted 5 lines
drivers/tty/ttyvs.c new file +5 -0
+     &dev_attr_odtropn.attr,
+     &dev_attr_pdtropn.attr,
+     &dev_attr_ostats.attr,
+     NULL,
+};

There are a _LOT_ of sysfs files here that are not documented anywhere in your Documentation/ABI/ entry. Why are these all needed?

I will double check this with my team or document why they are needed in v2.

Quoted 7 lines

drivers/tty/ttyvs.c line 510

Quoted 5 lines
drivers/tty/ttyvs.c new file +4 -0
+
+static const struct attribute_group vs_info_attr_grp = {
+     .attrs = vs_info_attrs,
+};

ATTRIBUTE_GROUPS()?

Okay, I will update in v2.

Quoted 18 lines
Quoted 18 lines
drivers/tty/ttyvs.c new file +17 -0
+/*
+ * Returns next minor number (index) free to be used for
+ * next tty device otherwise -ENOMEM. If a particular index
+ * is to be excluded it is provided by the caller in 'exclude'.
+ */
+static int vs_get_free_idx(unsigned int *idx, int exclude)
+{
+     int x;
+
+     for (x = 0; x < max_num_vs_devs; x++) {
+             if (db[x].index == -1) {
+                     if (x == exclude) {
+                             continue;
+                     } else {
+                             *idx = x;
+                             return 0;
+                     }
Quoted 8 lines

drivers/tty/ttyvs.c line 717

Quoted 5 lines
drivers/tty/ttyvs.c new file +5 -0
+             }
+     }
+
+     return -ENOMEM;
+}

Use an idr please. Or is it an 'ida'? Either way, NEVER open-code this type of logic anymore, you will get it wrong :(

Okay, I will update in v2.

Quoted 43 lines
Quoted 29 lines
drivers/tty/ttyvs.c new file +28 -0
+static int vs_alloc_reg_one_dev(int oidx, int pidx, int rtsmap,
+                     int dtrmap, int dtropn)
+{
+     int ret;
+     struct vs_dev *vsdev;
+     struct device *dev;
+
+     /* Allocate and init virtual tty device private data */
+     vsdev = kcalloc(1, sizeof(struct vs_dev), GFP_KERNEL);
+     if (!vsdev)
+             return -ENOMEM;
+
+     vsdev->own_tty = NULL;
+     vsdev->peer_tty = NULL;
+     vsdev->own_index = oidx;
+     vsdev->peer_index =  pidx;
+     vsdev->rts_mappings = rtsmap;
+     vsdev->dtr_mappings = dtrmap;
+     vsdev->set_odtr_at_open = dtropn;
+     vsdev->msr_reg = 0;
+     vsdev->mcr_reg = 0;
+     vsdev->waiting_msr_chg = 0;
+     vsdev->tx_paused = 0;
+     vsdev->faulty_cable = 0;
+     mutex_init(&vsdev->lock);
+
+     /* Register with tty core with specific minor number */
+     dev = tty_register_device(ttyvs_driver, oidx, NULL);

drivers/tty/ttyvs.c line 1674

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+     if (!dev) {
+             ret = -ENOMEM;
+             goto fail;
+     }
+
+     vsdev->device = dev;
+     dev_set_drvdata(dev, vsdev);
+
+     /* Create custom sysfs files for this device for events */
+     ret = sysfs_create_group(&dev->kobj, &vs_info_attr_grp);

Please no. You just raced with userspace and lost (i.e. userspace has no idea these files are present.)

Quoted 2 lines

Please use the correct apis for this, if you _REALLY_ want special sysfs files for a tty device.

Any specific API would you like to suggest. I am unable to progress on how to address this one.

Quoted 2 lines

greg k-h

maintainer
#5 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

Quoted 11 lines · rishi gupta
Quoted 10 lines

drivers/tty/ttyvs.c line 86

Quoted 8 lines
drivers/tty/ttyvs.c new file +8 -0
+/* UART frame structure definitions */
+#define VS_CRTSCTS       0x0001
+#define VS_XON           0x0002
+#define VS_NONE          0X0004
+#define VS_DATA_5        0X0008
+#define VS_DATA_6        0X0010
+#define VS_DATA_7        0X0020
+#define VS_DATA_8        0X0040

Why the "X"?

Sorry I did not understand, do you mean why VS_XON.

No, I mean why the "0X0040" instead of "0x0040" like all other hex digits in your list of defines.

Quoted 42 lines
Quoted 42 lines
Quoted 28 lines
drivers/tty/ttyvs.c new file +28 -0
+static int vs_alloc_reg_one_dev(int oidx, int pidx, int rtsmap,
+                     int dtrmap, int dtropn)
+{
+     int ret;
+     struct vs_dev *vsdev;
+     struct device *dev;
+
+     /* Allocate and init virtual tty device private data */
+     vsdev = kcalloc(1, sizeof(struct vs_dev), GFP_KERNEL);
+     if (!vsdev)
+             return -ENOMEM;
+
+     vsdev->own_tty = NULL;
+     vsdev->peer_tty = NULL;
+     vsdev->own_index = oidx;
+     vsdev->peer_index =  pidx;
+     vsdev->rts_mappings = rtsmap;
+     vsdev->dtr_mappings = dtrmap;
+     vsdev->set_odtr_at_open = dtropn;
+     vsdev->msr_reg = 0;
+     vsdev->mcr_reg = 0;
+     vsdev->waiting_msr_chg = 0;
+     vsdev->tx_paused = 0;
+     vsdev->faulty_cable = 0;
+     mutex_init(&vsdev->lock);
+
+     /* Register with tty core with specific minor number */
+     dev = tty_register_device(ttyvs_driver, oidx, NULL);

drivers/tty/ttyvs.c line 1674

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+     if (!dev) {
+             ret = -ENOMEM;
+             goto fail;
+     }
+
+     vsdev->device = dev;
+     dev_set_drvdata(dev, vsdev);
+
+     /* Create custom sysfs files for this device for events */
+     ret = sysfs_create_group(&dev->kobj, &vs_info_attr_grp);

Please no. You just raced with userspace and lost (i.e. userspace has no idea these files are present.)

Quoted 4 lines
Quoted 2 lines

Please use the correct apis for this, if you _REALLY_ want special sysfs files for a tty device.

Any specific API would you like to suggest. I am unable to progress on how to address this one.

Now that you have moved things to configfs, maybe you do not need the sysfs files anymore?

Ah your "control" sysfs files, ok, you need to set the driver's dev_groups variable to point to your sysfs attributes, and then the driver core will properly set up these files.

hope this helps,

greg k-h

#6 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

One problem (: about configfs. Desktop distros like Ubuntu doesn't enable configFS by default in kernel config. So users will have to build their own version of kernel. For my own purpose, as developer I have control over this but for others building kernel suggested ?

Quoted 12 lines · Greg KH
Quoted 10 lines · rishi gupta
Quoted 10 lines

drivers/tty/ttyvs.c line 86

Quoted 8 lines
drivers/tty/ttyvs.c new file +8 -0
+/* UART frame structure definitions */
+#define VS_CRTSCTS       0x0001
+#define VS_XON           0x0002
+#define VS_NONE          0X0004
+#define VS_DATA_5        0X0008
+#define VS_DATA_6        0X0010
+#define VS_DATA_7        0X0020
+#define VS_DATA_8        0X0040

Why the "X"?

Quoted 4 lines
Quoted 1 line

Sorry I did not understand, do you mean why VS_XON.

No, I mean why the "0X0040" instead of "0x0040" like all other hex digits in your list of defines.

Okay understood.

Quoted 58 lines
Quoted 43 lines
Quoted 43 lines
Quoted 29 lines
drivers/tty/ttyvs.c new file +28 -0
+static int vs_alloc_reg_one_dev(int oidx, int pidx, int rtsmap,
+                     int dtrmap, int dtropn)
+{
+     int ret;
+     struct vs_dev *vsdev;
+     struct device *dev;
+
+     /* Allocate and init virtual tty device private data */
+     vsdev = kcalloc(1, sizeof(struct vs_dev), GFP_KERNEL);
+     if (!vsdev)
+             return -ENOMEM;
+
+     vsdev->own_tty = NULL;
+     vsdev->peer_tty = NULL;
+     vsdev->own_index = oidx;
+     vsdev->peer_index =  pidx;
+     vsdev->rts_mappings = rtsmap;
+     vsdev->dtr_mappings = dtrmap;
+     vsdev->set_odtr_at_open = dtropn;
+     vsdev->msr_reg = 0;
+     vsdev->mcr_reg = 0;
+     vsdev->waiting_msr_chg = 0;
+     vsdev->tx_paused = 0;
+     vsdev->faulty_cable = 0;
+     mutex_init(&vsdev->lock);
+
+     /* Register with tty core with specific minor number */
+     dev = tty_register_device(ttyvs_driver, oidx, NULL);

drivers/tty/ttyvs.c line 1674

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+     if (!dev) {
+             ret = -ENOMEM;
+             goto fail;
+     }
+
+     vsdev->device = dev;
+     dev_set_drvdata(dev, vsdev);
+
+     /* Create custom sysfs files for this device for events */
+     ret = sysfs_create_group(&dev->kobj, &vs_info_attr_grp);

Please no. You just raced with userspace and lost (i.e. userspace has no idea these files are present.)

Quoted 4 lines
Quoted 2 lines

Please use the correct apis for this, if you _REALLY_ want special sysfs files for a tty device.

Any specific API would you like to suggest. I am unable to progress on how to address this one.

Now that you have moved things to configfs, maybe you do not need the sysfs files anymore?

Ah your "control" sysfs files, ok, you need to set the driver's dev_groups variable to point to your sysfs attributes, and then the driver core will properly set up these files.

hope this helps,

greg k-h

maintainer
#7 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

Quoted 4 lines · rishi gupta

One problem (: about configfs. Desktop distros like Ubuntu doesn't enable configFS by default in kernel config. So users will have to build their own version of kernel. For my own purpose, as developer I have control over this but for others building kernel suggested ?

I suggest taking that up with Ubuntu :)

Nothing we can do from the kernel side if we provide a good api that they just don't happen to want their users to use. Odds are no one noticed that it was needed for something...

thanks,

greg k-h

#8 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

In reply to Greg KH

Tried dev_groups approach, doesn't fit here. Please see inline.

Quoted 67 lines · Greg KH
Quoted 11 lines · rishi gupta
Quoted 10 lines

drivers/tty/ttyvs.c line 86

Quoted 8 lines
drivers/tty/ttyvs.c new file +8 -0
+/* UART frame structure definitions */
+#define VS_CRTSCTS       0x0001
+#define VS_XON           0x0002
+#define VS_NONE          0X0004
+#define VS_DATA_5        0X0008
+#define VS_DATA_6        0X0010
+#define VS_DATA_7        0X0020
+#define VS_DATA_8        0X0040

Why the "X"?

Sorry I did not understand, do you mean why VS_XON.

No, I mean why the "0X0040" instead of "0x0040" like all other hex digits in your list of defines.

Quoted 42 lines
Quoted 42 lines
Quoted 28 lines
drivers/tty/ttyvs.c new file +28 -0
+static int vs_alloc_reg_one_dev(int oidx, int pidx, int rtsmap,
+                     int dtrmap, int dtropn)
+{
+     int ret;
+     struct vs_dev *vsdev;
+     struct device *dev;
+
+     /* Allocate and init virtual tty device private data */
+     vsdev = kcalloc(1, sizeof(struct vs_dev), GFP_KERNEL);
+     if (!vsdev)
+             return -ENOMEM;
+
+     vsdev->own_tty = NULL;
+     vsdev->peer_tty = NULL;
+     vsdev->own_index = oidx;
+     vsdev->peer_index =  pidx;
+     vsdev->rts_mappings = rtsmap;
+     vsdev->dtr_mappings = dtrmap;
+     vsdev->set_odtr_at_open = dtropn;
+     vsdev->msr_reg = 0;
+     vsdev->mcr_reg = 0;
+     vsdev->waiting_msr_chg = 0;
+     vsdev->tx_paused = 0;
+     vsdev->faulty_cable = 0;
+     mutex_init(&vsdev->lock);
+
+     /* Register with tty core with specific minor number */
+     dev = tty_register_device(ttyvs_driver, oidx, NULL);

drivers/tty/ttyvs.c line 1674

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+     if (!dev) {
+             ret = -ENOMEM;
+             goto fail;
+     }
+
+     vsdev->device = dev;
+     dev_set_drvdata(dev, vsdev);
+
+     /* Create custom sysfs files for this device for events */
+     ret = sysfs_create_group(&dev->kobj, &vs_info_attr_grp);

Please no. You just raced with userspace and lost (i.e. userspace has no idea these files are present.)

Quoted 4 lines
Quoted 2 lines

Please use the correct apis for this, if you _REALLY_ want special sysfs files for a tty device.

Any specific API would you like to suggest. I am unable to progress on how to address this one.

Now that you have moved things to configfs, maybe you do not need the sysfs files anymore?

Quoted 7 lines

Ah your "control" sysfs files, ok, you need to set the driver's dev_groups variable to point to your sysfs attributes, and then the driver core will properly set up these files.

hope this helps,

greg k-h

Everything done except using dev_groups approach (full driver after all changes https://github.com/test209/t/blob/master/ttyvs.c#L1957).

Currently to emulate parity error (or any event), user writes to a device specific node (0 is device number):
echo "2" > /sys/devices/virtual/tty/ttyvs0/event

With dev_groups, sysfs is created (1) for driver not for devices (2) for platform devices only

Due to (1), parsing based approach will be needed, for ex (0 is device number); echo "0-2" > /sys/devices/platform/ttyvs-card@0/event
or
echo "0-parity" > /sys/devices/platform/ttyvs-card@0/event

Due to (2), event file will not exist on desktop systems as there will be no device tree node; no platform device.

Original problem was user space doesn't know when "/sys/devices/virtual/tty/ttyvs0/event" will exist.
User space gets a uevent when a device is registered with tty core. Application must access only after this.
Is this okay in case of this particular driver.

Only after open(/dev/ttyvs0) succeeds, application should access "/sys/devices/virtual/tty/ttyvs0/event".

Regards,
Rishi

maintainer
#9 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

Quoted 78 lines · rishi gupta

Tried dev_groups approach, doesn't fit here. Please see inline.

Quoted 67 lines · Greg KH
Quoted 11 lines · rishi gupta
Quoted 10 lines

drivers/tty/ttyvs.c line 86

Quoted 8 lines
drivers/tty/ttyvs.c new file +8 -0
+/* UART frame structure definitions */
+#define VS_CRTSCTS       0x0001
+#define VS_XON           0x0002
+#define VS_NONE          0X0004
+#define VS_DATA_5        0X0008
+#define VS_DATA_6        0X0010
+#define VS_DATA_7        0X0020
+#define VS_DATA_8        0X0040

Why the "X"?

Sorry I did not understand, do you mean why VS_XON.

No, I mean why the "0X0040" instead of "0x0040" like all other hex digits in your list of defines.

Quoted 42 lines
Quoted 42 lines
Quoted 28 lines
drivers/tty/ttyvs.c new file +28 -0
+static int vs_alloc_reg_one_dev(int oidx, int pidx, int rtsmap,
+                     int dtrmap, int dtropn)
+{
+     int ret;
+     struct vs_dev *vsdev;
+     struct device *dev;
+
+     /* Allocate and init virtual tty device private data */
+     vsdev = kcalloc(1, sizeof(struct vs_dev), GFP_KERNEL);
+     if (!vsdev)
+             return -ENOMEM;
+
+     vsdev->own_tty = NULL;
+     vsdev->peer_tty = NULL;
+     vsdev->own_index = oidx;
+     vsdev->peer_index =  pidx;
+     vsdev->rts_mappings = rtsmap;
+     vsdev->dtr_mappings = dtrmap;
+     vsdev->set_odtr_at_open = dtropn;
+     vsdev->msr_reg = 0;
+     vsdev->mcr_reg = 0;
+     vsdev->waiting_msr_chg = 0;
+     vsdev->tx_paused = 0;
+     vsdev->faulty_cable = 0;
+     mutex_init(&vsdev->lock);
+
+     /* Register with tty core with specific minor number */
+     dev = tty_register_device(ttyvs_driver, oidx, NULL);

drivers/tty/ttyvs.c line 1674

Quoted 10 lines
drivers/tty/ttyvs.c new file +10 -0
+     if (!dev) {
+             ret = -ENOMEM;
+             goto fail;
+     }
+
+     vsdev->device = dev;
+     dev_set_drvdata(dev, vsdev);
+
+     /* Create custom sysfs files for this device for events */
+     ret = sysfs_create_group(&dev->kobj, &vs_info_attr_grp);

Please no. You just raced with userspace and lost (i.e. userspace has no idea these files are present.)

Quoted 4 lines
Quoted 2 lines

Please use the correct apis for this, if you _REALLY_ want special sysfs files for a tty device.

Any specific API would you like to suggest. I am unable to progress on how to address this one.

Now that you have moved things to configfs, maybe you do not need the sysfs files anymore?

Quoted 7 lines

Ah your "control" sysfs files, ok, you need to set the driver's dev_groups variable to point to your sysfs attributes, and then the driver core will properly set up these files.

hope this helps,

greg k-h

Quoted 8 lines

Everything done except using dev_groups approach (full driver after all changes https://github.com/test209/t/blob/master/ttyvs.c#L1957).

Currently to emulate parity error (or any event), user writes to a device specific node (0 is device number):
echo "2" > /sys/devices/virtual/tty/ttyvs0/event

With dev_groups, sysfs is created (1) for driver not for devices

Huh? It's there for devices.

Quoted 1 line

(2) for platform devices only

No, should work for any device type, as the logic is in the driver core.

Quoted 4 lines

Due to (1), parsing based approach will be needed, for ex (0 is device number); echo "0-2" > /sys/devices/platform/ttyvs-card@0/event
or
echo "0-parity" > /sys/devices/platform/ttyvs-card@0/event

No, the 0- should not be needed, it should be a device-specific file.

Quoted 2 lines

Due to (2), event file will not exist on desktop systems as there will be no device tree node; no platform device.

I don't understand, this file belongs in the tty device that you have created, not in any other device.

Quoted 2 lines

Original problem was user space doesn't know when "/sys/devices/virtual/tty/ttyvs0/event" will exist.

And if you set the devices group up properly, the sysfs file will be created when the device is created.

Quoted 2 lines

User space gets a uevent when a device is registered with tty core. Application must access only after this.

Yes, but you will race in creation of your file with userspace unless you tell the core to do this properly.

Quoted 1 line

Is this okay in case of this particular driver.

No.

thanks,

greg k-h

#10 lore raw

Re: [PATCH v1 2/3] tty/serial: ttvys: add null modem driver emulating serial port

In reply to Rishi Gupta
I love your patch! Yet something to improve:

Hi Rishi,

I love your patch! Yet something to improve:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on robh/for-next usb/usb-testing linus/master v5.5-rc5 next-20200106] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Rishi-Gupta/Add-virtual-serial-null-modem-emulation-driver/20200106-155424
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 7.5.0

reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.5.0 make.cross ARCH=ia64

If you fix the issue, kindly add following tag

All errors (new ones prefixed by >>):

drivers//tty/ttyvs.c: In function 'vs_get_serinfo':

>> drivers//tty/ttyvs.c:1012:8: error: implicit declaration of function 'copy_to_user'; did you mean 'cpu_to_mem'? [-Werror=implicit-function-declaration]
     ret = copy_to_user((void __user *)arg, &info,
           ^~~~~~~~~~~~
           cpu_to_mem
   drivers//tty/ttyvs.c: In function 'vs_card_write':
>> drivers//tty/ttyvs.c:1996:7: error: implicit declaration of function 'copy_from_user'; did you mean 'copy_creds'? [-Werror=implicit-function-declaration]
      if (copy_from_user(data, buf, length) != 0)
          ^~~~~~~~~~~~~~
          copy_creds

cc1: some warnings being treated as errors

vim +1012 drivers//tty/ttyvs.c

985
986 /* Provides information as a repsonse to TIOCGSERIAL IOCTL */
987 static int vs_get_serinfo(struct tty_struct *tty, unsigned long arg)
988 {
989 int ret;
990 struct serial_struct info;
991 struct vs_dev *local_vsdev = db[tty->index].vsdev;
992 struct serial_struct serial = local_vsdev->serial;
993
994 if (!arg)
995 return -EFAULT;
996
997 memset(&info, 0, sizeof(info));
998

   999		info.type		    = PORT_UNKNOWN;
  1000		info.line		    = serial.line;
  1001		info.port		    = tty->index;
  1002		info.irq			= 0;
  1003		info.flags		    = tty->port->flags;
  1004		info.xmit_fifo_size = 0;
  1005		info.baud_base	    = 0;
  1006		info.close_delay	= tty->port->close_delay;
  1007		info.closing_wait   = tty->port->closing_wait;
  1008		info.custom_divisor = 0;
  1009		info.hub6		    = 0;
  1010		info.io_type		= SERIAL_IO_MEM;
  1011	
> 1012		ret = copy_to_user((void __user *)arg, &info,

1013 sizeof(struct serial_struct));
1014
1015 return ret ? -EFAULT : 0;
1016 }
1017

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org Intel Corporation

#11 lore raw

PATCH 3/3 tty: documentation: abi: add ttyvs null modem driver sysfs nodes

In reply to Rishi Gupta

The ttyvs driver exposes sysfs files to emulate various serial port events. This commit document these files.

---
 .../ABI/testing/sysfs-devices-virtual-tty_ttyvs        | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs
Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs new file +18 -0
new file mode 100644
index 0000000..69b04e0
@@ -0,0 +1,18 @@
+What:		/sys/devices/virtual/tty/ttyvsN/event
+Date:		January 2020
+Contact:	Rishi Gupta <[email protected]>
+KernelVersion:	5.5
+Description:
+		The ttyvs driver will emulate serial port event; parity error,
+		framing error, overrun error, asserting or de-asserting break
+		conditions and ring indication when user space application
+		writes an event code on this sysfs file.
+
+What:		/sys/devices/virtual/tty/ttyvsN/faultycable
+Date:		January 2020
+Contact:	Rishi Gupta <[email protected]>
+KernelVersion:	5.5
+Description:
+		The ttyvs driver will emulate as if the cable is faulty; i.e.
+		data sent will not be received when user space application
+		writes 1 on this file. Write 0 to disable this emulation.
Signature · 1 line
2.7.4
maintainer
#12 lore raw

Re: [PATCH v1 3/3] tty: documentation: abi: add ttyvs null modem driver sysfs nodes

Quoted 15 lines · Rishi Gupta

The ttyvs driver exposes sysfs files to emulate various serial port events. This commit document these files.

---
 .../ABI/testing/sysfs-devices-virtual-tty_ttyvs        | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs
Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs new file +0 -0
new file mode 100644
index 0000000..69b04e0

Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs line 9

Quoted 9 lines
Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs new file +9 -0
@@ -0,0 +1,18 @@
+What:		/sys/devices/virtual/tty/ttyvsN/event
+Date:		January 2020
+Contact:	Rishi Gupta <[email protected]>
+KernelVersion:	5.5
+Description:
+		The ttyvs driver will emulate serial port event; parity error,
+		framing error, overrun error, asserting or de-asserting break
+		conditions and ring indication when user space application
+		writes an event code on this sysfs file.

You did not actually document any of the values read/written to this file, like you did in your 0/X patch description :(

greg k-h

#13 lore raw

Re: [PATCH v1 3/3] tty: documentation: abi: add ttyvs null modem driver sysfs nodes

Oh sorry, I will update this.

Quoted 31 lines · Greg KH
Quoted 15 lines · Rishi Gupta

The ttyvs driver exposes sysfs files to emulate various serial port events. This commit document these files.

---
 .../ABI/testing/sysfs-devices-virtual-tty_ttyvs        | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs
Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs new file +0 -0
new file mode 100644
index 0000000..69b04e0

Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs line 9

Quoted 9 lines
Documentation/ABI/testing/sysfs-devices-virtual-tty_ttyvs new file +9 -0
@@ -0,0 +1,18 @@
+What:                /sys/devices/virtual/tty/ttyvsN/event
+Date:                January 2020
+Contact:     Rishi Gupta <[email protected]>
+KernelVersion:       5.5
+Description:
+             The ttyvs driver will emulate serial port event; parity error,
+             framing error, overrun error, asserting or de-asserting break
+             conditions and ring indication when user space application
+             writes an event code on this sysfs file.

You did not actually document any of the values read/written to this file, like you did in your 0/X patch description :(

greg k-h

maintainer
#14 lore raw
In reply to Rishi Gupta
Quoted 4 lines · Rishi Gupta

The driver named ttyvs creates virtual tty/serial device which emulates behaviour of a real serial port device. Serial port events like parity, frame, overflow errors, ring indications, break assertions, flow controls are also emulated.

Emulated in what way?

Quoted 35 lines

It supports both device-tree and non device-tree platforms. And works in both built-in and loadable driver methods.

Use cases
~~~~~~~~~~~~~~~~~
This driver saves time to market and have following use cases including but not limited to; automated testing, GPS and other data simulation, data injection for corner case testing, scaleability testing, data sniffing, robotics emulator/simulator, application development when hardware, firmware and driver is still not available, identifying hardware issues from software bugs quickly during development, development cost reduction across team, product demo where data from hardware needs to be sent to the GUI application, data forwarding, serial port redirection etc.

Basic idea
~~~~~~~~~~~~~~~~~

This driver implements a virtual multi-port serial card in such a way that the virtual card can have 0 to N number of virtual serial ports (tty devices). The devices created in this card are used in exactly the same way as the real tty devices using standard termios and Linux/Posix APIs.

/dev/ttyvs_card
+~~~~~~~~~~~~~~~~~~~~~+

   |   +-------------+   |
   |   | /dev/ttyvs0 |   |
   |   +-------------+   |
   |   .                 |
   |   .                 |
   |   +-------------+   |
   |   | /dev/ttyvsN |   |
   |   +-------------+   |

+~~~~~~~~~~~~~~~~~~~~~+

Quoted 7 lines

Creating devices
~~~~~~~~~~~~~~~~~

Devices can be created/deleted by writing to /dev/ttyvs_card node.

# Create a loop back device using given number (for ex; ttyvs8):
echo "genlb#00008#xxxxx#7-8,x,x,x#4-1,6,x,x#x-x,x,x,x#x-x,x,x,x#y#x" > /dev/ttyvs_card

That's a crazy api, why not just use configfs so you do not have to parse long strings in the kernel? That is exactly what configfs was created for.

And you are just creating a "fake" tty device, how is that going to be used to test anything? There's no hardware attached to it, are you just talking about testing userspace programs?

Quoted 16 lines

# Create a null modem pair using given numbers (for ex; ttyvs5/6):
echo "gennm#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#7-8,x,x,x#4-1,6,x,x#y#y" > /dev/ttyvs_card

# Create null modem pair using next free number (index)
echo "gennm#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#7-8,x,x,x#4-1,6,x,x#y#y" > /dev/ttyvs_card

# Create loopback devices using next free number (index)
echo "genlb#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#x-x,x,x,x#x-x,x,x,x#y#x" > /dev/ttyvs_card

Devices can also be created through DT. This patch describes this in detail:
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings

Deleting devices
~~~~~~~~~~~~~~~~~

Quoted 6 lines

Devices can be deleted by writing pre-formatted string only. Driver returns negative error code if invalid, out of range values or syntactically invalid values are supplied.

# To delete all devices in one shot write 'xxxxx' as shown below:
echo "del#xxxxx#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" > /dev/ttyvs_card

Again, please use configfs.

And document this all somewhere really really really good, in the kernel tree.

Quoted 25 lines

# To delete a device by number specify its number for ex; to delete 5th device:
echo "del#00005#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" > /dev/ttyvs_card

Device tree bindings
~~~~~~~~~~~~~~~~~~~~

Devices can also be created and configured through DT. Following patch describes how to do it in detail.
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings

Module parameters
~~~~~~~~~~~~~~~~~

The ttyvs driver can be passd 3 optional parameters.

max_num_vs_devs: specifies how may virtyal tty devices this driver should support. By default driver supports upto 64 devices. This can also be specified through DT property.

init_num_nm_pairs: specifies how many standard type null modem pairs should be created when driver is loaded. If this parameter is used and devices are also created through DT, then all of these devices will be deleted. DT is given more preference in all cases.

Quoted 4 lines

init_num_lb_devs: specifies how many standard type loop-back devices should be created when driver is loaded. If this parameter is used and devices are also created through DT, then all of these devices will be deleted. DT is given more preference in all cases.

Please no new module parameters, this is not the 1990's. :)

Quoted 9 lines

Udev rules example
~~~~~~~~~~~~~~~~~~

# Set permissions on card node to manage devices ACTION=="add", SUBSYSTEM=="misc", KERNEL=="ttyvs_card", MODE="0666"

# Set permissions of sysfs files for event emulation ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyvs[0-9]*", MODE="0666",\
RUN+="/bin/chmod 0666 %S%p/event %S%p/faultycable"

If you really want those permissions on your sysfs files, then set them to those values in your kernel code.

But I really doubt you want those permissions on them, that's really wide open.

Quoted 14 lines

Emulating events
~~~~~~~~~~~~~~~~~

Event emulation is through per-device sysfs file.

1. Emulate framing error (insert TTY_FRAME in data buffer):

$ echo "1" > /sys/devices/virtual/tty/ttyvsN/event

2. Emulate parity error (insert TTY_PARITY in data buffer):

$ echo "2" > /sys/devices/virtual/tty/ttyvsN/event

3. Emulate overrun error (insert TTY_OVERRUN in data buffer):

$ echo "3" > /sys/devices/virtual/tty/ttyvsN/event
Quoted 8 lines

4. Emulate ring indicator (set RI signal):

$ echo "4" > /sys/devices/virtual/tty/ttyvsN/event

5. Emulate ring indicator (unset RI signal):

$ echo "5" > /sys/devices/virtual/tty/ttyvsN/event

6. Emulate break received (insert TTY_BREAK in data buffer):

$ echo "6" > /sys/devices/virtual/tty/ttyvsN/event

We can handle strings, right? Why all of the numbers?

Quoted 5 lines

7. Emulate cable is faulty (data sent is not received):

$ echo "1" > /sys/devices/virtual/tty/ttyvsN/faultycable

8. Emulate cable is not faulty (default):

$ echo "0" > /sys/devices/virtual/tty/ttyvsN/faultycable

Why is this a separate sysfs file?

This all feels really odd, what is this going to be used for?

greg k-h

#15 lore raw

Thanks Greg for the review, please find my replies inline.

Quoted 8 lines · Greg KH
Quoted 4 lines · Rishi Gupta

The driver named ttyvs creates virtual tty/serial device which emulates behaviour of a real serial port device. Serial port events like parity, frame, overflow errors, ring indications, break assertions, flow controls are also emulated.

Emulated in what way?

It emulates as if the data is from real hardware. For ex; suppose a GPS receiver sends through UART interface.
GUI application simply opens /dev/ttyUSB0 and gets the MNEA strings. Through this driver we can create pair /dev/ttyvs0<--/dev/ttyvs1 where test app will write fake
data to /de/vttyvs0 while the GUI app (under testing) will receive it. This way dependency on
the hardware can be removed to certain extent.
Furthermore, suppose the GPS receiver uses 8N1 with even parity. UART driver on host
reads a register and finds that parity error has happened. To emulate this we expose a
sysfs node to user space. Test script can write '1' to this and driver will insert TTY-PARITY
in the tty buffer.

Quoted 39 lines
Quoted 39 lines

It supports both device-tree and non device-tree platforms. And works in both built-in and loadable driver methods.

Use cases
~~~~~~~~~~~~~~~~~
This driver saves time to market and have following use cases including but not limited to; automated testing, GPS and other data simulation, data injection for corner case testing, scaleability testing, data sniffing, robotics emulator/simulator, application development when hardware, firmware and driver is still not available, identifying hardware issues from software bugs quickly during development, development cost reduction across team, product demo where data from hardware needs to be sent to the GUI application, data forwarding, serial port redirection etc.

Basic idea
~~~~~~~~~~~~~~~~~

This driver implements a virtual multi-port serial card in such a way that the virtual card can have 0 to N number of virtual serial ports (tty devices). The devices created in this card are used in exactly the same way as the real tty devices using standard termios and Linux/Posix APIs.

/dev/ttyvs_card
+~~~~~~~~~~~~~~~~~~~~~+

   |   +-------------+   |
   |   | /dev/ttyvs0 |   |
   |   +-------------+   |
   |   .                 |
   |   .                 |
   |   +-------------+   |
   |   | /dev/ttyvsN |   |
   |   +-------------+   |

+~~~~~~~~~~~~~~~~~~~~~+

Creating devices
~~~~~~~~~~~~~~~~~

Quoted 8 lines
Quoted 4 lines

Devices can be created/deleted by writing to /dev/ttyvs_card node.

# Create a loop back device using given number (for ex; ttyvs8):
echo "genlb#00008#xxxxx#7-8,x,x,x#4-1,6,x,x#x-x,x,x,x#x-x,x,x,x#y#x" > /dev/ttyvs_card

That's a crazy api, why not just use configfs so you do not have to parse long strings in the kernel? That is exactly what configfs was created for.

I have updated the driver to use configfs and tested. Thanks for the guidance.

Quoted 4 lines

And you are just creating a "fake" tty device, how is that going to be used to test anything? There's no hardware attached to it, are you just talking about testing userspace programs?

Yes, testing user space programs. There are other use cases as well. IoT Smart nursery project: decoupling App, middleware and board Board gets data from 5 sensors. It sends this data to Host PC (GUI app) thorough RS-232 serial port.
Same board now located at a remote site will collect data and send to server through internet.
The middleware running on server will receive and write it to /dev/ttyvs0. GUI app will open /de/vttyvs1 and gets this data. This way GUI app can work seamlessly
in both local and remote setup. Similarly, dependency on board is also removed.

Quoted 18 lines
Quoted 18 lines

# Create a null modem pair using given numbers (for ex; ttyvs5/6):
echo "gennm#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#7-8,x,x,x#4-1,6,x,x#y#y" > /dev/ttyvs_card

# Create null modem pair using next free number (index)
echo "gennm#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#7-8,x,x,x#4-1,6,x,x#y#y" > /dev/ttyvs_card

# Create loopback devices using next free number (index)
echo "genlb#xxxxx#xxxxx#7-8,x,x,x#4-1,6,x,x#x-x,x,x,x#x-x,x,x,x#y#x" > /dev/ttyvs_card

Devices can also be created through DT. This patch describes this in detail:
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings

Deleting devices
~~~~~~~~~~~~~~~~~

Quoted 8 lines
Quoted 6 lines

Devices can be deleted by writing pre-formatted string only. Driver returns negative error code if invalid, out of range values or syntactically invalid values are supplied.

# To delete all devices in one shot write 'xxxxx' as shown below:
echo "del#xxxxx#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" > /dev/ttyvs_card

Again, please use configfs.

Done.

Quoted 30 lines

And document this all somewhere really really really good, in the kernel tree.

Quoted 25 lines

# To delete a device by number specify its number for ex; to delete 5th device:
echo "del#00005#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" > /dev/ttyvs_card

Device tree bindings
~~~~~~~~~~~~~~~~~~~~

Devices can also be created and configured through DT. Following patch describes how to do it in detail.
[PATCH 1/3] dt-bindings: ttyvs: document serial null modem driver dt bindings

Module parameters
~~~~~~~~~~~~~~~~~

The ttyvs driver can be passd 3 optional parameters.

max_num_vs_devs: specifies how may virtyal tty devices this driver should support. By default driver supports upto 64 devices. This can also be specified through DT property.

init_num_nm_pairs: specifies how many standard type null modem pairs should be created when driver is loaded. If this parameter is used and devices are also created through DT, then all of these devices will be deleted. DT is given more preference in all cases.

Quoted 6 lines
Quoted 4 lines

init_num_lb_devs: specifies how many standard type loop-back devices should be created when driver is loaded. If this parameter is used and devices are also created through DT, then all of these devices will be deleted. DT is given more preference in all cases.

Please no new module parameters, this is not the 1990's. :)

I need to learn something here. Do you mean we should avoid add parameters completely.
Or if possible we should avoid in general. However, if there is a reason we can use parameters.

I am removing them anyway as configfs view will go out of sync.

Quoted 7 lines
Quoted 7 lines

Udev rules example
~~~~~~~~~~~~~~~~~~

# Set permissions on card node to manage devices ACTION=="add", SUBSYSTEM=="misc", KERNEL=="ttyvs_card", MODE="0666"

Quoted 6 lines
Quoted 3 lines

# Set permissions of sysfs files for event emulation ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyvs[0-9]*", MODE="0666",\
RUN+="/bin/chmod 0666 %S%p/event %S%p/faultycable"

If you really want those permissions on your sysfs files, then set them to those values in your kernel code.

This is just an example. It completely depends upon end user to write udev rule.

Quoted 21 lines

But I really doubt you want those permissions on them, that's really wide open.

Quoted 17 lines

Emulating events
~~~~~~~~~~~~~~~~~

Event emulation is through per-device sysfs file.

1. Emulate framing error (insert TTY_FRAME in data buffer):

$ echo "1" > /sys/devices/virtual/tty/ttyvsN/event

2. Emulate parity error (insert TTY_PARITY in data buffer):

$ echo "2" > /sys/devices/virtual/tty/ttyvsN/event

3. Emulate overrun error (insert TTY_OVERRUN in data buffer):

$ echo "3" > /sys/devices/virtual/tty/ttyvsN/event

4. Emulate ring indicator (set RI signal):

$ echo "4" > /sys/devices/virtual/tty/ttyvsN/event
Quoted 7 lines
Quoted 5 lines

5. Emulate ring indicator (unset RI signal):

$ echo "5" > /sys/devices/virtual/tty/ttyvsN/event

6. Emulate break received (insert TTY_BREAK in data buffer):

$ echo "6" > /sys/devices/virtual/tty/ttyvsN/event

We can handle strings, right? Why all of the numbers?

Using numbers allowed me to write a switch case statement to handle all possible values. Should I replace them with string to make more user friendly.

Quoted 8 lines
Quoted 6 lines

7. Emulate cable is faulty (data sent is not received):

$ echo "1" > /sys/devices/virtual/tty/ttyvsN/faultycable

8. Emulate cable is not faulty (default):

$ echo "0" > /sys/devices/virtual/tty/ttyvsN/faultycable

Why is this a separate sysfs file?

Okay, I will merge with event file itself.

Quoted 2 lines

This all feels really odd, what is this going to be used for?

Let me give an example of faulty cable itself. We were testing a fleet tracker. During
field testing a cable become loose and we lost some of the data. Because there was
no logic written to handle this corner case, middleware could not detect this.

Quoted 2 lines

greg k-h

#16 lore raw
In reply to Rishi Gupta
Quoted 19 lines · Rishi Gupta

The driver named ttyvs creates virtual tty/serial device which emulates behaviour of a real serial port device. Serial port events like parity, frame, overflow errors, ring indications, break assertions, flow controls are also emulated.

It supports both device-tree and non device-tree platforms. And works in both built-in and loadable driver methods.

Use cases
~~~~~~~~~~~~~~~~~
This driver saves time to market and have following use cases including but not limited to; automated testing, GPS and other data simulation, data injection for corner case testing, scaleability testing, data sniffing, robotics emulator/simulator, application development when hardware, firmware and driver is still not available, identifying hardware issues from software bugs quickly during development, development cost reduction across team, product demo where data from hardware needs to be sent to the GUI application, data forwarding, serial port redirection etc.

Quoted 8 lines

Basic idea
~~~~~~~~~~~~~~~~~

This driver implements a virtual multi-port serial card in such a way that the virtual card can have 0 to N number of virtual serial ports (tty devices). The devices created in this card are used in exactly the same way as the real tty devices using standard termios and Linux/Posix APIs.

OK, I believe I have asked this before, at least when this has come up in other contexts: any reason not to do this by adding the missing elements to the pty interface? For fixed-name nodes, the legacy PTY interface is basically what you need.

It would probably have other benefits, as well.

-hpa

#17 lore raw
Quoted 6 lines · H. Peter Anvin
Quoted 4 lines · Rishi Gupta

The driver named ttyvs creates virtual tty/serial device which emulates behaviour of a real serial port device. Serial port events like parity, frame, overflow errors, ring indications, break assertions, flow controls are also emulated.

Brilliant! I've wanted that for decades. It would vastly simplify the implementation of some network-attached serial ports.

Quoted 4 lines

OK, I believe I have asked this before, at least when this has come up in other contexts: any reason not to do this by adding the missing elements to the pty interface? For fixed-name nodes, the legacy PTY interface is basically what you need.

I proposed doing exactly that many years ago, and I even offered to do it if there was some indication it would be accepted. The offer was ignored, and I never got far enough through the PTY code to determine if adding the required features would cause any problems for existing PTY users.

Signature · 3 lines
Grant Edwards               grant.b.edwards        Yow! What PROGRAM are they
                                  at               watching?
                              gmail.com