? pc-kbd.h
Index: Makefile
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/Makefile,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 Makefile
--- Makefile	17 Sep 2002 12:26:10 -0000	1.1
+++ Makefile	13 Mar 2004 16:35:29 -0000
@@ -21,7 +21,7 @@ makemode := utility
 target = console
 SRCS = console.c timer.c driver.c
 LCLHDRS = timer.h driver.h display.h input.h bell.h \
-	  unicode.h bdf.h \
+	  unicode.h bdf.h inputdev.h \
 	  vga-dynafont.h vga-dynacolor.h vga-hw.h vga.h
 
 OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
@@ -45,7 +45,9 @@ modules = vga pc_kbd generic_speaker
 
 vga.so.$(hurd-version): $(patsubst %.c,%_pic.o,bdf.c vga-dynafont.c \
 	vga-dynacolor.c vga-support.c vga.c)
-pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,pc-kbd.c)
+pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,pc-kbd.c kdioctlServer.o kbd-repeat.c)
+pc_kbd-LDLIBS = -ltrivfs
+
 generic_speaker.so.$(hurd-version): $(patsubst %.c,%_pic.o,generic-speaker.c)
 
 ifneq ($(LIBNCURSESW),)
Index: console.c
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/console.c,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 console.c
--- console.c	15 Aug 2003 21:07:31 -0000	1.3
+++ console.c	13 Mar 2004 16:35:31 -0000
@@ -1,5 +1,5 @@
 /* console.c -- A pluggable console client.
-   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
    Written by Marcus Brinkmann.
 
    This program is free software; you can redistribute it and/or
@@ -47,6 +47,12 @@ static struct mutex global_lock;
    displayed.  */
 static vcons_t active_vcons = NULL;
 
+/* Contains the VT id when switched away.  */
+static int saved_id = 0;
+
+/* The console, used to switch back.  */
+static cons_t saved_cons;
+
 
 /* Callbacks for input source drivers.  */
 
@@ -145,6 +151,52 @@ console_scrollback (cons_scroll_t type, 
       ports_port_deref (vcons);
     }
   return nr;
+}
+
+
+/* Switch away from the console an external use of the console like
+   XFree.  */
+void
+console_switch_away (void)
+{
+  mutex_lock (&global_lock);
+  saved_id = active_vcons->id;
+  saved_cons = active_vcons->cons;
+  cons_vcons_close (active_vcons);
+  active_vcons = NULL;
+  mutex_unlock (&global_lock);
+}
+
+/* Switch back to the console client from an external user of the
+   console like XFree.  */
+void
+console_switch_back (void)
+{
+  vcons_list_t conslist;
+  mutex_lock (&global_lock);
+  if (saved_cons)
+    {
+      error_t err;
+
+      err = cons_lookup (saved_cons, saved_id, 1, &conslist);
+      if (err)
+	{
+	  mutex_unlock (&global_lock);
+	  return;
+	}
+
+      err = cons_vcons_open (saved_cons, conslist, &active_vcons);
+      if (err)
+	{
+	  mutex_unlock (&global_lock);
+	  return;
+	}
+	
+      conslist->vcons = active_vcons;
+      saved_cons = NULL;
+      mutex_unlock (&active_vcons->lock);
+    }
+  mutex_unlock (&global_lock);
 }
 
 
Index: input.h
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/input.h,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 input.h
--- input.h	17 Sep 2002 12:26:10 -0000	1.1
+++ input.h	13 Mar 2004 16:35:31 -0000
@@ -1,5 +1,5 @@
 /* input.h - The interface to and for an input driver.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
    Written by Marcus Brinkmann.
 
    This file is part of the GNU Hurd.
@@ -64,6 +64,15 @@ void console_error (const wchar_t *const
 
 /* Exit the console client.  Does not return.  */
 void console_exit (void);
+
+/* Switch away from the console an external use of the console like
+   XFree.  */
+void console_switch_away (void);
+
+/* Switch back to the console client from an external user of the
+   console like XFree.  */
+void console_switch_back (void);
+
 
 #if QUAERENDO_INVENIETIS
 /* Do not use, do not remove.  */
