#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/idr.h>
#include "xhci.h"
#include "xhci-dbgcap.h"
static struct tty_driver *dbc_tty_driver;
+static struct idr dbc_tty_minors;
+static DEFINE_MUTEX(dbc_tty_minors_lock);
static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc)
{
static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
- struct dbc_port *port = driver->driver_state;
+ struct dbc_port *port;
+
+ mutex_lock(&dbc_tty_minors_lock);
+ port = idr_find(&dbc_tty_minors, tty->index);
+ mutex_unlock(&dbc_tty_minors_lock);
+
+ if (!port)
+ return -ENXIO;
tty->driver_data = port;
xhci_dbc_tty_init_port(dbc, port);
+ mutex_lock(&dbc_tty_minors_lock);
+ port->minor = idr_alloc(&dbc_tty_minors, port, 0, 64, GFP_KERNEL);
+ mutex_unlock(&dbc_tty_minors_lock);
+
+ if (port->minor < 0) {
+ ret = port->minor;
+ goto err_idr;
+ }
+
ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
if (ret)
goto err_exit_port;
goto err_free_requests;
tty_dev = tty_port_register_device(&port->port,
- dbc_tty_driver, 0, NULL);
+ dbc_tty_driver, port->minor, NULL);
if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);
goto err_free_requests;
err_free_fifo:
kfifo_free(&port->write_fifo);
err_exit_port:
+ idr_remove(&dbc_tty_minors, port->minor);
+err_idr:
xhci_dbc_tty_exit_port(port);
dev_err(dbc->dev, "can't register tty port, err %d\n", ret);
if (!port->registered)
return;
- tty_unregister_device(dbc_tty_driver, 0);
+ tty_unregister_device(dbc_tty_driver, port->minor);
xhci_dbc_tty_exit_port(port);
port->registered = false;
+ mutex_lock(&dbc_tty_minors_lock);
+ idr_remove(&dbc_tty_minors, port->minor);
+ mutex_unlock(&dbc_tty_minors_lock);
+
kfifo_free(&port->write_fifo);
xhci_dbc_free_requests(&port->read_pool);
xhci_dbc_free_requests(&port->read_queue);
if (!port)
return -ENOMEM;
- dbc_tty_driver->driver_state = port;
-
dbc = xhci_alloc_dbc(dev, base, &dbc_driver);
+
if (!dbc) {
status = -ENOMEM;
goto out2;
{
int ret;
- dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW |
+ idr_init(&dbc_tty_minors);
+
+ dbc_tty_driver = tty_alloc_driver(64, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
- if (IS_ERR(dbc_tty_driver))
+ if (IS_ERR(dbc_tty_driver)) {
+ idr_destroy(&dbc_tty_minors);
return PTR_ERR(dbc_tty_driver);
+ }
dbc_tty_driver->driver_name = "dbc_serial";
dbc_tty_driver->name = "ttyDBC";
if (ret) {
pr_err("Can't register dbc tty driver\n");
tty_driver_kref_put(dbc_tty_driver);
+ idr_destroy(&dbc_tty_minors);
}
+
return ret;
}
tty_driver_kref_put(dbc_tty_driver);
dbc_tty_driver = NULL;
}
+
+ idr_destroy(&dbc_tty_minors);
}