2012-08-07 19:55:18

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 00/41] TTY buffer in tty_port -- prep no. 4

Hi,

this is the fourth, and hopefully the last, series of patches which
allow tty buffers to be moved from tty_struct (present from open to
close/hangup) to tty_port (present as long as the device). This will
allow us to get rid of the tty refcounting in the interrupt service
routines and other hot paths after we are done. This is because we
will not need to handle races among ISRs, timers, hangups and others,
because tty_port lives as long as an interrupt/timer tick may occur.
Unlike tty_struct.

In this series, the fourth batch of drivers is converted to use
tty_port. Last time I promised that all drivers have a tty_port. It
was not really true. Now it should be. Here we also continued
assigning tty_port to tty_struct->port. And we should be done with
that here too. I.e. for all in-kernel drivers we have tty->port set
after driver->ops->install returns. So the TTY layer now finally has
an access to a tty_port in all of the drivers.

Now we can start moving tty buffers to tty_port and get rid of all the
refcounting as was mentioned above.

As usual, standard x86 stuff was runtime-tested. The rest is only
checked to be compilation-errors free.

Jiri Slaby (41):
TTY: pty, stop passing NULL to free_tty_struct
TTY: 68328serial, fix compilation
TTY: n_gsm, use tty_port_install
misc: pti, add const to pci_device_id table
misc: pti, pci drvdata cannot be NULL in ->remove
misc: pti, stop using iomap's unmap on ioremap space
misc: pti, move ->remove to the PCI code
misc: pti, do the opposite of ->probe in ->remove
misc: pti, fix fail paths
misc: pti, fix tty_port count
misc: pti, use tty_port_register_device
mxser: allow overlapping vector
TTY: ttyprintk, unregister tty driver on failure
TTY: ttyprintk, don't touch behind tty->write_buf
TTY: ttyprintk, initialize tty_port earlier
TTY: tty3270, free tty driver properly
TTY: pass flags to alloc_tty_driver
TTY: pty, switch to tty_alloc_driver
TTY: move allocations to tty_alloc_driver
TTY: add support for unnumbered device nodes
TTY: move cdev_add to tty_register_device
TTY: use tty_port_register_device
TTY: automatically create nodes for some drivers
TTY: tty_port, add some documentation
TTY: add tty_port_link_device
TTY: use tty_port_link_device
TTY: synclink_cs, sanitize fail paths
TTY: synclink_cs, use dynamic tty devices
TTY: synclink_cs, final cleanup in synclink_cs_init
TTY: moxa, convert to dynamic device
TTY: nfcon, add tty_port and link it
TTY: con3215, unset raw3215[line]
TTY: con3215, add tty install
TTY: i4l, add tty install
TTY: synclink, add tty install
TTY: synclinkmp, add tty install
TTY: ircomm_tty, add tty install
TTY: tty3270, add tty install
TTY: hvc_console, add tty install
TTY: hvcs, clean hvcs_open a bit
TTY: hvcs, add tty install

arch/alpha/kernel/srmcons.c | 1 +
arch/ia64/hp/sim/simserial.c | 1 +
arch/m68k/emu/nfcon.c | 4 +
arch/parisc/kernel/pdc_cons.c | 1 +
arch/um/drivers/line.c | 3 +-
arch/xtensa/platforms/iss/console.c | 1 +
drivers/char/pcmcia/synclink_cs.c | 105 ++++++++++-----------
drivers/char/ttyprintk.c | 29 +++---
drivers/isdn/capi/capi.c | 3 +-
drivers/isdn/gigaset/interface.c | 3 +-
drivers/isdn/i4l/isdn_tty.c | 25 +++--
drivers/misc/pti.c | 128 ++++++++++++-------------
drivers/mmc/card/sdio_uart.c | 4 +-
drivers/net/usb/hso.c | 7 +-
drivers/s390/char/con3215.c | 28 ++++--
drivers/s390/char/sclp_tty.c | 1 +
drivers/s390/char/sclp_vt220.c | 1 +
drivers/s390/char/tty3270.c | 34 +++++--
drivers/staging/ipack/devices/ipoctal.c | 2 +-
drivers/tty/amiserial.c | 9 +-
drivers/tty/bfin_jtag_comm.c | 1 +
drivers/tty/cyclades.c | 16 ++--
drivers/tty/ehv_bytechan.c | 9 +-
drivers/tty/hvc/hvc_console.c | 31 +++++--
drivers/tty/hvc/hvcs.c | 82 +++++++++-------
drivers/tty/hvc/hvsi.c | 2 +
drivers/tty/ipwireless/tty.c | 2 +-
drivers/tty/isicom.c | 3 +-
drivers/tty/moxa.c | 24 ++++-
drivers/tty/mxser.c | 41 ++++++--
drivers/tty/n_gsm.c | 30 ++++--
drivers/tty/nozomi.c | 4 +-
drivers/tty/pty.c | 36 +++++---
drivers/tty/rocket.c | 4 +-
drivers/tty/serial/68328serial.c | 23 +++--
drivers/tty/serial/crisv10.c | 11 ++-
drivers/tty/serial/ifx6x60.c | 4 +-
drivers/tty/serial/msm_smd_tty.c | 8 +-
drivers/tty/serial/serial_core.c | 3 +-
drivers/tty/synclink.c | 44 +++++----
drivers/tty/synclink_gt.c | 7 +-
drivers/tty/synclinkmp.c | 28 ++++--
drivers/tty/tty_io.c | 154 ++++++++++++++++++++-----------
drivers/tty/tty_port.c | 43 ++++++++-
drivers/usb/class/cdc-acm.c | 3 +-
drivers/usb/gadget/u_serial.c | 3 +-
include/linux/tty.h | 2 +
include/linux/tty_driver.h | 35 ++++++-
net/bluetooth/rfcomm/tty.c | 4 +-
net/irda/ircomm/ircomm_tty.c | 41 ++++----
50 files changed, 692 insertions(+), 396 deletions(-)

--
1.7.10.4


2012-08-07 19:53:15

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 35/41] TTY: synclink, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/synclink.c | 44 ++++++++++++++++++++++++++------------------
1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index bdeeb31..f147ccb 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -3362,6 +3362,29 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,

} /* end of block_til_ready() */

+static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct mgsl_struct *info;
+ int line = tty->index;
+
+ /* verify range of specified line number */
+ if (line >= mgsl_device_count) {
+ printk("%s(%d):mgsl_open with invalid line #%d.\n",
+ __FILE__, __LINE__, line);
+ return -ENODEV;
+ }
+
+ /* find the info structure for the specified line */
+ info = mgsl_device_list;
+ while (info && info->line != line)
+ info = info->next_device;
+ if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
+ return -ENODEV;
+ tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
/* mgsl_open()
*
* Called when a port is opened. Init and enable port.
@@ -3374,26 +3397,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
static int mgsl_open(struct tty_struct *tty, struct file * filp)
{
- struct mgsl_struct *info;
- int retval, line;
+ struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
+ int retval;

- /* verify range of specified line number */
- line = tty->index;
- if (line >= mgsl_device_count) {
- printk("%s(%d):mgsl_open with invalid line #%d.\n",
- __FILE__,__LINE__,line);
- return -ENODEV;
- }
-
- /* find the info structure for the specified line */
- info = mgsl_device_list;
- while(info && info->line != line)
- info = info->next_device;
- if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
- return -ENODEV;
-
- tty->driver_data = info;
info->port.tty = tty;

if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4297,6 +4304,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
} /* end of mgsl_allocate_device()*/

static const struct tty_operations mgsl_ops = {
+ .install = mgsl_install,
.open = mgsl_open,
.close = mgsl_close,
.write = mgsl_write,
--
1.7.10.4

2012-08-07 19:53:22

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 36/41] TTY: synclinkmp, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/synclinkmp.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index ae75a3c..b7c0a53 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -711,15 +711,11 @@ static void ldisc_receive_buf(struct tty_struct *tty,

/* tty callbacks */

-/* Called when a port is opened. Init and enable port.
- */
-static int open(struct tty_struct *tty, struct file *filp)
+static int install(struct tty_driver *driver, struct tty_struct *tty)
{
SLMP_INFO *info;
- int retval, line;
- unsigned long flags;
+ int line = tty->index;

- line = tty->index;
if (line >= synclinkmp_device_count) {
printk("%s(%d): open with invalid line #%d.\n",
__FILE__,__LINE__,line);
@@ -727,17 +723,30 @@ static int open(struct tty_struct *tty, struct file *filp)
}

info = synclinkmp_device_list;
- while(info && info->line != line)
+ while (info && info->line != line)
info = info->next_device;
if (sanity_check(info, tty->name, "open"))
return -ENODEV;
- if ( info->init_error ) {
+ if (info->init_error) {
printk("%s(%d):%s device is not allocated, init error=%d\n",
- __FILE__,__LINE__,info->device_name,info->init_error);
+ __FILE__, __LINE__, info->device_name,
+ info->init_error);
return -ENODEV;
}

tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
+/* Called when a port is opened. Init and enable port.
+ */
+static int open(struct tty_struct *tty, struct file *filp)
+{
+ SLMP_INFO *info = tty->driver_data;
+ unsigned long flags;
+ int retval;
+
info->port.tty = tty;

if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3881,6 +3890,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}

static const struct tty_operations ops = {
+ .install = install,
.open = open,
.close = close,
.write = write,
--
1.7.10.4

2012-08-07 19:53:24

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 37/41] TTY: ircomm_tty, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Samuel Ortiz <[email protected]>
---
net/irda/ircomm/ircomm_tty.c | 41 +++++++++++++++++++++++++----------------
1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 7a0d611..9668990 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -52,6 +52,8 @@
#include <net/irda/ircomm_tty_attach.h>
#include <net/irda/ircomm_tty.h>

+static int ircomm_tty_install(struct tty_driver *driver,
+ struct tty_struct *tty);
static int ircomm_tty_open(struct tty_struct *tty, struct file *filp);
static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
static int ircomm_tty_write(struct tty_struct * tty,
@@ -82,6 +84,7 @@ static struct tty_driver *driver;
static hashbin_t *ircomm_tty = NULL;

static const struct tty_operations ops = {
+ .install = ircomm_tty_install,
.open = ircomm_tty_open,
.close = ircomm_tty_close,
.write = ircomm_tty_write,
@@ -374,21 +377,11 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
return retval;
}

-/*
- * Function ircomm_tty_open (tty, filp)
- *
- * This routine is called when a particular tty device is opened. This
- * routine is mandatory; if this routine is not filled in, the attempted
- * open will fail with ENODEV.
- */
-static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+
+static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct ircomm_tty_cb *self;
unsigned int line = tty->index;
- unsigned long flags;
- int ret;
-
- IRDA_DEBUG(2, "%s()\n", __func__ );

/* Check if instance already exists */
self = hashbin_lock_find(ircomm_tty, line, NULL);
@@ -425,14 +418,30 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
tty->termios.c_oflag = 0;

/* Insert into hash */
- /* FIXME there is a window from find to here */
hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
}
+
+ return tty_port_install(&self->port, driver, tty);
+}
+
+/*
+ * Function ircomm_tty_open (tty, filp)
+ *
+ * This routine is called when a particular tty device is opened. This
+ * routine is mandatory; if this routine is not filled in, the attempted
+ * open will fail with ENODEV.
+ */
+static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct ircomm_tty_cb *self = tty->driver_data;
+ unsigned long flags;
+ int ret;
+
+ IRDA_DEBUG(2, "%s()\n", __func__ );
+
/* ++ is not atomic, so this should be protected - Jean II */
spin_lock_irqsave(&self->port.lock, flags);
self->port.count++;
-
- tty->driver_data = self;
spin_unlock_irqrestore(&self->port.lock, flags);
tty_port_tty_set(&self->port, tty);

@@ -472,7 +481,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
}

/* Check if this is a "normal" ircomm device, or an irlpt device */
- if (line < 0x10) {
+ if (self->line < 0x10) {
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
/* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
--
1.7.10.4

2012-08-07 19:53:28

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 33/41] TTY: con3215, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/s390/char/con3215.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 1655498..9ffb6d5 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -942,6 +942,19 @@ static int __init con3215_init(void)
console_initcall(con3215_init);
#endif

+static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct raw3215_info *raw;
+
+ raw = raw3215[tty->index];
+ if (raw == NULL)
+ return -ENODEV;
+
+ tty->driver_data = raw;
+
+ return tty_port_install(&raw->port, driver, tty);
+}
+
/*
* tty3215_open
*
@@ -949,14 +962,9 @@ console_initcall(con3215_init);
*/
static int tty3215_open(struct tty_struct *tty, struct file * filp)
{
- struct raw3215_info *raw;
+ struct raw3215_info *raw = tty->driver_data;
int retval;

- raw = raw3215[tty->index];
- if (raw == NULL)
- return -ENODEV;
-
- tty->driver_data = raw;
tty_port_tty_set(&raw->port, tty);

tty->low_latency = 0; /* don't use bottom half for pushing chars */
@@ -1117,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty)
}

static const struct tty_operations tty3215_ops = {
+ .install = tty3215_install,
.open = tty3215_open,
.close = tty3215_close,
.write = tty3215_write,
--
1.7.10.4

2012-08-07 19:53:39

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 04/41] misc: pti, add const to pci_device_id table

It is annotated as __devinitconst. Despite the annotation is useless
in most cases, const keyword is misssing there. So we are placing
non-const data into rodata section. Fix that now.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index b7eb545..5cb61f7 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -76,7 +76,7 @@ struct pti_dev {
*/
static DEFINE_MUTEX(alloclock);

-static struct pci_device_id pci_ids[] __devinitconst = {
+static const struct pci_device_id pci_ids[] __devinitconst = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
{0}
};
--
1.7.10.4

2012-08-07 19:53:47

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 17/41] TTY: pass flags to alloc_tty_driver

We need to allow drivers that use neither tty_port_install nor
tty_port_register_device to link a tty_port to a tty somehow. To
avoid a race with open, this has to be performed before
tty_register_device. But currently tty_driver->ports is allocated even
in tty_register_device because we do not know whether this is the PTY
driver. The PTY driver is special here due to an excessive count of
lines it declares to handle. We cannot handle tty_ports there this
way.

To circumvent this, we start passing tty_driver flags to
alloc_tty_driver already and we create tty_alloc_driver for this
purpose. There we can allocate tty_driver->ports and do all the magic
between tty_alloc_driver and tty_register_device. Later we will
introduce tty_port_link_device function for that purpose.

All drivers should eventually switch to this new tty driver allocation
interface.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_io.c | 34 +++++++++++++++++++++++++---------
include/linux/tty_driver.h | 23 +++++++++++++++++++----
2 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index c6f4d71..e024521 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3046,21 +3046,37 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
}
EXPORT_SYMBOL(tty_unregister_device);

-struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
+/**
+ * __tty_alloc_driver -- allocate tty driver
+ * @lines: count of lines this driver can handle at most
+ * @owner: module which is repsonsible for this driver
+ * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags
+ *
+ * This should not be called directly, some of the provided macros should be
+ * used instead. Use IS_ERR and friends on @retval.
+ */
+struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
+ unsigned long flags)
{
struct tty_driver *driver;

+ if (!lines)
+ return ERR_PTR(-EINVAL);
+
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
- if (driver) {
- kref_init(&driver->kref);
- driver->magic = TTY_DRIVER_MAGIC;
- driver->num = lines;
- driver->owner = owner;
- /* later we'll move allocation of tables here */
- }
+ if (!driver)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&driver->kref);
+ driver->magic = TTY_DRIVER_MAGIC;
+ driver->num = lines;
+ driver->owner = owner;
+ driver->flags = flags;
+ /* later we'll move allocation of tables here */
+
return driver;
}
-EXPORT_SYMBOL(__alloc_tty_driver);
+EXPORT_SYMBOL(__tty_alloc_driver);

static void destruct_tty_driver(struct kref *kref)
{
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 80e72dc..3adc362 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -296,11 +296,11 @@ struct tty_driver {
int name_base; /* offset of printed name */
int major; /* major device number */
int minor_start; /* start of minor device number */
- int num; /* number of devices allocated */
+ unsigned int num; /* number of devices allocated */
short type; /* type of tty driver */
short subtype; /* subtype of tty driver */
struct ktermios init_termios; /* Initial termios */
- int flags; /* tty driver flags */
+ unsigned long flags; /* tty driver flags */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */

@@ -322,7 +322,8 @@ struct tty_driver {

extern struct list_head tty_drivers;

-extern struct tty_driver *__alloc_tty_driver(int lines, struct module *owner);
+extern struct tty_driver *__tty_alloc_driver(unsigned int lines,
+ struct module *owner, unsigned long flags);
extern void put_tty_driver(struct tty_driver *driver);
extern void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op);
@@ -330,7 +331,21 @@ extern struct tty_driver *tty_find_polling_driver(char *name, int *line);

extern void tty_driver_kref_put(struct tty_driver *driver);

-#define alloc_tty_driver(lines) __alloc_tty_driver(lines, THIS_MODULE)
+/* Use TTY_DRIVER_* flags below */
+#define tty_alloc_driver(lines, flags) \
+ __tty_alloc_driver(lines, THIS_MODULE, flags)
+
+/*
+ * DEPRECATED Do not use this in new code, use tty_alloc_driver instead.
+ * (And change the return value checks.)
+ */
+static inline struct tty_driver *alloc_tty_driver(unsigned int lines)
+{
+ struct tty_driver *ret = tty_alloc_driver(lines, 0);
+ if (IS_ERR(ret))
+ return NULL;
+ return ret;
+}

static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
{
--
1.7.10.4

2012-08-07 19:54:06

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 05/41] misc: pti, pci drvdata cannot be NULL in ->remove

As we set drvdata unconditionally in ->probe, we need not check if it
is NULL. Let us remove the check.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 5cb61f7..88da085e 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -400,16 +400,13 @@ EXPORT_SYMBOL_GPL(pti_writedata);
*/
static void __devexit pti_pci_remove(struct pci_dev *pdev)
{
- struct pti_dev *drv_data;
+ struct pti_dev *drv_data = pci_get_drvdata(pdev);

- drv_data = pci_get_drvdata(pdev);
- if (drv_data != NULL) {
- pci_iounmap(pdev, drv_data->pti_ioaddr);
- pci_set_drvdata(pdev, NULL);
- kfree(drv_data);
- pci_release_region(pdev, 1);
- pci_disable_device(pdev);
- }
+ pci_iounmap(pdev, drv_data->pti_ioaddr);
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+ pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
}

/*
--
1.7.10.4

2012-08-07 19:54:24

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 02/41] TTY: 68328serial, fix compilation

tty_struct->termios is no longer a pointer. This was changed recently
by "tty: move the termios object into the tty". But 68328serial was
not changed, so we now have a compilation error:
68328serial.c: In function 'change_speed':
68328serial.c:518:22: error: invalid type argument of '->' (have 'struct ktermios')
68328serial.c: In function 'rs_set_ldisc':
68328serial.c:620:31: error: invalid type argument of '->' (have 'struct ktermios')
68328serial.c: In function 'rs_set_termios':
68328serial.c:988:20: error: invalid type argument of '->' (have 'struct ktermios')

Fix that now.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Alan Cox <[email protected]>
---
drivers/tty/serial/68328serial.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 3ed20e4..cc4c092 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
unsigned cflag;
int i;

- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
if (!(port = info->port))
return;

@@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
return;

- info->is_cons = (tty->termios->c_line == N_TTY);
+ info->is_cons = (tty->termios.c_line == N_TTY);

printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
}
@@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info, tty);

if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
+ tty->termios.c_line = N_TTY;
if (tty->ldisc.open)
(tty->ldisc.open)(tty);
}
--
1.7.10.4

2012-08-07 19:54:29

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 26/41] TTY: use tty_port_link_device

So now for those drivers that can use neither tty_port_install nor
tty_port_register_driver but still have tty_port available before
tty_register_driver we use newly added tty_port_link_device.

The rest of the drivers that still do not provide tty_struct <->
tty_port link will have to be converted to implement
tty->ops->install.

Signed-off-by: Jiri Slaby <[email protected]>
---
arch/alpha/kernel/srmcons.c | 1 +
arch/ia64/hp/sim/simserial.c | 1 +
arch/parisc/kernel/pdc_cons.c | 1 +
arch/xtensa/platforms/iss/console.c | 1 +
drivers/char/ttyprintk.c | 1 +
drivers/s390/char/sclp_tty.c | 1 +
drivers/s390/char/sclp_vt220.c | 1 +
drivers/tty/amiserial.c | 9 +++++----
drivers/tty/bfin_jtag_comm.c | 1 +
drivers/tty/hvc/hvsi.c | 2 ++
drivers/tty/serial/68328serial.c | 15 +++++++++------
drivers/tty/serial/crisv10.c | 9 ++++++---
12 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 3ea8094..5d58652 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -223,6 +223,7 @@ srmcons_init(void)
driver->subtype = SYSTEM_TYPE_SYSCONS;
driver->init_termios = tty_std_termios;
tty_set_operations(driver, &srmcons_ops);
+ tty_port_link_device(&srmcons_singleton.port, driver, 0);
err = tty_register_driver(driver);
if (err) {
put_tty_driver(driver);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 1ce97f4..ec536e4 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -545,6 +545,7 @@ static int __init simrs_init(void)
/* the port is imaginary */
printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);

+ tty_port_link_device(&state->port, hp_simserial_driver, 0);
retval = tty_register_driver(hp_simserial_driver);
if (retval) {
printk(KERN_ERR "Couldn't register simserial driver\n");
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 47341aa..8823863 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -202,6 +202,7 @@ static int __init pdc_console_tty_driver_init(void)
pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
+ tty_port_link_device(&tty_port, pdc_console_tty_driver, 0);

err = tty_register_driver(pdc_console_tty_driver);
if (err) {
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index f9726f6..2cd3d3a 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -223,6 +223,7 @@ int __init rs_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;

tty_set_operations(serial_driver, &serial_ops);
+ tty_port_link_device(&serial_port, serial_driver, 0);

if (tty_register_driver(serial_driver))
panic("Couldn't register serial driver\n");
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 9e6272f..561f8aa 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -198,6 +198,7 @@ static int __init ttyprintk_init(void)
ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+ tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);

ret = tty_register_driver(ttyprintk_driver);
if (ret < 0) {
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 0792c85..30ec09e 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -567,6 +567,7 @@ sclp_tty_init(void)
driver->init_termios.c_lflag = ISIG | ECHO;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_ops);
+ tty_port_link_device(&sclp_port, driver, 0);
rc = tty_register_driver(driver);
if (rc) {
put_tty_driver(driver);
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index edfc0fd..7e60f3d 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void)
driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_vt220_ops);
+ tty_port_link_device(&sclp_vt220_port, driver, 0);

rc = tty_register_driver(driver);
if (rc)
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 0e8441e..2acf199 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);

- error = tty_register_driver(serial_driver);
- if (error)
- goto fail_put_tty_driver;
-
state = rs_table;
state->port = (int)&custom.serdatr; /* Just to give it a value */
state->custom_divisor = 0;
@@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
state->icount.overrun = state->icount.brk = 0;
tty_port_init(&state->tport);
state->tport.ops = &amiga_port_ops;
+ tty_port_link_device(&state->tport, serial_driver, 0);
+
+ error = tty_register_driver(serial_driver);
+ if (error)
+ goto fail_put_tty_driver;

printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");

diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 61fc74f..02b7d3a 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -263,6 +263,7 @@ static int __init bfin_jc_init(void)
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
+ tty_port_link_device(&port, bfin_jc_driver, 0);

ret = tty_register_driver(bfin_jc_driver);
if (ret)
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index 6f5bc49..0083bc1 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1080,6 +1080,8 @@ static int __init hvsi_init(void)
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;

+ tty_port_link_device(&hp->port, hvsi_driver, i);
+
ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
if (ret)
printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index cc4c092..66c38a3 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -1189,12 +1189,6 @@ rs68328_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &rs_ops);

- if (tty_register_driver(serial_driver)) {
- put_tty_driver(serial_driver);
- printk(KERN_ERR "Couldn't register serial driver\n");
- return -ENOMEM;
- }
-
local_irq_save(flags);

for(i=0;i<NR_PORTS;i++) {
@@ -1224,8 +1218,17 @@ rs68328_init(void)
0,
"M68328_UART", info))
panic("Unable to attach 68328 serial interrupt\n");
+
+ tty_port_link_device(&info->tport, serial_driver, i);
}
local_irq_restore(flags);
+
+ if (tty_register_driver(serial_driver)) {
+ put_tty_driver(serial_driver);
+ printk(KERN_ERR "Couldn't register serial driver\n");
+ return -ENOMEM;
+ }
+
return 0;
}

diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 708c3bf..8ea2081 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -4447,10 +4447,8 @@ static int __init rs_init(void)

tty_set_operations(driver, &rs_ops);
serial_driver = driver;
- if (tty_register_driver(driver))
- panic("Couldn't register serial driver\n");
- /* do some initializing for the separate ports */

+ /* do some initializing for the separate ports */
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
if (info->enabled) {
if (cris_request_io_interface(info->io_if,
@@ -4502,7 +4500,12 @@ static int __init rs_init(void)
printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
serial_driver->name, info->line, info->ioport);
}
+ tty_port_link_device(&info->port, driver, i);
}
+
+ if (tty_register_driver(driver))
+ panic("Couldn't register serial driver\n");
+
#ifdef CONFIG_ETRAX_FAST_TIMER
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
memset(fast_timers, 0, sizeof(fast_timers));
--
1.7.10.4

2012-08-07 19:54:35

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 30/41] TTY: moxa, convert to dynamic device

This allows us to provide the tty layer with information about
tty_port for each link.

We also provide a tty_port for the service port. For this one we allow
only ioctl, so this is pretty ugly.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/moxa.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 89cc934..9dffc72 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock);
static unsigned long baseaddr[MAX_BOARDS];
static unsigned int type[MAX_BOARDS];
static unsigned int numports[MAX_BOARDS];
+static struct tty_port moxa_service_port;

MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
@@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
const struct firmware *fw;
const char *file;
struct moxa_port *p;
- unsigned int i;
+ unsigned int i, first_idx;
int ret;

brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
@@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
mod_timer(&moxaTimer, jiffies + HZ / 50);
spin_unlock_bh(&moxa_lock);

+ first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+ for (i = 0; i < brd->numPorts; i++)
+ tty_port_register_device(&brd->ports[i].port, moxaDriver,
+ first_idx + i, dev);
+
return 0;
err_free:
kfree(brd->ports);
@@ -896,7 +902,7 @@ err:

static void moxa_board_deinit(struct moxa_board_conf *brd)
{
- unsigned int a, opened;
+ unsigned int a, opened, first_idx;

mutex_lock(&moxa_openlock);
spin_lock_bh(&moxa_lock);
@@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
mutex_lock(&moxa_openlock);
}

+ first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+ for (a = 0; a < brd->numPorts; a++)
+ tty_unregister_device(moxaDriver, first_idx + a);
+
iounmap(brd->basemem);
brd->basemem = NULL;
kfree(brd->ports);
@@ -1031,7 +1041,12 @@ static int __init moxa_init(void)

printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
- moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
+
+ tty_port_init(&moxa_service_port);
+
+ moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
if (!moxaDriver)
return -ENOMEM;

@@ -1044,8 +1059,9 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
- moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
+ /* Having one more port only for ioctls is ugly */
+ tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);

if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
--
1.7.10.4

2012-08-07 19:55:22

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 27/41] TTY: synclink_cs, sanitize fail paths

We will need to change the order of tty and pcmcia drivers
initializations (see the reason later in this series). And the fail
path handling is currently performed in a separate function that as
well takes care of proper deinitialization in module_exit. It is hard
to read and will need to be adjusted by our changes anyway. Instead,
get rid of this helper function and do the fail paths handling
directly in the init function. (And move the body of the function to
module_exit.)

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/char/pcmcia/synclink_cs.c | 41 +++++++++++++------------------------
1 file changed, 14 insertions(+), 27 deletions(-)

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index d0cbd29..0606586 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2798,23 +2798,6 @@ static const struct tty_operations mgslpc_ops = {
.proc_fops = &mgslpc_proc_fops,
};

-static void synclink_cs_cleanup(void)
-{
- int rc;
-
- while(mgslpc_device_list)
- mgslpc_remove_device(mgslpc_device_list);
-
- if (serial_driver) {
- if ((rc = tty_unregister_driver(serial_driver)))
- printk("%s(%d) failed to unregister tty driver err=%d\n",
- __FILE__,__LINE__,rc);
- put_tty_driver(serial_driver);
- }
-
- pcmcia_unregister_driver(&mgslpc_driver);
-}
-
static int __init synclink_cs_init(void)
{
int rc;
@@ -2830,7 +2813,7 @@ static int __init synclink_cs_init(void)
serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
if (!serial_driver) {
rc = -ENOMEM;
- goto error;
+ goto err_pcmcia_drv;
}

/* Initialize the tty_driver structure */
@@ -2850,25 +2833,29 @@ static int __init synclink_cs_init(void)
if ((rc = tty_register_driver(serial_driver)) < 0) {
printk("%s(%d):Couldn't register serial driver\n",
__FILE__,__LINE__);
- put_tty_driver(serial_driver);
- serial_driver = NULL;
- goto error;
+ goto err_put_tty;
}

printk("%s %s, tty major#%d\n",
driver_name, driver_version,
serial_driver->major);

- return 0;
-
-error:
- synclink_cs_cleanup();
- return rc;
+ return 0;
+err_put_tty:
+ put_tty_driver(serial_driver);
+err_pcmcia_drv:
+ pcmcia_unregister_driver(&mgslpc_driver);
+ return rc;
}

static void __exit synclink_cs_exit(void)
{
- synclink_cs_cleanup();
+ while (mgslpc_device_list)
+ mgslpc_remove_device(mgslpc_device_list);
+
+ tty_unregister_driver(serial_driver);
+ put_tty_driver(serial_driver);
+ pcmcia_unregister_driver(&mgslpc_driver);
}

