2005-04-04 06:14:07

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 0/4] Input patches for 2.6.12

Hi Vojtech,

I have some patches that I would like to get in before 2.6.12 is out:

01-serio-resume-fix.patch
- do not attempt to disconnect port in resume handler if reconect
failed - let kseriod handle it. This fixes problem with swsusp
resuming devices before writing the image. If reconnect fails
at this point serio core will try to disconnect port and unregister
associated input device invoking hotplug which will block since
the system is half-frozen.

02-alps-reconnect-fix.patch
- apparently ALPS needs a reset before it starts responding with
proper IDs to the E6/E7 queries.

03-serport-oops-fix.patch
- serport should not call serio_interrupt or serio_write_wakeup on
unregistered port (happens if you move mouse aroung while shutting
down the system), also dynamic serio allocation needed to be reworked
to awoid memory leaks in case serport was never used.

04-serio-id-attribute-group.patch
- move serio port's 'id' attributes into separate subdirectory using
attribute group:
..devices/serioX/id_type -> ..devices/serioX/id/type
..devices/serioX/id_proto -> ..devices/serioX/id/proto
ID attributes were never part of a released kernel so if we were to
do the change now would be the time.

I have confirmation reports for patches 1-3. Please let me know what you
think.

Thanks!

--
Dmitry


2005-04-04 06:14:12

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 1/4] serio resume fix

===================================================================

Input: serio - do not attempt to immediately disconnect port if
resume failed, let kseriod take care of it. Otherwise we
may attempt to unregister associated input devices which
will generate hotplug events which are not handled well
during swsusp.

Signed-off-by: Dmitry Torokhov <[email protected]>


serio.c | 1 -
1 files changed, 1 deletion(-)

Index: dtor/drivers/input/serio/serio.c
===================================================================
--- dtor.orig/drivers/input/serio/serio.c
+++ dtor/drivers/input/serio/serio.c
@@ -779,7 +779,6 @@ static int serio_resume(struct device *d
struct serio *serio = to_serio_port(dev);

if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
- serio_disconnect_port(serio);
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.

2005-04-04 06:16:12

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 2/4] ALPS resume fix

===================================================================

Input: ALPS needs to be reset for detection to work reliably when
reconnecting.

Signed-off-by: Dmitry Torokhov <[email protected]>


alps.c | 2 ++
1 files changed, 2 insertions(+)

Index: dtor/drivers/input/mouse/alps.c
===================================================================
--- dtor.orig/drivers/input/mouse/alps.c
+++ dtor/drivers/input/mouse/alps.c
@@ -341,6 +341,8 @@ static int alps_reconnect(struct psmouse
unsigned char param[4];
int version;

+ psmouse_reset(psmouse);
+
if (!(priv->i = alps_get_model(psmouse, &version)))
return -1;

2005-04-04 06:16:20

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 4/4] serio 'id' attributes

===================================================================

Input: move serio port's id attributes into separate subdirectory:
..devices/serioX/id_type -> ..devices/serioX/id/type
..devices/serioX/id_proto -> ..devices/serioX/id/proto

Signed-off-by: Dmitry Torokhov <[email protected]>


serio.c | 24 ++++++++++++++++++++----
1 files changed, 20 insertions(+), 4 deletions(-)

Index: dtor/drivers/input/serio/serio.c
===================================================================
--- dtor.orig/drivers/input/serio/serio.c
+++ dtor/drivers/input/serio/serio.c
@@ -388,6 +388,24 @@ static ssize_t serio_show_id_extra(struc
return sprintf(buf, "%02x\n", serio->id.extra);
}

+static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL);
+static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL);
+static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL);
+static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL);
+
+static struct attribute *serio_device_id_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_proto.attr,
+ &dev_attr_id.attr,
+ &dev_attr_extra.attr,
+ NULL
+};
+
+static struct attribute_group serio_id_attr_group = {
+ .name = "id",
+ .attrs = serio_device_id_attrs,
+};
+
static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
{
struct serio *serio = to_serio_port(dev);
@@ -444,10 +462,6 @@ static ssize_t serio_set_bind_mode(struc

static struct device_attribute serio_device_attrs[] = {
__ATTR(description, S_IRUGO, serio_show_description, NULL),
- __ATTR(id_type, S_IRUGO, serio_show_id_type, NULL),
- __ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL),
- __ATTR(id_id, S_IRUGO, serio_show_id_id, NULL),
- __ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL),
__ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
__ATTR_NULL
@@ -498,6 +512,7 @@ static void serio_add_port(struct serio
if (serio->start)
serio->start(serio);
device_add(&serio->dev);
+ sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
serio->registered = 1;
}

@@ -526,6 +541,7 @@ static void serio_destroy_port(struct se
}

if (serio->registered) {
+ sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
device_del(&serio->dev);
list_del_init(&serio->node);
serio->registered = 0;

2005-04-04 06:16:19

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 3/4] serport oops fix

===================================================================

Input: serport - avoid calling serio_interrupt or serio_write_wakeup
on unregistered port. Also fix memory leak which could happen
if serport was left unused by moving serio allocation down to
serport_ldisc_read.

Signed-off-by: Dmitry Torokhov <[email protected]>


serport.c | 98 +++++++++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 68 insertions(+), 30 deletions(-)

Index: dtor/drivers/input/serio/serport.c
===================================================================
--- dtor.orig/drivers/input/serio/serport.c
+++ dtor/drivers/input/serio/serport.c
@@ -27,11 +27,15 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_MOUSE);

