|
@@ -34,7 +34,9 @@ static int tty_port_default_receive_buf(struct tty_port *port,
|
|
|
if (!disc)
|
|
|
return 0;
|
|
|
|
|
|
+ mutex_lock(&tty->atomic_write_lock);
|
|
|
ret = tty_ldisc_receive_buf(disc, p, (char *)f, count);
|
|
|
+ mutex_unlock(&tty->atomic_write_lock);
|
|
|
|
|
|
tty_ldisc_deref(disc);
|
|
|
|
|
@@ -128,20 +130,86 @@ struct device *tty_port_register_device_attr(struct tty_port *port,
|
|
|
struct tty_driver *driver, unsigned index,
|
|
|
struct device *device, void *drvdata,
|
|
|
const struct attribute_group **attr_grp)
|
|
|
+{
|
|
|
+ tty_port_link_device(port, driver, index);
|
|
|
+ return tty_register_device_attr(driver, index, device, drvdata,
|
|
|
+ attr_grp);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
|
|
|
+
|
|
|
+/**
|
|
|
+ * tty_port_register_device_attr_serdev - register tty or serdev device
|
|
|
+ * @port: tty_port of the device
|
|
|
+ * @driver: tty_driver for this device
|
|
|
+ * @index: index of the tty
|
|
|
+ * @device: parent if exists, otherwise NULL
|
|
|
+ * @drvdata: driver data for the device
|
|
|
+ * @attr_grp: attribute group for the device
|
|
|
+ *
|
|
|
+ * Register a serdev or tty device depending on if the parent device has any
|
|
|
+ * defined serdev clients or not.
|
|
|
+ */
|
|
|
+struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
|
|
|
+ struct tty_driver *driver, unsigned index,
|
|
|
+ struct device *device, void *drvdata,
|
|
|
+ const struct attribute_group **attr_grp)
|
|
|
{
|
|
|
struct device *dev;
|
|
|
|
|
|
tty_port_link_device(port, driver, index);
|
|
|
|
|
|
dev = serdev_tty_port_register(port, device, driver, index);
|
|
|
- if (PTR_ERR(dev) != -ENODEV)
|
|
|
+ if (PTR_ERR(dev) != -ENODEV) {
|
|
|
/* Skip creating cdev if we registered a serdev device */
|
|
|
return dev;
|
|
|
+ }
|
|
|
|
|
|
return tty_register_device_attr(driver, index, device, drvdata,
|
|
|
attr_grp);
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
|
|
|
+EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
|
|
|
+
|
|
|
+/**
|
|
|
+ * tty_port_register_device_serdev - register tty or serdev device
|
|
|
+ * @port: tty_port of the device
|
|
|
+ * @driver: tty_driver for this device
|
|
|
+ * @index: index of the tty
|
|
|
+ * @device: parent if exists, otherwise NULL
|
|
|
+ *
|
|
|
+ * Register a serdev or tty device depending on if the parent device has any
|
|
|
+ * defined serdev clients or not.
|
|
|
+ */
|
|
|
+struct device *tty_port_register_device_serdev(struct tty_port *port,
|
|
|
+ struct tty_driver *driver, unsigned index,
|
|
|
+ struct device *device)
|
|
|
+{
|
|
|
+ return tty_port_register_device_attr_serdev(port, driver, index,
|
|
|
+ device, NULL, NULL);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(tty_port_register_device_serdev);
|
|
|
+
|
|
|
+/**
|
|
|
+ * tty_port_unregister_device - deregister a tty or serdev device
|
|
|
+ * @port: tty_port of the device
|
|
|
+ * @driver: tty_driver for this device
|
|
|
+ * @index: index of the tty
|
|
|
+ *
|
|
|
+ * If a tty or serdev device is registered with a call to
|
|
|
+ * tty_port_register_device_serdev() then this function must be called when
|
|
|
+ * the device is gone.
|
|
|
+ */
|
|
|
+void tty_port_unregister_device(struct tty_port *port,
|
|
|
+ struct tty_driver *driver, unsigned index)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = serdev_tty_port_unregister(port);
|
|
|
+ if (ret == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ tty_unregister_device(driver, index);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(tty_port_unregister_device);
|
|
|
|
|
|
int tty_port_alloc_xmit_buf(struct tty_port *port)
|
|
|
{
|
|
@@ -189,9 +257,6 @@ static void tty_port_destructor(struct kref *kref)
|
|
|
/* check if last port ref was dropped before tty release */
|
|
|
if (WARN_ON(port->itty))
|
|
|
return;
|
|
|
-
|
|
|
- serdev_tty_port_unregister(port);
|
|
|
-
|
|
|
if (port->xmit_buf)
|
|
|
free_page((unsigned long)port->xmit_buf);
|
|
|
tty_port_destroy(port);
|