module_init(synclink_cs_init);
--
1.7.10.4

2012-08-07 19:56:44

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 24/41] TTY: tty_port, add some documentation

I forgot to document tty_port_register_device and tty_port_install
when they were added. Fix it now.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_port.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index edcb827..b36b33a 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -33,6 +33,17 @@ void tty_port_init(struct tty_port *port)
}
EXPORT_SYMBOL(tty_port_init);

+/**
+ * tty_port_register_device - register tty device
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ * @device: parent if exists, otherwise NULL
+ *
+ * It is the same as tty_register_device except the provided @port is linked to
+ * a concrete tty specified by @index. Use this or tty_port_install (or both).
+ * Call tty_port_link_device as a last resort.
+ */
struct device *tty_port_register_device(struct tty_port *port,
struct tty_driver *driver, unsigned index,
struct device *device)
@@ -422,6 +433,16 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
}
EXPORT_SYMBOL(tty_port_close);

+/**
+ * tty_port_install - generic tty->ops->install handler
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @tty: tty to be installed
+ *
+ * It is the same as tty_standard_install except the provided @port is linked
+ * to a concrete tty specified by @tty. Use this or tty_port_register_device
+ * (or both). Call tty_port_link_device as a last resort.
+ */
int tty_port_install(struct tty_port *port, struct tty_driver *driver,
struct tty_struct *tty)
{
--
1.7.10.4

2012-08-07 19:56:54

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 22/41] TTY: use tty_port_register_device

Currently we have no way to assign tty->port while performing tty
installation. There are two ways to provide the link tty_struct =>
tty_port. Either by calling tty_port_install from tty->ops->install or
tty_port_register_device called instead of tty_register_device when
the device is being set up after connected.

In this patch we modify most of the drivers to do the latter. When the
drivers use tty_register_device and we have tty_port already, we
switch to tty_port_register_device. So we have the tty_struct =>
tty_port link for free for those.

Signed-off-by: Jiri Slaby <[email protected]>
---
arch/um/drivers/line.c | 3 ++-
drivers/isdn/capi/capi.c | 3 ++-
drivers/isdn/gigaset/interface.c | 3 ++-
drivers/mmc/card/sdio_uart.c | 4 ++--
drivers/net/usb/hso.c | 7 ++++---
drivers/staging/ipack/devices/ipoctal.c | 2 +-
drivers/tty/cyclades.c | 16 +++++++++-------
drivers/tty/ehv_bytechan.c | 9 +++++----
drivers/tty/ipwireless/tty.c | 2 +-
drivers/tty/isicom.c | 3 ++-
drivers/tty/mxser.c | 6 ++++--
drivers/tty/nozomi.c | 4 ++--
drivers/tty/rocket.c | 4 ++--
drivers/tty/serial/ifx6x60.c | 4 ++--
drivers/tty/serial/msm_smd_tty.c | 8 +++++---
drivers/tty/serial/serial_core.c | 3 ++-
drivers/tty/synclink_gt.c | 7 +++++--
drivers/usb/class/cdc-acm.c | 3 ++-
drivers/usb/gadget/u_serial.c | 3 ++-
net/bluetooth/rfcomm/tty.c | 4 ++--
20 files changed, 58 insertions(+), 40 deletions(-)

diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index bbaf2c5..457475f 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -409,7 +409,8 @@ int setup_one_line(struct line *lines, int n, char *init,
line->valid = 1;
err = parse_chan_pair(new, line, n, opts, error_out);
if (!err) {
- struct device *d = tty_register_device(driver, n, NULL);
+ struct device *d = tty_port_register_device(&line->port,
+ driver, n, NULL);
if (IS_ERR(d)) {
*error_out = "Failed to register device";
err = PTR_ERR(d);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 38c4bd8..c679867 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)

mp->minor = minor;

- dev = tty_register_device(capinc_tty_driver, minor, NULL);
+ dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
+ NULL);
if (IS_ERR(dev))
goto err_out2;

diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index f9aab74..67abf3f 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs)
tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);

mutex_lock(&cs->mutex);
- cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
+ cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
+ cs->minor_index, NULL);

if (!IS_ERR(cs->tty_dev))
dev_set_drvdata(cs->tty_dev, cs);
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 372c032..d2339ea 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func,
kfree(port);
} else {
struct device *dev;
- dev = tty_register_device(sdio_uart_tty_driver,
- port->index, &func->dev);
+ dev = tty_port_register_device(&port->port,
+ sdio_uart_tty_driver, port->index, &func->dev);
if (IS_ERR(dev)) {
sdio_uart_port_remove(port);
ret = PTR_ERR(dev);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 7736af7..605a4ba 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2287,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
if (minor < 0)
goto exit;

+ tty_port_init(&serial->port);
+
/* register our minor number */
- serial->parent->dev = tty_register_device(tty_drv, minor,
- &serial->parent->interface->dev);
+ serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
+ minor, &serial->parent->interface->dev);
dev = serial->parent->dev;
dev_set_drvdata(dev, serial->parent);
i = device_create_file(dev, &dev_attr_hsotype);
@@ -2298,7 +2300,6 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->minor = minor;
serial->magic = HSO_SERIAL_MAGIC;
spin_lock_init(&serial->serial_lock);
- tty_port_init(&serial->port);
serial->num_rx_urbs = num_urbs;

/* RX, allocate urb and initialize */
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
index fd0e301..fbd18ad 100644
--- a/drivers/staging/ipack/devices/ipoctal.c
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -502,7 +502,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
ipoctal->pointer_read[i] = 0;
ipoctal->pointer_write[i] = 0;
ipoctal->nb_bytes[i] = 0;
- tty_register_device(tty, i, NULL);
+ tty_port_register_device(&ipoctal->tty_port[i], tty, i, NULL);

/*
* Enable again the RX. TX will be enabled when
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e77db71..27b30ef 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -3289,7 +3289,7 @@ static int __init cy_detect_isa(void)
struct cyclades_card *card;
unsigned short cy_isa_irq, nboard;
void __iomem *cy_isa_address;
- unsigned short i, j, cy_isa_nchan;
+ unsigned short i, j, k, cy_isa_nchan;
int isparam = 0;

nboard = 0;
@@ -3392,9 +3392,10 @@ static int __init cy_detect_isa(void)
(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
cy_isa_irq, cy_isa_nchan, cy_next_channel);

- for (j = cy_next_channel;
- j < cy_next_channel + cy_isa_nchan; j++)
- tty_register_device(cy_serial_driver, j, NULL);
+ for (k = 0, j = cy_next_channel;
+ j < cy_next_channel + cy_isa_nchan; j++, k++)
+ tty_port_register_device(&card->ports[k].port,
+ cy_serial_driver, j, NULL);
cy_next_channel += cy_isa_nchan;
}
return nboard;
@@ -3698,7 +3699,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
void __iomem *addr0 = NULL, *addr2 = NULL;
char *card_name = NULL;
u32 uninitialized_var(mailbox);
- unsigned int device_id, nchan = 0, card_no, i;
+ unsigned int device_id, nchan = 0, card_no, i, j;
unsigned char plx_ver;
int retval, irq;

@@ -3909,8 +3910,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,

dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
- for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
- tty_register_device(cy_serial_driver, i, &pdev->dev);
+ for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
+ tty_port_register_device(&card->ports[j].port,
+ cy_serial_driver, i, &pdev->dev);
cy_next_channel += nchan;

return 0;
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 4813684..4ab936b 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
goto error;
}

- bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
+ tty_port_init(&bc->port);
+ bc->port.ops = &ehv_bc_tty_port_ops;
+
+ bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i,
+ &pdev->dev);
if (IS_ERR(bc->dev)) {
ret = PTR_ERR(bc->dev);
dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
goto error;
}

- tty_port_init(&bc->port);
- bc->port.ops = &ehv_bc_tty_port_ops;
-
dev_set_drvdata(&pdev->dev, bc);

dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index f8b5fa0..160f0ad 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -476,7 +476,7 @@ static int add_tty(int j,
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);

- tty_register_device(ipw_tty_driver, j, NULL);
+ tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);

if (secondary_channel_idx != -1)
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index d593a7d..99cf22e 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
goto errunri;

for (index = 0; index < board->port_count; index++)
- tty_register_device(isicom_normal, board->index * 16 + index,
+ tty_port_register_device(&board->ports[index].port,
+ isicom_normal, board->index * 16 + index,
&pdev->dev);

return 0;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index e64fe40..8bc2651 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2625,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
goto err_rel3;

for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+ tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
+ brd->idx + i, &pdev->dev);

pci_set_drvdata(pdev, brd);

@@ -2722,7 +2723,8 @@ static int __init mxser_module_init(void)

brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
+ tty_port_register_device(&brd->ports[i].port,
+ mxvar_sdriver, brd->idx + i, NULL);

m++;
}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index e7592f9..b917c94 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
port->dc = dc;
tty_port_init(&port->port);
port->port.ops = &noz_tty_port_ops;
- tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
- &pdev->dev);
+ tty_dev = tty_port_register_device(&port->port, ntty_driver,
+ dc->index_start + i, &pdev->dev);

if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 016984a..9700d34 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
spin_lock_init(&info->slock);
mutex_init(&info->write_mtx);
rp_table[line] = info;
- tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
- NULL);
+ tty_port_register_device(&info->port, rocket_driver, line,
+ pci_dev ? &pci_dev->dev : NULL);
}

/*
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 144cd39..3f0c256 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
tty_port_init(pport);
pport->ops = &ifx_tty_port_ops;
ifx_dev->minor = IFX_SPI_TTY_ID;
- ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
- &ifx_dev->spi_dev->dev);
+ ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv,
+ ifx_dev->minor, &ifx_dev->spi_dev->dev);
if (IS_ERR(ifx_dev->tty_dev)) {
dev_dbg(&ifx_dev->spi_dev->dev,
"%s: registering tty device failed", __func__);
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
index b25e6ee..925d1fa 100644
--- a/drivers/tty/serial/msm_smd_tty.c
+++ b/drivers/tty/serial/msm_smd_tty.c
@@ -223,9 +223,11 @@ static int __init smd_tty_init(void)
return ret;

for (i = 0; i < smd_tty_channels_len; i++) {
- tty_port_init(&smd_tty[smd_tty_channels[i].id].port);
- smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops;
- tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0);
+ struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
+ tty_port_init(port);
+ port->ops = &smd_tty_port_ops;
+ tty_port_register_device(port, smd_tty_driver,
+ smd_tty_channels[i].id, NULL);
}

return 0;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index d98b1bd..5b308c8 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2346,7 +2346,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
- tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
+ tty_dev = tty_port_register_device(port, drv->tty_driver, uport->line,
+ uport->dev);
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, 1);
} else {
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index f02d18a..ccfd029d 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -3689,8 +3689,11 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
}

- for (i=0; i < port_count; ++i)
- tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
+ for (i = 0; i < port_count; ++i) {
+ struct slgt_info *info = port_array[i];
+ tty_port_register_device(&info->port, serial_driver, info->line,
+ &info->pdev->dev);
+ }
}

static int __devinit init_one(struct pci_dev *dev,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 18f4e62..455ef16 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1298,7 +1298,8 @@ skip_countries:
usb_set_intfdata(data_interface, acm);

usb_get_intf(control_interface);
- tty_register_device(acm_tty_driver, minor, &control_interface->dev);
+ tty_port_register_device(&acm->port, acm_tty_driver, minor,
+ &control_interface->dev);

return 0;
alloc_fail7:
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 5b3f5ff..2b5534c 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1129,7 +1129,8 @@ int gserial_setup(struct usb_gadget *g, unsigned count)
for (i = 0; i < count; i++) {
struct device *tty_dev;

- tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
+ tty_dev = tty_port_register_device(&ports[i].port->port,
+ gs_tty_driver, i, &g->dev);
if (IS_ERR(tty_dev))
pr_warning("%s: no classdev for port %d, err %ld\n",
__func__, i, PTR_ERR(tty_dev));
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 87ddd05..97151ed 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -278,8 +278,8 @@ out:
if (err < 0)
goto free;

- dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
-
+ dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
+ dev->id, NULL);
if (IS_ERR(dev->tty_dev)) {
err = PTR_ERR(dev->tty_dev);
list_del(&dev->list);
--
1.7.10.4

2012-08-07 19:56:50

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 15/41] TTY: ttyprintk, initialize tty_port earlier

After tty_register_driver is called, it is too late to initialize a
guy with which we operate in open. When a process already called
open(2) on that node, the structures may be in use uninitialized.

Move the initialization prior to tty_register_driver.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Samo Pogacnik <[email protected]>
---
drivers/char/ttyprintk.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 08755c5..be1c3fb 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -180,6 +180,10 @@ static int __init ttyprintk_init(void)
int ret = -ENOMEM;
void *rp;

+ tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
+ mutex_init(&tpk_port.port_write_mutex);
+
ttyprintk_driver = alloc_tty_driver(1);
if (!ttyprintk_driver)
return ret;
@@ -210,10 +214,6 @@ static int __init ttyprintk_init(void)
goto error;
}

- tty_port_init(&tpk_port.port);
- tpk_port.port.ops = &null_ops;
- mutex_init(&tpk_port.port_write_mutex);
-
return 0;

error:
--
1.7.10.4

2012-08-07 19:57:05

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 08/41] misc: pti, do the opposite of ->probe in ->remove

Currently, probe initializes some parts. Then, some of them are
unwound in ->remove, some in module_exit. Let us do the opposite of
whole ->probe in ->remove.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 21 +++++++--------------
1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 4a24421..be6e679 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -874,11 +874,18 @@ static void __devexit pti_pci_remove(struct pci_dev *pdev)
{
struct pti_dev *drv_data = pci_get_drvdata(pdev);

+ unregister_console(&pti_console);
+
+ tty_unregister_device(pti_tty_driver, 0);
+ tty_unregister_device(pti_tty_driver, 1);
+
iounmap(drv_data->pti_ioaddr);
pci_set_drvdata(pdev, NULL);
kfree(drv_data);
pci_release_region(pdev, 1);
pci_disable_device(pdev);
+
+ misc_deregister(&pti_char_driver);
}

static struct pci_driver pti_pci_driver = {
@@ -959,9 +966,6 @@ static void __exit pti_exit(void)
{
int retval;

- tty_unregister_device(pti_tty_driver, 0);
- tty_unregister_device(pti_tty_driver, 1);
-
retval = tty_unregister_driver(pti_tty_driver);
if (retval) {
pr_err("%s(%d): TTY unregistration failed of pti driver\n",
@@ -971,17 +975,6 @@ static void __exit pti_exit(void)
}

pci_unregister_driver(&pti_pci_driver);
-
- retval = misc_deregister(&pti_char_driver);
- if (retval) {
- pr_err("%s(%d): CHAR unregistration failed of pti driver\n",
- __func__, __LINE__);
- pr_err("%s(%d): Error value returned: %d\n",
- __func__, __LINE__, retval);
- }
-
- unregister_console(&pti_console);
- return;
}

module_init(pti_init);
--
1.7.10.4

2012-08-07 19:57:23

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 38/41] TTY: tty3270, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

In this case ->install is the only thing we want to do. We do not need
->open at all. See the tty->count > 1 check.

And since we take a reference in ->install, we need also ->cleanup to
drop the reference to a view.

Final note, see that we leave raw3270_find_view in place. It is
because views are removed even from module_exit.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/s390/char/tty3270.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index f2b8c6c..482ee02 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = {
};

/*
- * This routine is called whenever a 3270 tty is opened.
+ * This routine is called whenever a 3270 tty is opened first time.
*/
-static int
-tty3270_open(struct tty_struct *tty, struct file * filp)
+static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct raw3270_view *view;
struct tty3270 *tp;
int i, rc;

- if (tty->count > 1)
- return 0;
/* Check if the tty3270 is already there. */
view = raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
@@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
/* why to reassign? */
tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT;
- return 0;
+ return tty_port_install(&tp->port, driver, tty);
}
if (tty3270_max_index < tty->index + 1)
tty3270_max_index = tty->index + 1;
@@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)

tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0;
- tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols;

@@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
kbd_ascebc(tp->kbd, tp->view.ascebc);

raw3270_activate_view(&tp->view);
+
+ rc = tty_port_install(&tp->port, driver, tty);
+ if (rc) {
+ raw3270_put_view(&tp->view);
+ return rc;
+ }
+
+ tty->driver_data = tp;
+
return 0;
}

@@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
if (tp) {
tty->driver_data = NULL;
tty_port_tty_set(&tp->port, NULL);
- raw3270_put_view(&tp->view);
}
}

+static void tty3270_cleanup(struct tty_struct *tty)
+{
+ struct tty3270 *tp = tty->driver_data;
+
+ if (tp)
+ raw3270_put_view(&tp->view);
+}
+
/*
* We always have room.
*/
@@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
#endif

static const struct tty_operations tty3270_ops = {
- .open = tty3270_open,
+ .install = tty3270_install,
+ .cleanup = tty3270_cleanup,
.close = tty3270_close,
.write = tty3270_write,
.put_char = tty3270_put_char,
--
1.7.10.4

2012-08-07 19:57:12

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 01/41] TTY: pty, stop passing NULL to free_tty_struct

In case alloc_tty_struct fails in pty_common_install, we pass NULL to
free_tty_struct. This is invalid as the function is not ready to cope
with that. And even if it was, it is not nice to do that anyway.

Signed-off-by: Jiri Slaby <[email protected]>
Reported-by: Dan Carpenter <[email protected]>
---
drivers/tty/pty.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index d6579a9..b726c8b 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -302,9 +302,11 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
int retval = -ENOMEM;

o_tty = alloc_tty_struct();
+ if (!o_tty)
+ goto err;
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
- if (!o_tty || !ports[0] || !ports[1])
+ if (!ports[0] || !ports[1])
goto err_free_tty;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
@@ -359,6 +361,7 @@ err_free_tty:
kfree(ports[0]);
kfree(ports[1]);
free_tty_struct(o_tty);
+err:
return retval;
}

--
1.7.10.4

2012-08-07 19:57:28

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 03/41] TTY: n_gsm, use tty_port_install

We need to link a port to a tty in install. And since dlci is
allocated even in open, we need to create gsmtty_install, allocate
dlci there and create also the link.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/n_gsm.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 7a4bf30..3778687 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2868,14 +2868,14 @@ static const struct tty_port_operations gsm_port_ops = {
.dtr_rts = gsm_dtr_rts,
};

-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct gsm_mux *gsm;
struct gsm_dlci *dlci;
- struct tty_port *port;
unsigned int line = tty->index;
unsigned int mux = line >> 6;
+ bool alloc = false;
+ int ret;

line = line & 0x3F;

@@ -2890,13 +2890,30 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
if (gsm->dead)
return -EL2HLT;
dlci = gsm->dlci[line];
- if (dlci == NULL)
+ if (dlci == NULL) {
+ alloc = true;
dlci = gsm_dlci_alloc(gsm, line);
+ }
if (dlci == NULL)
return -ENOMEM;
- port = &dlci->port;
- port->count++;
+ ret = tty_port_install(&dlci->port, driver, tty);
+ if (ret) {
+ if (alloc)
+ dlci_put(dlci);
+ return ret;
+ }
+
tty->driver_data = dlci;
+
+ return 0;
+}
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct gsm_dlci *dlci = tty->driver_data;
+ struct tty_port *port = &dlci->port;
+
+ port->count++;
dlci_get(dlci);
dlci_get(dlci->gsm->dlci[0]);
mux_get(dlci->gsm);
@@ -3085,6 +3102,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)

/* Virtual ttys for the demux */
static const struct tty_operations gsmtty_ops = {
+ .install = gsmtty_install,
.open = gsmtty_open,
.close = gsmtty_close,
.write = gsmtty_write,
--
1.7.10.4

2012-08-07 19:57:33

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 40/41] TTY: hvcs, clean hvcs_open a bit

Make the code of hvcs_open a bit more readable by:
- moving all assignments out of if's
- redoing fail paths so that corresponding pieces are nearby
- we need only one of retval and rc

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/hvc/hvcs.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d56788c..6f5c3be 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1109,11 +1109,10 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
static int hvcs_open(struct tty_struct *tty, struct file *filp)
{
struct hvcs_struct *hvcsd;
- int rc, retval = 0;
- unsigned long flags;
- unsigned int irq;
struct vio_dev *vdev;
- unsigned long unit_address;
+ unsigned long unit_address, flags;
+ unsigned int irq;
+ int retval;

if (tty->driver_data)
goto fast_open;
@@ -1122,7 +1121,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* Is there a vty-server that shares the same index?
* This function increments the kref index.
*/
- if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+ hvcsd = hvcs_get_by_index(tty->index);
+ if (!hvcsd) {
printk(KERN_WARNING "HVCS: open failed, no device associated"
" with tty->index %d.\n", tty->index);
return -ENODEV;
@@ -1130,9 +1130,14 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)

spin_lock_irqsave(&hvcsd->lock, flags);

- if (hvcsd->connected == 0)
- if ((retval = hvcs_partner_connect(hvcsd)))
- goto error_release;
+ if (hvcsd->connected == 0) {
+ retval = hvcs_partner_connect(hvcsd);
+ if (retval) {
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ printk(KERN_WARNING "HVCS: partner connect failed.\n");
+ goto err_put;
+ }
+ }

hvcsd->port.count = 1;
hvcsd->port.tty = tty;
@@ -1155,10 +1160,10 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* This must be done outside of the spinlock because it requests irqs
* and will grab the spinlock and free the connection if it fails.
*/
- if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
- tty_port_put(&hvcsd->port);
+ retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
+ if (retval) {
printk(KERN_WARNING "HVCS: enable device failed.\n");
- return rc;
+ goto err_put;
}

goto open_success;
@@ -1179,12 +1184,9 @@ open_success:
hvcsd->vdev->unit_address );

return 0;
-
-error_release:
- spin_unlock_irqrestore(&hvcsd->lock, flags);
+err_put:
tty_port_put(&hvcsd->port);

- printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval;
}

--
1.7.10.4

2012-08-07 19:57:56

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 39/41] TTY: hvc_console, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

Since we take a reference to a port in ->install, we need also
->cleanup to drop that reference.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: [email protected]
---
drivers/tty/hvc/hvc_console.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 2d691eb..7f80f15 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty)
hvc_kick();
}

+static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct hvc_struct *hp;
+ int rc;
+
+ /* Auto increments kref reference if found. */
+ if (!(hp = hvc_get_by_index(tty->index)))
+ return -ENODEV;
+
+ tty->driver_data = hp;
+
+ rc = tty_port_install(&hp->port, driver, tty);
+ if (rc)
+ tty_port_put(&hp->port);
+ return rc;
+}
+
/*
* The TTY interface won't be used until after the vio layer has exposed the vty
* adapter to the kernel.
*/
static int hvc_open(struct tty_struct *tty, struct file * filp)
{
- struct hvc_struct *hp;
+ struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
int rc = 0;

- /* Auto increments kref reference if found. */
- if (!(hp = hvc_get_by_index(tty->index)))
- return -ENODEV;
-
spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
if (hp->port.count++ > 0) {
@@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
} /* else count == 0 */
spin_unlock_irqrestore(&hp->port.lock, flags);

- tty->driver_data = hp;
tty_port_tty_set(&hp->port, tty);

if (hp->ops->notifier_add)
@@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp->vtermno, hp->port.count);
spin_unlock_irqrestore(&hp->port.lock, flags);
}
+}
+
+static void hvc_cleanup(struct tty_struct *tty)
+{
+ struct hvc_struct *hp = tty->driver_data;

tty_port_put(&hp->port);
}
@@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
#endif

static const struct tty_operations hvc_ops = {
+ .install = hvc_install,
.open = hvc_open,
.close = hvc_close,
+ .cleanup = hvc_cleanup,
.write = hvc_write,
.hangup = hvc_hangup,
.unthrottle = hvc_unthrottle,
--
1.7.10.4

2012-08-07 19:58:04

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 32/41] TTY: con3215, unset raw3215[line]

raw3215[line] is set in probe, but not unset in remove. This will lead
to random crashes if the device is removed and the corresponding tty
opened later. open would dereference freed memory.

So set raw3215[line] to NULL in remove to fix that.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/s390/char/con3215.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6c0116d..1655498 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev)
static void raw3215_remove (struct ccw_device *cdev)
{
struct raw3215_info *raw;
+ unsigned int line;

ccw_device_set_offline(cdev);
raw = dev_get_drvdata(&cdev->dev);
if (raw) {
+ spin_lock(&raw3215_device_lock);
+ for (line = 0; line < NR_3215; line++)
+ if (raw3215[line] == raw)
+ break;
+ raw3215[line] = NULL;
+ spin_unlock(&raw3215_device_lock);
dev_set_drvdata(&cdev->dev, NULL);
raw3215_free_info(raw);
}
--
1.7.10.4

2012-08-07 19:58:17

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 06/41] misc: pti, stop using iomap's unmap on ioremap space

Ioremap space is different to iomap. ->probe function uses ioremap,
but ->remove calls pci_iounmap. That one is illegal. Fix that by using
iounmap.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 88da085e..3bfc8e3 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -402,7 +402,7 @@ static void __devexit pti_pci_remove(struct pci_dev *pdev)
{
struct pti_dev *drv_data = pci_get_drvdata(pdev);

- pci_iounmap(pdev, drv_data->pti_ioaddr);
+ iounmap(drv_data->pti_ioaddr);
pci_set_drvdata(pdev, NULL);
kfree(drv_data);
pci_release_region(pdev, 1);
--
1.7.10.4

2012-08-07 19:58:24

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 28/41] TTY: synclink_cs, use dynamic tty devices

This allows us to provide the tty layer with information about
tty_port for each link. And it also allows us to get rid of the
remove_device loop in synclink_cs_exit because we had to reorder
pcmcia and tty driver registration in init. This was because we need
to have serial_driver initialized when calling
tty_port_register_device from pcmcia ->probe.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/char/pcmcia/synclink_cs.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0606586..ce277f7 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2731,6 +2731,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
#if SYNCLINK_GENERIC_HDLC
hdlcdev_init(info);
#endif
+ tty_port_register_device(&info->port, serial_driver, info->line,
+ &info->p_dev.dev);
}

static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@@ -2744,6 +2746,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
last->next_device = info->next_device;
else
mgslpc_device_list = info->next_device;
+ tty_unregister_device(serial_driver, info->line);
#if SYNCLINK_GENERIC_HDLC
hdlcdev_exit(info);
#endif
@@ -2807,13 +2810,12 @@ static int __init synclink_cs_init(void)
BREAKPOINT();
}

- if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
- return rc;
-
- serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
+ serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
if (!serial_driver) {
rc = -ENOMEM;
- goto err_pcmcia_drv;
+ goto err;
}

/* Initialize the tty_driver structure */
@@ -2827,7 +2829,6 @@ static int __init synclink_cs_init(void)
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &mgslpc_ops);

if ((rc = tty_register_driver(serial_driver)) < 0) {
@@ -2836,26 +2837,28 @@ static int __init synclink_cs_init(void)
goto err_put_tty;
}

+ rc = pcmcia_register_driver(&mgslpc_driver);
+ if (rc < 0)
+ goto err_unreg_tty;
+
printk("%s %s, tty major#%d\n",
driver_name, driver_version,
serial_driver->major);

return 0;
+err_unreg_tty:
+ tty_unregister_driver(serial_driver);
err_put_tty:
put_tty_driver(serial_driver);
-err_pcmcia_drv:
- pcmcia_unregister_driver(&mgslpc_driver);
+err:
return rc;
}

static void __exit synclink_cs_exit(void)
{
- while (mgslpc_device_list)
- mgslpc_remove_device(mgslpc_device_list);
-
+ pcmcia_unregister_driver(&mgslpc_driver);
tty_unregister_driver(serial_driver);
put_tty_driver(serial_driver);
- pcmcia_unregister_driver(&mgslpc_driver);
}

module_init(synclink_cs_init);
--
1.7.10.4

2012-08-07 19:58:36

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 34/41] TTY: i4l, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

The "tty->port = port" assignment is not needed anymore since it
happens in tty_port_install implicitly.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Karsten Keil <[email protected]>
Cc: [email protected]
---
drivers/isdn/i4l/isdn_tty.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 576ce4b..b817809 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* ------------------------------------------------------------
*/

+static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ modem_info *info = &dev->mdm.info[tty->index];
+
+ if (isdn_tty_paranoia_check(info, tty->name, __func__))
+ return -ENODEV;
+
+ tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its async structure into
@@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
- struct tty_port *port;
- modem_info *info;
+ modem_info *info = tty->driver_data;
+ struct tty_port *port = &info->port;
int retval;

- info = &dev->mdm.info[tty->index];
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
- return -ENODEV;
- port = &info->port;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
port->count);
#endif
port->count++;
- tty->driver_data = info;
port->tty = tty;
- tty->port = port;
/*
* Start up serial port
*/
@@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m)
}

static const struct tty_operations modem_ops = {
+ .install = isdn_tty_install,
.open = isdn_tty_open,
.close = isdn_tty_close,
.write = isdn_tty_write,
--
1.7.10.4

2012-08-07 19:58:00

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 41/41] TTY: hvcs, add tty install

This has two outcomes:
* we give the TTY layer a tty_port
* we do not find the info structure every time open is called on that
tty

>From now on, we only increase the reference count in ->install (and
decrease in ->cleanup).

Signed-off-by: Jiri Slaby <[email protected]>
Cc: [email protected]
---
drivers/tty/hvc/hvcs.c | 52 ++++++++++++++++++++++++++++++------------------
1 file changed, 33 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 6f5c3be..cab5c7a 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1102,11 +1102,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
return NULL;
}

-/*
- * This is invoked via the tty_open interface when a user app connects to the
- * /dev node.
- */
-static int hvcs_open(struct tty_struct *tty, struct file *filp)
+static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct hvcs_struct *hvcsd;
struct vio_dev *vdev;
@@ -1114,9 +1110,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
unsigned int irq;
int retval;

