Patchwork Add support for multiple simultaneously used keyboard devices.

login
register
mail settings
Submitter Filip Navara
Date Oct. 24, 2009, 3:09 p.m.
Message ID <E1N1hIq-0004SO-Eo@lists.gnu.org>
Download mbox | patch
Permalink /patch/36842/
State New
Headers show

Comments

Filip Navara - Oct. 24, 2009, 3:09 p.m.
The support for multiple keyboard devices is essential for emulating embedded boards where multiple input devices are present (eg. keypad and rotary encoder) which are implemented using separate QEMU devices.

Signed-off-by: Filip Navara <filip.navara@gmail.com>
---
 console.h  |   11 ++++++++++-
 hw/xenfb.c |    8 ++++++--
 vl.c       |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 69 insertions(+), 10 deletions(-)
Juha.Riihimaki@nokia.com - Oct. 26, 2009, 5:27 a.m.
On Oct 24, 2009, at 18:09, ext Filip Navara wrote:

> The support for multiple keyboard devices is essential for emulating  
> embedded boards where multiple input devices are present (eg. keypad  
> and rotary encoder) which are implemented using separate QEMU devices.

Nice to see someone else needs this as well. I just did a very similar  
implementation a short while ago.


Regards,
Juha
Anthony Liguori - Nov. 9, 2009, 2:35 p.m.
Filip Navara wrote:
> The support for multiple keyboard devices is essential for emulating embedded boards where multiple input devices are present (eg. keypad and rotary encoder) which are implemented using separate QEMU devices.
>
> Signed-off-by: Filip Navara <filip.navara@gmail.com>
>   

What boards would we actually expose multiple keyboards with?

Moreover, we're not doing anything useful here.  We're just repeating a 
single keypress to multiple keyboards which seems rather hackish.

Regards,

Anthony Liguori
Filip Navara - Nov. 11, 2009, 6:17 p.m.
On Mon, Nov 9, 2009 at 3:35 PM, Anthony Liguori <anthony@codemonkey.ws>wrote:

> Filip Navara wrote:
>
>> The support for multiple keyboard devices is essential for emulating
>> embedded boards where multiple input devices are present (eg. keypad and
>> rotary encoder) which are implemented using separate QEMU devices.
>>
>> Signed-off-by: Filip Navara <filip.navara@gmail.com>
>>
>>
>
> What boards would we actually expose multiple keyboards with?
>

The one that I was about to submit in the next weeks and which I sent
patches for few months ago (search for AT91). It is a custom board with
rotary encoder and matrix keyboard, quite a common configuration. The PXA
controllers even have special "GPIO" pins for these two input devices.

Moreover, we're not doing anything useful here.  We're just repeating a
> single keypress to multiple keyboards which seems rather hackish.
>

The embedded systems I target don't have keyboards in the traditional sense,
they have some input devices connected to the GPIO controller. These input
devices could be reduced keyboards (eg. like on the classic mobile phones),
various kinds of buttons, rotary encoders and so on. Since no direct mapping
exists for these input devices on PC, the easiest way to emulate the input
is with real keyboard.

What I am trying to accomplish is to allow these emulated devices each
handle a distinct subset of the PC keys. The matrix keyboard emulation would
capture the numbers and few other keys and ignore the rest. The rotary
encoder would capture arrows and ignore the rest.

Current QEMU emulations hack it by hard-coding all the real input devices
into one emulated device, which is specific for the board and not reusable.
My emulation is based on the QDEV model and the approach used in Paul Brooks
machine description patches.

Obviously I am open to suggestions on how to better handle this.

Best regards,
Filip Navara

Patch

diff --git a/console.h b/console.h
index 9615f56..568d097 100644
--- a/console.h
+++ b/console.h
@@ -26,7 +26,16 @@  typedef struct QEMUPutMouseEntry {
     struct QEMUPutMouseEntry *next;
 } QEMUPutMouseEntry;
 
