Input patches for 2.6.12
Subsystems (2)
cover 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!
Signature · 1 line
Dmitry
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.
serio.c | 1 - 1 files changed, 1 deletion(-)
drivers/input/serio/serio.c +0 -1
@@ -779,7 +779,6 @@ static int serio_resume(struct device *dstruct 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.
PATCH 2/4 ALPS resume fix
===================================================================
Input: ALPS needs to be reset for detection to work reliably when
reconnecting.
alps.c | 2 ++ 1 files changed, 2 insertions(+)
drivers/input/mouse/alps.c +2 -0
@@ -341,6 +341,8 @@ static int alps_reconnect(struct psmouseunsigned char param[4 ];int version; +psmouse_reset (psmouse); +if (!(priv->i =alps_get_model (psmouse, &version)))return -1 ;
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.
serport.c | 98 +++++++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 68 insertions(+), 30 deletions(-)
drivers/input/serio/serport.c +68 -30
@@ -27,11 +27,15 @@ MODULE_LICENSE("GPL");MODULE_ALIAS_LDISC (N_MOUSE );#define SERPORT_BUSY 1 +#define SERPORT_ACTIVE 2 +#define SERPORT_DEAD 3struct 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 sereturn -(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 sstatic 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 ttystatic 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 tstatic 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 ttystatic 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(structstatic 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 ttstatic 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); }/*
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/protoserio.c | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-)
drivers/input/serio/serio.c +20 -4
@@ -388,6 +388,24 @@ static ssize_t serio_show_id_extra(strucreturn 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(strucstatic 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 serioif (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 ;