- if (tty->driver_data)
- goto fast_open;
-
/*
* Is there a vty-server that shares the same index?
* This function increments the kref index.
@@ -1139,7 +1132,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
}
}

- hvcsd->port.count = 1;
+ hvcsd->port.count = 0;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;

@@ -1166,28 +1159,42 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
goto err_put;
}

- goto open_success;
+ retval = tty_port_install(&hvcsd->port, driver, tty);
+ if (retval)
+ goto err_irq;

-fast_open:
- hvcsd = tty->driver_data;
+ return 0;
+err_irq:
+ spin_lock_irqsave(&hvcsd->lock, flags);
+ vio_disable_interrupts(hvcsd->vdev);
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ free_irq(irq, hvcsd);
+err_put:
+ tty_port_put(&hvcsd->port);
+
+ return retval;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+ unsigned long flags;

spin_lock_irqsave(&hvcsd->lock, flags);
- tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);

-open_success:
hvcs_kick();

printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
hvcsd->vdev->unit_address );

return 0;
-err_put:
- tty_port_put(&hvcsd->port);
-
- return retval;
}

static void hvcs_close(struct tty_struct *tty, struct file *filp)
@@ -1238,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;

free_irq(irq, hvcsd);
- tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1247,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
}

spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+static void hvcs_cleanup(struct tty_struct * tty)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+
tty_port_put(&hvcsd->port);
}

@@ -1433,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
}

static const struct tty_operations hvcs_ops = {
+ .install = hvcs_install,
.open = hvcs_open,
.close = hvcs_close,
+ .cleanup = hvcs_cleanup,
.hangup = hvcs_hangup,
.write = hvcs_write,
.write_room = hvcs_write_room,
--
1.7.10.4

2012-08-07 19:59:07

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 31/41] TTY: nfcon, add tty_port and link it

Every tty driver needs tty_port for each line. So let us add one to
nfcon too. And link it so that the tty layer knows about it.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: [email protected]
---
arch/m68k/emu/nfcon.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 8db25e8..16d170f 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -19,6 +19,7 @@
#include <asm/natfeat.h>

static int stderr_id;
+static struct tty_port nfcon_tty_port;
static struct tty_driver *nfcon_tty_driver;

static void nfputs(const char *str, unsigned int count)
@@ -119,6 +120,8 @@ static int __init nfcon_init(void)
{
int res;

+ tty_port_init(&nfcon_tty_port);
+
stderr_id = nf_get_id("NF_STDERR");
if (!stderr_id)
return -ENODEV;
@@ -135,6 +138,7 @@ static int __init nfcon_init(void)
nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;

tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
+ tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
res = tty_register_driver(nfcon_tty_driver);
if (res) {
pr_err("failed to register nfcon tty driver\n");
--
1.7.10.4

2012-08-07 19:59:46

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 20/41] TTY: add support for unnumbered device nodes

This allows drivers like ttyprintk to avoid hacks to create an
unnumbered node in /dev. It used to set TTY_DRIVER_DYNAMIC_DEV in
flags and call device_create on its own. That is incorrect, because
TTY_DRIVER_DYNAMIC_DEV may be set only if tty_register_device is
called explicitly.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/char/ttyprintk.c | 17 ++++-------------
drivers/tty/tty_io.c | 7 +++++--
include/linux/tty_driver.h | 6 ++++++
3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index be1c3fb..9e6272f 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -178,13 +178,15 @@ static struct tty_driver *ttyprintk_driver;
static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
- void *rp;

tty_port_init(&tpk_port.port);
tpk_port.port.ops = &null_ops;
mutex_init(&tpk_port.port_write_mutex);

- ttyprintk_driver = alloc_tty_driver(1);
+ ttyprintk_driver = tty_alloc_driver(1,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_UNNUMBERED_NODE);
if (!ttyprintk_driver)
return ret;

@@ -195,8 +197,6 @@ static int __init ttyprintk_init(void)
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
- ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ttyprintk_driver, &ttyprintk_ops);

ret = tty_register_driver(ttyprintk_driver);
@@ -205,15 +205,6 @@ static int __init ttyprintk_init(void)
goto error;
}

- /* create our unnumbered device */
- rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
- ttyprintk_driver->name);
- if (IS_ERR(rp)) {
- printk(KERN_ERR "Couldn't create ttyprintk device\n");
- ret = PTR_ERR(rp);
- goto error;
- }
-
return 0;

error:
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 8181cb5..135e0e4 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1213,7 +1213,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
*/
static void tty_line_name(struct tty_driver *driver, int index, char *p)
{
- sprintf(p, "%s%d", driver->name, index + driver->name_base);
+ if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
+ strcpy(p, driver->name);
+ else
+ sprintf(p, "%s%d", driver->name, index + driver->name_base);
}

/**
@@ -3061,7 +3064,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
struct tty_driver *driver;
int err;

- if (!lines)
+ if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
return ERR_PTR(-EINVAL);

driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index bea95ca..ca8eb54 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -394,6 +394,11 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
* TTY_DRIVER_EXCESSIVE_LINES -- do not allocate structures which are
* needed per line for this driver as it would waste memory.
* Applicable only to pty.
+ *
+ * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In
+ * other words create /dev/ttyprintk and not /dev/ttyprintk0.
+ * Applicable only when a driver for a single tty device is
+ * being allocated.
*/
#define TTY_DRIVER_INSTALLED 0x0001
#define TTY_DRIVER_RESET_TERMIOS 0x0002
@@ -402,6 +407,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
#define TTY_DRIVER_DEVPTS_MEM 0x0010
#define TTY_DRIVER_HARDWARE_BREAK 0x0020
#define TTY_DRIVER_EXCESSIVE_LINES 0x0040
+#define TTY_DRIVER_UNNUMBERED_NODE 0x0080

/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
--
1.7.10.4

2012-08-07 19:59:53

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 18/41] TTY: pty, switch to tty_alloc_driver

Switch to the new driver allocation interface, as this is one of the
special call-sites. Here, we need TTY_DRIVER_EXCESSIVE_LINES to not
allocate tty_driver->ports, cdevs and potentially other structures
because we reserve too many lines in pty. Instead, it provides the
tty_port<->tty_struct link in tty->ops->install already.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/pty.c | 31 ++++++++++++++++++++-----------
include/linux/tty_driver.h | 4 ++++
2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index b726c8b..e44a11d 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -443,11 +443,17 @@ static void __init legacy_pty_init(void)
if (legacy_count <= 0)
return;

- pty_driver = alloc_tty_driver(legacy_count);
+ pty_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_EXCESSIVE_LINES);
if (!pty_driver)
panic("Couldn't allocate pty driver");

- pty_slave_driver = alloc_tty_driver(legacy_count);
+ pty_slave_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_EXCESSIVE_LINES);
if (!pty_slave_driver)
panic("Couldn't allocate pty slave driver");

@@ -464,7 +470,6 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_lflag = 0;
pty_driver->init_termios.c_ispeed = 38400;
pty_driver->init_termios.c_ospeed = 38400;
- pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &master_pty_ops_bsd);

@@ -478,8 +483,6 @@ static void __init legacy_pty_init(void)
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_slave_driver->init_termios.c_ispeed = 38400;
pty_slave_driver->init_termios.c_ospeed = 38400;
- pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);

@@ -670,10 +673,20 @@ static struct file_operations ptmx_fops;

static void __init unix98_pty_init(void)
{
- ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+ ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_EXCESSIVE_LINES);
if (!ptm_driver)
panic("Couldn't allocate Unix98 ptm driver");
- pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+ pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_EXCESSIVE_LINES);
if (!pts_driver)
panic("Couldn't allocate Unix98 pts driver");

@@ -690,8 +703,6 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->init_termios.c_ispeed = 38400;
ptm_driver->init_termios.c_ospeed = 38400;
- ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &ptm_unix98_ops);

@@ -705,8 +716,6 @@ static void __init unix98_pty_init(void)
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->init_termios.c_ispeed = 38400;
pts_driver->init_termios.c_ospeed = 38400;
- pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver, &pty_unix98_ops);

diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 3adc362..bea95ca 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -391,6 +391,9 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
* the requested timeout to the caller instead of using a simple
* on/off interface.
*
+ * TTY_DRIVER_EXCESSIVE_LINES -- do not allocate structures which are
+ * needed per line for this driver as it would waste memory.
+ * Applicable only to pty.
*/
#define TTY_DRIVER_INSTALLED 0x0001
#define TTY_DRIVER_RESET_TERMIOS 0x0002
@@ -398,6 +401,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
#define TTY_DRIVER_DYNAMIC_DEV 0x0008
#define TTY_DRIVER_DEVPTS_MEM 0x0010
#define TTY_DRIVER_HARDWARE_BREAK 0x0020
+#define TTY_DRIVER_EXCESSIVE_LINES 0x0040

/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
--
1.7.10.4

2012-08-07 19:59:51

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 11/41] misc: pti, use tty_port_register_device

So now we have enough of tty_ports, so we can signal the TTY layer to
use them by tty_port_register_device.

The upside is that we look like we can introduce tty_port_easy_open
and put it directly as tty_operations->open to drivers doing nothing
in open and using tty_port_register_device. Because the easy open can
obtain a tty_port rather easily from a tty now. Heh, what a nice
by-product.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index fe76f9d..4999b34 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -427,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
* also removes a locking requirement for the actual write
* procedure.
*/
- return tty_port_open(&drv_data->port[tty->index], tty, filp);
+ return tty_port_open(tty->port, tty, filp);
}

/**
@@ -443,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
*/
static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
{
- tty_port_close(&drv_data->port[tty->index], tty, filp);
+ tty_port_close(tty->port, tty, filp);
}

/**
@@ -856,7 +856,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
tty_port_init(port);
port->ops = &tty_port_ops;

- tty_register_device(pti_tty_driver, a, &pdev->dev);
+ tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
}

register_console(&pti_console);
--
1.7.10.4

2012-08-07 19:59:49

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 07/41] misc: pti, move ->remove to the PCI code

The function is lost somewhere in the forest. Move it to have it along
with probe and other pci_driver stuff.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 3bfc8e3..4a24421 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -393,22 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
}
EXPORT_SYMBOL_GPL(pti_writedata);

-/**
- * pti_pci_remove()- Driver exit method to remove PTI from
- * PCI bus.
- * @pdev: variable containing pci info of PTI.
- */
-static void __devexit pti_pci_remove(struct pci_dev *pdev)
-{
- struct pti_dev *drv_data = pci_get_drvdata(pdev);
-
- iounmap(drv_data->pti_ioaddr);
- pci_set_drvdata(pdev, NULL);
- kfree(drv_data);
- pci_release_region(pdev, 1);
- pci_disable_device(pdev);
-}
-
/*
* for the tty_driver_*() basic function descriptions, see tty_driver.h.
* Specific header comments made for PTI-related specifics.
@@ -881,6 +865,22 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
return retval;
}

+/**
+ * pti_pci_remove()- Driver exit method to remove PTI from
+ * PCI bus.
+ * @pdev: variable containing pci info of PTI.
+ */
+static void __devexit pti_pci_remove(struct pci_dev *pdev)
+{
+ struct pti_dev *drv_data = pci_get_drvdata(pdev);
+
+ iounmap(drv_data->pti_ioaddr);
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+ pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
+}
+
static struct pci_driver pti_pci_driver = {
.name = PCINAME,
.id_table = pci_ids,
--
1.7.10.4

2012-08-07 20:00:31

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 16/41] TTY: tty3270, free tty driver properly

On module unload, in tty3270_exit, we forgot to free the tty driver.
Add there a call to put_tty_driver.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
drivers/s390/char/tty3270.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 1928f34..215037c 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -1800,6 +1800,7 @@ tty3270_exit(void)
driver = tty3270_driver;
tty3270_driver = NULL;
tty_unregister_driver(driver);
+ put_tty_driver(driver);
tty3270_del_views();
}

--
1.7.10.4

2012-08-07 20:00:30

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 23/41] TTY: automatically create nodes for some drivers

This looks like it was a mistake not to create device nodes for these
drivers. Let us create them from now on.

It will be necessary to call tty_register_device some way, either by
tty_register_driver implicitly or to call tty_register_device proper.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
drivers/isdn/i4l/isdn_tty.c | 2 +-
drivers/s390/char/tty3270.c | 2 +-
drivers/tty/serial/crisv10.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 7a61ef6..576ce4b 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1782,7 +1782,7 @@ isdn_tty_modem_init(void)
m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
m->tty_modem->init_termios = tty_std_termios;
m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
m->tty_modem->driver_name = "isdn_tty";
tty_set_operations(m->tty_modem, &modem_ops);
retval = tty_register_driver(m->tty_modem);
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 215037c..f2b8c6c 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -1781,7 +1781,7 @@ static int __init tty3270_init(void)
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
- driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
+ driver->flags = TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver);
if (ret) {
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 6b705b2..708c3bf 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -4443,7 +4443,7 @@ static int __init rs_init(void)
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
driver->init_termios.c_ispeed = 115200;
driver->init_termios.c_ospeed = 115200;
- driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ driver->flags = TTY_DRIVER_REAL_RAW;

tty_set_operations(driver, &rs_ops);
serial_driver = driver;
--
1.7.10.4

2012-08-07 20:01:40

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 13/41] TTY: ttyprintk, unregister tty driver on failure

When the tty_printk driver fails to create a node in sysfs, the system
crashes. It is because the driver registers a tty driver and frees it
without deregistering it first. The fix is easy: add a call to
tty_unregister_driver to the fail path.

This is very unlikely to happen in usual environment => no need for
stable.

