1 From 2bc18590e6b7b403dcec22a09820010748c48972 Mon Sep 17 00:00:00 2001 2 From: Alan Coopersmith <alan.coopersmith (a] sun.com> 3 Date: Thu, 30 Apr 2009 16:26:23 -0700 4 Subject: [PATCH] Solaris keyboard fixes for HAL hotplugging support 5 6 - Handle hot-unplug by checking for ENODEV on read and removing device 7 - Make sure to re-push streams module on resume 8 9 Signed-off-by: Alan Coopersmith <alan.coopersmith (a] sun.com> 10 --- 11 src/sun_kbd.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 12 src/sun_kbd.h | 1 + 13 2 files changed, 97 insertions(+), 18 deletions(-) 14 15 diff --git a/src/sun_kbd.c b/src/sun_kbd.c 16 index a222d38..b4ebc57 100644 17 --- a/src/sun_kbd.c 18 +++ b/src/sun_kbd.c 19 @@ -22,7 +22,7 @@ 20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 -/* Copyright 2004-2007 Sun Microsystems, Inc. All rights reserved. 24 +/* Copyright 2004-2009 Sun Microsystems, Inc. All rights reserved. 25 * 26 * Permission is hereby granted, free of charge, to any person obtaining a 27 * copy of this software and associated documentation files (the 28 @@ -64,6 +64,8 @@ 29 #include <sys/vuid_event.h> 30 #include <sys/kbd.h> 31 32 +static int KbdOn(InputInfoPtr pInfo, int what); 33 + 34 static void 35 sunKbdSetLeds(InputInfoPtr pInfo, int leds) 36 { 37 @@ -105,6 +107,7 @@ KbdInit(InputInfoPtr pInfo, int what) 38 int ktype, klayout, i; 39 const char *ktype_name; 40 41 + priv->kbdActive = FALSE; 42 priv->otranslation = -1; 43 priv->odirect = -1; 44 45 @@ -114,15 +117,11 @@ KbdInit(InputInfoPtr pInfo, int what) 46 priv->strmod = NULL; 47 } 48 49 - if (priv->strmod) { 50 - SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod)); 51 - if (i < 0) { 52 - xf86Msg(X_ERROR, 53 - "%s: cannot push module '%s' onto keyboard device: %s\n", 54 - pInfo->name, priv->strmod, strerror(errno)); 55 - } 56 + i = KbdOn(pInfo, DEVICE_INIT); 57 + if (i != Success) { 58 + return i; 59 } 60 - 61 + 62 SYSCALL(i = ioctl(pInfo->fd, KIOCTYPE, &ktype)); 63 if (i < 0) { 64 xf86Msg(X_ERROR, "%s: Unable to determine keyboard type: %s\n", 65 @@ -155,7 +154,6 @@ KbdInit(InputInfoPtr pInfo, int what) 66 xf86Msg(X_PROBED, "%s: Keyboard layout: %d\n", pInfo->name, klayout); 67 68 priv->ktype = ktype; 69 - priv->oleds = sunKbdGetLeds(pInfo); 70 71 return Success; 72 } 73 @@ -169,6 +167,19 @@ KbdOn(InputInfoPtr pInfo, int what) 74 75 int ktrans, kdirect, i; 76 77 + if (priv->kbdActive) { 78 + return Success; 79 + } 80 + 81 + if (priv->strmod) { 82 + SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod)); 83 + if (i < 0) { 84 + xf86Msg(X_ERROR, 85 + "%s: cannot push module '%s' onto keyboard device: %s\n", 86 + pInfo->name, priv->strmod, strerror(errno)); 87 + } 88 + } 89 + 90 SYSCALL(i = ioctl(pInfo->fd, KIOCGDIRECT, &kdirect)); 91 if (i < 0) { 92 xf86Msg(X_ERROR, 93 @@ -207,6 +218,13 @@ KbdOn(InputInfoPtr pInfo, int what) 94 return BadImplementation; 95 } 96 97 + priv->oleds = sunKbdGetLeds(pInfo); 98 + 99 + /* Allocate here so we don't alloc in ReadInput which may be called 100 + from SIGIO handler. */ 101 + priv->remove_timer = TimerSet(priv->remove_timer, 0, 0, NULL, NULL); 102 + 103 + priv->kbdActive = TRUE; 104 return Success; 105 } 106 107 @@ -218,6 +236,20 @@ KbdOff(InputInfoPtr pInfo, int what) 108 109 int i; 110 111 + if (!priv->kbdActive) { 112 + return Success; 113 + } 114 + 115 + if (pInfo->fd == -1) { 116 + priv->kbdActive = FALSE; 117 + return Success; 118 + } 119 + 120 + if (priv->remove_timer) { 121 + TimerFree(priv->remove_timer); 122 + priv->remove_timer = NULL; 123 + } 124 + 125 /* restore original state */ 126 127 if (priv->oleds != -1) { 128 @@ -254,9 +286,9 @@ KbdOff(InputInfoPtr pInfo, int what) 129 "%s: cannot pop module '%s' off keyboard device: %s\n", 130 pInfo->name, priv->strmod, strerror(errno)); 131 } 132 - priv->strmod = NULL; 133 } 134 135 + priv->kbdActive = FALSE; 136 return Success; 137 } 138 139 @@ -353,20 +385,66 @@ SetKbdRepeat(InputInfoPtr pInfo, char rad) 140 /* Nothing to do */ 141 } 142 143 +/* Called from OsTimer callback, since removing a device from the device 144 + list or changing pInfo->fd while xf86Wakeup is looping through the list 145 + causes server crashes */ 146 +static CARD32 147 +RemoveKeyboard(OsTimerPtr timer, CARD32 time, pointer arg) 148 +{ 149 + InputInfoPtr pInfo = (InputInfoPtr) arg; 150 + KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 151 + sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 152 + 153 + close(pInfo->fd); 154 + pInfo->fd = -1; 155 + priv->kbdActive = FALSE; 156 + 157 + xf86DisableDevice(pInfo->dev, TRUE); 158 + 159 + return 0; /* All done, don't set to run again */ 160 +} 161 + 162 static void 163 ReadInput(InputInfoPtr pInfo) 164 { 165 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 166 + sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 167 Firm_event event[64]; 168 int nBytes, i; 169 170 - /* I certainly hope its not possible to read partial events */ 171 - 172 - if ((nBytes = read(pInfo->fd, (char *)event, sizeof(event))) > 0) 173 - { 174 - for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) { 175 - pKbd->PostEvent(pInfo, event[i].id & 0xFF, 176 - event[i].value == VKEY_DOWN ? TRUE : FALSE); 177 + while (TRUE) { 178 + /* I certainly hope it's not possible to read partial events */ 179 + nBytes = read(pInfo->fd, (char *)event, sizeof(event)); 180 + if (nBytes > 0) { 181 + for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) { 182 + pKbd->PostEvent(pInfo, event[i].id & 0xFF, 183 + event[i].value == VKEY_DOWN ? TRUE : FALSE); 184 + } 185 + } else if (nBytes == -1) { 186 + switch (errno) { 187 + case EAGAIN: /* Nothing to read now */ 188 + return; 189 + case EINTR: /* Interrupted, try again */ 190 + break; 191 + case ENODEV: /* May happen when USB kbd is unplugged */ 192 + /* We use X_NONE here because it doesn't alloc since we 193 + may be called from SIGIO handler */ 194 + xf86MsgVerb(X_NONE, 0, 195 + "%s: Device no longer present - removing.\n", 196 + pInfo->name); 197 + xf86RemoveEnabledDevice(pInfo); 198 + priv->remove_timer = TimerSet(priv->remove_timer, 0, 1, 199 + RemoveKeyboard, pInfo); 200 + return; 201 + default: /* All other errors */ 202 + /* We use X_NONE here because it doesn't alloc since we 203 + may be called from SIGIO handler */ 204 + xf86MsgVerb(X_NONE, 0, "%s: Read error: %s\n", pInfo->name, 205 + strerror(errno)); 206 + return; 207 + } 208 + } else { /* nBytes == 0, so nothing more to read */ 209 + return; 210 } 211 } 212 } 213 diff --git a/src/sun_kbd.h b/src/sun_kbd.h 214 index a73e201..080cbb5 100644 215 --- a/src/sun_kbd.h 216 +++ b/src/sun_kbd.h 217 @@ -36,6 +36,7 @@ typedef struct { 218 int odirect; /* Original "direct" mode setting */ 219 int oleds; /* Original LED state */ 220 const char * strmod; /* Streams module pushed on kbd device */ 221 + OsTimerPtr remove_timer; /* Callback for removal on ENODEV */ 222 } sunKbdPrivRec, *sunKbdPrivPtr; 223 224 /* sun_kbdMap.c */ 225 -- 226 1.5.6.5 227 228
