* [PATCH] Change behaviour of psmouse-base.c under error conditions. @ 2005-09-05 20:58 Bryan O'Donoghue 2005-09-05 21:12 ` Dmitry Torokhov 0 siblings, 1 reply; 5+ messages in thread From: Bryan O'Donoghue @ 2005-09-05 20:58 UTC (permalink / raw) To: vojtech, linux-kernel [-- Attachment #1: Type: text/plain, Size: 2771 bytes --] Greetings. The contained patch addresses a problem I have with a Belkin SOHO KVM, it is in fact a work around for breakage with the Belkin. Here is a trace of some normal upwards movement with my intellimouse. psmouse_process_byte 0x8 0x0 0x1 0x0 psmouse_process_byte 0x8 0x0 0x1 0x0 At this point if I cycle through ports on the KVM (4 port) returning to the tracing machine and move the mouse upwards, I get packets like this. psmouse_process_byte 0x18 0x0 0x1 0x0 psmouse_process_byte 0x18 0xff 0x1 0x0 psmouse_process_byte 0x18 0xff 0x2 0x0 psmouse_process_byte 0x18 0xff 0x2 0x8 psmouse_process_byte 0x0 0xff 0x2 0x8 Even though a) I'm fairly sure I made no X axis movement with the mouse b) emphatically no roller movement is happening. What's being returned from the KVM, for the IMPS/2 protocol, is just all wrong at this point in time. From the point of view of psmouse-base.c though, there doesn't really seem to be a way of actually knowing that, ie, even though the post switched packets are not what's actually being done with the mouse, they are possible and valid for the mouse to return. However, the KVM in question invariably ends up sending a packet like this packet= 0x0 0xff 0x2 0x8 Which is completely invalid for PS/2 and IMPS/2, the specification of PS/2 defines bit 4 in byte 0 as always being 1. My patch validates this bit, generating a PSMOUSE_BAD_DATA result code if this bit is not set to 1. This has the effect of changing the flow of control in psmouse_interrupt such that serio_reconnect(); gets called, which is what's actually needed to fixup the error. The second bit of the patch changes the default resetafter value from zero to one, which has the effect that if one PSMOUSE_BAD_DATA result code should happen, then serio_reconnect() shall be called. The rationale behind that behaviour is that from a user's point of view it makes more sense for the code to correct errors as a default, then it does for a user to explicately specify "Yes I can see packets being dropped and if 'n' become dropped reset". This behaviour can still be switched off setting the variable to zero. Also, it's worth noting that to date, with this KVM people have been reverting to the bare PS/2 protocol (no third wheel) as a fix. A google for "Belkin lost synchronization throwing bytes away", will show the appropiate references here. My own tests with a simple two button standard PS/2 mouse reveal that the Belkin doesn't mangle the protocol after a switch away + switch back cycle and that this bug with the KVM only happens with IMPS/2. In the Kernel it should be safe to validate bit 4 of byte 0 and to throw an error if that bit is not present, based on the PS/2 specification. Signed-off-by: Bryan O'Donoghue <typedef@eircom.net> [-- Attachment #2: psmouse-base-patch --] [-- Type: text/plain, Size: 919 bytes --] diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -53,7 +53,7 @@ static unsigned int psmouse_smartscroll module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); -static unsigned int psmouse_resetafter; +static unsigned int psmouse_resetafter = 1; module_param_named(resetafter, psmouse_resetafter, uint, 0644); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); @@ -96,6 +96,10 @@ static psmouse_ret_t psmouse_process_byt struct input_dev *dev = &psmouse->dev; unsigned char *packet = psmouse->packet; + if ((packet[0] & 8) == 0) + return PSMOUSE_BAD_DATA; + + if (psmouse->pktcnt < psmouse->pktsize) return PSMOUSE_GOOD_DATA; ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Change behaviour of psmouse-base.c under error conditions. 2005-09-05 20:58 [PATCH] Change behaviour of psmouse-base.c under error conditions Bryan O'Donoghue @ 2005-09-05 21:12 ` Dmitry Torokhov 2005-09-05 21:55 ` Vojtech Pavlik 0 siblings, 1 reply; 5+ messages in thread From: Dmitry Torokhov @ 2005-09-05 21:12 UTC (permalink / raw) To: linux-kernel; +Cc: Bryan O'Donoghue, vojtech On Monday 05 September 2005 15:58, Bryan O'Donoghue wrote: > > However, the KVM in question invariably ends up sending a packet like this > > packet= 0x0 0xff 0x2 0x8 > > Which is completely invalid for PS/2 and IMPS/2, the specification of > PS/2 defines bit 4 in byte 0 as always being 1. > > My patch validates this bit, generating a PSMOUSE_BAD_DATA result code > if this bit is not set to 1. This has the effect of changing the flow of > control in psmouse_interrupt such that serio_reconnect(); gets called, > which is what's actually needed to fixup the error. Not all mice folow the protocol unfortunately. PLease try instead the patch below - I hope it will go in as soon as we sort out ALPS troubles it causes. Note that it will give some offsets when applying but shoudl work nonetheless. -- Dmitry drivers/input/mouse/alps.c | 34 ++++ drivers/input/mouse/logips2pp.c | 2 drivers/input/mouse/psmouse-base.c | 303 +++++++++++++++++++++++++++++-------- drivers/input/mouse/psmouse.h | 7 4 files changed, 281 insertions(+), 65 deletions(-) Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- Index: work/drivers/input/mouse/psmouse.h =================================================================== --- work.orig/drivers/input/mouse/psmouse.h +++ work/drivers/input/mouse/psmouse.h @@ -7,7 +7,7 @@ #define PSMOUSE_CMD_GETINFO 0x03e9 #define PSMOUSE_CMD_SETSTREAM 0x00ea #define PSMOUSE_CMD_SETPOLL 0x00f0 -#define PSMOUSE_CMD_POLL 0x03eb +#define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */ #define PSMOUSE_CMD_GETID 0x02f2 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 @@ -23,6 +23,7 @@ enum psmouse_state { PSMOUSE_IGNORE, PSMOUSE_INITIALIZING, + PSMOUSE_RESYNCING, PSMOUSE_CMD_MODE, PSMOUSE_ACTIVATED, }; @@ -38,9 +39,11 @@ struct psmouse { void *private; struct input_dev dev; struct ps2dev ps2dev; + struct work_struct resync_work; char *vendor; char *name; unsigned char packet[8]; + unsigned char badbyte; unsigned char pktcnt; unsigned char pktsize; unsigned char type; @@ -54,6 +57,7 @@ struct psmouse { unsigned int rate; unsigned int resolution; unsigned int resetafter; + unsigned int resync_time; unsigned int smartscroll; /* Logitech only */ psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); @@ -62,6 +66,7 @@ struct psmouse { int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); + int (*poll)(struct psmouse *psmouse); void (*pt_activate)(struct psmouse *psmouse); void (*pt_deactivate)(struct psmouse *psmouse); Index: work/drivers/input/mouse/psmouse-base.c =================================================================== --- work.orig/drivers/input/mouse/psmouse-base.c +++ work/drivers/input/mouse/psmouse-base.c @@ -58,10 +58,15 @@ static unsigned int psmouse_resetafter; module_param_named(resetafter, psmouse_resetafter, uint, 0644); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); +static unsigned int psmouse_resync_time = 5; +module_param_named(resync_time, psmouse_resync_time, uint, 0644); +MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never)."); + PSMOUSE_DEFINE_ATTR(protocol); PSMOUSE_DEFINE_ATTR(rate); PSMOUSE_DEFINE_ATTR(resolution); PSMOUSE_DEFINE_ATTR(resetafter); +PSMOUSE_DEFINE_ATTR(resync_time); __obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_resolution="); @@ -78,6 +83,8 @@ __obsolete_setup("psmouse_rate="); */ static DECLARE_MUTEX(psmouse_sem); +static struct workqueue_struct *kpsmoused_wq; + struct psmouse_protocol { enum psmouse_type type; char *name; @@ -158,15 +165,79 @@ static psmouse_ret_t psmouse_process_byt } /* - * psmouse_interrupt() handles incoming characters, either gathering them into - * packets or passing them to the command routine as command output. + * __psmouse_set_state() sets new psmouse state and resets all flags. + */ + +static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) +{ + psmouse->state = new_state; + psmouse->pktcnt = psmouse->out_of_sync = 0; + psmouse->ps2dev.flags = 0; + psmouse->last = jiffies; +} + + +/* + * psmouse_set_state() sets new psmouse state and resets all flags and + * counters while holding serio lock so fighting with interrupt handler + * is not a concern. + */ + +static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) +{ + serio_pause_rx(psmouse->ps2dev.serio); + __psmouse_set_state(psmouse, new_state); + serio_continue_rx(psmouse->ps2dev.serio); +} + +/* + * psmouse_handle_byte() processes one byte of the input data stream + * by calling corresponding protocol handler. + */ + +static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs) +{ + psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs); + + switch (rc) { + case PSMOUSE_BAD_DATA: + if (psmouse->state == PSMOUSE_ACTIVATED) { + printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", + psmouse->name, psmouse->phys, psmouse->pktcnt); + if (++psmouse->out_of_sync == psmouse->resetafter) { + __psmouse_set_state(psmouse, PSMOUSE_IGNORE); + printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); + serio_reconnect(psmouse->ps2dev.serio); + return -1; + } + } + psmouse->pktcnt = 0; + break; + + case PSMOUSE_FULL_PACKET: + psmouse->pktcnt = 0; + if (psmouse->out_of_sync) { + psmouse->out_of_sync = 0; + printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", + psmouse->name, psmouse->phys); + } + break; + + case PSMOUSE_GOOD_DATA: + break; + } + return 0; +} + +/* + * psmouse_interrupt() handles incoming characters, either passing them + * for normal processing or gathering them as command response. */ static irqreturn_t psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) { struct psmouse *psmouse = serio_get_drvdata(serio); - psmouse_ret_t rc; if (psmouse->state == PSMOUSE_IGNORE) goto out; @@ -188,67 +259,58 @@ static irqreturn_t psmouse_interrupt(str if (ps2_handle_response(&psmouse->ps2dev, data)) goto out; - if (psmouse->state == PSMOUSE_INITIALIZING) + if (psmouse->state <= PSMOUSE_RESYNCING) goto out; if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { - printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", + printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", psmouse->name, psmouse->phys, psmouse->pktcnt); - psmouse->pktcnt = 0; + psmouse->badbyte = psmouse->packet[0]; + __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); + queue_work(kpsmoused_wq, &psmouse->resync_work); + goto out; } - psmouse->last = jiffies; psmouse->packet[psmouse->pktcnt++] = data; - - if (psmouse->packet[0] == PSMOUSE_RET_BAT) { +/* + * Check if this is a new device announcement (0xAA 0x00) + */ + if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { if (psmouse->pktcnt == 1) goto out; - if (psmouse->pktcnt == 2) { - if (psmouse->packet[1] == PSMOUSE_RET_ID) { - psmouse->state = PSMOUSE_IGNORE; - serio_reconnect(serio); - goto out; - } - if (psmouse->type == PSMOUSE_SYNAPTICS) { - /* neither 0xAA nor 0x00 are valid first bytes - * for a packet in absolute mode - */ - psmouse->pktcnt = 0; - goto out; - } + if (psmouse->packet[1] == PSMOUSE_RET_ID) { + __psmouse_set_state(psmouse, PSMOUSE_IGNORE); + serio_reconnect(serio); + goto out; } - } - - rc = psmouse->protocol_handler(psmouse, regs); +/* + * Not a new device, try processing first byte normally + */ + psmouse->pktcnt = 1; + if (psmouse_handle_byte(psmouse, regs)) + goto out; - switch (rc) { - case PSMOUSE_BAD_DATA: - printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); - psmouse->pktcnt = 0; + psmouse->packet[psmouse->pktcnt++] = data; + } - if (++psmouse->out_of_sync == psmouse->resetafter) { - psmouse->state = PSMOUSE_IGNORE; - printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); - serio_reconnect(psmouse->ps2dev.serio); - } - break; +/* + * See if we need to force resync because mouse was idle for too long + */ + if (psmouse->state == PSMOUSE_ACTIVATED && + psmouse->pktcnt == 1 && psmouse->resync_time && + time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { + psmouse->badbyte = psmouse->packet[0]; + __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); + queue_work(kpsmoused_wq, &psmouse->resync_work); + goto out; + } - case PSMOUSE_FULL_PACKET: - psmouse->pktcnt = 0; - if (psmouse->out_of_sync) { - psmouse->out_of_sync = 0; - printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", - psmouse->name, psmouse->phys); - } - break; + psmouse->last = jiffies; + psmouse_handle_byte(psmouse, regs); - case PSMOUSE_GOOD_DATA: - break; - } -out: + out: return IRQ_HANDLED; } @@ -736,21 +798,6 @@ static void psmouse_initialize(struct ps } /* - * psmouse_set_state() sets new psmouse state and resets all flags and - * counters while holding serio lock so fighting with interrupt handler - * is not a concern. - */ - -static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) -{ - serio_pause_rx(psmouse->ps2dev.serio); - psmouse->state = new_state; - psmouse->pktcnt = psmouse->out_of_sync = 0; - psmouse->ps2dev.flags = 0; - serio_continue_rx(psmouse->ps2dev.serio); -} - -/* * psmouse_activate() enables the mouse so that we get motion reports from it. */ @@ -778,6 +825,100 @@ static void psmouse_deactivate(struct ps psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); } +/* + * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it. + */ + +static int psmouse_poll(struct psmouse *psmouse) +{ + return ps2_command(&psmouse->ps2dev, psmouse->packet, + PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); +} + + +/* + * psmouse_resync() attempts to re-validate current protocol. + */ + +static void psmouse_resync(void *p) +{ + struct psmouse *psmouse = p, *parent = NULL; + struct serio *serio = psmouse->ps2dev.serio; + psmouse_ret_t rc = PSMOUSE_GOOD_DATA; + int failed = 0, enabled = 0; + int i; + + down(&psmouse_sem); + + if (psmouse->state != PSMOUSE_RESYNCING) + goto out; + + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { + parent = serio_get_drvdata(serio->parent); + psmouse_deactivate(parent); + } + +/* + * Some mice don't ACK commands sent while they are in the middle of + * transmitting motion packet. To avoid delay we use ps2_sendbyte() + * instead of ps2_command() which would wait for 200ms for an ACK + * that may never come. + */ + ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20); + +/* + * Poll the mouse. If it was reset the packet will be shorter than + * psmouse->pktsize and ps2_command will fail. We do not expect and + * do not handle scenario when mouse "upgrades" its protocol while + * disconnected since it would require additional delay. If we ever + * see a mouse that does it we'll adjust the code. + */ + if (psmouse->poll(psmouse)) + failed = 1; + else { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + for (i = 0; i < psmouse->pktsize; i++) { + psmouse->pktcnt++; + rc = psmouse->protocol_handler(psmouse, NULL); + if (rc != PSMOUSE_GOOD_DATA) + break; + } + if (rc != PSMOUSE_FULL_PACKET) + failed = 1; + psmouse_set_state(psmouse, PSMOUSE_RESYNCING); + } + +/* + * Now try to enable mouse. We try to do that even if poll failed and also + * repeat our attempts 5 times, otherwise we may be left out with disabled + * mouse. + */ + for (i = 0; i < 5; i++) { + if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { + enabled = 1; + break; + } + msleep(200); + } + + if (!enabled) { + printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", + psmouse->ps2dev.serio->phys); + failed = 1; + } + + if (failed) { + psmouse_set_state(psmouse, PSMOUSE_IGNORE); + printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n"); + serio_reconnect(serio); + } else + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + + if (parent) + psmouse_activate(parent); + out: + up(&psmouse_sem); +} /* * psmouse_cleanup() resets the mouse into power-on state. @@ -804,11 +945,17 @@ static void psmouse_disconnect(struct se device_remove_file(&serio->dev, &psmouse_attr_rate); device_remove_file(&serio->dev, &psmouse_attr_resolution); device_remove_file(&serio->dev, &psmouse_attr_resetafter); + device_remove_file(&serio->dev, &psmouse_attr_resync_time); down(&psmouse_sem); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + /* make sure we don't have a resync in progress */ + up(&psmouse_sem); + flush_workqueue(kpsmoused_wq); + down(&psmouse_sem); + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); @@ -848,6 +995,7 @@ static int psmouse_switch_protocol(struc psmouse->set_rate = psmouse_set_rate; psmouse->set_resolution = psmouse_set_resolution; + psmouse->poll = psmouse_poll; psmouse->protocol_handler = psmouse_process_byte; psmouse->pktsize = 3; @@ -902,6 +1050,7 @@ static int psmouse_connect(struct serio } ps2_init(&psmouse->ps2dev, serio); + INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); sprintf(psmouse->phys, "%s/input0", serio->phys); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); @@ -926,6 +1075,7 @@ static int psmouse_connect(struct serio psmouse->rate = psmouse_rate; psmouse->resolution = psmouse_resolution; psmouse->resetafter = psmouse_resetafter; + psmouse->resync_time = parent ? 0 : psmouse_resync_time; psmouse->smartscroll = psmouse_smartscroll; psmouse_switch_protocol(psmouse, NULL); @@ -944,6 +1094,7 @@ static int psmouse_connect(struct serio device_create_file(&serio->dev, &psmouse_attr_rate); device_create_file(&serio->dev, &psmouse_attr_resolution); device_create_file(&serio->dev, &psmouse_attr_resetafter); + device_create_file(&serio->dev, &psmouse_attr_resync_time); psmouse_activate(psmouse); @@ -1233,6 +1384,24 @@ static ssize_t psmouse_attr_set_resetaft return count; } +static ssize_t psmouse_attr_show_resync_time(struct psmouse *psmouse, char *buf) +{ + return sprintf(buf, "%d\n", psmouse->resync_time); +} + +static ssize_t psmouse_attr_set_resync_time(struct psmouse *psmouse, const char *buf, size_t count) +{ + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest) + return -EINVAL; + + psmouse->resync_time = value; + return count; +} + static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) { struct psmouse_protocol *proto; @@ -1259,13 +1428,21 @@ static int psmouse_get_maxproto(char *bu static int __init psmouse_init(void) { + kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); + if (!kpsmoused_wq) { + printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); + return -ENOMEM; + } + serio_register_driver(&psmouse_drv); + return 0; } static void __exit psmouse_exit(void) { serio_unregister_driver(&psmouse_drv); + destroy_workqueue(kpsmoused_wq); } module_init(psmouse_init); Index: work/drivers/input/mouse/logips2pp.c =================================================================== --- work.orig/drivers/input/mouse/logips2pp.c +++ work/drivers/input/mouse/logips2pp.c @@ -117,7 +117,7 @@ static int ps2pp_cmd(struct psmouse *psm if (psmouse_sliced_command(psmouse, command)) return -1; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL)) + if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300)) return -1; return 0; Index: work/drivers/input/mouse/alps.c =================================================================== --- work.orig/drivers/input/mouse/alps.c +++ work/drivers/input/mouse/alps.c @@ -347,6 +347,39 @@ static int alps_tap_mode(struct psmouse return 0; } +/* + * alps_poll() - poll the touchpad for current motion packet. + * Used in resync. + */ +static int alps_poll(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + unsigned char buf[6]; + + if (priv->i->flags & ALPS_PASS) + alps_passthrough_mode(psmouse, 1); + + if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (psmouse->pktsize << 8))) + return -1; + + if ((buf[0] & priv->i->mask0) != priv->i->byte0) + return -1; + + if (priv->i->flags & ALPS_PASS) + alps_passthrough_mode(psmouse, 0); + + if ((psmouse->badbyte & 0xc8) == 0x08) { +/* + * Poll the track stick ... + */ + if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) + return -1; + } + + memcpy(psmouse->packet, buf, sizeof(buf)); + return 0; +} + static int alps_reconnect(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; @@ -448,6 +481,7 @@ int alps_init(struct psmouse *psmouse) printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys); psmouse->protocol_handler = alps_process_byte; + psmouse->poll = alps_poll; psmouse->disconnect = alps_disconnect; psmouse->reconnect = alps_reconnect; psmouse->pktsize = 6; ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Change behaviour of psmouse-base.c under error conditions. 2005-09-05 21:12 ` Dmitry Torokhov @ 2005-09-05 21:55 ` Vojtech Pavlik 2005-09-05 22:56 ` Bryan O'Donoghue 2005-09-06 0:20 ` Dmitry Torokhov 0 siblings, 2 replies; 5+ messages in thread From: Vojtech Pavlik @ 2005-09-05 21:55 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-kernel, Bryan O'Donoghue On Mon, Sep 05, 2005 at 04:12:13PM -0500, Dmitry Torokhov wrote: > On Monday 05 September 2005 15:58, Bryan O'Donoghue wrote: > > > > However, the KVM in question invariably ends up sending a packet like this > > > > packet= 0x0 0xff 0x2 0x8 > > > > Which is completely invalid for PS/2 and IMPS/2, the specification of > > PS/2 defines bit 4 in byte 0 as always being 1. Just for the record: Bit 4 was supposed to indicate an external (=1) mouse, while internal mice would have a '0' there. This then would allow to differentiate between two devices on the same bus. I've even seen that in action on one very old laptop. Of course, extended protocols break that completely. > > My patch validates this bit, generating a PSMOUSE_BAD_DATA result code > > if this bit is not set to 1. This has the effect of changing the flow of > > control in psmouse_interrupt such that serio_reconnect(); gets called, > > which is what's actually needed to fixup the error. > > Not all mice folow the protocol unfortunately. PLease try instead the > patch below - I hope it will go in as soon as we sort out ALPS troubles > it causes. > > Note that it will give some offsets when applying but shoudl work > nonetheless. > > -- > Dmitry > > drivers/input/mouse/alps.c | 34 ++++ > drivers/input/mouse/logips2pp.c | 2 > drivers/input/mouse/psmouse-base.c | 303 +++++++++++++++++++++++++++++-------- > drivers/input/mouse/psmouse.h | 7 > 4 files changed, 281 insertions(+), 65 deletions(-) > > Signed-off-by: Dmitry Torokhov <dtor@mail.ru> > --- > > Index: work/drivers/input/mouse/psmouse.h > =================================================================== > --- work.orig/drivers/input/mouse/psmouse.h > +++ work/drivers/input/mouse/psmouse.h > @@ -7,7 +7,7 @@ > #define PSMOUSE_CMD_GETINFO 0x03e9 > #define PSMOUSE_CMD_SETSTREAM 0x00ea > #define PSMOUSE_CMD_SETPOLL 0x00f0 > -#define PSMOUSE_CMD_POLL 0x03eb > +#define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */ > #define PSMOUSE_CMD_GETID 0x02f2 > #define PSMOUSE_CMD_SETRATE 0x10f3 > #define PSMOUSE_CMD_ENABLE 0x00f4 > @@ -23,6 +23,7 @@ > enum psmouse_state { > PSMOUSE_IGNORE, > PSMOUSE_INITIALIZING, > + PSMOUSE_RESYNCING, > PSMOUSE_CMD_MODE, > PSMOUSE_ACTIVATED, > }; > @@ -38,9 +39,11 @@ struct psmouse { > void *private; > struct input_dev dev; > struct ps2dev ps2dev; > + struct work_struct resync_work; > char *vendor; > char *name; > unsigned char packet[8]; > + unsigned char badbyte; > unsigned char pktcnt; > unsigned char pktsize; > unsigned char type; > @@ -54,6 +57,7 @@ struct psmouse { > unsigned int rate; > unsigned int resolution; > unsigned int resetafter; > + unsigned int resync_time; > unsigned int smartscroll; /* Logitech only */ > > psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); > @@ -62,6 +66,7 @@ struct psmouse { > > int (*reconnect)(struct psmouse *psmouse); > void (*disconnect)(struct psmouse *psmouse); > + int (*poll)(struct psmouse *psmouse); > > void (*pt_activate)(struct psmouse *psmouse); > void (*pt_deactivate)(struct psmouse *psmouse); > Index: work/drivers/input/mouse/psmouse-base.c > =================================================================== > --- work.orig/drivers/input/mouse/psmouse-base.c > +++ work/drivers/input/mouse/psmouse-base.c > @@ -58,10 +58,15 @@ static unsigned int psmouse_resetafter; > module_param_named(resetafter, psmouse_resetafter, uint, 0644); > MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); > > +static unsigned int psmouse_resync_time = 5; > +module_param_named(resync_time, psmouse_resync_time, uint, 0644); > +MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never)."); > + > PSMOUSE_DEFINE_ATTR(protocol); > PSMOUSE_DEFINE_ATTR(rate); > PSMOUSE_DEFINE_ATTR(resolution); > PSMOUSE_DEFINE_ATTR(resetafter); > +PSMOUSE_DEFINE_ATTR(resync_time); > > __obsolete_setup("psmouse_noext"); > __obsolete_setup("psmouse_resolution="); > @@ -78,6 +83,8 @@ __obsolete_setup("psmouse_rate="); > */ > static DECLARE_MUTEX(psmouse_sem); > > +static struct workqueue_struct *kpsmoused_wq; > + > struct psmouse_protocol { > enum psmouse_type type; > char *name; > @@ -158,15 +165,79 @@ static psmouse_ret_t psmouse_process_byt > } > > /* > - * psmouse_interrupt() handles incoming characters, either gathering them into > - * packets or passing them to the command routine as command output. > + * __psmouse_set_state() sets new psmouse state and resets all flags. > + */ > + > +static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) > +{ > + psmouse->state = new_state; > + psmouse->pktcnt = psmouse->out_of_sync = 0; > + psmouse->ps2dev.flags = 0; > + psmouse->last = jiffies; > +} > + > + > +/* > + * psmouse_set_state() sets new psmouse state and resets all flags and > + * counters while holding serio lock so fighting with interrupt handler > + * is not a concern. > + */ > + > +static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) > +{ > + serio_pause_rx(psmouse->ps2dev.serio); > + __psmouse_set_state(psmouse, new_state); > + serio_continue_rx(psmouse->ps2dev.serio); > +} > + > +/* > + * psmouse_handle_byte() processes one byte of the input data stream > + * by calling corresponding protocol handler. > + */ > + > +static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs) > +{ > + psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs); > + > + switch (rc) { > + case PSMOUSE_BAD_DATA: > + if (psmouse->state == PSMOUSE_ACTIVATED) { > + printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", > + psmouse->name, psmouse->phys, psmouse->pktcnt); > + if (++psmouse->out_of_sync == psmouse->resetafter) { > + __psmouse_set_state(psmouse, PSMOUSE_IGNORE); > + printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); > + serio_reconnect(psmouse->ps2dev.serio); > + return -1; > + } > + } > + psmouse->pktcnt = 0; > + break; > + > + case PSMOUSE_FULL_PACKET: > + psmouse->pktcnt = 0; > + if (psmouse->out_of_sync) { > + psmouse->out_of_sync = 0; > + printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", > + psmouse->name, psmouse->phys); > + } > + break; > + > + case PSMOUSE_GOOD_DATA: > + break; > + } > + return 0; > +} > + > +/* > + * psmouse_interrupt() handles incoming characters, either passing them > + * for normal processing or gathering them as command response. > */ > > static irqreturn_t psmouse_interrupt(struct serio *serio, > unsigned char data, unsigned int flags, struct pt_regs *regs) > { > struct psmouse *psmouse = serio_get_drvdata(serio); > - psmouse_ret_t rc; > > if (psmouse->state == PSMOUSE_IGNORE) > goto out; > @@ -188,67 +259,58 @@ static irqreturn_t psmouse_interrupt(str > if (ps2_handle_response(&psmouse->ps2dev, data)) > goto out; > > - if (psmouse->state == PSMOUSE_INITIALIZING) > + if (psmouse->state <= PSMOUSE_RESYNCING) > goto out; > > if (psmouse->state == PSMOUSE_ACTIVATED && > psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { > - printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", > + printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", > psmouse->name, psmouse->phys, psmouse->pktcnt); > - psmouse->pktcnt = 0; > + psmouse->badbyte = psmouse->packet[0]; > + __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); > + queue_work(kpsmoused_wq, &psmouse->resync_work); > + goto out; > } > > - psmouse->last = jiffies; > psmouse->packet[psmouse->pktcnt++] = data; > - > - if (psmouse->packet[0] == PSMOUSE_RET_BAT) { > +/* > + * Check if this is a new device announcement (0xAA 0x00) > + */ > + if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { > if (psmouse->pktcnt == 1) > goto out; > > - if (psmouse->pktcnt == 2) { > - if (psmouse->packet[1] == PSMOUSE_RET_ID) { > - psmouse->state = PSMOUSE_IGNORE; > - serio_reconnect(serio); > - goto out; > - } > - if (psmouse->type == PSMOUSE_SYNAPTICS) { > - /* neither 0xAA nor 0x00 are valid first bytes > - * for a packet in absolute mode > - */ > - psmouse->pktcnt = 0; > - goto out; > - } > + if (psmouse->packet[1] == PSMOUSE_RET_ID) { > + __psmouse_set_state(psmouse, PSMOUSE_IGNORE); > + serio_reconnect(serio); > + goto out; > } > - } > - > - rc = psmouse->protocol_handler(psmouse, regs); > +/* > + * Not a new device, try processing first byte normally > + */ > + psmouse->pktcnt = 1; > + if (psmouse_handle_byte(psmouse, regs)) > + goto out; > > - switch (rc) { > - case PSMOUSE_BAD_DATA: > - printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", > - psmouse->name, psmouse->phys, psmouse->pktcnt); > - psmouse->pktcnt = 0; > + psmouse->packet[psmouse->pktcnt++] = data; > + } > > - if (++psmouse->out_of_sync == psmouse->resetafter) { > - psmouse->state = PSMOUSE_IGNORE; > - printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); > - serio_reconnect(psmouse->ps2dev.serio); > - } > - break; > +/* > + * See if we need to force resync because mouse was idle for too long > + */ > + if (psmouse->state == PSMOUSE_ACTIVATED && > + psmouse->pktcnt == 1 && psmouse->resync_time && > + time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { > + psmouse->badbyte = psmouse->packet[0]; > + __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); > + queue_work(kpsmoused_wq, &psmouse->resync_work); > + goto out; > + } > > - case PSMOUSE_FULL_PACKET: > - psmouse->pktcnt = 0; > - if (psmouse->out_of_sync) { > - psmouse->out_of_sync = 0; > - printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", > - psmouse->name, psmouse->phys); > - } > - break; > + psmouse->last = jiffies; > + psmouse_handle_byte(psmouse, regs); > > - case PSMOUSE_GOOD_DATA: > - break; > - } > -out: > + out: > return IRQ_HANDLED; > } > > @@ -736,21 +798,6 @@ static void psmouse_initialize(struct ps > } > > /* > - * psmouse_set_state() sets new psmouse state and resets all flags and > - * counters while holding serio lock so fighting with interrupt handler > - * is not a concern. > - */ > - > -static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) > -{ > - serio_pause_rx(psmouse->ps2dev.serio); > - psmouse->state = new_state; > - psmouse->pktcnt = psmouse->out_of_sync = 0; > - psmouse->ps2dev.flags = 0; > - serio_continue_rx(psmouse->ps2dev.serio); > -} > - > -/* > * psmouse_activate() enables the mouse so that we get motion reports from it. > */ > > @@ -778,6 +825,100 @@ static void psmouse_deactivate(struct ps > psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); > } > > +/* > + * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it. > + */ > + > +static int psmouse_poll(struct psmouse *psmouse) > +{ > + return ps2_command(&psmouse->ps2dev, psmouse->packet, > + PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); > +} > + > + > +/* > + * psmouse_resync() attempts to re-validate current protocol. > + */ > + > +static void psmouse_resync(void *p) > +{ > + struct psmouse *psmouse = p, *parent = NULL; > + struct serio *serio = psmouse->ps2dev.serio; > + psmouse_ret_t rc = PSMOUSE_GOOD_DATA; > + int failed = 0, enabled = 0; > + int i; > + > + down(&psmouse_sem); > + > + if (psmouse->state != PSMOUSE_RESYNCING) > + goto out; > + > + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { > + parent = serio_get_drvdata(serio->parent); > + psmouse_deactivate(parent); > + } > + > +/* > + * Some mice don't ACK commands sent while they are in the middle of > + * transmitting motion packet. To avoid delay we use ps2_sendbyte() > + * instead of ps2_command() which would wait for 200ms for an ACK > + * that may never come. > + */ > + ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20); > + > +/* > + * Poll the mouse. If it was reset the packet will be shorter than > + * psmouse->pktsize and ps2_command will fail. We do not expect and > + * do not handle scenario when mouse "upgrades" its protocol while > + * disconnected since it would require additional delay. If we ever > + * see a mouse that does it we'll adjust the code. > + */ > + if (psmouse->poll(psmouse)) > + failed = 1; > + else { > + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); > + for (i = 0; i < psmouse->pktsize; i++) { > + psmouse->pktcnt++; > + rc = psmouse->protocol_handler(psmouse, NULL); > + if (rc != PSMOUSE_GOOD_DATA) > + break; > + } > + if (rc != PSMOUSE_FULL_PACKET) > + failed = 1; > + psmouse_set_state(psmouse, PSMOUSE_RESYNCING); > + } > + > +/* > + * Now try to enable mouse. We try to do that even if poll failed and also > + * repeat our attempts 5 times, otherwise we may be left out with disabled > + * mouse. > + */ > + for (i = 0; i < 5; i++) { > + if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { > + enabled = 1; > + break; > + } > + msleep(200); > + } > + > + if (!enabled) { > + printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", > + psmouse->ps2dev.serio->phys); > + failed = 1; > + } > + > + if (failed) { > + psmouse_set_state(psmouse, PSMOUSE_IGNORE); > + printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n"); > + serio_reconnect(serio); > + } else > + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); > + > + if (parent) > + psmouse_activate(parent); > + out: > + up(&psmouse_sem); > +} > > /* > * psmouse_cleanup() resets the mouse into power-on state. > @@ -804,11 +945,17 @@ static void psmouse_disconnect(struct se > device_remove_file(&serio->dev, &psmouse_attr_rate); > device_remove_file(&serio->dev, &psmouse_attr_resolution); > device_remove_file(&serio->dev, &psmouse_attr_resetafter); > + device_remove_file(&serio->dev, &psmouse_attr_resync_time); > > down(&psmouse_sem); > > psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); > > + /* make sure we don't have a resync in progress */ > + up(&psmouse_sem); > + flush_workqueue(kpsmoused_wq); > + down(&psmouse_sem); > + > if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { > parent = serio_get_drvdata(serio->parent); > psmouse_deactivate(parent); > @@ -848,6 +995,7 @@ static int psmouse_switch_protocol(struc > > psmouse->set_rate = psmouse_set_rate; > psmouse->set_resolution = psmouse_set_resolution; > + psmouse->poll = psmouse_poll; > psmouse->protocol_handler = psmouse_process_byte; > psmouse->pktsize = 3; > > @@ -902,6 +1050,7 @@ static int psmouse_connect(struct serio > } > > ps2_init(&psmouse->ps2dev, serio); > + INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); > sprintf(psmouse->phys, "%s/input0", serio->phys); > > psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); > @@ -926,6 +1075,7 @@ static int psmouse_connect(struct serio > psmouse->rate = psmouse_rate; > psmouse->resolution = psmouse_resolution; > psmouse->resetafter = psmouse_resetafter; > + psmouse->resync_time = parent ? 0 : psmouse_resync_time; > psmouse->smartscroll = psmouse_smartscroll; > > psmouse_switch_protocol(psmouse, NULL); > @@ -944,6 +1094,7 @@ static int psmouse_connect(struct serio > device_create_file(&serio->dev, &psmouse_attr_rate); > device_create_file(&serio->dev, &psmouse_attr_resolution); > device_create_file(&serio->dev, &psmouse_attr_resetafter); > + device_create_file(&serio->dev, &psmouse_attr_resync_time); > > psmouse_activate(psmouse); > > @@ -1233,6 +1384,24 @@ static ssize_t psmouse_attr_set_resetaft > return count; > } > > +static ssize_t psmouse_attr_show_resync_time(struct psmouse *psmouse, char *buf) > +{ > + return sprintf(buf, "%d\n", psmouse->resync_time); > +} > + > +static ssize_t psmouse_attr_set_resync_time(struct psmouse *psmouse, const char *buf, size_t count) > +{ > + unsigned long value; > + char *rest; > + > + value = simple_strtoul(buf, &rest, 10); > + if (*rest) > + return -EINVAL; > + > + psmouse->resync_time = value; > + return count; > +} > + > static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) > { > struct psmouse_protocol *proto; > @@ -1259,13 +1428,21 @@ static int psmouse_get_maxproto(char *bu > > static int __init psmouse_init(void) > { > + kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); > + if (!kpsmoused_wq) { > + printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); > + return -ENOMEM; > + } > + > serio_register_driver(&psmouse_drv); > + > return 0; > } > > static void __exit psmouse_exit(void) > { > serio_unregister_driver(&psmouse_drv); > + destroy_workqueue(kpsmoused_wq); > } > > module_init(psmouse_init); > Index: work/drivers/input/mouse/logips2pp.c > =================================================================== > --- work.orig/drivers/input/mouse/logips2pp.c > +++ work/drivers/input/mouse/logips2pp.c > @@ -117,7 +117,7 @@ static int ps2pp_cmd(struct psmouse *psm > if (psmouse_sliced_command(psmouse, command)) > return -1; > > - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL)) > + if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300)) > return -1; > > return 0; > Index: work/drivers/input/mouse/alps.c > =================================================================== > --- work.orig/drivers/input/mouse/alps.c > +++ work/drivers/input/mouse/alps.c > @@ -347,6 +347,39 @@ static int alps_tap_mode(struct psmouse > return 0; > } > > +/* > + * alps_poll() - poll the touchpad for current motion packet. > + * Used in resync. > + */ > +static int alps_poll(struct psmouse *psmouse) > +{ > + struct alps_data *priv = psmouse->private; > + unsigned char buf[6]; > + > + if (priv->i->flags & ALPS_PASS) > + alps_passthrough_mode(psmouse, 1); > + > + if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (psmouse->pktsize << 8))) > + return -1; > + > + if ((buf[0] & priv->i->mask0) != priv->i->byte0) > + return -1; > + > + if (priv->i->flags & ALPS_PASS) > + alps_passthrough_mode(psmouse, 0); > + > + if ((psmouse->badbyte & 0xc8) == 0x08) { > +/* > + * Poll the track stick ... > + */ > + if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) > + return -1; > + } > + > + memcpy(psmouse->packet, buf, sizeof(buf)); > + return 0; > +} > + > static int alps_reconnect(struct psmouse *psmouse) > { > struct alps_data *priv = psmouse->private; > @@ -448,6 +481,7 @@ int alps_init(struct psmouse *psmouse) > printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys); > > psmouse->protocol_handler = alps_process_byte; > + psmouse->poll = alps_poll; > psmouse->disconnect = alps_disconnect; > psmouse->reconnect = alps_reconnect; > psmouse->pktsize = 6; > -- Vojtech Pavlik SuSE Labs, SuSE CR ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Change behaviour of psmouse-base.c under error conditions. 2005-09-05 21:55 ` Vojtech Pavlik @ 2005-09-05 22:56 ` Bryan O'Donoghue 2005-09-06 0:20 ` Dmitry Torokhov 1 sibling, 0 replies; 5+ messages in thread From: Bryan O'Donoghue @ 2005-09-05 22:56 UTC (permalink / raw) To: Vojtech Pavlik; +Cc: Dmitry Torokhov, linux-kernel Vojtech Pavlik wrote: >>Not all mice folow the protocol unfortunately. PLease try instead the >>patch below Yes Dmitry, that does as advertised. Bryan ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Change behaviour of psmouse-base.c under error conditions. 2005-09-05 21:55 ` Vojtech Pavlik 2005-09-05 22:56 ` Bryan O'Donoghue @ 2005-09-06 0:20 ` Dmitry Torokhov 1 sibling, 0 replies; 5+ messages in thread From: Dmitry Torokhov @ 2005-09-06 0:20 UTC (permalink / raw) To: Vojtech Pavlik; +Cc: linux-kernel, Bryan O'Donoghue On Monday 05 September 2005 16:55, Vojtech Pavlik wrote: > On Mon, Sep 05, 2005 at 04:12:13PM -0500, Dmitry Torokhov wrote: > > On Monday 05 September 2005 15:58, Bryan O'Donoghue wrote: > > > > > > However, the KVM in question invariably ends up sending a packet like this > > > > > > packet= 0x0 0xff 0x2 0x8 > > > > > > Which is completely invalid for PS/2 and IMPS/2, the specification of > > > PS/2 defines bit 4 in byte 0 as always being 1. > > Just for the record: Bit 4 was supposed to indicate an external (=1) > mouse, while internal mice would have a '0' there. This then would allow > to differentiate between two devices on the same bus. > > I've even seen that in action on one very old laptop. > > Of course, extended protocols break that completely. IBM Trackpoint controllers can force that bit to 1 for internal device and to 0 for external. If we ever implement pass-through port for trackpoints we might use it do demultiplex data streams. -- Dmitry ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2005-09-06 0:20 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-09-05 20:58 [PATCH] Change behaviour of psmouse-base.c under error conditions Bryan O'Donoghue 2005-09-05 21:12 ` Dmitry Torokhov 2005-09-05 21:55 ` Vojtech Pavlik 2005-09-05 22:56 ` Bryan O'Donoghue 2005-09-06 0:20 ` Dmitry Torokhov
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.