Index: inputdev.h
===================================================================
RCS file: inputdev.h
diff -N inputdev.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ inputdev.h	13 Mar 2004 16:35:31 -0000
@@ -0,0 +1,122 @@
+/* inputdev.h - Interfaces for the PC pc-kbd and mouse input drivers.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   Written by Marco Gerards.
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+/* This gross stuff is cut & pasted from Mach sources, as Mach doesn't
+   export the interface we are using here.  */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _INPUTDEV_H_
+#define _INPUTDEV_H_ 1
+
+typedef u_short kev_type;               /* kd event type */
+
+/* (used for event records) */
+struct mouse_motion {
+  short mm_deltaX;                /* units? */
+  short mm_deltaY;
+};
+typedef u_char Scancode;
+
+typedef struct {
+  kev_type type;                  /* see below */
+  struct timeval time;            /* timestamp */
+  union {                         /* value associated with event */
+    boolean_t up;           /* MOUSE_LEFT .. MOUSE_RIGHT */
+    Scancode sc;            /* KEYBD_EVENT */
+    struct mouse_motion mmotion;    /* MOUSE_MOTION */
+  } value;
+} kd_event;
+#define m_deltaX        mmotion.mm_deltaX
+#define m_deltaY        mmotion.mm_deltaY
+
+/*
+ * kd_event ID's.
+ */
+#define MOUSE_LEFT      1               /* mouse left button up/down */
+#define MOUSE_MIDDLE    2
+#define MOUSE_RIGHT     3
+#define MOUSE_MOTION    4               /* mouse motion */
+#define KEYBD_EVENT     5               /* key up/down */
+
+
+#define IOCPARM_MASK    0x1fff          /* parameter length, at most 13 bits */
+#define IOC_OUT         0x40000000      /* copy out parameters */
+#define IOC_IN          0x80000000U     /* copy in parameters */
+
+#ifndef _IOC
+#define _IOC(inout,group,num,len) \
+        (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+#endif
+#ifndef _IOR
+#define _IOR(g,n,t)     _IOC(IOC_OUT,   (g), (n), sizeof(t))
+#endif
+#ifndef _IOW
+#define _IOW(g,n,t)     _IOC(IOC_IN,    (g), (n), sizeof(t))
+#endif
+
+#define KDSKBDMODE      _IOW('K', 1, int)       /* set keyboard mode */
+#define KB_EVENT        1
+#define KB_ASCII        2
+
+#define KDGKBDTYPE      _IOR('K', 2, int)       /* get keyboard type */
+#define KB_VANILLAKB    0
+
+#define KDSETLEDS      _IOW('K', 5, int)        /* set keyboard leds */
+
+
+/* End of Mach code.  */
+
+
+/* Amount of times the device was opened.  Normally this translator
+   should be only opened once.  */ 
+extern int kbd_repeater_opened;
+
+/* Place the keyboard event KEY in the keyboard buffer.  */
+void repeat_key (kd_event *key);
+
+/* Set the repeater translator on the node PATH.  */
+error_t setrepeater (const char *path);
+
+#endif	/* _INPUTDEV_H_ */
Index: kbd-repeat.c
===================================================================
RCS file: kbd-repeat.c
diff -N kbd-repeat.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ kbd-repeat.c	13 Mar 2004 16:35:31 -0000
@@ -0,0 +1,347 @@
+/* kbd-repeat.c - Keyboard repeater.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by Marco Gerards.
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+
+#include <hurd/trivfs.h>
+#include <stdlib.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "kdioctl_S.h"
+#include "inputdev.h"
+#include "input.h"
+
+/* The size of the keyboard buffer in bytes.  */
+#define KBDBUFSZ	(20 * sizeof (kd_event))
+
+/* Return the position of X in the buffer.  */
+#define KBDBUF_POS(x)	((x) % KBDBUFSZ)
+
+/* The keyboard buffer.  */
+struct kbdbuf
+{
+  char keybuffer[KBDBUFSZ];
+  int pos;
+  size_t size;
+  struct condition readcond;
+  struct condition writecond;
+} kbdbuf;
+
+/* Wakeup for select */
+static struct condition select_alert;
+
+/* The global lock */
+static struct mutex global_lock;
+
+/* Bucket to handle the keyboard RPCs.  */
+static struct port_bucket *kbdbucket;
+
+/* Amount of times the device was opened.  Normally this translator
+   should be only opened once.  */ 
+int kbd_repeater_opened;
+
+
+static int
+kdioctl_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+  extern int kdioctl_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+  return kdioctl_server (inp, outp) || trivfs_demuxer (inp, outp);
+}
+
+
+/* Place the keyboard event KEY in the keyboard buffer.  */
+void
+repeat_key (kd_event *key)
+{
+  kd_event *ev;
+
+  mutex_lock (&global_lock);
+  while (kbdbuf.size + sizeof (kd_event) > KBDBUFSZ)
+    {
+      /* The input buffer is full, wait until there is some space.  */
+      if (hurd_condition_wait (&kbdbuf.writecond, &global_lock))
+	{
+	  mutex_unlock (&global_lock);
+	  /* Interrupt, silently continue.  */
+	}
+    }
+  ev = (kd_event *) &kbdbuf.keybuffer[KBDBUF_POS (kbdbuf.pos 
+						  + kbdbuf.size)];
+  kbdbuf.size += sizeof (kd_event);
+  memcpy (ev, key, sizeof (kd_event));
+  condition_broadcast (&kbdbuf.readcond);
+  mutex_unlock (&global_lock);
+}
+
+
+/*  Thread to handle operations on the kbdbucket.  */
+static any_t
+repeater_translator_function (void *arg)
+{
+  ports_manage_port_operations_one_thread (kbdbucket, kdioctl_demuxer, 0);
+  return 0;
+}
+
+
+/* Set the repeater translator on the node PATH.  */
+error_t
+setrepeater (const char *path)
+{
+  error_t err;
+  struct trivfs_control *control;
+  file_t node;
+
+  kbdbucket = ports_create_bucket ();
+
+  node = file_name_lookup (path, O_CREAT|O_NOTRANS, 0664);
+  if (node == MACH_PORT_NULL)
+    return errno;
+  
+  err = trivfs_create_control (node, 0, kbdbucket,  0, kbdbucket, &control);
+  if (! err)
+    {
+      mach_port_t right = ports_get_send_right (control);
+      err = file_set_translator (node, 0, FS_TRANS_EXCL | FS_TRANS_SET, 0, 0, 0,
+				 right, MACH_MSG_TYPE_COPY_SEND); 
+      mach_port_deallocate (mach_task_self (), right);
+    }
+  else
+    return err;
+  
+  mutex_init (&global_lock);
+
+  condition_init (&kbdbuf.readcond);
+  condition_init (&kbdbuf.writecond);
+
+  condition_init (&select_alert);
+  condition_implies (&kbdbuf.readcond, &select_alert);
+
+  cthread_detach (cthread_fork (repeater_translator_function, 0));
+
+  return 0;
+}
+
+
+/* Just act like the Mach kbd device.  */
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred, mach_port_t reply,
+		    mach_msg_type_name_t reply_type, int *type)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  if (*type & ~SELECT_READ)
+    return EINVAL;
+
+  if (*type == 0)
+    return 0;
+
+  available = 0;
+
+  mutex_lock (&global_lock);
+  while (1)
+    {
+      if (available && kbdbuf.size > 0)
+	{
+	  *type = SELECT_READ;
+	  mutex_unlock (&global_lock);
+
+	  return 0;
+	}
+
+      if (cred->po->openmodes & O_NONBLOCK)
+	{
+	  mutex_unlock (&global_lock);
+
+	  return EWOULDBLOCK;
+	}
+
+      ports_interrupt_self_on_port_death (cred, reply);
+      if (hurd_condition_wait (&select_alert, &global_lock))
+	{
+	  *type = 0;
+	  mutex_unlock (&global_lock);
+
+	  return EINTR;
+	}
+    }
+}
+
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t *st)
+{
+  /* Mark the node as a read-only plain file. */
+  st->st_mode &= ~(S_IFMT);
+  st->st_mode |= (S_IRUSR | S_IFCHR);
+
+  st->st_size = 0;
+  st->st_blocks = 0;
+
+}
+
+
+/* No one wants this.  Use the console client to terminate the console
+   client or send a signal.  */
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+  return EOPNOTSUPP;
+}
+
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+  /* Make sure the console does not access the hardware anymore.  */
+  if (! kbd_repeater_opened)
+    console_switch_away ();
+  kbd_repeater_opened++;
+
+  return 0;
+}
+
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+  kbd_repeater_opened--;
+
+  /* Allow the console to access the hardware again.  */
+  if (! kbd_repeater_opened)
+    console_switch_back ();
+}
+
+
+/* Read data from an IO object.  If offset is -1, read from the object
+   maintained file pointer.  If the object is not seekable, offset is
+   ignored.  The amount desired to be read is in AMOUNT.  */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+		  mach_port_t reply, mach_msg_type_name_t reply_type,
+		  char **data, mach_msg_type_number_t *data_len,
+		  loff_t offs, mach_msg_type_number_t amount)
+{
+  /* Deny access if they have bad credentials. */
+  if (! cred)
+    return EOPNOTSUPP;
+  else if (! (cred->po->openmodes & O_READ))
+    return EBADF;
+
+
+  mutex_lock (&global_lock);
+  while (amount > kbdbuf.size)
+    {
+      if (cred->po->openmodes & O_NONBLOCK && amount > kbdbuf.size)
+	{
+	  mutex_unlock (&global_lock);
+	  return EWOULDBLOCK;
+	}
+
+      if (hurd_condition_wait (&kbdbuf.readcond, &global_lock))
+	{
+	  mutex_unlock (&global_lock);
+	  return EINTR;
+	}
+    }
+  
+  if (amount > 0)
+    {
+      char *keydata;
+      unsigned int i = 0;
+
+      /* Allocate a buffer when this is required.  */
+      if (*data_len < amount)
+	{
+	  *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+	  if (*data == MAP_FAILED)
+	    {
+	      mutex_unlock (&global_lock);
+	      return ENOMEM;
+	    }
+	}
+
+      /* Copy the bytes to the user's buffer and remove them from the
+	 keyboard buffer.  */
+      keydata = *data;
+      while (i != amount)
+	{
+	  keydata[i++] = kbdbuf.keybuffer[kbdbuf.pos++];
+	  kbdbuf.pos = KBDBUF_POS (kbdbuf.pos);
+	}
+      kbdbuf.size -= amount;
+      condition_broadcast (&kbdbuf.writecond);
+    }
+  
+  *data_len = amount;
+  mutex_unlock (&global_lock);
+
+  return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+		  mach_port_t reply, mach_msg_type_name_t reply_type,
+		  off_t offs, int whence, off_t *new_offs)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+  else
+    return ESPIPE;
+}
+
+
+/* If this variable is set, it is called every time a new peropen
+   structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+   is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+
+/* Some RPC calls for controlling the keyboard.  These calls are just
+   ignored and just exist to make XFree happy.  */
+
+kern_return_t
+S_kdioctl_kdskbdmode (io_t port, int mode)
+{
+  return 0;
+}
+
+
+kern_return_t
+S_kdioctl_kdgkbdmode (io_t port, int *mode)
+{
+  return 0;
+}
Index: pc-kbd.c
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/pc-kbd.c,v
retrieving revision 1.9
diff -u -p -u -p -r1.9 pc-kbd.c
--- pc-kbd.c	2 Feb 2004 22:08:14 -0000	1.9
+++ pc-kbd.c	13 Mar 2004 16:35:32 -0000
@@ -31,6 +31,7 @@
 #include <hurd/cons.h>
 
 #include "driver.h"