-void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
+typedef struct QEMUPutKeyboardEntry {
+    QEMUPutKBDEvent *qemu_put_kbd_event;
+    void *qemu_put_kbd_event_opaque;
+
+    /* used internally by qemu for handling mice */
+    struct QEMUPutKeyboardEntry *next;
+} QEMUPutKeyboardEntry;
+
+QEMUPutKeyboardEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
+void qemu_remove_kbd_event_handler(QEMUPutKeyboardEntry *entry);
 QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
                                                 void *opaque, int absolute,
                                                 const char *name);
diff --git a/hw/xenfb.c b/hw/xenfb.c
index 795a326..090f857 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -68,6 +68,7 @@  struct XenInput {
     int button_state;       /* Last seen pointer button state */
     int extended;
     QEMUPutMouseEntry *qmouse;
+    QEMUPutKeyboardEntry *qkeyboard;
 };
 
 #define UP_QUEUE 8
@@ -373,7 +374,7 @@  static int input_connect(struct XenDevice *xendev)
     if (rc != 0)
 	return rc;
 
-    qemu_add_kbd_event_handler(xenfb_key_event, in);
+    in->qkeyboard = qemu_add_kbd_event_handler(xenfb_key_event, in);
     in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
 					      in->abs_pointer_wanted,
 					      "Xen PVFB Mouse");
@@ -388,7 +389,10 @@  static void input_disconnect(struct XenDevice *xendev)
 	qemu_remove_mouse_event_handler(in->qmouse);
 	in->qmouse = NULL;
     }
-    qemu_add_kbd_event_handler(NULL, NULL);
+    if (in->qkeyboard) {
+	qemu_remove_kbd_event_handler(in->qkeyboard);
+	in->qkeyboard = NULL;
+    }
     common_unbind(&in->c);
 }
 
diff --git a/vl.c b/vl.c
index eb2744e..1bb7d40 100644
--- a/vl.c
+++ b/vl.c
@@ -346,15 +346,57 @@  ram_addr_t qemu_balloon_status(void)
 /***********************************************************/
 /* keyboard/mouse */
 
-static QEMUPutKBDEvent *qemu_put_kbd_event;
-static void *qemu_put_kbd_event_opaque;
+static QEMUPutKeyboardEntry *qemu_put_kbd_event_head;
 static QEMUPutMouseEntry *qemu_put_mouse_event_head;
 static QEMUPutMouseEntry *qemu_put_mouse_event_current;
 
-void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
+QEMUPutKeyboardEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
 {
-    qemu_put_kbd_event_opaque = opaque;
-    qemu_put_kbd_event = func;
+    QEMUPutKeyboardEntry *s, *cursor;
+
+    s = qemu_mallocz(sizeof(QEMUPutKeyboardEntry));
+
+    s->qemu_put_kbd_event = func;
+    s->qemu_put_kbd_event_opaque = opaque;
+    s->next = NULL;
+
+    if (!qemu_put_kbd_event_head) {
+        qemu_put_kbd_event_head = s;
+        return s;
+    }
+
+    cursor = qemu_put_kbd_event_head;
+    while (cursor->next != NULL)
+        cursor = cursor->next;
+
+    cursor->next = s;
+
+    return s;
+}
+
+void qemu_remove_kbd_event_handler(QEMUPutKeyboardEntry *entry)
+{
+    QEMUPutKeyboardEntry *prev = NULL, *cursor;
+
+    if (!qemu_put_kbd_event_head || entry == NULL)
+        return;
+
+    cursor = qemu_put_kbd_event_head;
+    while (cursor != NULL && cursor != entry) {
+        prev = cursor;
+        cursor = cursor->next;
+    }
+
+    if (cursor == NULL) // does not exist or list empty
+        return;
+    else if (prev == NULL) { // entry is head
+        qemu_put_kbd_event_head = cursor->next;
+        qemu_free(entry);
+        return;
+    }
+
+    prev->next = entry->next;
+    qemu_free(entry);
 }
 
 QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
@@ -421,8 +463,12 @@  void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
 
 void kbd_put_keycode(int keycode)
 {
-    if (qemu_put_kbd_event) {
-        qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
+    QEMUPutKeyboardEntry *cursor;
+
+    cursor = qemu_put_kbd_event_head;
+    while (cursor != NULL) {
+        cursor->qemu_put_kbd_event(cursor->qemu_put_kbd_event_opaque, keycode);
+        cursor = cursor->next;
     }
 }