The crash occurs at some place where we iterate over tty drivers
first. It may look like this:
BUG: unable to handle kernel paging request at ffffffffffffff84
IP: [<ffffffff81278d56>] tty_open+0xd6/0x650
PGD 1a0d067 PUD 1a0e067 PMD 0
Oops: 0000 [#1] PREEMPT SMP
Modules linked in:
CPU 0
Pid: 1183, comm: boot.localnet Tainted: G W 3.5.0-rc7-next-20120716+ #369 Bochs Bochs
RIP: 0010:[<ffffffff81278d56>] [<ffffffff81278d56>] tty_open+0xd6/0x650
RSP: 0018:ffff8800162b3b98 EFLAGS: 00010207
RAX: 0000000000000000 RBX: ffff880016ba6200 RCX: 0000000000002208
RDX: 0000000000000000 RSI: 00000000000000d0 RDI: ffffffff81a35080
RBP: ffff8800162b3c08 R08: ffffffff81276f42 R09: 0000000000400040
R10: ffff8800161dc005 R11: ffff8800188ee048 R12: 0000000000000000
R13: ffffffffffffff58 R14: 0000000000400040 R15: 0000000000008000
FS: 00007f3684abd700(0000) GS:ffff880018e00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffffffffffffff84 CR3: 000000001503e000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process boot.localnet (pid: 1183, threadinfo ffff8800162b2000, task ffff8800188c5880)
Stack:
ffff8800162b3c08 ffffffff81363d63 ffffffff81a62940 ffff8800189b4e88
ffff8800188c5880 ffffffff81123180 0000000000000000 ffffffff18b20600
0000000000000000 ffff8800189b4e88 ffff880016ba6200 ffff880018b20600
Call Trace:
[<ffffffff81363d63>] ? kobj_lookup+0x103/0x160
[<ffffffff81123180>] ? mount_fs+0x110/0x110
[<ffffffff81123a9c>] chrdev_open+0x9c/0x1a0
[<ffffffff81123a00>] ? cdev_put+0x30/0x30
[<ffffffff8111de76>] do_dentry_open.isra.19+0x1e6/0x270
[<ffffffff8111df65>] finish_open+0x65/0xa0
[<ffffffff8112dc9e>] do_last.isra.52+0x26e/0xd80
[<ffffffff8112b163>] ? inode_permission+0x13/0x50
[<ffffffff8112b203>] ? link_path_walk+0x63/0x940
[<ffffffff8112e85b>] path_openat+0xab/0x3d0
[<ffffffff8112ef5d>] do_filp_open+0x3d/0xa0
[<ffffffff8113ba72>] ? alloc_fd+0xd2/0x120
[<ffffffff8111eee3>] do_sys_open+0xf3/0x1d0
[<ffffffff8111efdc>] sys_open+0x1c/0x20
[<ffffffff815b5fe2>] system_call_fastpath+0x16/0x1b

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Samo Pogacnik <[email protected]>
---
drivers/char/ttyprintk.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 46b77ed..9b1e5e0 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -217,6 +217,7 @@ static int __init ttyprintk_init(void)
return 0;

error:
+ tty_unregister_driver(ttyprintk_driver);
put_tty_driver(ttyprintk_driver);
ttyprintk_driver = NULL;
return ret;
--
1.7.10.4

2012-08-07 20:01:38

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 14/41] TTY: ttyprintk, don't touch behind tty->write_buf

If a user provides a buffer larger than a tty->write_buf chunk and
passes '\r' at the end of the buffer, we touch an out-of-bound memory.

Add a check there to prevent this.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: [email protected] (everything maintained past v2.6.37)
Cc: Samo Pogacnik <[email protected]>
---
drivers/char/ttyprintk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 9b1e5e0..08755c5 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
- if (buf[i + 1] == '\n')
+ if ((i + 1) < count && buf[i + 1] == '\n')
i++;
break;
case '\n':
--
1.7.10.4

2012-08-07 20:01:37

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 25/41] TTY: add tty_port_link_device

This is for those drivers which do not have dynamic device creation
(do not call tty_port_register_device) and do not want to implement
tty->ops->install (will not call tty_port_install). They still have to
provide the link somehow though.

And this newly added function is exactly to serve that purpose.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_port.c | 22 +++++++++++++++++++++-
include/linux/tty.h | 2 ++
2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index b36b33a..b4be732 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -34,6 +34,26 @@ void tty_port_init(struct tty_port *port)
EXPORT_SYMBOL(tty_port_init);

/**
+ * tty_port_link_device - link tty and tty_port
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ *
+ * Provide the tty layer wit ha link from a tty (specified by @index) to a
+ * tty_port (@port). Use this only if neither tty_port_register_device nor
+ * tty_port_install is used in the driver. If used, this has to be called before
+ * tty_register_driver.
+ */
+void tty_port_link_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index)
+{
+ if (WARN_ON(index >= driver->num))
+ return;
+ driver->ports[index] = port;
+}
+EXPORT_SYMBOL_GPL(tty_port_link_device);
+
+/**
* tty_port_register_device - register tty device
* @port: tty_port of the device
* @driver: tty_driver for this device
@@ -48,7 +68,7 @@ struct device *tty_port_register_device(struct tty_port *port,
struct tty_driver *driver, unsigned index,
struct device *device)
{
- driver->ports[index] = port;
+ tty_port_link_device(port, driver, index);
return tty_register_device(driver, index, device);
}
EXPORT_SYMBOL_GPL(tty_port_register_device);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index a39e723..aebf2ab 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -496,6 +496,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock))

extern void tty_port_init(struct tty_port *port);
+extern void tty_port_link_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index);
extern struct device *tty_port_register_device(struct tty_port *port,
struct tty_driver *driver, unsigned index,
struct device *device);
--
1.7.10.4

2012-08-07 20:02:34

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 12/41] mxser: allow overlapping vector

For many cards, this saves some IO space because interrupt status port
has precedence over the rest of ports on the card. Hence it can be
mapped to a hole in I/O ports.

Here we add a kernel parameter which allows that if a user wants to.
But they need to explicitly enable it by a module parameter.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/mxser.c | 35 +++++++++++++++++++++++++++++++----
1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index c162ee9..e64fe40 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/

+static bool allow_overlapping_vector;
+module_param(allow_overlapping_vector, bool, 444);
+MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");
+
+static bool mxser_overlapping_vector(struct mxser_board *brd)
+{
+ return allow_overlapping_vector &&
+ brd->vector >= brd->ports[0].ioaddr &&
+ brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports;
+}
+
+static int mxser_request_vector(struct mxser_board *brd)
+{
+ if (mxser_overlapping_vector(brd))
+ return 0;
+ return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO;
+}
+
+static void mxser_release_vector(struct mxser_board *brd)
+{
+ if (mxser_overlapping_vector(brd))
+ return;
+ release_region(brd->vector, 1);
+}
+
static void mxser_release_ISA_res(struct mxser_board *brd)
{
free_irq(brd->irq, brd);
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- release_region(brd->vector, 1);
+ mxser_release_vector(brd);
}

static int __devinit mxser_initbrd(struct mxser_board *brd,
@@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,

static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
{
- int id, i, bits;
+ int id, i, bits, ret;
unsigned short regs[16], irq;
unsigned char scratch, scratch2;

@@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
8 * brd->info->nports - 1);
return -EIO;
}
- if (!request_region(brd->vector, 1, "mxser(vector)")) {
+
+ ret = mxser_request_vector(brd);
+ if (ret) {
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
printk(KERN_ERR "mxser: can't request interrupt vector region: "
"0x%.8lx-0x%.8lx\n",
brd->ports[0].ioaddr, brd->ports[0].ioaddr +
8 * brd->info->nports - 1);
- return -EIO;
+ return ret;
}
return brd->info->nports;

--
1.7.10.4

2012-08-07 20:02:32

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 10/41] misc: pti, fix tty_port count

We now have *one* tty_port for both TTYs. How this was supposed to
work? Change it to have a tty_port for each of TTYs.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 90de855..fe76f9d 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -60,7 +60,7 @@ struct pti_tty {
};

struct pti_dev {
- struct tty_port port;
+ struct tty_port port[PTITTY_MINOR_NUM];
unsigned long pti_addr;
unsigned long aperture_base;
void __iomem *pti_ioaddr;
@@ -427,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
* also removes a locking requirement for the actual write
* procedure.
*/
- return tty_port_open(&drv_data->port, tty, filp);
+ return tty_port_open(&drv_data->port[tty->index], tty, filp);
}

/**
@@ -443,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
*/
static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
{
- tty_port_close(&drv_data->port, tty, filp);
+ tty_port_close(&drv_data->port[tty->index], tty, filp);
}

/**
@@ -799,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = {
static int __devinit pti_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ unsigned int a;
int retval = -EINVAL;
int pci_bar = 1;

@@ -850,11 +851,13 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,

pci_set_drvdata(pdev, drv_data);

- tty_port_init(&drv_data->port);
- drv_data->port.ops = &tty_port_ops;
+ for (a = 0; a < PTITTY_MINOR_NUM; a++) {
+ struct tty_port *port = &drv_data->port[a];
+ tty_port_init(port);
+ port->ops = &tty_port_ops;

- tty_register_device(pti_tty_driver, 0, &pdev->dev);
- tty_register_device(pti_tty_driver, 1, &pdev->dev);
+ tty_register_device(pti_tty_driver, a, &pdev->dev);
+ }

register_console(&pti_console);

--
1.7.10.4

2012-08-07 20:03:05

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 21/41] TTY: move cdev_add to tty_register_device

We need the /dev/ node not to be available before we call
tty_register_device. Otherwise we might race with open and
tty_struct->port might not be available at that time.

This is not an issue now, but would be a problem after "TTY: use
tty_port_register_device" is applied.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_io.c | 48 +++++++++++++++++++++++++++++++++++++-------
include/linux/tty_driver.h | 2 +-
2 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 135e0e4..35a24e6 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2991,6 +2991,15 @@ EXPORT_SYMBOL_GPL(tty_put_char);

struct class *tty_class;

+static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
+ unsigned int index, unsigned int count)
+{
+ /* init here, since reused cdevs cause crashes */
+ cdev_init(&driver->cdevs[index], &tty_fops);
+ driver->cdevs[index].owner = driver->owner;
+ return cdev_add(&driver->cdevs[index], dev, count);
+}
+
/**
* tty_register_device - register a tty device
* @driver: the tty driver that describes the tty device
@@ -3013,8 +3022,10 @@ struct class *tty_class;
struct device *tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
+ struct device *ret;
char name[64];
dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+ bool cdev = false;

if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
@@ -3027,7 +3038,18 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
else
tty_line_name(driver, index, name);

- return device_create(tty_class, device, dev, NULL, name);
+ if (!(driver->flags & TTY_DRIVER_EXCESSIVE_LINES)) {
+ int error = tty_cdev_add(driver, dev, index, 1);
+ if (error)
+ return ERR_PTR(error);
+ cdev = true;
+ }
+
+ ret = device_create(tty_class, device, dev, NULL, name);
+ if (IS_ERR(ret) && cdev)
+ cdev_del(&driver->cdevs[index]);
+
+ return ret;
}
EXPORT_SYMBOL(tty_register_device);

@@ -3046,6 +3068,8 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
device_destroy(tty_class,
MKDEV(driver->major, driver->minor_start) + index);
+ if (!(driver->flags & TTY_DRIVER_EXCESSIVE_LINES))
+ cdev_del(&driver->cdevs[index]);
}
EXPORT_SYMBOL(tty_unregister_device);

@@ -3062,6 +3086,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
unsigned long flags)
{
struct tty_driver *driver;
+ unsigned int cdevs = 1;
int err;

if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
@@ -3095,6 +3120,13 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
err = -ENOMEM;
goto err_free_all;
}
+ cdevs = lines;
+ }
+
+ driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
+ if (!driver->cdevs) {
+ err = -ENOMEM;
+ goto err_free_all;
}

return driver;
@@ -3129,8 +3161,10 @@ static void destruct_tty_driver(struct kref *kref)
tty_unregister_device(driver, i);
}
proc_tty_unregister_driver(driver);
- cdev_del(&driver->cdev);
+ if (driver->flags & TTY_DRIVER_EXCESSIVE_LINES)
+ cdev_del(&driver->cdevs[0]);
}
+ kfree(driver->cdevs);
kfree(driver->ports);
kfree(driver->termios);
kfree(driver->ttys);
@@ -3180,11 +3214,11 @@ int tty_register_driver(struct tty_driver *driver)
if (error < 0)
goto err;

- cdev_init(&driver->cdev, &tty_fops);
- driver->cdev.owner = driver->owner;
- error = cdev_add(&driver->cdev, dev, driver->num);
- if (error)
- goto err_unreg_char;
+ if (driver->flags & TTY_DRIVER_EXCESSIVE_LINES) {
+ error = tty_cdev_add(driver, dev, 0, driver->num);
+ if (error)
+ goto err_unreg_char;
+ }

mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index ca8eb54..d2ba0e4 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -289,7 +289,7 @@ struct tty_operations {
struct tty_driver {
int magic; /* magic number for this structure */
struct kref kref; /* Reference management */
- struct cdev cdev;
+ struct cdev *cdevs;
struct module *owner;
const char *driver_name;
const char *name;
--
1.7.10.4

2012-08-07 20:03:07

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 19/41] TTY: move allocations to tty_alloc_driver

So now, that we have flags and know everything needed, keep a promise
and move all the tables and ports allocation from tty_register_driver
to tty_alloc_driver.

Not only that it makes sense, but we need this for
tty_port_link_device which needs tty_driver->ports but is to be called
before tty_register_driver.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_io.c | 73 +++++++++++++++++++++++---------------------------
1 file changed, 33 insertions(+), 40 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e024521..8181cb5 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3059,6 +3059,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
unsigned long flags)
{
struct tty_driver *driver;
+ int err;

if (!lines)
return ERR_PTR(-EINVAL);
@@ -3072,9 +3073,34 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
driver->num = lines;
driver->owner = owner;
driver->flags = flags;
- /* later we'll move allocation of tables here */
+
+ if (!(flags & TTY_DRIVER_DEVPTS_MEM)) {
+ driver->ttys = kcalloc(lines, sizeof(*driver->ttys),
+ GFP_KERNEL);
+ driver->termios = kcalloc(lines, sizeof(*driver->termios),
+ GFP_KERNEL);
+ if (!driver->ttys || !driver->termios) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+ }
+
+ if (!(flags & TTY_DRIVER_EXCESSIVE_LINES)) {
+ driver->ports = kcalloc(lines, sizeof(*driver->ports),
+ GFP_KERNEL);
+ if (!driver->ports) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+ }

return driver;
+err_free_all:
+ kfree(driver->ports);
+ kfree(driver->ttys);
+ kfree(driver->termios);
+ kfree(driver);
+ return ERR_PTR(err);
}
EXPORT_SYMBOL(__tty_alloc_driver);

@@ -3083,7 +3109,6 @@ static void destruct_tty_driver(struct kref *kref)
struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
int i;
struct ktermios *tp;
- void *p;

if (driver->flags & TTY_DRIVER_INSTALLED) {
/*
@@ -3100,14 +3125,12 @@ static void destruct_tty_driver(struct kref *kref)
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
- p = driver->ttys;
proc_tty_unregister_driver(driver);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
cdev_del(&driver->cdev);
}
kfree(driver->ports);
+ kfree(driver->termios);
+ kfree(driver->ttys);
kfree(driver);
}

@@ -3138,27 +3161,8 @@ int tty_register_driver(struct tty_driver *driver)
int error;
int i;
dev_t dev;
- void **p = NULL;
struct device *d;

- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
- p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- }
- /*
- * There is too many lines in PTY and we won't need the array there
- * since it has an ->install hook where it assigns ports properly.
- */
- if (driver->type != TTY_DRIVER_TYPE_PTY) {
- driver->ports = kcalloc(driver->num, sizeof(struct tty_port *),
- GFP_KERNEL);
- if (!driver->ports) {
- error = -ENOMEM;
- goto err_free_p;
- }
- }
-
if (!driver->major) {
error = alloc_chrdev_region(&dev, driver->minor_start,
driver->num, driver->name);
@@ -3171,15 +3175,7 @@ int tty_register_driver(struct tty_driver *driver)
error = register_chrdev_region(dev, driver->num, driver->name);
}
if (error < 0)
- goto err_free_p;
-
- if (p) {
- driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct ktermios **)(p + driver->num);
- } else {
- driver->ttys = NULL;
- driver->termios = NULL;
- }
+ goto err;

