[PATCH v1 4/4] usb: serial: mxuport: add sysfs control for UART FIFO

Crescent Hsieh posted 4 patches 1 week, 3 days ago
[PATCH v1 4/4] usb: serial: mxuport: add sysfs control for UART FIFO
Posted by Crescent Hsieh 1 week, 3 days ago
Add a per-port sysfs attribute, uart_fifo, to allow userspace to enable
or disable the UART FIFO at runtime.

Map the requested state to the RQ_VENDOR_SET_FIFO_DISABLE vendor command
and track the current FIFO setting in the per-port private data.

Initialize the FIFO state during port probe and remove the sysfs
attribute when the port is released.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
 drivers/usb/serial/mxuport.c | 75 ++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c
index 9a8bb4f02da3..24b86d1a31d4 100644
--- a/drivers/usb/serial/mxuport.c
+++ b/drivers/usb/serial/mxuport.c
@@ -183,6 +183,7 @@ struct mxuport_port {
 	u32 hold_reason;
 	u8 mcr_state;		/* Last MCR state */
 	u8 msr_state;		/* Last MSR state */
+	bool fifo_enabled;
 	struct serial_rs485 rs485;
 	struct mutex mutex;	/* Protects mcr_state */
 	spinlock_t spinlock;	/* Protects msr_state */
@@ -1242,6 +1243,68 @@ static int mxuport_probe(struct usb_serial *serial,
 	return err;
 }
 
+static ssize_t uart_fifo_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct usb_serial_port *port = to_usb_serial_port(dev);
+	struct mxuport_port *mxport = usb_get_serial_port_data(port);
+
+	if (mxport->fifo_enabled)
+		return sysfs_emit(buf, "enabled\n");
+
+	return sysfs_emit(buf, "disabled\n");
+}
+
+static ssize_t uart_fifo_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct usb_serial_port *port = to_usb_serial_port(dev);
+	struct mxuport_port *mxport = usb_get_serial_port_data(port);
+	struct usb_serial *serial = port->serial;
+	bool state;
+	int ret;
+
+	if (!count)
+		return -EINVAL;
+
+	ret = kstrtobool(buf, &state);
+	if (ret < 0)
+		return ret;
+
+	if (state == 1) {
+		ret = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_FIFO_DISABLE,
+					    0, port->port_number);
+		if (ret)
+			return ret;
+
+		mxport->fifo_enabled = true;
+	} else if (state == 0) {
+		ret = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_FIFO_DISABLE,
+					    1, port->port_number);
+		if (ret)
+			return ret;
+
+		mxport->fifo_enabled = false;
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+static DEVICE_ATTR_RW(uart_fifo);
+
+static int mxuport_create_sysfs_attrs(struct usb_serial_port *port)
+{
+	return device_create_file(&port->dev, &dev_attr_uart_fifo);
+}
+
+static int mxuport_remove_sysfs_attrs(struct usb_serial_port *port)
+{
+	device_remove_file(&port->dev, &dev_attr_uart_fifo);
+
+	return 0;
+}
 
 static int mxuport_port_probe(struct usb_serial_port *port)
 {
@@ -1266,18 +1329,29 @@ static int mxuport_port_probe(struct usb_serial_port *port)
 	if (err)
 		return err;
 
+	mxport->fifo_enabled = true;
+
 	/* Set transmission mode (Hi-Performance) */
 	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_HIGH_PERFOR,
 				    0, port->port_number);
 	if (err)
 		return err;
 
+	err = mxuport_create_sysfs_attrs(port);
+	if (err)
+		return err;
+
 	/* Set interface (RS-232) */
 	return mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE,
 				     MX_INT_RS232,
 				     port->port_number);
 }
 
+static void mxuport_port_remove(struct usb_serial_port *port)
+{
+	mxuport_remove_sysfs_attrs(port);
+}
+
 static int mxuport_attach(struct usb_serial *serial)
 {
 	struct usb_serial_port *port0 = serial->port[0];
@@ -1501,6 +1575,7 @@ static struct usb_serial_driver mxuport_device = {
 	.num_bulk_out		= 1,
 	.probe			= mxuport_probe,
 	.port_probe		= mxuport_port_probe,
+	.port_remove		= mxuport_port_remove,
 	.attach			= mxuport_attach,
 	.release		= mxuport_release,
 	.calc_num_ports		= mxuport_calc_num_ports,
-- 
2.43.0