diff options
author | Alan Coopersmith <alan.coopersmith@sun.com> | 2009-04-30 16:26:23 -0700 |
---|---|---|
committer | Alan Coopersmith <alan.coopersmith@sun.com> | 2009-04-30 23:26:46 -0700 |
commit | 2bc18590e6b7b403dcec22a09820010748c48972 (patch) | |
tree | b21ca789101cc24f86002def4a140f126a6e20f9 | |
parent | 810fe3a4afd7e77a645c312f9475e75c2f7e925c (diff) | |
download | xorg-driver-xf86-input-keyboard-2bc18590e6b7b403dcec22a09820010748c48972.tar.gz |
Solaris keyboard fixes for HAL hotplugging support
- Handle hot-unplug by checking for ENODEV on read and removing device
- Make sure to re-push streams module on resume
Signed-off-by: Alan Coopersmith <alan.coopersmith@sun.com>
-rw-r--r-- | src/sun_kbd.c | 114 | ||||
-rw-r--r-- | src/sun_kbd.h | 1 |
2 files changed, 97 insertions, 18 deletions
diff --git a/src/sun_kbd.c b/src/sun_kbd.c index a222d38..b4ebc57 100644 --- a/src/sun_kbd.c +++ b/src/sun_kbd.c @@ -22,7 +22,7 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* Copyright 2004-2007 Sun Microsystems, Inc. All rights reserved. +/* Copyright 2004-2009 Sun Microsystems, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -64,6 +64,8 @@ #include <sys/vuid_event.h> #include <sys/kbd.h> +static int KbdOn(InputInfoPtr pInfo, int what); + static void sunKbdSetLeds(InputInfoPtr pInfo, int leds) { @@ -105,6 +107,7 @@ KbdInit(InputInfoPtr pInfo, int what) int ktype, klayout, i; const char *ktype_name; + priv->kbdActive = FALSE; priv->otranslation = -1; priv->odirect = -1; @@ -114,15 +117,11 @@ KbdInit(InputInfoPtr pInfo, int what) priv->strmod = NULL; } - if (priv->strmod) { - SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod)); - if (i < 0) { - xf86Msg(X_ERROR, - "%s: cannot push module '%s' onto keyboard device: %s\n", - pInfo->name, priv->strmod, strerror(errno)); - } + i = KbdOn(pInfo, DEVICE_INIT); + if (i != Success) { + return i; } - + SYSCALL(i = ioctl(pInfo->fd, KIOCTYPE, &ktype)); if (i < 0) { xf86Msg(X_ERROR, "%s: Unable to determine keyboard type: %s\n", @@ -155,7 +154,6 @@ KbdInit(InputInfoPtr pInfo, int what) xf86Msg(X_PROBED, "%s: Keyboard layout: %d\n", pInfo->name, klayout); priv->ktype = ktype; - priv->oleds = sunKbdGetLeds(pInfo); return Success; } @@ -169,6 +167,19 @@ KbdOn(InputInfoPtr pInfo, int what) int ktrans, kdirect, i; + if (priv->kbdActive) { + return Success; + } + + if (priv->strmod) { + SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod)); + if (i < 0) { + xf86Msg(X_ERROR, + "%s: cannot push module '%s' onto keyboard device: %s\n", + pInfo->name, priv->strmod, strerror(errno)); + } + } + SYSCALL(i = ioctl(pInfo->fd, KIOCGDIRECT, &kdirect)); if (i < 0) { xf86Msg(X_ERROR, @@ -207,6 +218,13 @@ KbdOn(InputInfoPtr pInfo, int what) return BadImplementation; } + priv->oleds = sunKbdGetLeds(pInfo); + + /* Allocate here so we don't alloc in ReadInput which may be called + from SIGIO handler. */ + priv->remove_timer = TimerSet(priv->remove_timer, 0, 0, NULL, NULL); + + priv->kbdActive = TRUE; return Success; } @@ -218,6 +236,20 @@ KbdOff(InputInfoPtr pInfo, int what) int i; + if (!priv->kbdActive) { + return Success; + } + + if (pInfo->fd == -1) { + priv->kbdActive = FALSE; + return Success; + } + + if (priv->remove_timer) { + TimerFree(priv->remove_timer); + priv->remove_timer = NULL; + } + /* restore original state */ if (priv->oleds != -1) { @@ -254,9 +286,9 @@ KbdOff(InputInfoPtr pInfo, int what) "%s: cannot pop module '%s' off keyboard device: %s\n", pInfo->name, priv->strmod, strerror(errno)); } - priv->strmod = NULL; } + priv->kbdActive = FALSE; return Success; } @@ -353,20 +385,66 @@ SetKbdRepeat(InputInfoPtr pInfo, char rad) /* Nothing to do */ } +/* Called from OsTimer callback, since removing a device from the device + list or changing pInfo->fd while xf86Wakeup is looping through the list + causes server crashes */ +static CARD32 +RemoveKeyboard(OsTimerPtr timer, CARD32 time, pointer arg) +{ + InputInfoPtr pInfo = (InputInfoPtr) arg; + KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; + sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; + + close(pInfo->fd); + pInfo->fd = -1; + priv->kbdActive = FALSE; + + xf86DisableDevice(pInfo->dev, TRUE); + + return 0; /* All done, don't set to run again */ +} + static void ReadInput(InputInfoPtr pInfo) { KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; + sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; Firm_event event[64]; int nBytes, i; - /* I certainly hope its not possible to read partial events */ - - if ((nBytes = read(pInfo->fd, (char *)event, sizeof(event))) > 0) - { - for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) { - pKbd->PostEvent(pInfo, event[i].id & 0xFF, - event[i].value == VKEY_DOWN ? TRUE : FALSE); + while (TRUE) { + /* I certainly hope it's not possible to read partial events */ + nBytes = read(pInfo->fd, (char *)event, sizeof(event)); + if (nBytes > 0) { + for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) { + pKbd->PostEvent(pInfo, event[i].id & 0xFF, + event[i].value == VKEY_DOWN ? TRUE : FALSE); + } + } else if (nBytes == -1) { + switch (errno) { + case EAGAIN: /* Nothing to read now */ + return; + case EINTR: /* Interrupted, try again */ + break; + case ENODEV: /* May happen when USB kbd is unplugged */ + /* We use X_NONE here because it doesn't alloc since we + may be called from SIGIO handler */ + xf86MsgVerb(X_NONE, 0, + "%s: Device no longer present - removing.\n", + pInfo->name); + xf86RemoveEnabledDevice(pInfo); + priv->remove_timer = TimerSet(priv->remove_timer, 0, 1, + RemoveKeyboard, pInfo); + return; + default: /* All other errors */ + /* We use X_NONE here because it doesn't alloc since we + may be called from SIGIO handler */ + xf86MsgVerb(X_NONE, 0, "%s: Read error: %s\n", pInfo->name, + strerror(errno)); + return; + } + } else { /* nBytes == 0, so nothing more to read */ + return; } } } diff --git a/src/sun_kbd.h b/src/sun_kbd.h index a73e201..080cbb5 100644 --- a/src/sun_kbd.h +++ b/src/sun_kbd.h @@ -36,6 +36,7 @@ typedef struct { int odirect; /* Original "direct" mode setting */ int oleds; /* Original LED state */ const char * strmod; /* Streams module pushed on kbd device */ + OsTimerPtr remove_timer; /* Callback for removal on ENODEV */ } sunKbdPrivRec, *sunKbdPrivPtr; /* sun_kbdMap.c */ |