cdev_init(&driver->cdev, &tty_fops);
driver->cdev.owner = driver->owner;
@@ -3196,7 +3192,7 @@ int tty_register_driver(struct tty_driver *driver)
d = tty_register_device(driver, i, NULL);
if (IS_ERR(d)) {
error = PTR_ERR(d);
- goto err;
+ goto err_unreg_devs;
}
}
}
@@ -3204,7 +3200,7 @@ int tty_register_driver(struct tty_driver *driver)
driver->flags |= TTY_DRIVER_INSTALLED;
return 0;

-err:
+err_unreg_devs:
for (i--; i >= 0; i--)
tty_unregister_device(driver, i);

@@ -3214,10 +3210,7 @@ err:

err_unreg_char:
unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
-err_free_p: /* destruct_tty_driver will free driver->ports */
- kfree(p);
+err:
return error;
}
EXPORT_SYMBOL(tty_register_driver);
--
1.7.10.4

2012-08-07 20:03:03

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 09/41] misc: pti, fix fail paths

Fail paths in ->probe and pti_init are incomplete. Fix that by adding
proper clean-up paths.

Note that we used to leak tty_driver on module unload. This is fixed
here too.

tty_unregister_driver needs not retval checking, so remove that.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: J Freyensee <[email protected]>
---
drivers/misc/pti.c | 53 +++++++++++++++++++++++++---------------------------
1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index be6e679..90de855 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -811,7 +811,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
- return retval;
+ goto err;
}

retval = pci_enable_device(pdev);
@@ -819,17 +819,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s: pci_enable_device() returned error %d\n",
__func__, retval);
- return retval;
+ goto err_unreg_misc;
}

drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
-
if (drv_data == NULL) {
retval = -ENOMEM;
dev_err(&pdev->dev,
"%s(%d): kmalloc() returned NULL memory.\n",
__func__, __LINE__);
- return retval;
+ goto err_disable_pci;
}
drv_data->pti_addr = pci_resource_start(pdev, pci_bar);

@@ -838,18 +837,15 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s(%d): pci_request_region() returned error %d\n",
__func__, __LINE__, retval);
- kfree(drv_data);
- return retval;
+ goto err_free_dd;
}
drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
drv_data->pti_ioaddr =
ioremap_nocache((u32)drv_data->aperture_base,
APERTURE_LEN);
if (!drv_data->pti_ioaddr) {
- pci_release_region(pdev, pci_bar);
retval = -ENOMEM;
- kfree(drv_data);
- return retval;
+ goto err_rel_reg;
}

pci_set_drvdata(pdev, drv_data);
@@ -862,6 +858,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,

register_console(&pti_console);

+ return 0;
+err_rel_reg:
+ pci_release_region(pdev, pci_bar);
+err_free_dd:
+ kfree(drv_data);
+err_disable_pci:
+ pci_disable_device(pdev);
+err_unreg_misc:
+ misc_deregister(&pti_char_driver);
+err:
return retval;
}

@@ -937,25 +943,24 @@ static int __init pti_init(void)
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);

- pti_tty_driver = NULL;
- return retval;
+ goto put_tty;
}

retval = pci_register_driver(&pti_pci_driver);
-
if (retval) {
pr_err("%s(%d): PCI registration failed of pti driver\n",
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
-
- tty_unregister_driver(pti_tty_driver);
- pr_err("%s(%d): Unregistering TTY part of pti driver\n",
- __func__, __LINE__);
- pti_tty_driver = NULL;
- return retval;
+ goto unreg_tty;
}

+ return 0;
+unreg_tty:
+ tty_unregister_driver(pti_tty_driver);
+put_tty:
+ put_tty_driver(pti_tty_driver);
+ pti_tty_driver = NULL;
return retval;
}

@@ -964,17 +969,9 @@ static int __init pti_init(void)
*/
static void __exit pti_exit(void)
{
- int retval;
-
- retval = tty_unregister_driver(pti_tty_driver);
- if (retval) {
- pr_err("%s(%d): TTY unregistration failed of pti driver\n",
- __func__, __LINE__);
- pr_err("%s(%d): Error value returned: %d\n",
- __func__, __LINE__, retval);
- }
-
+ tty_unregister_driver(pti_tty_driver);
pci_unregister_driver(&pti_pci_driver);
+ put_tty_driver(pti_tty_driver);
}

module_init(pti_init);
--
1.7.10.4

2012-08-07 20:04:32

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH 29/41] TTY: synclink_cs, final cleanup in synclink_cs_init

* use <tab> for indentation
* add KERN_* to printks
* no more assignments in if's like if ((rc = function()))

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/char/pcmcia/synclink_cs.c | 65 ++++++++++++++++++-------------------
1 file changed, 32 insertions(+), 33 deletions(-)

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index ce277f7..923c3a4 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2803,47 +2803,46 @@ static const struct tty_operations mgslpc_ops = {

static int __init synclink_cs_init(void)
{
- int rc;
+ int rc;

- if (break_on_load) {
- mgslpc_get_text_ptr();
- BREAKPOINT();
- }
+ if (break_on_load) {
+ mgslpc_get_text_ptr();
+ BREAKPOINT();
+ }

- serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
- TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV);
- if (!serial_driver) {
- rc = -ENOMEM;
- goto err;
- }
+ serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (!serial_driver) {
+ rc = -ENOMEM;
+ goto err;
+ }

- /* Initialize the tty_driver structure */
-
- serial_driver->driver_name = "synclink_cs";
- serial_driver->name = "ttySLP";
- serial_driver->major = ttymajor;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- tty_set_operations(serial_driver, &mgslpc_ops);
-
- if ((rc = tty_register_driver(serial_driver)) < 0) {
- printk("%s(%d):Couldn't register serial driver\n",
- __FILE__,__LINE__);
- goto err_put_tty;
- }
+ /* Initialize the tty_driver structure */
+ serial_driver->driver_name = "synclink_cs";
+ serial_driver->name = "ttySLP";
+ serial_driver->major = ttymajor;
+ serial_driver->minor_start = 64;
+ serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_driver->init_termios = tty_std_termios;
+ serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty_set_operations(serial_driver, &mgslpc_ops);
+
+ rc = tty_register_driver(serial_driver);
+ if (rc < 0) {
+ printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
+ __FILE__, __LINE__);
+ goto err_put_tty;
+ }

rc = pcmcia_register_driver(&mgslpc_driver);
if (rc < 0)
goto err_unreg_tty;

- printk("%s %s, tty major#%d\n",
- driver_name, driver_version,
- serial_driver->major);
+ printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
+ serial_driver->major);

return 0;
err_unreg_tty:
--
1.7.10.4

2012-08-08 15:07:56

by Alan

[permalink] [raw]
Subject: Re: [PATCH 02/41] TTY: 68328serial, fix compilation

On Tue, 7 Aug 2012 21:47:27 +0200
Jiri Slaby <[email protected]> wrote:

> tty_struct->termios is no longer a pointer. This was changed recently
> by "tty: move the termios object into the tty". But 68328serial was
> not changed, so we now have a compilation error:
> 68328serial.c: In function 'change_speed':
> 68328serial.c:518:22: error: invalid type argument of '->' (have
> 'struct ktermios') 68328serial.c: In function 'rs_set_ldisc':
> 68328serial.c:620:31: error: invalid type argument of '->' (have
> 'struct ktermios') 68328serial.c: In function 'rs_set_termios':
> 68328serial.c:988:20: error: invalid type argument of '->' (have
> 'struct ktermios')
>
> Fix that now.
>
> Signed-off-by: Jiri Slaby <[email protected]>
> Cc: Alan Cox <[email protected]>

Cool - I couldn't even find a compile chain or config to test this. I'd
assumed it was broken and really wanted dumping in staging (it still
looks that way 8))

Acked-by: Alan Cox <[email protected]>

2012-08-08 15:20:38

by Alan

[permalink] [raw]
Subject: Re: [PATCH 18/41] TTY: pty, switch to tty_alloc_driver

On Tue, 7 Aug 2012 21:47:43 +0200
Jiri Slaby <[email protected]> wrote:

> Switch to the new driver allocation interface, as this is one of the
> special call-sites. Here, we need TTY_DRIVER_EXCESSIVE_LINES to not
> allocate tty_driver->ports, cdevs and potentially other structures
> because we reserve too many lines in pty. Instead, it provides the
> tty_port<->tty_struct link in tty->ops->install already.

This is the only thing I would quibble about in the entire patch set.

We've got a pile of things that the pty does and one or two other
drivers might want to do about dynamic allocation (termios objects is
the same problem).

I think it's a mistake to call it EXCESSIVE_LINES, better a name which
indicates what it implies - say TTY_DRIVER_DYNAMIC_ALLOC. Then it means
other drivers can move that way if they wish.

Otherwise

Acked-by: Alan Cox <[email protected]>

for the entire series, and next time we are both at the same conference
I owe you a a couple of beers at least !

2012-08-08 19:33:24

by Jiri Slaby

[permalink] [raw]
Subject: Re: [PATCH 02/41] TTY: 68328serial, fix compilation

On 08/08/2012 05:24 PM, Alan Cox wrote:
> On Tue, 7 Aug 2012 21:47:27 +0200
> Jiri Slaby <[email protected]> wrote:
>
>> tty_struct->termios is no longer a pointer. This was changed recently
>> by "tty: move the termios object into the tty". But 68328serial was
>> not changed, so we now have a compilation error:
>> 68328serial.c: In function 'change_speed':
>> 68328serial.c:518:22: error: invalid type argument of '->' (have
>> 'struct ktermios') 68328serial.c: In function 'rs_set_ldisc':
>> 68328serial.c:620:31: error: invalid type argument of '->' (have
>> 'struct ktermios') 68328serial.c: In function 'rs_set_termios':
>> 68328serial.c:988:20: error: invalid type argument of '->' (have
>> 'struct ktermios')
>>
>> Fix that now.
>>
>> Signed-off-by: Jiri Slaby <[email protected]>
>> Cc: Alan Cox <[email protected]>
>
> Cool - I couldn't even find a compile chain or config to test this. I'd
> assumed it was broken and really wanted dumping in staging (it still
> looks that way 8))

Heh, I cannot tell if there is any user at all. The only thing I know is
it used to compile cleanly the last time I tried and it became broken
now :).

BTW you perhaps know that, compilers for most arches are at:
ftp.kernel.org/pub/tools/crosstool/files/bin/

regards,
--
js
suse labs

2012-08-08 20:11:54

by Jiri Slaby

[permalink] [raw]
Subject: Re: [PATCH 18/41] TTY: pty, switch to tty_alloc_driver

On 08/08/2012 05:37 PM, Alan Cox wrote:
> On Tue, 7 Aug 2012 21:47:43 +0200
> Jiri Slaby <[email protected]> wrote:
>
>> Switch to the new driver allocation interface, as this is one of the
>> special call-sites. Here, we need TTY_DRIVER_EXCESSIVE_LINES to not
>> allocate tty_driver->ports, cdevs and potentially other structures
>> because we reserve too many lines in pty. Instead, it provides the
>> tty_port<->tty_struct link in tty->ops->install already.
>
> This is the only thing I would quibble about in the entire patch set.
>
> We've got a pile of things that the pty does and one or two other
> drivers might want to do about dynamic allocation (termios objects is
> the same problem).
>
> I think it's a mistake to call it EXCESSIVE_LINES, better a name which
> indicates what it implies - say TTY_DRIVER_DYNAMIC_ALLOC. Then it means
> other drivers can move that way if they wish.

I would stick only to the rename at this moment -- I will send a v2 for
this and 19/41. The merge with DEVPTS_MEM (the termios case) needs
devpts_kill_index to be moved from tty_release to
pty_driver->ops->cleanup/shutdown, but I don't feel comfortable to do it
now since it needs some testing. So I would add this to TODO and will
send it after the next merge window. If I understood your point correctly?

> for the entire series, and next time we are both at the same conference
> I owe you a a couple of beers at least !

Heh, OK, it would be honor for me ;).

thanks,
--
js
suse labs

2012-08-08 20:26:55

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v2 19/41] TTY: move allocations to tty_alloc_driver

So now, that we have flags and know everything needed, keep a promise
and move all the tables and ports allocation from tty_register_driver
to tty_alloc_driver.

Not only that it makes sense, but we need this for
tty_port_link_device which needs tty_driver->ports but is to be called
before tty_register_driver.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_io.c | 73 +++++++++++++++++++++++---------------------------
1 file changed, 33 insertions(+), 40 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e024521..3098fa1 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3059,6 +3059,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
unsigned long flags)
{
struct tty_driver *driver;
+ int err;

if (!lines)
return ERR_PTR(-EINVAL);
@@ -3072,9 +3073,34 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
driver->num = lines;
driver->owner = owner;
driver->flags = flags;
- /* later we'll move allocation of tables here */
+
+ if (!(flags & TTY_DRIVER_DEVPTS_MEM)) {
+ driver->ttys = kcalloc(lines, sizeof(*driver->ttys),
+ GFP_KERNEL);
+ driver->termios = kcalloc(lines, sizeof(*driver->termios),
+ GFP_KERNEL);
+ if (!driver->ttys || !driver->termios) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+ }
+
+ if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ driver->ports = kcalloc(lines, sizeof(*driver->ports),
+ GFP_KERNEL);
+ if (!driver->ports) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+ }

return driver;
+err_free_all:
+ kfree(driver->ports);
+ kfree(driver->ttys);
+ kfree(driver->termios);
+ kfree(driver);
+ return ERR_PTR(err);
}
EXPORT_SYMBOL(__tty_alloc_driver);

@@ -3083,7 +3109,6 @@ static void destruct_tty_driver(struct kref *kref)
struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
int i;
struct ktermios *tp;
- void *p;

if (driver->flags & TTY_DRIVER_INSTALLED) {
/*
@@ -3100,14 +3125,12 @@ static void destruct_tty_driver(struct kref *kref)
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
- p = driver->ttys;
proc_tty_unregister_driver(driver);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
cdev_del(&driver->cdev);
}
kfree(driver->ports);
+ kfree(driver->termios);
+ kfree(driver->ttys);
kfree(driver);
}

@@ -3138,27 +3161,8 @@ int tty_register_driver(struct tty_driver *driver)
int error;
int i;
dev_t dev;
- void **p = NULL;
struct device *d;

- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
- p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- }
- /*
- * There is too many lines in PTY and we won't need the array there
- * since it has an ->install hook where it assigns ports properly.
- */
- if (driver->type != TTY_DRIVER_TYPE_PTY) {
- driver->ports = kcalloc(driver->num, sizeof(struct tty_port *),
- GFP_KERNEL);
- if (!driver->ports) {
- error = -ENOMEM;
- goto err_free_p;
- }
- }
-
if (!driver->major) {
error = alloc_chrdev_region(&dev, driver->minor_start,
driver->num, driver->name);
@@ -3171,15 +3175,7 @@ int tty_register_driver(struct tty_driver *driver)
error = register_chrdev_region(dev, driver->num, driver->name);
}
if (error < 0)
- goto err_free_p;
-
- if (p) {
- driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct ktermios **)(p + driver->num);
- } else {
- driver->ttys = NULL;
- driver->termios = NULL;
- }
+ goto err;

