aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/kdrive
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/kdrive')
-rw-r--r--xorg-server/hw/kdrive/ephyr/ephyrdriext.c4
-rw-r--r--xorg-server/hw/kdrive/ephyr/ephyrglxext.c179
-rw-r--r--xorg-server/hw/kdrive/ephyr/ephyrhostglx.c121
-rw-r--r--xorg-server/hw/kdrive/ephyr/ephyrhostglx.h9
-rw-r--r--xorg-server/hw/kdrive/src/kinput.c2
5 files changed, 264 insertions, 51 deletions
diff --git a/xorg-server/hw/kdrive/ephyr/ephyrdriext.c b/xorg-server/hw/kdrive/ephyr/ephyrdriext.c
index a42be07d5..1a98a2dff 100644
--- a/xorg-server/hw/kdrive/ephyr/ephyrdriext.c
+++ b/xorg-server/hw/kdrive/ephyr/ephyrdriext.c
@@ -561,7 +561,7 @@ ProcXF86DRIQueryDirectRenderingCapable(register ClientPtr client)
return BadValue;
}
- if (!LocalClient(client) || client->swapped)
+ if (!client->local || client->swapped)
isCapable = 0;
rep = (xXF86DRIQueryDirectRenderingCapableReply) {
@@ -1229,7 +1229,7 @@ ProcXF86DRIDispatch(register ClientPtr client)
}
}
- if (!LocalClient(client))
+ if (!client->local)
return DRIErrorBase + XF86DRIClientNotLocal;
switch (stuff->data) {
diff --git a/xorg-server/hw/kdrive/ephyr/ephyrglxext.c b/xorg-server/hw/kdrive/ephyr/ephyrglxext.c
index df285cfcb..22d510891 100644
--- a/xorg-server/hw/kdrive/ephyr/ephyrglxext.c
+++ b/xorg-server/hw/kdrive/ephyr/ephyrglxext.c
@@ -61,10 +61,16 @@ int ephyrGLXGetFBConfigsSGIX(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXGetFBConfigsSGIXSwap(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXCreateContext(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXCreateContextSwap(__GLXclientState * a_cl, GLbyte * a_pc);
+int ephyrGLXCreateNewContext(__GLXclientState * a_cl, GLbyte * a_pc);
+int ephyrGLXCreateNewContextSwap(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXDestroyContext(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXDestroyContextSwap(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXMakeCurrent(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXMakeCurrentSwap(__GLXclientState * a_cl, GLbyte * a_pc);
+int ephyrGLXMakeCurrentReadSGI(__GLXclientState * a_cl, GLbyte * a_pc);
+int ephyrGLXMakeCurrentReadSGISwap(__GLXclientState * a_cl, GLbyte * a_pc);
+int ephyrGLXMakeContextCurrent(__GLXclientState * a_cl, GLbyte * a_pc);
+int ephyrGLXMakeContextCurrentSwap(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXGetString(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXGetStringSwap(__GLXclientState * a_cl, GLbyte * a_pc);
int ephyrGLXGetIntegerv(__GLXclientState * a_cl, GLbyte * a_pc);
@@ -108,6 +114,9 @@ ephyrHijackGLXExtension(void)
dispatch_functions[X_GLXCreateContext][0] = ephyrGLXCreateContext;
dispatch_functions[X_GLXCreateContext][1] = ephyrGLXCreateContextSwap;
+ dispatch_functions[X_GLXCreateNewContext][0] = ephyrGLXCreateNewContext;
+ dispatch_functions[X_GLXCreateNewContext][1] = ephyrGLXCreateNewContextSwap;
+
dispatch_functions[X_GLXDestroyContext][0] = ephyrGLXDestroyContext;
dispatch_functions[X_GLXDestroyContext][1] = ephyrGLXDestroyContextSwap;
@@ -123,14 +132,24 @@ ephyrHijackGLXExtension(void)
dispatch_functions[61][0] = ephyrGLXGetIntegerv;
dispatch_functions[61][1] = ephyrGLXGetIntegervSwap;
+ dispatch_functions[X_GLXMakeContextCurrent][0] =
+ ephyrGLXMakeContextCurrent;
+ dispatch_functions[X_GLXMakeContextCurrent][1] =
+ ephyrGLXMakeContextCurrentSwap;
+
/*
* hijack some vendor priv entry point dispatch functions
*/
dispatch_functions = VendorPriv_dispatch_info.dispatch_functions;
dispatch_functions[92][0] = ephyrGLXGetFBConfigsSGIX;
dispatch_functions[92][1] = ephyrGLXGetFBConfigsSGIXSwap;
+
+ dispatch_functions[89][0] = ephyrGLXMakeCurrentReadSGI;
+ dispatch_functions[89][1] = ephyrGLXMakeCurrentReadSGISwap;
+
EPHYR_LOG("hijacked glx entry points to forward requests to host X\n");
+
return TRUE;
}
@@ -445,7 +464,8 @@ ephyrGLXCreateContextReal(xGLXCreateContextReq * a_req, Bool a_do_swap)
if (!ephyrHostGLXCreateContext(a_req->screen,
host_w_attrs.visualid,
a_req->context,
- a_req->shareList, a_req->isDirect)) {
+ a_req->shareList, 0,
+ a_req->isDirect, X_GLXCreateContext)) {
EPHYR_LOG_ERROR("ephyrHostGLXCreateContext() failed\n");
goto out;
}
@@ -455,6 +475,45 @@ ephyrGLXCreateContextReal(xGLXCreateContextReq * a_req, Bool a_do_swap)
return res;
}
+static int
+ephyrGLXCreateNewContextReal(xGLXCreateNewContextReq * a_req, Bool a_do_swap)
+{
+ int res = BadImplementation;
+
+ __GLX_DECLARE_SWAP_VARIABLES;
+
+ EPHYR_RETURN_VAL_IF_FAIL(a_req, BadValue);
+ EPHYR_LOG("enter\n");
+
+ if (a_do_swap) {
+ __GLX_SWAP_SHORT(&a_req->length);
+ __GLX_SWAP_INT(&a_req->context);
+ __GLX_SWAP_INT(&a_req->fbconfig);
+ __GLX_SWAP_INT(&a_req->screen);
+ __GLX_SWAP_INT(&a_req->renderType);
+ __GLX_SWAP_INT(&a_req->shareList);
+ }
+
+ EPHYR_LOG("context creation requested. localid:%d, "
+ "screen:%d, fbconfig:%d, renderType:%d, direct:%d\n",
+ (int) a_req->context, (int) a_req->screen,
+ (int) a_req->fbconfig, (int) a_req->renderType,
+ (int) a_req->isDirect);
+
+ if (!ephyrHostGLXCreateContext(a_req->screen,
+ a_req->fbconfig,
+ a_req->context,
+ a_req->shareList, a_req->renderType,
+ a_req->isDirect, X_GLXCreateNewContext)) {
+ EPHYR_LOG_ERROR("ephyrHostGLXCreateNewContext() failed\n");
+ goto out;
+ }
+ res = Success;
+ out:
+ EPHYR_LOG("leave\n");
+ return res;
+}
+
int
ephyrGLXCreateContext(__GLXclientState * cl, GLbyte * pc)
{
@@ -471,6 +530,22 @@ ephyrGLXCreateContextSwap(__GLXclientState * cl, GLbyte * pc)
return ephyrGLXCreateContextReal(req, TRUE);
}
+int
+ephyrGLXCreateNewContext(__GLXclientState * cl, GLbyte * pc)
+{
+ xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
+
+ return ephyrGLXCreateNewContextReal(req, FALSE);
+}
+
+int
+ephyrGLXCreateNewContextSwap(__GLXclientState * cl, GLbyte * pc)
+{
+ xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
+
+ return ephyrGLXCreateNewContextReal(req, TRUE);
+}
+
static int
ephyrGLXDestroyContextReal(__GLXclientState * a_cl,
GLbyte * a_pc, Bool a_do_swap)
@@ -505,26 +580,34 @@ ephyrGLXDestroyContextSwap(__GLXclientState * a_cl, GLbyte * a_pc)
}
static int
-ephyrGLXMakeCurrentReal(__GLXclientState * a_cl, GLbyte * a_pc, Bool a_do_swap)
+ephyrGLXMakeCurrentReal(__GLXclientState * a_cl, GLXDrawable write,
+ GLXDrawable read, GLXContextTag ctx,
+ GLXContextTag old_ctx, Bool a_do_swap)
{
int res = BadImplementation;
- xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc;
xGLXMakeCurrentReply reply;
- DrawablePtr drawable = NULL;
- GLXContextTag contextTag = 0;
- int rc = 0;
+ DrawablePtr drawableR = NULL, drawableW = NULL;
+ GLXContextTag new_ctx = 0;
EPHYR_LOG("enter\n");
- rc = dixLookupDrawable(&drawable,
- req->drawable, a_cl->client, 0, DixReadAccess);
- EPHYR_RETURN_VAL_IF_FAIL(drawable, BadValue);
- EPHYR_RETURN_VAL_IF_FAIL(drawable->pScreen, BadValue);
- EPHYR_LOG("screen nummber requested:%d\n", drawable->pScreen->myNum);
-
- if (!ephyrHostGLXMakeCurrent(hostx_get_window(drawable->pScreen->myNum),
- req->context,
- req->oldContextTag,
- (int *) &contextTag)) {
+ res = dixLookupDrawable(&drawableW, write, a_cl->client, 0, DixReadAccess);
+ EPHYR_RETURN_VAL_IF_FAIL(drawableW, BadValue);
+ EPHYR_RETURN_VAL_IF_FAIL(drawableW->pScreen, BadValue);
+ EPHYR_LOG("screen nummber requested:%d\n", drawableW->pScreen->myNum);
+
+ if (read != write) {
+ res = dixLookupDrawable(&drawableR, read, a_cl->client, 0,
+ DixReadAccess);
+ EPHYR_RETURN_VAL_IF_FAIL(drawableR, BadValue);
+ EPHYR_RETURN_VAL_IF_FAIL(drawableR->pScreen, BadValue);
+ }
+ else {
+ drawableR = drawableW;
+ }
+
+ if (!ephyrHostGLXMakeCurrent(hostx_get_window(drawableW->pScreen->myNum),
+ hostx_get_window(drawableR->pScreen->myNum),
+ ctx, old_ctx, (int *) &new_ctx)) {
EPHYR_LOG_ERROR("ephyrHostGLXMakeCurrent() failed\n");
goto out;
}
@@ -532,7 +615,7 @@ ephyrGLXMakeCurrentReal(__GLXclientState * a_cl, GLbyte * a_pc, Bool a_do_swap)
.type = X_Reply,
.sequenceNumber = a_cl->client->sequence,
.length = 0,
- .contextTag = contextTag
+ .contextTag = new_ctx
};
if (a_do_swap) {
__GLX_DECLARE_SWAP_VARIABLES;
@@ -551,13 +634,71 @@ ephyrGLXMakeCurrentReal(__GLXclientState * a_cl, GLbyte * a_pc, Bool a_do_swap)
int
ephyrGLXMakeCurrent(__GLXclientState * a_cl, GLbyte * a_pc)
{
- return ephyrGLXMakeCurrentReal(a_cl, a_pc, FALSE);
+ xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc;
+ return ephyrGLXMakeCurrentReal(a_cl, req->drawable, req->drawable,
+ req->context, req->oldContextTag, FALSE);
}
int
ephyrGLXMakeCurrentSwap(__GLXclientState * a_cl, GLbyte * a_pc)
{
- return ephyrGLXMakeCurrentReal(a_cl, a_pc, TRUE);
+ xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc;
+ __GLX_DECLARE_SWAP_VARIABLES;
+
+ __GLX_SWAP_INT(&req->drawable);
+ __GLX_SWAP_INT(&req->context);
+ __GLX_SWAP_INT(&req->oldContextTag);
+
+ return ephyrGLXMakeCurrentReal(a_cl, req->drawable, req->drawable,
+ req->context, req->oldContextTag, TRUE);
+}
+
+int
+ephyrGLXMakeCurrentReadSGI(__GLXclientState * a_cl, GLbyte * a_pc)
+{
+ xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) a_pc;
+
+ return ephyrGLXMakeCurrentReal(a_cl, req->drawable, req->readable,
+ req->context, req->oldContextTag, FALSE);
+}
+
+int
+ephyrGLXMakeCurrentReadSGISwap(__GLXclientState * a_cl, GLbyte * a_pc)
+{
+ xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) a_pc;
+ __GLX_DECLARE_SWAP_VARIABLES;
+
+ __GLX_SWAP_INT(&req->drawable);
+ __GLX_SWAP_INT(&req->readable);
+ __GLX_SWAP_INT(&req->context);
+ __GLX_SWAP_INT(&req->oldContextTag);
+
+ return ephyrGLXMakeCurrentReal(a_cl, req->drawable, req->readable,
+ req->context, req->oldContextTag, TRUE);
+}
+
+int
+ephyrGLXMakeContextCurrent(__GLXclientState * a_cl, GLbyte * a_pc)
+{
+ xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) a_pc;
+
+ return ephyrGLXMakeCurrentReal(a_cl, req->drawable, req->readdrawable,
+ req->context, req->oldContextTag, FALSE);
+}
+
+int
+ephyrGLXMakeContextCurrentSwap(__GLXclientState * a_cl, GLbyte * a_pc)
+{
+ xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) a_pc;
+ __GLX_DECLARE_SWAP_VARIABLES;
+
+ __GLX_SWAP_INT(&req->drawable);
+ __GLX_SWAP_INT(&req->readdrawable);
+ __GLX_SWAP_INT(&req->context);
+ __GLX_SWAP_INT(&req->oldContextTag);
+
+ return ephyrGLXMakeCurrentReal(a_cl, req->drawable, req->readdrawable,
+ req->context, req->oldContextTag, TRUE);
}
static int
diff --git a/xorg-server/hw/kdrive/ephyr/ephyrhostglx.c b/xorg-server/hw/kdrive/ephyr/ephyrhostglx.c
index 6b9da6fb1..392489a00 100644
--- a/xorg-server/hw/kdrive/ephyr/ephyrhostglx.c
+++ b/xorg-server/hw/kdrive/ephyr/ephyrhostglx.c
@@ -52,6 +52,8 @@
#include "ephyrlog.h"
#include "hostx.h"
+static int glx_major, glx_minor;
+
enum VisualConfRequestType {
EPHYR_GET_FB_CONFIG,
EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
@@ -99,6 +101,12 @@ ephyrHostGLXQueryVersion(int *a_major, int *a_minor)
EPHYR_RETURN_VAL_IF_FAIL(a_major && a_minor, FALSE);
EPHYR_LOG("enter\n");
+ if (glx_major) {
+ *a_major = glx_major;
+ *a_minor = glx_minor;
+ return TRUE;
+ }
+
if (!ephyrHostGLXGetMajorOpcode(&major_opcode)) {
EPHYR_LOG_ERROR("failed to get major opcode\n");
goto out;
@@ -117,8 +125,8 @@ ephyrHostGLXQueryVersion(int *a_major, int *a_minor)
UnlockDisplay(dpy);
SyncHandle();
- *a_major = reply.majorVersion;
- *a_minor = reply.minorVersion;
+ *a_major = glx_major = reply.majorVersion;
+ *a_minor = glx_minor = reply.minorVersion;
EPHYR_LOG("major:%d, minor:%d\n", *a_major, *a_minor);
@@ -431,17 +439,20 @@ ephyrHostGLXSendClientInfo(int32_t a_major, int32_t a_minor,
Bool
ephyrHostGLXCreateContext(int a_screen,
- int a_visual_id,
+ int a_generic_id,
int a_context_id,
- int a_share_list_ctxt_id, Bool a_direct)
+ int a_share_list_ctxt_id,
+ int a_render_type,
+ Bool a_direct,
+ int code)
{
Bool is_ok = FALSE;
Display *dpy = hostx_get_display();
int major_opcode = 0, remote_context_id = 0;
- xGLXCreateContextReq *req;
- EPHYR_LOG("enter. screen:%d, visual:%d, contextid:%d, direct:%d\n",
- a_screen, a_visual_id, a_context_id, a_direct);
+ EPHYR_LOG("enter. screen:%d, generic_id:%d, contextid:%d, rendertype:%d, "
+ "direct:%d\n", a_screen, a_generic_id, a_context_id,
+ a_render_type, a_direct);
if (!hostx_allocate_resource_id_peer(a_context_id, &remote_context_id)) {
EPHYR_LOG_ERROR("failed to peer the context id %d host X",
@@ -456,15 +467,38 @@ ephyrHostGLXCreateContext(int a_screen,
LockDisplay(dpy);
- /* Send the glXCreateContext request */
- GetReq(GLXCreateContext, req);
- req->reqType = major_opcode;
- req->glxCode = X_GLXCreateContext;
- req->context = remote_context_id;
- req->visual = a_visual_id;
- req->screen = DefaultScreen(dpy);
- req->shareList = a_share_list_ctxt_id;
- req->isDirect = a_direct;
+ switch (code) {
+ case X_GLXCreateContext: {
+ /* Send the glXCreateContext request */
+ xGLXCreateContextReq *req;
+ GetReq(GLXCreateContext, req);
+ req->reqType = major_opcode;
+ req->glxCode = X_GLXCreateContext;
+ req->context = remote_context_id;
+ req->visual = a_generic_id;
+ req->screen = DefaultScreen(dpy);
+ req->shareList = a_share_list_ctxt_id;
+ req->isDirect = a_direct;
+ }
+
+ case X_GLXCreateNewContext: {
+ /* Send the glXCreateNewContext request */
+ xGLXCreateNewContextReq *req;
+ GetReq(GLXCreateNewContext, req);
+ req->reqType = major_opcode;
+ req->glxCode = X_GLXCreateNewContext;
+ req->context = remote_context_id;
+ req->fbconfig = a_generic_id;
+ req->screen = DefaultScreen(dpy);
+ req->renderType = a_render_type;
+ req->shareList = a_share_list_ctxt_id;
+ req->isDirect = a_direct;
+ }
+
+ default:
+ /* This should never be reached !*/
+ EPHYR_LOG("Internal error! Invalid CreateContext code!\n");
+ }
UnlockDisplay(dpy);
SyncHandle();
@@ -512,20 +546,19 @@ ephyrHostDestroyContext(int a_ctxt_id)
}
Bool
-ephyrHostGLXMakeCurrent(int a_drawable,
+ephyrHostGLXMakeCurrent(int a_drawable, int a_readable,
int a_glx_ctxt_id, int a_old_ctxt_tag, int *a_ctxt_tag)
{
Bool is_ok = FALSE;
Display *dpy = hostx_get_display();
int32_t major_opcode = 0;
int remote_glx_ctxt_id = 0;
- xGLXMakeCurrentReq *req;
xGLXMakeCurrentReply reply;
EPHYR_RETURN_VAL_IF_FAIL(a_ctxt_tag, FALSE);
- EPHYR_LOG("enter. drawable:%d, context:%d, oldtag:%d\n",
- a_drawable, a_glx_ctxt_id, a_old_ctxt_tag);
+ EPHYR_LOG("enter. drawable:%d, read:%d, context:%d, oldtag:%d\n",
+ a_drawable, a_readable, a_glx_ctxt_id, a_old_ctxt_tag);
if (!ephyrHostGLXGetMajorOpcode(&major_opcode)) {
EPHYR_LOG_ERROR("failed to get major opcode\n");
@@ -538,12 +571,48 @@ ephyrHostGLXMakeCurrent(int a_drawable,
LockDisplay(dpy);
- GetReq(GLXMakeCurrent, req);
- req->reqType = major_opcode;
- req->glxCode = X_GLXMakeCurrent;
- req->drawable = a_drawable;
- req->context = remote_glx_ctxt_id;
- req->oldContextTag = a_old_ctxt_tag;
+ /* If both drawables are the same, use the old MakeCurrent request.
+ * Otherwise, if we have GLX 1.3 or higher, use the MakeContextCurrent
+ * request which supports separate read and draw targets. Failing that,
+ * try the SGI MakeCurrentRead extension. Logic cribbed from Mesa. */
+ if (a_drawable == a_readable) {
+ xGLXMakeCurrentReq *req;
+
+ GetReq(GLXMakeCurrent, req);
+ req->reqType = major_opcode;
+ req->glxCode = X_GLXMakeCurrent;
+ req->drawable = a_drawable;
+ req->context = remote_glx_ctxt_id;
+ req->oldContextTag = a_old_ctxt_tag;
+ }
+ else if (glx_major > 1 || glx_minor >= 3) {
+ xGLXMakeContextCurrentReq *req;
+
+ GetReq(GLXMakeContextCurrent, req);
+ req->reqType = major_opcode;
+ req->glxCode = X_GLXMakeContextCurrent;
+ req->drawable = a_drawable;
+ req->readdrawable = a_readable;
+ req->context = remote_glx_ctxt_id;
+ req->oldContextTag = a_old_ctxt_tag;
+ }
+ else {
+ xGLXVendorPrivateWithReplyReq *vpreq;
+ xGLXMakeCurrentReadSGIReq *req;
+
+ GetReqExtra(GLXVendorPrivateWithReply,
+ (sz_xGLXMakeCurrentReadSGIReq -
+ sz_xGLXVendorPrivateWithReplyReq),
+ vpreq);
+ req = (xGLXMakeCurrentReadSGIReq *) vpreq;
+ req->reqType = major_opcode;
+ req->glxCode = X_GLXVendorPrivateWithReply;
+ req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
+ req->drawable = a_drawable;
+ req->readable = a_readable;
+ req->context = remote_glx_ctxt_id;
+ req->oldContextTag = a_old_ctxt_tag;
+ }
memset(&reply, 0, sizeof(reply));
if (!_XReply(dpy, (xReply *) & reply, 0, False)) {
diff --git a/xorg-server/hw/kdrive/ephyr/ephyrhostglx.h b/xorg-server/hw/kdrive/ephyr/ephyrhostglx.h
index 9c6012070..7ff515dc2 100644
--- a/xorg-server/hw/kdrive/ephyr/ephyrhostglx.h
+++ b/xorg-server/hw/kdrive/ephyr/ephyrhostglx.h
@@ -55,13 +55,16 @@ Bool ephyrHostGLXGetMajorOpcode(int32_t * a_opcode);
Bool ephyrHostGLXSendClientInfo(int32_t a_major, int32_t a_minor,
const char *a_extension_list);
Bool ephyrHostGLXCreateContext(int a_screen,
- int a_visual_id,
+ int a_generic_id,
int a_context_id,
- int a_shared_list_ctx_id, Bool a_direct);
+ int a_share_list_ctxt_id,
+ int a_render_type,
+ Bool a_direct,
+ int code);
Bool ephyrHostDestroyContext(int a_ctxt_id);
-Bool ephyrHostGLXMakeCurrent(int a_drawable, int a_glx_ctxt_id,
+Bool ephyrHostGLXMakeCurrent(int a_drawable, int a_readable, int a_glx_ctxt_id,
int a_olg_ctxt_tag, int *a_ctxt_tag);
Bool ephyrHostGetIntegerValue(int a_current_context_tag, int a_int, int *a_val);
diff --git a/xorg-server/hw/kdrive/src/kinput.c b/xorg-server/hw/kdrive/src/kinput.c
index d35dcf848..b1068bbee 100644
--- a/xorg-server/hw/kdrive/src/kinput.c
+++ b/xorg-server/hw/kdrive/src/kinput.c
@@ -1034,7 +1034,7 @@ KdGetOptions(InputOption **options, char *string)
if (strchr(string, '=')) {
tam_key = (strchr(string, '=') - string);
- key = strndup(string, tam_key + 1);
+ key = strndup(string, tam_key);
if (!key)
goto out;