+#include "inputdev.h"
 
 
 /* The keyboard device in the kernel.  */
@@ -52,6 +53,10 @@ int gnumach_v1_compat;
 /* Forward declaration.  */
 static struct input_ops pc_kbd_ops;
 
+
+/* The node on which the repeater translator is set.  */
+static char *repeater_node;
+
 
 /* A list of scan codes generated by the keyboard, in the set 2 encoding.  */
 enum scancode
@@ -558,87 +563,6 @@ enum scancode sc_set1_to_set2_x1[] =
     SC_X1_DEL
   };
 
-
-/* This gross stuff is cut & pasted from Mach sources, as Mach doesn't
-   export the interface we are using here.  */
-
-/*
- * Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
- *  School of Computer Science
- *  Carnegie Mellon University
- *  Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
-
-typedef u_short kev_type;               /* kd event type */
-
-/* (used for event records) */
-struct mouse_motion {
-  short mm_deltaX;                /* units? */
-  short mm_deltaY;
-};
-typedef u_char Scancode;
-
-typedef struct {
-  kev_type type;                  /* see below */
-  struct timeval time;            /* timestamp */
-  union {                         /* value associated with event */
-    boolean_t up;           /* MOUSE_LEFT .. MOUSE_RIGHT */
-    Scancode sc;            /* KEYBD_EVENT */
-    struct mouse_motion mmotion;    /* MOUSE_MOTION */
-  } value;
-} kd_event;
-#define m_deltaX        mmotion.mm_deltaX
-#define m_deltaY        mmotion.mm_deltaY
-
-/*
- * kd_event ID's.
- */
-#define MOUSE_LEFT      1               /* mouse left button up/down */
-#define MOUSE_MIDDLE    2
-#define MOUSE_RIGHT     3
-#define MOUSE_MOTION    4               /* mouse motion */
-#define KEYBD_EVENT     5               /* key up/down */
-
-
-#define IOCPARM_MASK    0x1fff          /* parameter length, at most 13 bits */
-#define IOC_OUT         0x40000000      /* copy out parameters */
-#define IOC_IN          0x80000000U     /* copy in parameters */
-#define _IOC(inout,group,num,len) \
-        (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
-#define _IOR(g,n,t)     _IOC(IOC_OUT,   (g), (n), sizeof(t))
-#define _IOW(g,n,t)     _IOC(IOC_IN,    (g), (n), sizeof(t))
-
-#define KDSKBDMODE      _IOW('K', 1, int)       /* set keyboard mode */
-#define KB_EVENT        1
-#define KB_ASCII        2
-
-#define KDGKBDTYPE      _IOR('K', 2, int)       /* get keyboard type */
-#define KB_VANILLAKB    0
-
-#define KDSETLEDS      _IOW('K', 5, int)        /* set keyboard leds */
-
-
-/* End of Mach code.  */
-
 static enum scancode
 gnumach_v1_input_next ()
 {
@@ -658,6 +582,13 @@ gnumach_v1_input_next ()
 	 terminate.  */
       if (err)
 	return 0;
+
+      if (kbd_repeater_opened && data_buf.type == KEYBD_EVENT)
+	{
+	  repeat_key (&data_buf);
+	  data_buf.type = 0;
+	  continue;
+	}
     }
   while (data_buf.type != KEYBD_EVENT);
 
@@ -1092,6 +1023,12 @@ input_loop (any_t unused)
 static error_t
 pc_kbd_init (void **handle, int no_exit, int argc, char *argv[], int *next)
 {
+  if (!strcmp (argv[*next], "--repeat"))
+    {
+      (*next)++;
+      repeater_node = argv[(*next)++];
+    }
+
   return 0;
 }
 
@@ -1156,6 +1093,10 @@ pc_kbd_start (void *handle)
       iconv_close (cd);
       return err;
     }
+
+  if (repeater_node)
+    setrepeater (repeater_node);
+
   cthread_detach (cthread_fork (input_loop, NULL));
 
   return 0;
