summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Coopersmith <alan.coopersmith@sun.com>2009-04-30 16:26:23 -0700
committerAlan Coopersmith <alan.coopersmith@sun.com>2009-04-30 23:26:46 -0700
commit2bc18590e6b7b403dcec22a09820010748c48972 (patch)
treeb21ca789101cc24f86002def4a140f126a6e20f9
parent810fe3a4afd7e77a645c312f9475e75c2f7e925c (diff)
downloadxorg-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.c114
-rw-r--r--src/sun_kbd.h1
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 */