#define SERPORT_BUSY 1
+#define SERPORT_ACTIVE 2
+#define SERPORT_DEAD 3

struct serport {
struct tty_struct *tty;
wait_queue_head_t wait;
struct serio *serio;
+ struct serio_device_id id;
+ spinlock_t lock;
unsigned long flags;
};

@@ -45,11 +49,29 @@ static int serport_serio_write(struct se
return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
}

+static int serport_serio_open(struct serio *serio)
+{
+ struct serport *serport = serio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serport->lock, flags);
+ set_bit(SERPORT_ACTIVE, &serport->flags);
+ spin_unlock_irqrestore(&serport->lock, flags);
+
+ return 0;
+}
+
+
static void serport_serio_close(struct serio *serio)
{
struct serport *serport = serio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serport->lock, flags);
+ clear_bit(SERPORT_ACTIVE, &serport->flags);
+ set_bit(SERPORT_DEAD, &serport->flags);
+ spin_unlock_irqrestore(&serport->lock, flags);

- serport->serio->id.type = 0;
wake_up_interruptible(&serport->wait);
}

@@ -61,36 +83,21 @@ static void serport_serio_close(struct s
static int serport_ldisc_open(struct tty_struct *tty)
{
struct serport *serport;
- struct serio *serio;
- char name[64];

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

- serport = kmalloc(sizeof(struct serport), GFP_KERNEL);
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
- if (unlikely(!serport || !serio)) {
- kfree(serport);
- kfree(serio);
+ serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
+ if (!serport)
return -ENOMEM;
- }

- memset(serport, 0, sizeof(struct serport));
- serport->serio = serio;
- set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
serport->tty = tty;
- tty->disc_data = serport;
-
- memset(serio, 0, sizeof(struct serio));
- strlcpy(serio->name, "Serial port", sizeof(serio->name));
- snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
- serio->id.type = SERIO_RS232;
- serio->write = serport_serio_write;
- serio->close = serport_serio_close;
- serio->port_data = serport;
-
+ spin_lock_init(&serport->lock);
init_waitqueue_head(&serport->wait);

+ tty->disc_data = serport;
+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
return 0;
}

@@ -100,7 +107,8 @@ static int serport_ldisc_open(struct tty

static void serport_ldisc_close(struct tty_struct *tty)
{
- struct serport *serport = (struct serport*) tty->disc_data;
+ struct serport *serport = (struct serport *) tty->disc_data;
+
kfree(serport);
}

@@ -116,9 +124,19 @@ static void serport_ldisc_close(struct t
static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
+ unsigned long flags;
int i;
+
+ spin_lock_irqsave(&serport->lock, flags);
+
+ if (!test_bit(SERPORT_ACTIVE, &serport->flags))
+ goto out;
+
for (i = 0; i < count; i++)
serio_interrupt(serport->serio, cp[i], 0, NULL);
+
+out:
+ spin_unlock_irqrestore(&serport->lock, flags);
}

/*
@@ -141,16 +159,33 @@ static int serport_ldisc_room(struct tty
static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)
{
struct serport *serport = (struct serport*) tty->disc_data;
+ struct serio *serio;
char name[64];

if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY;

+ serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
+ if (!serio)
+ return -ENOMEM;
+
+ strlcpy(serio->name, "Serial port", sizeof(serio->name));
+ snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
+ serio->id = serport->id;
+ serio->id.type = SERIO_RS232;
+ serio->write = serport_serio_write;
+ serio->open = serport_serio_open;
+ serio->close = serport_serio_close;
+ serio->port_data = serport;
+
serio_register_port(serport->serio);
printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
- wait_event_interruptible(serport->wait, !serport->serio->id.type);
+
+ wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
serio_unregister_port(serport->serio);
+ serport->serio = NULL;

+ clear_bit(SERPORT_DEAD, &serport->flags);
clear_bit(SERPORT_BUSY, &serport->flags);

return 0;
@@ -163,16 +198,15 @@ static ssize_t serport_ldisc_read(struct
static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct serport *serport = (struct serport*) tty->disc_data;
- struct serio *serio = serport->serio;
unsigned long type;

if (cmd == SPIOCSTYPE) {
if (get_user(type, (unsigned long __user *) arg))
return -EFAULT;

- serio->id.proto = type & 0x000000ff;
- serio->id.id = (type & 0x0000ff00) >> 8;
- serio->id.extra = (type & 0x00ff0000) >> 16;
+ serport->id.proto = type & 0x000000ff;
+ serport->id.id = (type & 0x0000ff00) >> 8;
+ serport->id.extra = (type & 0x00ff0000) >> 16;

return 0;
}
@@ -182,9 +216,13 @@ static int serport_ldisc_ioctl(struct tt

static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{
- struct serport *sp = (struct serport *) tty->disc_data;
+ struct serport *serport = (struct serport *) tty->disc_data;
+ unsigned long flags;

- serio_drv_write_wakeup(sp->serio);
+ spin_lock_irqsave(&serport->lock, flags);
+ if (test_bit(SERPORT_ACTIVE, &serport->flags))
+ serio_drv_write_wakeup(serport->serio);
+ spin_unlock_irqrestore(&serport->lock, flags);
}

/*