cdev_init(&driver->cdev, &tty_fops);
driver->cdev.owner = driver->owner;
@@ -3196,7 +3192,7 @@ int tty_register_driver(struct tty_driver *driver)
d = tty_register_device(driver, i, NULL);
if (IS_ERR(d)) {
error = PTR_ERR(d);
- goto err;
+ goto err_unreg_devs;
}
}
}
@@ -3204,7 +3200,7 @@ int tty_register_driver(struct tty_driver *driver)
driver->flags |= TTY_DRIVER_INSTALLED;
return 0;

-err:
+err_unreg_devs:
for (i--; i >= 0; i--)
tty_unregister_device(driver, i);

@@ -3214,10 +3210,7 @@ err:

err_unreg_char:
unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
-err_free_p: /* destruct_tty_driver will free driver->ports */
- kfree(p);
+err:
return error;
}
EXPORT_SYMBOL(tty_register_driver);
--
1.7.10.4

2012-08-08 20:26:54

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v2 20/41] TTY: add support for unnumbered device nodes

This allows drivers like ttyprintk to avoid hacks to create an
unnumbered node in /dev. It used to set TTY_DRIVER_DYNAMIC_DEV in
flags and call device_create on its own. That is incorrect, because
TTY_DRIVER_DYNAMIC_DEV may be set only if tty_register_device is
called explicitly.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/char/ttyprintk.c | 17 ++++-------------
drivers/tty/tty_io.c | 7 +++++--
include/linux/tty_driver.h | 6 ++++++
3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index be1c3fb..9e6272f 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -178,13 +178,15 @@ static struct tty_driver *ttyprintk_driver;
static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
- void *rp;

tty_port_init(&tpk_port.port);
tpk_port.port.ops = &null_ops;
mutex_init(&tpk_port.port_write_mutex);

- ttyprintk_driver = alloc_tty_driver(1);
+ ttyprintk_driver = tty_alloc_driver(1,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_UNNUMBERED_NODE);
if (!ttyprintk_driver)
return ret;

@@ -195,8 +197,6 @@ static int __init ttyprintk_init(void)
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
- ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ttyprintk_driver, &ttyprintk_ops);

ret = tty_register_driver(ttyprintk_driver);
@@ -205,15 +205,6 @@ static int __init ttyprintk_init(void)
goto error;
}

- /* create our unnumbered device */
- rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
- ttyprintk_driver->name);
- if (IS_ERR(rp)) {
- printk(KERN_ERR "Couldn't create ttyprintk device\n");
- ret = PTR_ERR(rp);
- goto error;
- }
-
return 0;

error:
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 3098fa1..59a73af 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1213,7 +1213,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
*/
static void tty_line_name(struct tty_driver *driver, int index, char *p)
{
- sprintf(p, "%s%d", driver->name, index + driver->name_base);
+ if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
+ strcpy(p, driver->name);
+ else
+ sprintf(p, "%s%d", driver->name, index + driver->name_base);
}

/**
@@ -3061,7 +3064,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
struct tty_driver *driver;
int err;

- if (!lines)
+ if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
return ERR_PTR(-EINVAL);

driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 1a85f00..44e05b7 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -394,6 +394,11 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
* TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are
* needed per line for this driver as it would waste memory.
* The driver will take care.
+ *
+ * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In
+ * other words create /dev/ttyprintk and not /dev/ttyprintk0.
+ * Applicable only when a driver for a single tty device is
+ * being allocated.
*/
#define TTY_DRIVER_INSTALLED 0x0001
#define TTY_DRIVER_RESET_TERMIOS 0x0002
@@ -402,6 +407,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
#define TTY_DRIVER_DEVPTS_MEM 0x0010
#define TTY_DRIVER_HARDWARE_BREAK 0x0020
#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040
+#define TTY_DRIVER_UNNUMBERED_NODE 0x0080

/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
--
1.7.10.4

2012-08-08 20:26:53

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v2 21/41] TTY: move cdev_add to tty_register_device

We need the /dev/ node not to be available before we call
tty_register_device. Otherwise we might race with open and
tty_struct->port might not be available at that time.

This is not an issue now, but would be a problem after "TTY: use
tty_port_register_device" is applied.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_io.c | 48 +++++++++++++++++++++++++++++++++++++-------
include/linux/tty_driver.h | 2 +-
2 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 59a73af..f83d450 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2991,6 +2991,15 @@ EXPORT_SYMBOL_GPL(tty_put_char);

struct class *tty_class;

+static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
+ unsigned int index, unsigned int count)
+{
+ /* init here, since reused cdevs cause crashes */
+ cdev_init(&driver->cdevs[index], &tty_fops);
+ driver->cdevs[index].owner = driver->owner;
+ return cdev_add(&driver->cdevs[index], dev, count);
+}
+
/**
* tty_register_device - register a tty device
* @driver: the tty driver that describes the tty device
@@ -3013,8 +3022,10 @@ struct class *tty_class;
struct device *tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
+ struct device *ret;
char name[64];
dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+ bool cdev = false;

if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
@@ -3027,7 +3038,18 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
else
tty_line_name(driver, index, name);

- return device_create(tty_class, device, dev, NULL, name);
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ int error = tty_cdev_add(driver, dev, index, 1);
+ if (error)
+ return ERR_PTR(error);
+ cdev = true;
+ }
+
+ ret = device_create(tty_class, device, dev, NULL, name);
+ if (IS_ERR(ret) && cdev)
+ cdev_del(&driver->cdevs[index]);
+
+ return ret;
}
EXPORT_SYMBOL(tty_register_device);

@@ -3046,6 +3068,8 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
device_destroy(tty_class,
MKDEV(driver->major, driver->minor_start) + index);
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC))
+ cdev_del(&driver->cdevs[index]);
}
EXPORT_SYMBOL(tty_unregister_device);

@@ -3062,6 +3086,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
unsigned long flags)
{
struct tty_driver *driver;
+ unsigned int cdevs = 1;
int err;

if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
@@ -3095,6 +3120,13 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
err = -ENOMEM;
goto err_free_all;
}
+ cdevs = lines;
+ }
+
+ driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
+ if (!driver->cdevs) {
+ err = -ENOMEM;
+ goto err_free_all;
}

return driver;
@@ -3129,8 +3161,10 @@ static void destruct_tty_driver(struct kref *kref)
tty_unregister_device(driver, i);
}
proc_tty_unregister_driver(driver);
- cdev_del(&driver->cdev);
+ if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
+ cdev_del(&driver->cdevs[0]);
}
+ kfree(driver->cdevs);
kfree(driver->ports);
kfree(driver->termios);
kfree(driver->ttys);
@@ -3180,11 +3214,11 @@ int tty_register_driver(struct tty_driver *driver)
if (error < 0)
goto err;

- cdev_init(&driver->cdev, &tty_fops);
- driver->cdev.owner = driver->owner;
- error = cdev_add(&driver->cdev, dev, driver->num);
- if (error)
- goto err_unreg_char;
+ if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
+ error = tty_cdev_add(driver, dev, 0, driver->num);
+ if (error)
+ goto err_unreg_char;
+ }

mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 44e05b7..dd976cf 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -289,7 +289,7 @@ struct tty_operations {
struct tty_driver {
int magic; /* magic number for this structure */
struct kref kref; /* Reference management */
- struct cdev cdev;
+ struct cdev *cdevs;
struct module *owner;
const char *driver_name;
const char *name;
--
1.7.10.4

2012-08-08 20:27:37

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v2 18/41] TTY: pty, switch to tty_alloc_driver

Switch to the new driver allocation interface, as this is one of the
special call-sites. Here, we need TTY_DRIVER_DYNAMIC_ALLOC to not
allocate tty_driver->ports, cdevs and potentially other structures
because we reserve too many lines in pty. Instead, it provides the
tty_port<->tty_struct link in tty->ops->install already.

Signed-off-by: Jiri Slaby <[email protected]>
---
drivers/tty/pty.c | 31 ++++++++++++++++++++-----------
include/linux/tty_driver.h | 4 ++++
2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index b726c8b..db7c6f9 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -443,11 +443,17 @@ static void __init legacy_pty_init(void)
if (legacy_count <= 0)
return;

- pty_driver = alloc_tty_driver(legacy_count);
+ pty_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_ALLOC);
if (!pty_driver)
panic("Couldn't allocate pty driver");

- pty_slave_driver = alloc_tty_driver(legacy_count);
+ pty_slave_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_ALLOC);
if (!pty_slave_driver)
panic("Couldn't allocate pty slave driver");

@@ -464,7 +470,6 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_lflag = 0;
pty_driver->init_termios.c_ispeed = 38400;
pty_driver->init_termios.c_ospeed = 38400;
- pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &master_pty_ops_bsd);

@@ -478,8 +483,6 @@ static void __init legacy_pty_init(void)
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_slave_driver->init_termios.c_ispeed = 38400;
pty_slave_driver->init_termios.c_ospeed = 38400;
- pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);

@@ -670,10 +673,20 @@ static struct file_operations ptmx_fops;

static void __init unix98_pty_init(void)
{
- ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+ ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_DYNAMIC_ALLOC);
if (!ptm_driver)
panic("Couldn't allocate Unix98 ptm driver");
- pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+ pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_DYNAMIC_ALLOC);
if (!pts_driver)
panic("Couldn't allocate Unix98 pts driver");

@@ -690,8 +703,6 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->init_termios.c_ispeed = 38400;
ptm_driver->init_termios.c_ospeed = 38400;
- ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &ptm_unix98_ops);

@@ -705,8 +716,6 @@ static void __init unix98_pty_init(void)
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->init_termios.c_ispeed = 38400;
pts_driver->init_termios.c_ospeed = 38400;
- pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver, &pty_unix98_ops);

diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 3adc362..1a85f00 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -391,6 +391,9 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
* the requested timeout to the caller instead of using a simple
* on/off interface.
*
+ * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are
+ * needed per line for this driver as it would waste memory.
+ * The driver will take care.
*/
#define TTY_DRIVER_INSTALLED 0x0001
#define TTY_DRIVER_RESET_TERMIOS 0x0002
@@ -398,6 +401,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
#define TTY_DRIVER_DYNAMIC_DEV 0x0008
#define TTY_DRIVER_DEVPTS_MEM 0x0010
#define TTY_DRIVER_HARDWARE_BREAK 0x0020
+#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040

/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
--
1.7.10.4

2012-08-08 22:14:52

by Alan

[permalink] [raw]
Subject: Re: [PATCH 18/41] TTY: pty, switch to tty_alloc_driver

> this and 19/41. The merge with DEVPTS_MEM (the termios case) needs
> devpts_kill_index to be moved from tty_release to
> pty_driver->ops->cleanup/shutdown, but I don't feel comfortable to do it
> now since it needs some testing. So I would add this to TODO and will
> send it after the next merge window. If I understood your point correctly?

That seems sensible - its on my list to sort as well. We don't need to
allocate some of the pointer arrays for many of the drivers (anything
which doesn't save termios state for example)

Alan

2012-08-13 03:30:23

by Rusty Russell

[permalink] [raw]
Subject: Re: [PATCH 12/41] mxser: allow overlapping vector

On Tue, 7 Aug 2012 21:47:37 +0200, Jiri Slaby <[email protected]> wrote:
> For many cards, this saves some IO space because interrupt status port
> has precedence over the rest of ports on the card. Hence it can be
> mapped to a hole in I/O ports.
>
> Here we add a kernel parameter which allows that if a user wants to.
> But they need to explicitly enable it by a module parameter.
>
> Signed-off-by: Jiri Slaby <[email protected]>
> ---
> drivers/tty/mxser.c | 35 +++++++++++++++++++++++++++++++----
> 1 file changed, 31 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
> index c162ee9..e64fe40 100644
> --- a/drivers/tty/mxser.c
> +++ b/drivers/tty/mxser.c
> @@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
> * The MOXA Smartio/Industio serial driver boot-time initialization code!
> */
>
> +static bool allow_overlapping_vector;
> +module_param(allow_overlapping_vector, bool, 444);

You mean 0444, right?

Cheers,
Rusty.

2012-08-13 07:23:50

by Jiri Slaby

[permalink] [raw]
Subject: Re: [PATCH 12/41] mxser: allow overlapping vector

On 08/13/2012 03:50 AM, Rusty Russell wrote:
> On Tue, 7 Aug 2012 21:47:37 +0200, Jiri Slaby <[email protected]> wrote:
>> For many cards, this saves some IO space because interrupt status port
>> has precedence over the rest of ports on the card. Hence it can be
>> mapped to a hole in I/O ports.
>>
>> Here we add a kernel parameter which allows that if a user wants to.
>> But they need to explicitly enable it by a module parameter.
>>
>> Signed-off-by: Jiri Slaby <[email protected]>
>> ---
>> drivers/tty/mxser.c | 35 +++++++++++++++++++++++++++++++----
>> 1 file changed, 31 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
>> index c162ee9..e64fe40 100644
>> --- a/drivers/tty/mxser.c
>> +++ b/drivers/tty/mxser.c
>> @@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
>> * The MOXA Smartio/Industio serial driver boot-time initialization code!
>> */
>>
>> +static bool allow_overlapping_vector;
>> +module_param(allow_overlapping_vector, bool, 444);
>
> You mean 0444, right?

Of course I did. I wonder why patch posters like numbers instead of
names. I will change this to S_IRUGO.

thanks,
--
js
suse labs

2012-08-13 08:16:31

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH] TTY: mxser, fix invalid module_parm permissions

444 means 0674 and we do not definitely want that. Use S_IRUGO which
is much more safer.

Signed-off-by: Jiri Slaby <[email protected]>
Reported-by: Rusty Russell <[email protected]>
---
drivers/tty/mxser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 8bc2651..bb2da4c 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2338,7 +2338,7 @@ static struct tty_port_operations mxser_port_ops = {
*/

static bool allow_overlapping_vector;
-module_param(allow_overlapping_vector, bool, 444);
+module_param(allow_overlapping_vector, bool, S_IRUGO);
MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");

static bool mxser_overlapping_vector(struct mxser_board *brd)
--
1.7.10.4

2012-08-13 08:18:16

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH] TTY: mxser, fix invalid module_parm permissions

444 means 0674 and we do not definitely want that. Use S_IRUGO which
is much more safer.

Signed-off-by: Jiri Slaby <[email protected]>
Reported-by: Rusty Russell <[email protected]>
---

Sorry for multiple copies (if any).

drivers/tty/mxser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 8bc2651..bb2da4c 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2338,7 +2338,7 @@ static struct tty_port_operations mxser_port_ops = {
*/

static bool allow_overlapping_vector;
-module_param(allow_overlapping_vector, bool, 444);
+module_param(allow_overlapping_vector, bool, S_IRUGO);
MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");

static bool mxser_overlapping_vector(struct mxser_board *brd)
--
1.7.10.4