* [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards @ 2010-08-16 11:26 Dmitry Eremin-Solenikov 2010-08-16 11:26 ` [PATCH 1/2] serio: support multiple child devices per single parent Dmitry Eremin-Solenikov ` (2 more replies) 0 siblings, 3 replies; 7+ messages in thread From: Dmitry Eremin-Solenikov @ 2010-08-16 11:26 UTC (permalink / raw) To: linux-input; +Cc: Dmitry Torokhov On tqm85xx boards (and several others) keyboard and mice are connected to CPU via special controller multiplexing KBD and MS traffic into single UART. Changes since v1: * Rewrote serio to use iterative algorithms instead of recursion for serio tree traversal * Changed ps2mult to register as SERIO_8042, not it's own special type * Small cleanup in ps2mult -- With best wishes Dmitry ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] serio: support multiple child devices per single parent 2010-08-16 11:26 [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov @ 2010-08-16 11:26 ` Dmitry Eremin-Solenikov 2010-09-15 5:03 ` Dmitry Torokhov 2010-08-16 11:26 ` [PATCH 2/2] serio: add support for PS2Mult multiplexer protocol Dmitry Eremin-Solenikov 2010-08-31 10:49 ` [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov 2 siblings, 1 reply; 7+ messages in thread From: Dmitry Eremin-Solenikov @ 2010-08-16 11:26 UTC (permalink / raw) To: linux-input; +Cc: Dmitry Torokhov Some (rare) serio devices need to have multiple serio children. One of the examples is PS/2 multiplexer present on several TQC STKxxx boards, which connect PS/2 keyboard and mouse to single tty port. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> --- drivers/input/mouse/psmouse-base.c | 2 +- drivers/input/mouse/synaptics.c | 11 +++- drivers/input/serio/serio.c | 114 +++++++++++++++++++----------------- include/linux/serio.h | 5 +- 4 files changed, 73 insertions(+), 59 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 979c502..0eeed6c 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1582,7 +1582,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (!new_dev) return -ENOMEM; - while (serio->child) { + while (!list_empty(&serio->children)) { if (++retry > 3) { printk(KERN_WARNING "psmouse: failed to destroy child port, " diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 705589d..9295ad0 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -315,7 +315,9 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet static void synaptics_pt_activate(struct psmouse *psmouse) { - struct serio *ptport = psmouse->ps2dev.serio->child; + struct serio *ptport = + list_first_entry(&psmouse->ps2dev.serio->children, + struct serio, child_list); struct psmouse *child = serio_get_drvdata(ptport); struct synaptics_data *priv = psmouse->private; @@ -577,8 +579,11 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) priv->pkt_type = synaptics_detect_pkt_type(psmouse); if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { - if (psmouse->ps2dev.serio->child) - synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); + if (!list_empty(&psmouse->ps2dev.serio->children)) + synaptics_pass_pt_packet( + list_first_entry(&psmouse->ps2dev.serio->children, + struct serio, child_list), + psmouse->packet); } else synaptics_process_packet(psmouse); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index c3b626e..55c46e8 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -312,12 +312,9 @@ static void serio_handle_event(void) * Remove all events that have been submitted for a given * object, be it serio port or driver. */ -static void serio_remove_pending_events(void *object) +static void __serio_remove_pending_events(void *object) { struct serio_event *event, *next; - unsigned long flags; - - spin_lock_irqsave(&serio_event_lock, flags); list_for_each_entry_safe(event, next, &serio_event_list, node) { if (event->object == object) { @@ -325,38 +322,41 @@ static void serio_remove_pending_events(void *object) serio_free_event(event); } } +} + +static void serio_remove_pending_events(void *object) +{ + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + __serio_remove_pending_events(object); spin_unlock_irqrestore(&serio_event_lock, flags); } /* * Destroy child serio port (if any) that has not been fully registered yet. - * - * Note that we rely on the fact that port can have only one child and therefore - * only one child registration request can be pending. Additionally, children - * are registered by driver's connect() handler so there can't be a grandchild - * pending registration together with a child. */ -static struct serio *serio_get_pending_child(struct serio *parent) +static void serio_drop_pending_children(struct serio *parent) { - struct serio_event *event; - struct serio *serio, *child = NULL; + struct serio_event *event, *temp; + struct serio *serio; unsigned long flags; spin_lock_irqsave(&serio_event_lock, flags); - list_for_each_entry(event, &serio_event_list, node) { + list_for_each_entry_safe(event, temp, &serio_event_list, node) { if (event->type == SERIO_REGISTER_PORT) { serio = event->object; if (serio->parent == parent) { - child = serio; - break; + __serio_remove_pending_events(serio); + put_device(&serio->dev); } } } spin_unlock_irqrestore(&serio_event_lock, flags); - return child; } static int serio_thread(void *nothing) @@ -516,6 +516,9 @@ static void serio_init_port(struct serio *serio) __module_get(THIS_MODULE); INIT_LIST_HEAD(&serio->node); + INIT_LIST_HEAD(&serio->children); + INIT_LIST_HEAD(&serio->child_list); + INIT_LIST_HEAD(&serio->internal); spin_lock_init(&serio->lock); mutex_init(&serio->drv_mutex); device_initialize(&serio->dev); @@ -542,7 +545,7 @@ static void serio_add_port(struct serio *serio) if (serio->parent) { serio_pause_rx(serio->parent); - serio->parent->child = serio; + list_add_tail(&serio->child_list, &serio->parent->children); serio_continue_rx(serio->parent); } @@ -564,20 +567,14 @@ static void serio_add_port(struct serio *serio) */ static void serio_destroy_port(struct serio *serio) { - struct serio *child; - - child = serio_get_pending_child(serio); - if (child) { - serio_remove_pending_events(child); - put_device(&child->dev); - } + serio_drop_pending_children(serio); if (serio->stop) serio->stop(serio); if (serio->parent) { serio_pause_rx(serio->parent); - serio->parent->child = NULL; + list_del(&serio->child_list); serio_continue_rx(serio->parent); serio->parent = NULL; } @@ -613,13 +610,19 @@ static int serio_reconnect_port(struct serio *serio) */ static void serio_reconnect_chain(struct serio *serio) { - do { - if (serio_reconnect_port(serio)) { - /* Ok, old children are now gone, we are done */ - break; - } - serio = serio->child; - } while (serio); + struct serio *child; + LIST_HEAD(todo); + + list_add_tail(&serio->internal, &todo); + + while (!list_empty(&todo)) { + serio = list_first_entry(&todo, struct serio, internal); + list_del_init(&serio->internal); + + if (!serio_reconnect_port(serio)) + list_for_each_entry(child, &serio->children, child_list) + list_add_tail(&child->internal, &todo); + } } /* @@ -628,29 +631,31 @@ static void serio_reconnect_chain(struct serio *serio) */ static void serio_disconnect_port(struct serio *serio) { - struct serio *s, *parent; + struct serio *s, *child; + LIST_HEAD(todo); - if (serio->child) { - /* - * Children ports should be disconnected and destroyed - * first, staring with the leaf one, since we don't want - * to do recursion - */ - for (s = serio; s->child; s = s->child) - /* empty */; + list_add_tail(&serio->internal, &todo); - do { - parent = s->parent; + while (!list_empty(&todo)) { + s = list_first_entry(&todo, struct serio, internal); + + if (!list_empty(&s->children)) { + list_for_each_entry(child, &s->children, child_list) + list_add(&child->internal, &todo); + + /* + * We will return to this item later, when it will have + * no children. + */ + } else { + list_del_init(&s->internal); device_release_driver(&s->dev); - serio_destroy_port(s); - } while ((s = parent) != serio); - } - /* - * Ok, no children left, now disconnect this port - */ - device_release_driver(&serio->dev); + if (s != serio) + serio_destroy_port(s); + } + } } void serio_rescan(struct serio *serio) @@ -689,14 +694,15 @@ void serio_unregister_port(struct serio *serio) EXPORT_SYMBOL(serio_unregister_port); /* - * Safely unregisters child port if one is present. + * Safely unregisters child ports if any is present. */ void serio_unregister_child_port(struct serio *serio) { + struct serio *s, *temp; mutex_lock(&serio_mutex); - if (serio->child) { - serio_disconnect_port(serio->child); - serio_destroy_port(serio->child); + list_for_each_entry_safe(s, temp, &serio->children, child_list) { + serio_disconnect_port(s); + serio_destroy_port(s); } mutex_unlock(&serio_mutex); } diff --git a/include/linux/serio.h b/include/linux/serio.h index b555256..861a72a 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -41,7 +41,9 @@ struct serio { int (*start)(struct serio *); void (*stop)(struct serio *); - struct serio *parent, *child; + struct serio *parent; + struct list_head child_list; + struct list_head children; unsigned int depth; /* level of nesting in serio hierarchy */ struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ @@ -50,6 +52,7 @@ struct serio { struct device dev; struct list_head node; + struct list_head internal; /* Used internally to avoid recursion */ }; #define to_serio_port(d) container_of(d, struct serio, dev) -- 1.7.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] serio: support multiple child devices per single parent 2010-08-16 11:26 ` [PATCH 1/2] serio: support multiple child devices per single parent Dmitry Eremin-Solenikov @ 2010-09-15 5:03 ` Dmitry Torokhov 2010-09-23 16:36 ` Dmitry Eremin-Solenikov 0 siblings, 1 reply; 7+ messages in thread From: Dmitry Torokhov @ 2010-09-15 5:03 UTC (permalink / raw) To: Dmitry Eremin-Solenikov; +Cc: linux-input [-- Attachment #1: Type: text/plain, Size: 9614 bytes --] Hi Dmitry, On Mon, Aug 16, 2010 at 03:26:36PM +0400, Dmitry Eremin-Solenikov wrote: > @@ -50,6 +52,7 @@ struct serio { > struct device dev; > > struct list_head node; > + struct list_head internal; /* Used internally to avoid recursion */ I think we can do without this one, how about the patch below? (Depends on synaptics changes in attached patch). Thanks. -- Dmitry Input: serio - support multiple child devices per single parent From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Some (rare) serio devices need to have multiple serio children. One of the examples is PS/2 multiplexer present on several TQC STKxxx boards, which connect PS/2 keyboard and mouse to single tty port. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/mouse/psmouse-base.c | 4 + drivers/input/serio/serio.c | 124 ++++++++++++++++++++++++------------ include/linux/serio.h | 4 + 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 2f7408a..35356ba 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (!new_dev) return -ENOMEM; - while (serio->child) { + while (!list_empty(&serio->children)) { if (++retry > 3) { printk(KERN_WARNING - "psmouse: failed to destroy child port, " + "psmouse: failed to destroy children ports, " "protocol change aborted.\n"); input_free_device(new_dev); return -EIO; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index b2730b4..be0e93a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -54,7 +54,7 @@ static struct bus_type serio_bus; static void serio_add_port(struct serio *serio); static int serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); -static void serio_reconnect_chain(struct serio *serio); +static void serio_reconnect_subtree(struct serio *serio); static void serio_attach_driver(struct serio_driver *drv); static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) @@ -150,7 +150,7 @@ static void serio_find_driver(struct serio *serio) enum serio_event_type { SERIO_RESCAN_PORT, SERIO_RECONNECT_PORT, - SERIO_RECONNECT_CHAIN, + SERIO_RECONNECT_SUBTREE, SERIO_REGISTER_PORT, SERIO_ATTACH_DRIVER, }; @@ -237,8 +237,8 @@ static void serio_handle_event(struct work_struct *work) serio_find_driver(event->object); break; - case SERIO_RECONNECT_CHAIN: - serio_reconnect_chain(event->object); + case SERIO_RECONNECT_SUBTREE: + serio_reconnect_subtree(event->object); break; case SERIO_ATTACH_DRIVER: @@ -328,12 +328,10 @@ static void serio_remove_pending_events(void *object) } /* - * Destroy child serio port (if any) that has not been fully registered yet. + * Locate child serio port (if any) that has not been fully registered yet. * - * Note that we rely on the fact that port can have only one child and therefore - * only one child registration request can be pending. Additionally, children - * are registered by driver's connect() handler so there can't be a grandchild - * pending registration together with a child. + * Children are registered by driver's connect() handler so there can't be a + * grandchild pending registration together with a child. */ static struct serio *serio_get_pending_child(struct serio *parent) { @@ -435,7 +433,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * if (!strncmp(buf, "none", count)) { serio_disconnect_port(serio); } else if (!strncmp(buf, "reconnect", count)) { - serio_reconnect_chain(serio); + serio_reconnect_subtree(serio); } else if (!strncmp(buf, "rescan", count)) { serio_disconnect_port(serio); serio_find_driver(serio); @@ -502,6 +500,8 @@ static void serio_init_port(struct serio *serio) __module_get(THIS_MODULE); INIT_LIST_HEAD(&serio->node); + INIT_LIST_HEAD(&serio->child_node); + INIT_LIST_HEAD(&serio->children); spin_lock_init(&serio->lock); mutex_init(&serio->drv_mutex); device_initialize(&serio->dev); @@ -524,12 +524,13 @@ static void serio_init_port(struct serio *serio) */ static void serio_add_port(struct serio *serio) { + struct serio *parent = serio->parent; int error; - if (serio->parent) { - serio_pause_rx(serio->parent); - serio->parent->child = serio; - serio_continue_rx(serio->parent); + if (parent) { + serio_pause_rx(parent); + list_add_tail(&serio->child_node, &parent->children); + serio_continue_rx(parent); } list_add_tail(&serio->node, &serio_list); @@ -545,15 +546,14 @@ static void serio_add_port(struct serio *serio) } /* - * serio_destroy_port() completes deregistration process and removes + * serio_destroy_port() completes unregistration process and removes * port from the system */ static void serio_destroy_port(struct serio *serio) { struct serio *child; - child = serio_get_pending_child(serio); - if (child) { + while ((child = serio_get_pending_child(serio)) != NULL) { serio_remove_pending_events(child); put_device(&child->dev); } @@ -563,7 +563,7 @@ static void serio_destroy_port(struct serio *serio) if (serio->parent) { serio_pause_rx(serio->parent); - serio->parent->child = NULL; + list_del_init(&serio->child_node); serio_continue_rx(serio->parent); serio->parent = NULL; } @@ -595,46 +595,82 @@ static int serio_reconnect_port(struct serio *serio) } /* - * Reconnect serio port and all its children (re-initialize attached devices) + * Reconnect serio port and all its children (re-initialize attached + * devices). */ -static void serio_reconnect_chain(struct serio *serio) +static void serio_reconnect_subtree(struct serio *root) { + struct serio *s = root; + int error; + do { - if (serio_reconnect_port(serio)) { - /* Ok, old children are now gone, we are done */ - break; + error = serio_reconnect_port(s); + if (!error) { + /* + * Reconnect was successful, move on to do the + * first child. + */ + if (!list_empty(&s->children)) { + s = list_first_entry(&s->children, + struct serio, child_node); + continue; + } } - serio = serio->child; - } while (serio); + + /* + * Either it was a leaf node or reconnect failed and it + * became a leaf node. Continue reconnecting starting with + * the next sibling of the parent node. + */ + while (s != root) { + struct serio *parent = s->parent; + + if (!list_is_last(&s->child_node, &parent->children)) { + s = list_entry(s->child_node.next, + struct serio, child_node); + break; + } + + s = parent; + } + } while (s != root); } /* * serio_disconnect_port() unbinds a port from its driver. As a side effect - * all child ports are unbound and destroyed. + * all children ports are unbound and destroyed. */ static void serio_disconnect_port(struct serio *serio) { - struct serio *s, *parent; + struct serio *s = serio; + + /* + * Children ports should be disconnected and destroyed + * first; we travel the tree in depth-first order. + */ + while (!list_empty(&serio->children)) { + + /* Locate a leaf */ + while (!list_empty(&s->children)) + s = list_first_entry(&s->children, + struct serio, child_node); - if (serio->child) { /* - * Children ports should be disconnected and destroyed - * first, staring with the leaf one, since we don't want - * to do recursion + * Prune this leaf node unless it is the one we + * started with. */ - for (s = serio; s->child; s = s->child) - /* empty */; - - do { - parent = s->parent; + if (s != serio) { + struct serio *parent = s->parent; device_release_driver(&s->dev); serio_destroy_port(s); - } while ((s = parent) != serio); + + s = parent; + } } /* - * Ok, no children left, now disconnect this port + * OK, no children left, now disconnect this port. */ device_release_driver(&serio->dev); } @@ -647,7 +683,7 @@ EXPORT_SYMBOL(serio_rescan); void serio_reconnect(struct serio *serio) { - serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); + serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE); } EXPORT_SYMBOL(serio_reconnect); @@ -675,14 +711,16 @@ void serio_unregister_port(struct serio *serio) EXPORT_SYMBOL(serio_unregister_port); /* - * Safely unregisters child port if one is present. + * Safely unregisters children ports if they are present. */ void serio_unregister_child_port(struct serio *serio) { + struct serio *s, *next; + mutex_lock(&serio_mutex); - if (serio->child) { - serio_disconnect_port(serio->child); - serio_destroy_port(serio->child); + list_for_each_entry_safe(s, next, &serio->children, child_node) { + serio_disconnect_port(s); + serio_destroy_port(s); } mutex_unlock(&serio_mutex); } diff --git a/include/linux/serio.h b/include/linux/serio.h index 111ad50..109b237 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -41,7 +41,9 @@ struct serio { int (*start)(struct serio *); void (*stop)(struct serio *); - struct serio *parent, *child; + struct serio *parent; + struct list_head child_node; /* Entry in parent->children list */ + struct list_head children; unsigned int depth; /* level of nesting in serio hierarchy */ struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ [-- Attachment #2: synaptics-ptport-handling.patch --] [-- Type: text/plain, Size: 3449 bytes --] Input: synaptics - simplify pass-through port handling From: Dmitry Torokhov <dmitry.torokhov@gmail.com> There was too much knowledge about internals if serio in the pass-through handling, clean it up. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/mouse/synaptics.c | 36 ++++++++++++++++++++++++++++++------ drivers/input/mouse/synaptics.h | 2 ++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 96b70a4..60b7817 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -294,7 +294,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c) return 0; } -static inline int synaptics_is_pt_packet(unsigned char *buf) +static int synaptics_pt_start(struct serio *serio) +{ + struct psmouse *parent = serio_get_drvdata(serio->parent); + struct synaptics_data *priv = parent->private; + + serio_pause_rx(parent->ps2dev.serio); + priv->pt_port = serio; + serio_continue_rx(parent->ps2dev.serio); + + return 0; +} + +static void synaptics_pt_stop(struct serio *serio) +{ + struct psmouse *parent = serio_get_drvdata(serio->parent); + struct synaptics_data *priv = parent->private; + + serio_pause_rx(parent->ps2dev.serio); + priv->pt_port = NULL; + serio_continue_rx(parent->ps2dev.serio); +} + +static int synaptics_is_pt_packet(unsigned char *buf) { return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; } @@ -315,9 +337,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet static void synaptics_pt_activate(struct psmouse *psmouse) { - struct serio *ptport = psmouse->ps2dev.serio->child; - struct psmouse *child = serio_get_drvdata(ptport); struct synaptics_data *priv = psmouse->private; + struct psmouse *child = serio_get_drvdata(priv->pt_port); /* adjust the touchpad to child's choice of protocol */ if (child) { @@ -345,6 +366,8 @@ static void synaptics_pt_create(struct psmouse *psmouse) strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); serio->write = synaptics_pt_write; + serio->start = synaptics_pt_start; + serio->stop = synaptics_pt_stop; serio->parent = psmouse->ps2dev.serio; psmouse->pt_activate = synaptics_pt_activate; @@ -578,9 +601,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { - if (psmouse->ps2dev.serio->child) - synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); + if (SYN_CAP_PASS_THROUGH(priv->capabilities) && + synaptics_is_pt_packet(psmouse->packet)) { + if (priv->pt_port) + synaptics_pass_pt_packet(priv->pt_port, psmouse->packet); } else synaptics_process_packet(psmouse); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index b6aa7d2..613a365 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -110,6 +110,8 @@ struct synaptics_data { unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ int scroll; + + struct serio *pt_port; /* Pass-through serio port */ }; void synaptics_module_init(void); ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] serio: support multiple child devices per single parent 2010-09-15 5:03 ` Dmitry Torokhov @ 2010-09-23 16:36 ` Dmitry Eremin-Solenikov 0 siblings, 0 replies; 7+ messages in thread From: Dmitry Eremin-Solenikov @ 2010-09-23 16:36 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-input On Tue, Sep 14, 2010 at 10:03:16PM -0700, Dmitry Torokhov wrote: > Hi Dmitry, > > On Mon, Aug 16, 2010 at 03:26:36PM +0400, Dmitry Eremin-Solenikov wrote: > > @@ -50,6 +52,7 @@ struct serio { > > struct device dev; > > > > struct list_head node; > > + struct list_head internal; /* Used internally to avoid recursion */ > > I think we can do without this one, how about the patch below? (Depends > on synaptics changes in attached patch). Yes, it works for me. Sorry for the (long) delay in testing - I was on vacation. I'll resubmit updated ps2mult driver in a few minutes. -- With best wishes Dmitry ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] serio: add support for PS2Mult multiplexer protocol 2010-08-16 11:26 [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov 2010-08-16 11:26 ` [PATCH 1/2] serio: support multiple child devices per single parent Dmitry Eremin-Solenikov @ 2010-08-16 11:26 ` Dmitry Eremin-Solenikov 2010-09-08 5:35 ` Dmitry Torokhov 2010-08-31 10:49 ` [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov 2 siblings, 1 reply; 7+ messages in thread From: Dmitry Eremin-Solenikov @ 2010-08-16 11:26 UTC (permalink / raw) To: linux-input; +Cc: Dmitry Torokhov PS2Mult is a simple serial protocol used for multiplexing several PS/2 streams into one serial data stream. It's used e.g. on TQM85xx serie of boards. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> --- drivers/input/serio/Kconfig | 8 ++ drivers/input/serio/Makefile | 1 + drivers/input/serio/ps2mult.c | 265 +++++++++++++++++++++++++++++++++++++++++ include/linux/serio.h | 2 + 4 files changed, 276 insertions(+), 0 deletions(-) create mode 100644 drivers/input/serio/ps2mult.c diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 3bfe8fa..63f4658 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -226,4 +226,12 @@ config SERIO_AMS_DELTA To compile this driver as a module, choose M here; the module will be called ams_delta_serio. +config SERIO_PS2MULT + tristate "TQC PS/2 multiplexer" + help + Say Y here if you have the PS/2 line multiplexer like present on TQC boads + + To compile this driver as a module, choose M here: the + module will be called ps2mult. + endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 84c80bf..26714c5 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o +obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c new file mode 100644 index 0000000..e9b7951 --- /dev/null +++ b/drivers/input/serio/ps2mult.c @@ -0,0 +1,265 @@ +/* + * TQC PS/2 Multiplexer driver + * + * Copyright (C) 2010 Dmitry Eremin-Solenikov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/serio.h> + +MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>"); +MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver"); +MODULE_LICENSE("GPL"); + +#define PS2MULT_KB_SELECTOR 0xA0 +#define PS2MULT_MS_SELECTOR 0xA1 +#define PS2MULT_ESCAPE 0x7D +#define PS2MULT_BSYNC 0x7E +#define PS2MULT_SESSION_START 0x55 +#define PS2MULT_SESSION_END 0x56 + +struct ps2mult_port { + struct serio *serio; + unsigned char sel; + unsigned char port; +}; + +#define PS2MULT_NUM_PORTS 2 + +struct ps2mult { + struct serio *serio; + struct ps2mult_port ports[PS2MULT_NUM_PORTS]; + + spinlock_t lock; + unsigned char cur_out_port; + unsigned char cur_in_port; + unsigned escape:1; +}; + +static unsigned char ps2mult_selectors[PS2MULT_NUM_PORTS] = { + PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR, +}; + +static struct serio_device_id ps2mult_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_PS2MULT, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids); + +static int ps2mult_serio_write(struct serio *serio, unsigned char data) +{ + struct ps2mult *psm = serio_get_drvdata(serio->parent); + struct ps2mult_port *psmp = serio->port_data; + bool need_escape; + unsigned long flags; + + spin_lock_irqsave(&psm->lock, flags); + if (psm->cur_out_port != psmp->port) { + psm->serio->write(psm->serio, psmp->sel); + psm->cur_out_port = psmp->port; + dev_dbg(&serio->dev, "switched to sel %02x\n", psmp->sel); + } + + need_escape = data == PS2MULT_ESCAPE + || data == PS2MULT_BSYNC + || data == PS2MULT_SESSION_START + || data == PS2MULT_SESSION_END + || memchr(ps2mult_selectors, data, PS2MULT_NUM_PORTS); + + dev_dbg(&serio->dev, "write: %s%02x\n", + need_escape ? "ESC " : "", data); + + if (need_escape) + psm->serio->write(psm->serio, PS2MULT_ESCAPE); + psm->serio->write(psm->serio, data); + + spin_unlock_irqrestore(&psm->lock, flags); + + return 0; +} + +static int ps2mult_create_port(struct ps2mult *psm, int i) +{ + struct serio *serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), + "%s/port%d", psm->serio->phys, i); + serio->id.type = SERIO_PS2MULT_T; + serio->write = ps2mult_serio_write; + serio->parent = psm->serio; + + serio->port_data = &psm->ports[i]; + + psm->ports[i].serio = serio; + psm->ports[i].port = i; + psm->ports[i].sel = ps2mult_selectors[i]; + + serio_register_port(serio); + dev_info(&serio->dev, "%s port at %s\n", serio->name, psm->serio->phys); + + return 0; +} + +static int ps2mult_reconnect(struct serio *serio) +{ + struct ps2mult *psm = serio_get_drvdata(serio); + + serio->write(serio, PS2MULT_SESSION_END); + serio->write(serio, PS2MULT_SESSION_START); + psm->cur_out_port = 0; + serio->write(serio, psm->ports[psm->cur_out_port].sel); + + return 0; +} + +static void ps2mult_disconnect(struct serio *serio) +{ + struct ps2mult *psm = serio_get_drvdata(serio); + int i; + + serio->write(serio, PS2MULT_SESSION_END); + + for (i = 0; i < PS2MULT_NUM_PORTS; i++) + psm->ports[i].serio = NULL; + + serio_close(serio); + serio_set_drvdata(serio, NULL); + + kfree(psm); +} + +static int ps2mult_connect(struct serio *serio, struct serio_driver *drv) +{ + struct ps2mult *psm; + int i; + int rc; + + if (!serio->write) + return -EINVAL; + + psm = kzalloc(sizeof(*psm), GFP_KERNEL); + if (!psm) + return -ENOMEM; + + spin_lock_init(&psm->lock); + psm->serio = serio; + + serio_set_drvdata(serio, psm); + serio_open(serio, drv); + + for (i = 0; i < PS2MULT_NUM_PORTS; i++) { + rc = ps2mult_create_port(psm, i); + if (rc) + goto err_out; + } + + rc = ps2mult_reconnect(serio); + if (rc) + goto err_out; + + return 0; + +err_out: + ps2mult_disconnect(serio); + + return rc; +} + +static void ps2mult_selector(struct ps2mult *psm, unsigned char data) +{ + int i; + + dev_dbg(&psm->serio->dev, "Received selector %02x\n", data); + + spin_lock(&psm->lock); + + for (i = 0; i < PS2MULT_NUM_PORTS; i++) + if (psm->ports[i].sel == data) { + psm->cur_in_port = i; + break; + } + + spin_unlock(&psm->lock); +} + +static irqreturn_t ps2mult_interrupt(struct serio *serio, unsigned char data, + unsigned int flags) +{ + struct ps2mult *psm = serio_get_drvdata(serio); + + dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); + if (psm->escape) { + serio_interrupt(psm->ports[psm->cur_in_port].serio, + data, flags); + psm->escape = 0; + } else + switch (data) { + case PS2MULT_ESCAPE: + dev_dbg(&serio->dev, "ESCAPE\n"); + psm->escape = 1; + break; + case PS2MULT_BSYNC: + dev_dbg(&serio->dev, "BSYNC\n"); + psm->cur_in_port = psm->cur_out_port; + break; + case PS2MULT_SESSION_START: + dev_dbg(&serio->dev, "SS\n"); + break; + case PS2MULT_SESSION_END: + dev_dbg(&serio->dev, "SE\n"); + break; + case PS2MULT_KB_SELECTOR: + dev_dbg(&serio->dev, "KB\n"); + ps2mult_selector(psm, data); + break; + case PS2MULT_MS_SELECTOR: + dev_dbg(&serio->dev, "MS\n"); + ps2mult_selector(psm, data); + break; + default: + serio_interrupt(psm->ports[psm->cur_in_port].serio, + data, flags); + } + return IRQ_HANDLED; +} + +static struct serio_driver ps2mult_drv = { + .driver = { + .name = "ps2mult", + }, + .description = "TQC PS/2 Multiplexer driver", + .id_table = ps2mult_serio_ids, + .interrupt = ps2mult_interrupt, + .connect = ps2mult_connect, + .disconnect = ps2mult_disconnect, + .reconnect = ps2mult_reconnect, +}; + +static int __init ps2mult_init(void) +{ + return serio_register_driver(&ps2mult_drv); +} + +static void __exit ps2mult_exit(void) +{ + serio_unregister_driver(&ps2mult_drv); +} + +module_init(ps2mult_init); +module_exit(ps2mult_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index 861a72a..7257e6c 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -156,6 +156,7 @@ static inline void serio_continue_rx(struct serio *serio) #define SERIO_HIL_MLC 0x03 #define SERIO_PS_PSTHRU 0x05 #define SERIO_8042_XL 0x06 +#define SERIO_PS2MULT_T 0x07 /* * Serio protocols @@ -200,5 +201,6 @@ static inline void serio_continue_rx(struct serio *serio) #define SERIO_W8001 0x39 #define SERIO_DYNAPRO 0x3a #define SERIO_HAMPSHIRE 0x3b +#define SERIO_PS2MULT 0x3c #endif -- 1.7.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] serio: add support for PS2Mult multiplexer protocol 2010-08-16 11:26 ` [PATCH 2/2] serio: add support for PS2Mult multiplexer protocol Dmitry Eremin-Solenikov @ 2010-09-08 5:35 ` Dmitry Torokhov 0 siblings, 0 replies; 7+ messages in thread From: Dmitry Torokhov @ 2010-09-08 5:35 UTC (permalink / raw) To: Dmitry Eremin-Solenikov; +Cc: linux-input Hi Dmitry, On Mon, Aug 16, 2010 at 03:26:37PM +0400, Dmitry Eremin-Solenikov wrote: > PS2Mult is a simple serial protocol used for multiplexing several PS/2 streams > into one serial data stream. It's used e.g. on TQM85xx serie of boards. > > Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> > --- > drivers/input/serio/Kconfig | 8 ++ > drivers/input/serio/Makefile | 1 + > drivers/input/serio/ps2mult.c | 265 +++++++++++++++++++++++++++++++++++++++++ > include/linux/serio.h | 2 + > 4 files changed, 276 insertions(+), 0 deletions(-) > create mode 100644 drivers/input/serio/ps2mult.c > > diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig > index 3bfe8fa..63f4658 100644 > --- a/drivers/input/serio/Kconfig > +++ b/drivers/input/serio/Kconfig > @@ -226,4 +226,12 @@ config SERIO_AMS_DELTA > To compile this driver as a module, choose M here; > the module will be called ams_delta_serio. > > +config SERIO_PS2MULT > + tristate "TQC PS/2 multiplexer" > + help > + Say Y here if you have the PS/2 line multiplexer like present on TQC boads > + > + To compile this driver as a module, choose M here: the > + module will be called ps2mult. > + > endif > diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile > index 84c80bf..26714c5 100644 > --- a/drivers/input/serio/Makefile > +++ b/drivers/input/serio/Makefile > @@ -24,3 +24,4 @@ obj-$(CONFIG_SERIO_RAW) += serio_raw.o > obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o > obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o > obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o > +obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o > diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c > new file mode 100644 > index 0000000..e9b7951 > --- /dev/null > +++ b/drivers/input/serio/ps2mult.c > @@ -0,0 +1,265 @@ > +/* > + * TQC PS/2 Multiplexer driver > + * > + * Copyright (C) 2010 Dmitry Eremin-Solenikov > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + */ > + > + > +#include <linux/kernel.h> > +#include <linux/slab.h> > +#include <linux/module.h> > +#include <linux/serio.h> > + > +MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>"); > +MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver"); > +MODULE_LICENSE("GPL"); > + > +#define PS2MULT_KB_SELECTOR 0xA0 > +#define PS2MULT_MS_SELECTOR 0xA1 > +#define PS2MULT_ESCAPE 0x7D > +#define PS2MULT_BSYNC 0x7E > +#define PS2MULT_SESSION_START 0x55 > +#define PS2MULT_SESSION_END 0x56 > + > +struct ps2mult_port { > + struct serio *serio; > + unsigned char sel; > + unsigned char port; > +}; > + > +#define PS2MULT_NUM_PORTS 2 > + > +struct ps2mult { > + struct serio *serio; > + struct ps2mult_port ports[PS2MULT_NUM_PORTS]; > + > + spinlock_t lock; > + unsigned char cur_out_port; > + unsigned char cur_in_port; I wonder if instead of indices you should make them serio * pointers - it will save a few cycles at the expense of about 14 bytes in the structure. > + unsigned escape:1; bool please. > +}; > + > +static unsigned char ps2mult_selectors[PS2MULT_NUM_PORTS] = { > + PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR, > +}; > + > +static struct serio_device_id ps2mult_serio_ids[] = { > + { > + .type = SERIO_RS232, > + .proto = SERIO_PS2MULT, > + .id = SERIO_ANY, > + .extra = SERIO_ANY, > + }, > + { 0 } > +}; > + > +MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids); > + > +static int ps2mult_serio_write(struct serio *serio, unsigned char data) > +{ > + struct ps2mult *psm = serio_get_drvdata(serio->parent); > + struct ps2mult_port *psmp = serio->port_data; > + bool need_escape; > + unsigned long flags; > + > + spin_lock_irqsave(&psm->lock, flags); > + if (psm->cur_out_port != psmp->port) { > + psm->serio->write(psm->serio, psmp->sel); > + psm->cur_out_port = psmp->port; > + dev_dbg(&serio->dev, "switched to sel %02x\n", psmp->sel); > + } > + > + need_escape = data == PS2MULT_ESCAPE > + || data == PS2MULT_BSYNC > + || data == PS2MULT_SESSION_START > + || data == PS2MULT_SESSION_END > + || memchr(ps2mult_selectors, data, PS2MULT_NUM_PORTS); Maybe pull all commands into ps2mult_ctrl_bytes[] array and use single need_escape = memchr(ps2mult_ctrl_bytes, data, sizeof(ps2mult_ctrl_bytes)); ? > + > + dev_dbg(&serio->dev, "write: %s%02x\n", > + need_escape ? "ESC " : "", data); > + > + if (need_escape) > + psm->serio->write(psm->serio, PS2MULT_ESCAPE); > + psm->serio->write(psm->serio, data); > + > + spin_unlock_irqrestore(&psm->lock, flags); > + > + return 0; > +} > + > +static int ps2mult_create_port(struct ps2mult *psm, int i) > +{ > + struct serio *serio = kzalloc(sizeof(struct serio), GFP_KERNEL); > + if (!serio) > + return -ENOMEM; > + > + strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name)); > + snprintf(serio->phys, sizeof(serio->phys), > + "%s/port%d", psm->serio->phys, i); > + serio->id.type = SERIO_PS2MULT_T; I thought you were going to use SERIO_I8042? > + serio->write = ps2mult_serio_write; > + serio->parent = psm->serio; You also need to define serio->stop() method that would mark appropriate port as being dead and ensure that ps2mult_interrupt() does not try to use ports that are being destroyed. Otherwise, during tear-down, when children are being disconnected first, there potential to get interrupt at a bad time. > + > + serio->port_data = &psm->ports[i]; > + > + psm->ports[i].serio = serio; > + psm->ports[i].port = i; > + psm->ports[i].sel = ps2mult_selectors[i]; > + > + serio_register_port(serio); > + dev_info(&serio->dev, "%s port at %s\n", serio->name, psm->serio->phys); > + > + return 0; > +} > + > +static int ps2mult_reconnect(struct serio *serio) > +{ > + struct ps2mult *psm = serio_get_drvdata(serio); > + > + serio->write(serio, PS2MULT_SESSION_END); > + serio->write(serio, PS2MULT_SESSION_START); > + psm->cur_out_port = 0; > + serio->write(serio, psm->ports[psm->cur_out_port].sel); > + > + return 0; > +} > + > +static void ps2mult_disconnect(struct serio *serio) > +{ > + struct ps2mult *psm = serio_get_drvdata(serio); > + int i; > + > + serio->write(serio, PS2MULT_SESSION_END); > + > + for (i = 0; i < PS2MULT_NUM_PORTS; i++) > + psm->ports[i].serio = NULL; Meaningless since you free the structure couple of lines below. > + > + serio_close(serio); > + serio_set_drvdata(serio, NULL); > + > + kfree(psm); > +} > + > +static int ps2mult_connect(struct serio *serio, struct serio_driver *drv) > +{ > + struct ps2mult *psm; > + int i; > + int rc; > + > + if (!serio->write) > + return -EINVAL; > + > + psm = kzalloc(sizeof(*psm), GFP_KERNEL); > + if (!psm) > + return -ENOMEM; > + > + spin_lock_init(&psm->lock); > + psm->serio = serio; > + > + serio_set_drvdata(serio, psm); > + serio_open(serio, drv); > + > + for (i = 0; i < PS2MULT_NUM_PORTS; i++) { > + rc = ps2mult_create_port(psm, i); > + if (rc) > + goto err_out; > + } I'd move call to serio_open() here, just in case. > + > + rc = ps2mult_reconnect(serio); > + if (rc) > + goto err_out; > + > + return 0; > + > +err_out: > + ps2mult_disconnect(serio); > + > + return rc; > +} > + > +static void ps2mult_selector(struct ps2mult *psm, unsigned char data) > +{ > + int i; > + > + dev_dbg(&psm->serio->dev, "Received selector %02x\n", data); > + > + spin_lock(&psm->lock); Why do you need this lock? > + > + for (i = 0; i < PS2MULT_NUM_PORTS; i++) > + if (psm->ports[i].sel == data) { > + psm->cur_in_port = i; > + break; > + } > + > + spin_unlock(&psm->lock); > +} > + > +static irqreturn_t ps2mult_interrupt(struct serio *serio, unsigned char data, > + unsigned int flags) > +{ > + struct ps2mult *psm = serio_get_drvdata(serio); > + > + dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); > + if (psm->escape) { > + serio_interrupt(psm->ports[psm->cur_in_port].serio, > + data, flags); > + psm->escape = 0; > + } else > + switch (data) { Incorrect indentation. > + case PS2MULT_ESCAPE: > + dev_dbg(&serio->dev, "ESCAPE\n"); > + psm->escape = 1; > + break; > + case PS2MULT_BSYNC: > + dev_dbg(&serio->dev, "BSYNC\n"); > + psm->cur_in_port = psm->cur_out_port; > + break; > + case PS2MULT_SESSION_START: > + dev_dbg(&serio->dev, "SS\n"); > + break; > + case PS2MULT_SESSION_END: > + dev_dbg(&serio->dev, "SE\n"); > + break; > + case PS2MULT_KB_SELECTOR: > + dev_dbg(&serio->dev, "KB\n"); > + ps2mult_selector(psm, data); > + break; > + case PS2MULT_MS_SELECTOR: > + dev_dbg(&serio->dev, "MS\n"); > + ps2mult_selector(psm, data); If there are only 2 ports why don't you do: psm->current_in_port = psm->ports[PSM_MOUSE_IDX].serio; ? > + break; > + default: > + serio_interrupt(psm->ports[psm->cur_in_port].serio, > + data, flags); > + } > + return IRQ_HANDLED; > +} > + > +static struct serio_driver ps2mult_drv = { > + .driver = { > + .name = "ps2mult", > + }, > + .description = "TQC PS/2 Multiplexer driver", > + .id_table = ps2mult_serio_ids, > + .interrupt = ps2mult_interrupt, > + .connect = ps2mult_connect, > + .disconnect = ps2mult_disconnect, > + .reconnect = ps2mult_reconnect, > +}; > + > +static int __init ps2mult_init(void) > +{ > + return serio_register_driver(&ps2mult_drv); > +} > + > +static void __exit ps2mult_exit(void) > +{ > + serio_unregister_driver(&ps2mult_drv); > +} > + > +module_init(ps2mult_init); > +module_exit(ps2mult_exit); > diff --git a/include/linux/serio.h b/include/linux/serio.h > index 861a72a..7257e6c 100644 > --- a/include/linux/serio.h > +++ b/include/linux/serio.h > @@ -156,6 +156,7 @@ static inline void serio_continue_rx(struct serio *serio) > #define SERIO_HIL_MLC 0x03 > #define SERIO_PS_PSTHRU 0x05 > #define SERIO_8042_XL 0x06 > +#define SERIO_PS2MULT_T 0x07 > > /* > * Serio protocols > @@ -200,5 +201,6 @@ static inline void serio_continue_rx(struct serio *serio) > #define SERIO_W8001 0x39 > #define SERIO_DYNAPRO 0x3a > #define SERIO_HAMPSHIRE 0x3b > +#define SERIO_PS2MULT 0x3c > > #endif > -- > 1.7.1 > Still pondering your other patch... Thanks. -- Dmitry ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards 2010-08-16 11:26 [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov 2010-08-16 11:26 ` [PATCH 1/2] serio: support multiple child devices per single parent Dmitry Eremin-Solenikov 2010-08-16 11:26 ` [PATCH 2/2] serio: add support for PS2Mult multiplexer protocol Dmitry Eremin-Solenikov @ 2010-08-31 10:49 ` Dmitry Eremin-Solenikov 2 siblings, 0 replies; 7+ messages in thread From: Dmitry Eremin-Solenikov @ 2010-08-31 10:49 UTC (permalink / raw) To: linux-input; +Cc: Dmitry Torokhov Hello, On Mon, Aug 16, 2010 at 3:26 PM, Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote: > On tqm85xx boards (and several others) keyboard and mice are connected to CPU via > special controller multiplexing KBD and MS traffic into single UART. What about this two patches? Are they going to be included for 2.6.37? Thank you for your answer. > Changes since v1: > > * Rewrote serio to use iterative algorithms instead of recursion for serio > tree traversal > > * Changed ps2mult to register as SERIO_8042, not it's own special type > > * Small cleanup in ps2mult > > -- > With best wishes > Dmitry > > -- With best wishes Dmitry -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-09-23 16:36 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-08-16 11:26 [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov 2010-08-16 11:26 ` [PATCH 1/2] serio: support multiple child devices per single parent Dmitry Eremin-Solenikov 2010-09-15 5:03 ` Dmitry Torokhov 2010-09-23 16:36 ` Dmitry Eremin-Solenikov 2010-08-16 11:26 ` [PATCH 2/2] serio: add support for PS2Mult multiplexer protocol Dmitry Eremin-Solenikov 2010-09-08 5:35 ` Dmitry Torokhov 2010-08-31 10:49 ` [PATCH 0/2 v2] Add drivers necessary to support PS/2 port on TQM85xx boards Dmitry Eremin-Solenikov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).