From 0985f9bfec1ddb3e49983e2a91e2a8fdf7dc98ce Mon Sep 17 00:00:00 2001 From: Benjamin David Lunt Date: Sun, 9 Apr 2023 10:44:00 -0700 Subject: [PATCH] hid mouse improvements --- bochs/iodev/usb/usb_common.cc | 8 +- bochs/iodev/usb/usb_hid.cc | 1188 ++++++++++++++++++++++++--------- bochs/iodev/usb/usb_hid.h | 96 ++- 3 files changed, 980 insertions(+), 312 deletions(-) diff --git a/bochs/iodev/usb/usb_common.cc b/bochs/iodev/usb/usb_common.cc index aab0b2c4a..ec5cf4082 100644 --- a/bochs/iodev/usb/usb_common.cc +++ b/bochs/iodev/usb/usb_common.cc @@ -455,7 +455,11 @@ int usb_device_c::handle_packet(USBPacket *p) #endif memcpy(data, d.data_buf + d.setup_index, l); d.setup_index += l; - if (d.setup_index >= d.setup_len) + // if the count of bytes transfered is an even packet size, we have to allow the host controller to (possibly) do a short packet + // on the next zero byte transfer, so even if d.setup_index == d.setup_len we still have to allow another packet to be processed before + // we go to SETUP_STATE_ACK. If there is not another IN packet (meaning the STATUS packet is next), the OUT code below handles + // the STATUS stage for us. + if ((d.setup_index >= d.setup_len) && (l < get_mps(USB_CONTROL_EP))) d.setup_state = SETUP_STATE_ACK; ret = l; usb_dump_packet(data, ret, 0, p->devaddr, USB_DIR_IN | p->devep, USB_TRANS_TYPE_CONTROL, false, true); @@ -537,6 +541,8 @@ int usb_device_c::handle_packet(USBPacket *p) // it is okay for a host to send an OUT before it reads // all of the expected IN. It is telling the controller // that it doesn't want any more from that particular call. + // or + // we have (unexpectedly) encountered the STATUS packet. ret = 0; d.setup_state = SETUP_STATE_IDLE; } diff --git a/bochs/iodev/usb/usb_hid.cc b/bochs/iodev/usb/usb_hid.cc index 4141352b1..160505f61 100644 --- a/bochs/iodev/usb/usb_hid.cc +++ b/bochs/iodev/usb/usb_hid.cc @@ -2,12 +2,12 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// USB HID emulation support (mouse and tablet) ported from QEMU -// USB keypad emulation based on code by Benjamin D Lunt (fys [at] fysnet [dot] net) -// USB keyboard emulation is an extension to the keypad based on specs +// USB HID emulation support (mouse and tablet) originally ported from QEMU +// Current USB emulation based on code by Benjamin D Lunt (fys [at] fysnet [dot] net) // // Copyright (c) 2005 Fabrice Bellard // Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) +// Copyright (C) 2004-2023 Benjamin D Lunt (fys [at] fysnet [dot] net) // Copyright (C) 2009-2023 The Bochs Project // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -28,24 +28,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. ///////////////////////////////////////////////////////////////////////// -// Portions of this file contain code released under the LGPL. -// -// Copyright (C) 2004-2023 Benjamin D Lunt (fys [at] fysnet [dot] net) -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -///////////////////////////////////////////////////////////////////////// // Define BX_PLUGGABLE in files that can be compiled into plugins. For // platforms that require a special tag on exported symbols, BX_PLUGGABLE @@ -104,11 +86,6 @@ protected: #define PROTOCOL_BOOT 0 #define PROTOCOL_REPORT 1 -struct USBKBD { - Bit8u code; - bool modkey; -}; - // If you change any of the Max Packet Size, or other fields within these // descriptors, you must also change the d.endpoint_info[] array // to match your changes. @@ -155,7 +132,170 @@ static const Bit8u bx_mouse_dev_descriptor2[] = { 0x01 /* u8 bNumConfigurations; */ }; -static const Bit8u bx_mouse_hid_report_descriptor[] = { +// The following hid report descriptors are for the mouse/tablet +// depending on the model given. + +// hid_mouse_2x2x8 +// default 2-button, 3-byte, X and Y coords, 8-bit (+ report id) +// 00000001 (report id) +// 000000BB +// XXXXXXXX +// YYYYYYYY +static const Bit8u bx_mouse_hid_report_descriptor_228[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0x85, HID_REPORT_ID, // Report ID (HID_REPORT_ID) + 0x89, HID_CLASS_STR4, // Starting String Index (4) + 0x99, HID_CLASS_STR5, // Ending String Index (5) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x02, // Usage Maximum (0x02) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x02, // Report Count (2) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x06, // Report Size (6) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x95, 0x02, // Report Count (2) + 0x15, 0x80, // Logical Minimum (-128) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0 // End Collection +}; + +// hid_mouse_3x3x8 +// 3-button, 4-byte X, Y, and Wheel coords, 8-bit +// 00000BBB +// XXXXXXXX +// YYYYYYYY +// WWWWWWWW +static const Bit8u bx_mouse_hid_report_descriptor_338[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0x89, HID_CLASS_STR4, // Starting String Index (4) + 0x99, HID_CLASS_STR5, // Ending String Index (5) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x03, // Usage Maximum (0x03) + 0x95, 0x03, // Report Count (3) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x05, // Report Size (5) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x95, 0x03, // Report Count (3) + 0x15, 0x80, // Logical Minimum (-128) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +// this model is deliberately irregular by design, so that a Guest can test its HID Report Descriptor Parser. +// - the button fields are not consecutive and are at arbitrary positions in the report. +// - the coords fields are not byte aligned or consecutively spaced. +// - the coords fields are of an irregular size, each a different size. +// - there are padding fields between entries that *do not* align the next field on a byte boundary. +// - this also uses he push/pop mechanism to test the function of your parser. +// (Again, this is deliberate. A correctly written parser will extract the neccessary fields no matter the irregularity) +// hid_mouse_3x3xDebug +// 3-button, 5-byte X, Y, and Wheel coords (debug model) +// YYYYYYY0 - 10 bit Y displacement +// WWWW0YYY - 8 bit W displacement +// 0B00WWWW - bit 6 is Button #2 (right button) +// XXXXX0B0 - 9 bit X displacement, bit 1 is Button #1 (left button) +// 0B00XXXX - bit 6 is Button #3 (middle button) +static const Bit8u bx_mouse_hid_report_descriptor_33debug[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x95, 0x01, // Report Count (1) + 0x75, 0x01, // Report Size (1) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x00, // Logical Maximum (0) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, // Usage (Y) + 0x75, 0x0A, // Report Size (10) + 0x16, 0x00, 0xFE, // Logical Minimum (-512) + 0x26, 0xFF, 0x01, // Logical Maximum (511) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x38, // Usage (Wheel) + 0x75, 0x08, // Report Size (8) + 0x15, 0x80, // Logical Minimum (-128) + 0x25, 0x7F, // Logical Maximum (127) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xA4, // Push + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0xA4, // Push + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x09, // Usage Page (Button) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x09, 0x02, // Usage (0x02) + 0x95, 0x01, // Report Count (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xB4, // Pop + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x09, // Usage Page (Button) + 0x09, 0x01, // Usage (0x01) + 0x95, 0x01, // Report Count (1) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xB4, // Pop + 0x09, 0x30, // Usage (X) + 0x75, 0x09, // Report Size (9) + 0x16, 0x00, 0xFF, // Logical Minimum (-256) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x02, // Report Count (2) + 0x75, 0x01, // Report Size (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x09, // Usage Page (Button) + 0x09, 0x03, // Usage (0x03) + 0x95, 0x01, // Report Count (1) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +// hid_mouse_3x3x12 +// 3-button, 5-byte X, Y, and Wheel coords, 12-bit +// 00000BBB +// XXXXXXXX (lsb) +// YYYYXXXX (lsb of y, msb of x) +// YYYYYYYY (msb) +// WWWWWWWW +static const Bit8u bx_mouse_hid_report_descriptor_3312[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) @@ -175,17 +315,111 @@ static const Bit8u bx_mouse_hid_report_descriptor[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) + 0x95, 0x02, // Report Count (2) + 0x16, 0x00, 0xF8, // Logical Minimum (-2048) + 0x26, 0xFF, 0x07, // Logical Maximum (2047) + 0x75, 0x0C, // Report Size (12) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0x09, 0x38, // Usage (Wheel) - 0x15, 0x81, // Logical Minimum (-127) + 0x95, 0x01, // Report Count (1) + 0x15, 0x80, // Logical Minimum (-128) 0x25, 0x7F, // Logical Maximum (127) 0x75, 0x08, // Report Size (8) - 0x95, 0x03, // Report Count (3) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xC0, // End Collection }; -static const Bit8u bx_mouse_config_descriptor[] = { +// hid_mouse_3x3x16 +// 3-button, 6-byte X, Y, and Wheel coords, 16-bit +// 00000BBB +// XXXXXXXX (lsb) +// XXXXXXXX (msb) +// YYYYYYYY (lsb) +// YYYYYYYY (msb) +// WWWWWWWW +static const Bit8u bx_mouse_hid_report_descriptor_3316[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x03, // Usage Maximum (0x03) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x03, // Report Count (3) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x05, // Report Size (5) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x95, 0x02, // Report Count (2) + 0x16, 0x00, 0x80, // Logical Minimum (-32768) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x75, 0x10, // Report Size (16) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x38, // Usage (Wheel) + 0x95, 0x01, // Report Count (1) + 0x15, 0x80, // Logical Minimum (-128) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +// This Report Descriptor uses Designator values to point to an entry in the +// HID Physical Descriptor. WinXP doesn't like the Designator entries, so +// don't use this model when using a WinXP guest. +// hid_mouse_3x3x8phy +// 3-button, 3-byte X, Y, and Wheel coords, 8-bit +// 00000BBB +// XXXXXXXX +// YYYYYYYY +// WWWWWWWW +static const Bit8u bx_mouse_hid_report_descriptor_338phy[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0x89, HID_CLASS_STR4, // Starting String Index (4) + 0x99, HID_CLASS_STR5, // Ending String Index (5) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x03, // Usage Maximum (0x03) + 0x95, 0x03, // Report Count (3) + 0x75, 0x01, // Report Size (1) + 0x49, 0x01, // Designator Minimum (1) + 0x59, 0x03, // Designator Maximum (3) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x05, // Report Size (5) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x95, 0x03, // Report Count (3) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +// standard low-, full-speed configuration (w/o physical descriptor) +// (this define must be the zero based byte offset of the HID length field below) +#define BX_Mouse_Config_Descriptor0_pos 25 +static Bit8u bx_mouse_config_descriptor0[] = { /* one configuration */ 0x09, /* u8 bLength; */ 0x02, /* u8 bDescriptorType; Configuration */ @@ -194,10 +428,10 @@ static const Bit8u bx_mouse_config_descriptor[] = { 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ 50, /* u8 MaxPower; */ /* one interface */ @@ -214,34 +448,108 @@ static const Bit8u bx_mouse_config_descriptor[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_mouse_hid_report_descriptor), 0, /* u16 len */ - + 0x00, 0x00, /* u16 len (updated on the fly) */ + /* one endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x04, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ 0x0a, /* u8 ep_bInterval; (0 - 255ms -- usb 2.0 spec) */ }; -static const Bit8u bx_mouse_config_descriptor2[] = { +#define HID_PHYS_DESC_SET_LEN 7 +static const Bit8u bx_mouse_phys_descriptor[] = { + /* HID Physical descriptor */ + /* Descriptor set 0 */ + 0x02, /* u8 Number of physical Descriptor sets to follow */ + HID_PHYS_DESC_SET_LEN, /* u8 Length of each descriptor set */ + 0x00, 0x00, 0x00, 0x00, 0x00, /* pad to HID_PHYS_DESC_SET_LEN bytes */ + + /* Descriptor set 1 */ + (HID_PHYS_BIAS_RIGHT_HAND << 5) | 0, /* u8 bPhysicalInfo; (right hand, 0 = most prefered) */ + IndexFinger, (Right << 5) | 0, /* u8*2 DescritorData[0] (index 1) (Index Finger, right, 0 = easy */ + MiddleFinger, (Right << 5) | 0, /* u8*2 DescritorData[1] (index 2) (Middle Finger, right, 0 = easy */ + IndexFinger, (Right << 5) | 0, /* u8*2 DescritorData[2] (index 3) (Index Finger, right, 0 = easy */ + + /* Descriptor set 2 */ + (HID_PHYS_BIAS_LEFT_HAND << 5) | 1, /* u8 bPhysicalInfo; (left hand, 1 = next prefered) */ + MiddleFinger, (Left << 5) | 0, /* u8*2 DescritorData[0] (index 1) (Middle Finger, left, 0 = easy */ + IndexFinger, (Left << 5) | 0, /* u8*2 DescritorData[1] (index 2) (Index Finger, left, 0 = easy */ + IndexFinger, (Left << 5) | 0, /* u8*2 DescritorData[2] (index 3) (Index Finger, left, 0 = easy */ +}; + +// standard low-, full-speed configuration (w/ physical descriptor) +// (this define must be the zero based byte offset of the HID length field below) +#define BX_Mouse_Config_Descriptor1_pos 25 +static Bit8u bx_mouse_config_descriptor1[] = { /* one configuration */ 0x09, /* u8 bLength; */ 0x02, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ + 0x25, 0x00, /* u16 wTotalLength; */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; */ + 0x05, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x0C, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ + 0x00, /* u8 country_code */ + 0x02, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 0x00, 0x00, /* u16 len (updated on the fly) */ + 0x23, /* u8 type; Physical */ + sizeof(bx_mouse_phys_descriptor), + 0x00, /* u16 len */ + + /* one endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (0 - 255ms -- usb 2.0 spec) */ +}; + +// standard high-speed configuration (w/o physical descriptor) +// (this define must be the zero based byte offset of the HID length field below) +#define BX_Mouse_Config_Descriptor2_pos 25 +static Bit8u bx_mouse_config_descriptor2[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x25, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ 50, /* u8 MaxPower; */ /* one interface */ @@ -258,37 +566,57 @@ static const Bit8u bx_mouse_config_descriptor2[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_mouse_hid_report_descriptor), 0, /* u16 len */ + 0x00, 0x00, /* u16 len (updated on the fly) */ /* one endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x04, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ 0x07, /* u8 ep_bInterval; (2 ^ (8-1) * 125 usecs = 8 ms) */ }; -static const Bit8u bx_mouse_hid_descriptor[] = { +// standard hid descriptor (w/o physical descriptor) +// (this define must be the zero based byte offset of the HID length field below) +#define BX_Mouse_Hid_Descriptor0 7 +static Bit8u bx_mouse_hid_descriptor0[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_mouse_hid_report_descriptor), 0, /* u16 len */ + 0x00, 0x00, /* u16 len (updated on the fly) */ +}; + +// standard hid descriptor (w/ physical descriptor) +// (this define must be the zero based byte offset of the HID length field below) +#define BX_Mouse_Hid_Descriptor1 7 +static Bit8u bx_mouse_hid_descriptor1[] = { + /* HID descriptor */ + 0x0C, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ + 0x00, /* u8 country_code */ + 0x02, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 0x00, 0x00, /* u16 len (updated on the fly) */ + 0x23, /* u8 type; Physical */ + sizeof(bx_mouse_phys_descriptor), + 0x00, /* u16 len */ }; //////////////////////////////////////////////// // tablet static const Bit8u bx_tablet_hid_report_descriptor[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x01, // Usage (Pointer) + 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) @@ -335,10 +663,10 @@ static const Bit8u bx_tablet_config_descriptor[] = { 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ 50, /* u8 MaxPower; */ /* one interface */ @@ -355,18 +683,19 @@ static const Bit8u bx_tablet_config_descriptor[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_tablet_hid_report_descriptor), 0, /* u16 len */ + sizeof(bx_tablet_hid_report_descriptor), + 0x00, /* u16 len */ /* one endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x06, 0x00, /* u16 ep_wMaxPacketSize; */ 0x0a, /* u8 ep_bInterval; (0 - 255ms -- usb 2.0 spec) */ }; @@ -379,10 +708,10 @@ static const Bit8u bx_tablet_config_descriptor2[] = { 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ 50, /* u8 MaxPower; */ /* one interface */ @@ -399,18 +728,19 @@ static const Bit8u bx_tablet_config_descriptor2[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_tablet_hid_report_descriptor), 0, /* u16 len */ + sizeof(bx_tablet_hid_report_descriptor), + 0x00, /* u16 len */ /* one endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x06, 0x00, /* u16 ep_wMaxPacketSize; */ 0x04, /* u8 ep_bInterval; (2 ^ (4-1) * 125 usecs = 1 ms) */ }; @@ -418,22 +748,23 @@ static const Bit8u bx_tablet_hid_descriptor[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_tablet_hid_report_descriptor), 0, /* u16 len */ + sizeof(bx_tablet_hid_report_descriptor), + 0x00, /* u16 len */ }; //////////////////////////////////////////////// -// keypad +// keyboard/keypad static const Bit8u bx_keypad_hid_report_descriptor[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0xE0, // Usage Minimum (0xE0) - 0x29, 0xE7, // Usage Maximum (0xE7) + 0x19, 0xE0, // Usage Minimum (Keyboard Left Control) + 0x29, 0xE7, // Usage Maximum (Keyboard Right GUI) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) @@ -456,8 +787,8 @@ static const Bit8u bx_keypad_hid_report_descriptor[] = { 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0x00, // Usage Minimum (0x00) - 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF) + 0x19, 0x00, // Usage Minimum (0) + 0x29, 0xE7, // Usage Maximum (Keyboard Right GUI) 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection }; @@ -511,10 +842,10 @@ static const Bit8u bx_keypad_config_descriptor[] = { 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ 50, /* u8 MaxPower; */ /* one interface */ @@ -531,11 +862,12 @@ static const Bit8u bx_keypad_config_descriptor[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_keypad_hid_report_descriptor), 0, /* u16 len */ + sizeof(bx_keypad_hid_report_descriptor), + 0x00, /* u16 len */ /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ @@ -555,10 +887,10 @@ static const Bit8u bx_keypad_config_descriptor2[] = { 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ 50, /* u8 MaxPower; */ /* one interface */ @@ -575,11 +907,12 @@ static const Bit8u bx_keypad_config_descriptor2[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_keypad_hid_report_descriptor), 0, /* u16 len */ + sizeof(bx_keypad_hid_report_descriptor), + 0x00, /* u16 len */ /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ @@ -594,133 +927,146 @@ static const Bit8u bx_keypad_hid_descriptor[] = { /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ - 0x00, 0x01, /* u16 HID_class */ + 0x01, 0x01, /* u16 HID_class (0x0101) */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - sizeof(bx_keypad_hid_report_descriptor), 0, /* u16 len */ + sizeof(bx_keypad_hid_report_descriptor), + 0x00, /* u16 len */ }; +// just for fun: if it is a modifying key, the high-nibble will be 0xE, +// while the low-nibble is the bit position in the packet.Modifier byte :-) struct USBKBD usbkbd_conv[BX_KEY_NBKEYS] = { - 0x01, 1, - 0x02, 1, - 0x3a, 0, /* F1 ... F12 */ - 0x3b, 0, - 0x3c, 0, - 0x3d, 0, - 0x3e, 0, - 0x3f, 0, - 0x40, 0, - 0x41, 0, - 0x42, 0, - 0x43, 0, - 0x44, 0, - 0x45, 0, - 0x10, 1, - 0x20, 1, - 0x39, 0, - 0x53, 0, - 0x04, 1, - 0x40, 1, - 0x04, 0, /* a ... z */ - 0x05, 0, - 0x06, 0, - 0x07, 0, - 0x08, 0, - 0x09, 0, - 0x0a, 0, - 0x0b, 0, - 0x0c, 0, - 0x0d, 0, - 0x0e, 0, - 0x0f, 0, - 0x10, 0, - 0x11, 0, - 0x12, 0, - 0x13, 0, - 0x14, 0, - 0x15, 0, - 0x16, 0, - 0x17, 0, - 0x18, 0, - 0x19, 0, - 0x1a, 0, - 0x1b, 0, - 0x1c, 0, - 0x1d, 0, - 0x27, 0, /* 0 ... 9 */ - 0x1e, 0, - 0x1f, 0, - 0x20, 0, - 0x21, 0, - 0x22, 0, - 0x23, 0, - 0x24, 0, - 0x25, 0, - 0x26, 0, - 0x29, 0, - 0x2c, 0, - 0x34, 0, - 0x36, 0, - 0x37, 0, - 0x38, 0, - 0x33, 0, - 0x2e, 0, - 0x2f, 0, - 0x31, 0, - 0x30, 0, - 0x2d, 0, - 0x35, 0, - 0x2a, 0, - 0x28, 0, - 0x2b, 0, - 0x64, 0, - 0x46, 0, - 0x47, 0, - 0x48, 0, - 0x49, 0, - 0x4c, 0, - 0x4a, 0, - 0x4d, 0, - 0x4b, 0, - 0x4e, 0, - 0x57, 0, - 0x56, 0, - 0x59, 0, - 0x5a, 0, - 0x5b, 0, - 0x5c, 0, - 0x5e, 0, - 0x5f, 0, - 0x60, 0, - 0x61, 0, - 0x62, 0, - 0x63, 0, - 0x5d, 0, - 0x52, 0, - 0x51, 0, - 0x50, 0, - 0x4f, 0, - 0x58, 0, - 0x55, 0, - 0x54, 0, - 0xe3, 0, - 0xe7, 0, - 0x65, 0, - 0x00, 0, /* BX_KEY_ALT_SYSREQ */ - 0x00, 0, /* BX_KEY_CTRL_BREAK */ - 0x00, 0, /* BX_KEY_INT_BACK */ - 0x00, 0, /* BX_KEY_INT_FORWARD */ - 0x00, 0, /* BX_KEY_INT_STOP */ - 0x00, 0, /* BX_KEY_INT_MAIL */ - 0x00, 0, /* BX_KEY_INT_SEARCH */ - 0x00, 0, /* BX_KEY_INT_FAV */ - 0x00, 0, /* BX_KEY_INT_HOME */ - 0x00, 0, /* BX_KEY_MYCOMP */ - 0x00, 0, /* BX_KEY_CALC */ - 0x00, 0, /* BX_KEY_SLEEP */ - 0x66, 0, - 0x00, 0 /* BX_KEY_WAKE */ + 0xE0, BX_MODS_LEFT_CTRL, // BX_KEY_CTRL_L (Bit 0 in packet.Modifier byte) + 0xE1, BX_MODS_LEFT_SHIFT, // BX_KEY_SHIFT_L (Bit 1 in packet.Modifier byte) + + 0x3A, BX_MODS_NONE, // F1 ... F12 + 0x3B, BX_MODS_NONE, + 0x3C, BX_MODS_NONE, + 0x3D, BX_MODS_NONE, + 0x3E, BX_MODS_NONE, + 0x3F, BX_MODS_NONE, + 0x40, BX_MODS_NONE, + 0x41, BX_MODS_NONE, + 0x42, BX_MODS_NONE, + 0x43, BX_MODS_NONE, + 0x44, BX_MODS_NONE, + 0x45, BX_MODS_NONE, + + 0xE4, BX_MODS_RIGHT_CTRL, // BX_KEY_CTRL_R (Bit 4 in packet.Modifier byte) + 0xE5, BX_MODS_RIGHT_SHIFT, // BX_KEY_SHIFT_R (Bit 5 in packet.Modifier byte) + 0x39, BX_MODS_NONE, // BX_KEY_CAPS_LOCK + 0x53, BX_MODS_NONE, // BX_KEY_NUM_LOCK + 0xE2, BX_MODS_LEFT_ALT, // BX_KEY_ALT_L (Bit 2 in packet.Modifier byte) + 0xE6, BX_MODS_RIGHT_ALT, // BX_KEY_ALT_R (Bit 6 in packet.Modifier byte) + + 0x04, BX_MODS_NONE, // A ... Z + 0x05, BX_MODS_NONE, + 0x06, BX_MODS_NONE, + 0x07, BX_MODS_NONE, + 0x08, BX_MODS_NONE, + 0x09, BX_MODS_NONE, + 0x0A, BX_MODS_NONE, + 0x0B, BX_MODS_NONE, + 0x0C, BX_MODS_NONE, + 0x0D, BX_MODS_NONE, + 0x0E, BX_MODS_NONE, + 0x0F, BX_MODS_NONE, + 0x10, BX_MODS_NONE, + 0x11, BX_MODS_NONE, + 0x12, BX_MODS_NONE, + 0x13, BX_MODS_NONE, + 0x14, BX_MODS_NONE, + 0x15, BX_MODS_NONE, + 0x16, BX_MODS_NONE, + 0x17, BX_MODS_NONE, + 0x18, BX_MODS_NONE, + 0x19, BX_MODS_NONE, + 0x1A, BX_MODS_NONE, + 0x1B, BX_MODS_NONE, + 0x1C, BX_MODS_NONE, + 0x1D, BX_MODS_NONE, + + 0x27, BX_MODS_NONE, // 0 ... 9 + 0x1E, BX_MODS_NONE, + 0x1F, BX_MODS_NONE, + 0x20, BX_MODS_NONE, + 0x21, BX_MODS_NONE, + 0x22, BX_MODS_NONE, + 0x23, BX_MODS_NONE, + 0x24, BX_MODS_NONE, + 0x25, BX_MODS_NONE, + 0x26, BX_MODS_NONE, + + 0x29, BX_MODS_NONE, // BX_KEY_ESC + 0x2C, BX_MODS_NONE, // BX_KEY_SPACE + 0x34, BX_MODS_NONE, // BX_KEY_SINGLE_QUOTE + 0x36, BX_MODS_NONE, // BX_KEY_COMMA + 0x37, BX_MODS_NONE, // BX_KEY_PERIOD + 0x38, BX_MODS_NONE, // BX_KEY_SLASH + 0x33, BX_MODS_NONE, // BX_KEY_SEMICOLON + 0x2E, BX_MODS_NONE, // BX_KEY_EQUALS + 0x2F, BX_MODS_NONE, // BX_KEY_LEFT_BRACKET + 0x31, BX_MODS_NONE, // BX_KEY_BACKSLASH + 0x30, BX_MODS_NONE, // BX_KEY_RIGHT_BRACKET + 0x2D, BX_MODS_NONE, // BX_KEY_MINUS + 0x35, BX_MODS_NONE, // BX_KEY_GRAVE + 0x2A, BX_MODS_NONE, // BX_KEY_BACKSPACE + 0x28, BX_MODS_NONE, // BX_KEY_ENTER + 0x2B, BX_MODS_NONE, // BX_KEY_TAB + 0x64, BX_MODS_NONE, // BX_KEY_LEFT_BACKSLASH + 0x46, BX_MODS_NONE, // BX_KEY_PRINT + 0x47, BX_MODS_NONE, // BX_KEY_SCRL_LOCK + 0x48, BX_MODS_NONE, // BX_KEY_PAUSE + 0x49, BX_MODS_NONE, // BX_KEY_INSERT + 0x4C, BX_MODS_NONE, // BX_KEY_DELETE + 0x4A, BX_MODS_NONE, // BX_KEY_HOME + 0x4D, BX_MODS_NONE, // BX_KEY_END + 0x4B, BX_MODS_NONE, // BX_KEY_PAGE_UP + 0x4E, BX_MODS_NONE, // BX_KEY_PAGE_DOWN + + 0x57, BX_MODS_NONE, // BX_KEY_KP_ADD + 0x56, BX_MODS_NONE, // BX_KEY_KP_SUBTRACT + 0x59, BX_MODS_NONE, // BX_KEY_KP_END + 0x5A, BX_MODS_NONE, // BX_KEY_KP_DOWN + 0x5B, BX_MODS_NONE, // BX_KEY_KP_PAGE_DOWN + 0x5C, BX_MODS_NONE, // BX_KEY_KP_LEFT + 0x5E, BX_MODS_NONE, // BX_KEY_KP_RIGHT + 0x5F, BX_MODS_NONE, // BX_KEY_KP_HOME + 0x60, BX_MODS_NONE, // BX_KEY_KP_UP + 0x61, BX_MODS_NONE, // BX_KEY_KP_PAGE_UP + 0x62, BX_MODS_NONE, // BX_KEY_KP_INSERT + 0x63, BX_MODS_NONE, // BX_KEY_KP_DELETE + 0x5D, BX_MODS_NONE, // BX_KEY_KP_5 + + 0x52, BX_MODS_NONE, // BX_KEY_UP + 0x51, BX_MODS_NONE, // BX_KEY_DOWN + 0x50, BX_MODS_NONE, // BX_KEY_LEFT + 0x4F, BX_MODS_NONE, // BX_KEY_RIGHT + + 0x58, BX_MODS_NONE, // BX_KEY_KP_ENTER + 0x55, BX_MODS_NONE, // BX_KEY_KP_MULTIPLY + 0x54, BX_MODS_NONE, // BX_KEY_KP_DIVIDE + + 0xE3, BX_MODS_LEFT_GUI, // BX_KEY_WIN_L (Bit 3 in packet.Modifier byte) + 0xE7, BX_MODS_RIGHT_GUI, // BX_KEY_WIN_R (Bit 7 in packet.Modifier byte) + 0x65, BX_MODS_NONE, // BX_KEY_MENU + + 0x9A, BX_MODS_NONE, // BX_KEY_ALT_SYSREQ + 0x00, BX_MODS_NONE, // BX_KEY_CTRL_BREAK + 0x00, BX_MODS_NONE, // BX_KEY_INT_BACK + 0x00, BX_MODS_NONE, // BX_KEY_INT_FORWARD + 0x78, BX_MODS_NONE, // BX_KEY_INT_STOP + 0x00, BX_MODS_NONE, // BX_KEY_INT_MAIL + 0x00, BX_MODS_NONE, // BX_KEY_INT_SEARCH + 0x00, BX_MODS_NONE, // BX_KEY_INT_FAV + 0x00, BX_MODS_NONE, // BX_KEY_INT_HOME + 0x00, BX_MODS_NONE, // BX_KEY_MYCOMP + 0x00, BX_MODS_NONE, // BX_KEY_CALC + 0x00, BX_MODS_NONE, // BX_KEY_SLEEP + 0x66, BX_MODS_NONE, // BX_KEY_POWER_POWER + 0x00, BX_MODS_NONE // BX_KEY_WAKE }; usb_hid_device_c::usb_hid_device_c(const char *devname) @@ -769,6 +1115,11 @@ usb_hid_device_c::usb_hid_device_c(const char *devname) // HID 1.11, section 7.2.6, page 54(64): // "When initialized, all devices default to report protocol." s.boot_protocol = PROTOCOL_REPORT; + s.report_id = 0; + if (d.type == USB_HID_TYPE_MOUSE) + s.model = hid_mouse_3x3x8; // default model + // next will be byte 2 in the 8 byte packet + s.kbd_packet_indx = 1; put("usb_hid", "USBHID"); } @@ -792,7 +1143,7 @@ bool usb_hid_device_c::init() * in the configuration, simply uncomment this line. I use * it when I am working on this emulation. */ - //LOG_THIS setonoff(LOGLEV_DEBUG, ACT_REPORT); + // LOG_THIS setonoff(LOGLEV_DEBUG, ACT_REPORT); if ((d.type == USB_HID_TYPE_MOUSE) || (d.type == USB_HID_TYPE_TABLET)) { @@ -801,14 +1152,14 @@ bool usb_hid_device_c::init() d.device_desc_size = sizeof(bx_mouse_dev_descriptor2); d.endpoint_info[USB_CONTROL_EP].max_packet_size = 64; // Control ep0 d.endpoint_info[USB_CONTROL_EP].max_burst_size = 0; - d.endpoint_info[1].max_packet_size = 4; // In ep1 + d.endpoint_info[1].max_packet_size = 8; // In ep1 d.endpoint_info[1].max_burst_size = 0; } else { d.dev_descriptor = bx_mouse_dev_descriptor; d.device_desc_size = sizeof(bx_mouse_dev_descriptor); d.endpoint_info[USB_CONTROL_EP].max_packet_size = 8; // Control ep0 d.endpoint_info[USB_CONTROL_EP].max_burst_size = 0; - d.endpoint_info[1].max_packet_size = 4; // In ep1 + d.endpoint_info[1].max_packet_size = 8; // In ep1 d.endpoint_info[1].max_burst_size = 0; } if (d.type == USB_HID_TYPE_MOUSE) { @@ -816,10 +1167,16 @@ bool usb_hid_device_c::init() d.config_descriptor = bx_mouse_config_descriptor2; d.config_desc_size = sizeof(bx_mouse_config_descriptor2); } else { - d.config_descriptor = bx_mouse_config_descriptor; - d.config_desc_size = sizeof(bx_mouse_config_descriptor); + if (s.model >= hid_mouse_3x3x8phy) { + d.config_descriptor = bx_mouse_config_descriptor1; + d.config_desc_size = sizeof(bx_mouse_config_descriptor1); + } else { + d.config_descriptor = bx_mouse_config_descriptor0; + d.config_desc_size = sizeof(bx_mouse_config_descriptor0); + } } } else { + // Tablet if (d.speed == USB_SPEED_HIGH) { d.config_descriptor = bx_tablet_config_descriptor2; d.config_desc_size = sizeof(bx_tablet_config_descriptor2); @@ -828,7 +1185,36 @@ bool usb_hid_device_c::init() d.config_desc_size = sizeof(bx_tablet_config_descriptor); } } - } else { + // initialize the correct hid descriptor + if (s.model == hid_mouse_2x2x8) { + s.bx_mouse_hid_report_descriptor = bx_mouse_hid_report_descriptor_228; + s.bx_mouse_hid_report_descriptor_len = sizeof(bx_mouse_hid_report_descriptor_228); + } else if (s.model == hid_mouse_3x3x8) { + s.bx_mouse_hid_report_descriptor = bx_mouse_hid_report_descriptor_338; + s.bx_mouse_hid_report_descriptor_len = sizeof(bx_mouse_hid_report_descriptor_338); + } else if (s.model == hid_mouse_3x3xDebug) { + s.bx_mouse_hid_report_descriptor = bx_mouse_hid_report_descriptor_33debug; + s.bx_mouse_hid_report_descriptor_len = sizeof(bx_mouse_hid_report_descriptor_33debug); + } else if (s.model == hid_mouse_3x3x12) { + s.bx_mouse_hid_report_descriptor = bx_mouse_hid_report_descriptor_3312; + s.bx_mouse_hid_report_descriptor_len = sizeof(bx_mouse_hid_report_descriptor_3312); + } else if (s.model == hid_mouse_3x3x16) { + s.bx_mouse_hid_report_descriptor = bx_mouse_hid_report_descriptor_3316; + s.bx_mouse_hid_report_descriptor_len = sizeof(bx_mouse_hid_report_descriptor_3316); + } else if (s.model == hid_mouse_3x3x8phy) { + s.bx_mouse_hid_report_descriptor = bx_mouse_hid_report_descriptor_338phy; + s.bx_mouse_hid_report_descriptor_len = sizeof(bx_mouse_hid_report_descriptor_338phy); + } else { + BX_PANIC(("Unknown mouse model type used")); + } + // update the hid descriptor length fields + * (Bit16u *) &bx_mouse_config_descriptor0[BX_Mouse_Config_Descriptor0_pos] = + * (Bit16u *) &bx_mouse_config_descriptor1[BX_Mouse_Config_Descriptor1_pos] = + * (Bit16u *) &bx_mouse_config_descriptor2[BX_Mouse_Config_Descriptor2_pos] = + * (Bit16u *) &bx_mouse_hid_descriptor0[BX_Mouse_Hid_Descriptor0] = + * (Bit16u *) &bx_mouse_hid_descriptor1[BX_Mouse_Hid_Descriptor1] = + s.bx_mouse_hid_report_descriptor_len; + } else { // keyboard or keypad if (d.speed == USB_SPEED_HIGH) { d.dev_descriptor = bx_keypad_dev_descriptor2; d.device_desc_size = sizeof(bx_keypad_dev_descriptor2); @@ -836,7 +1222,7 @@ bool usb_hid_device_c::init() d.config_desc_size = sizeof(bx_keypad_config_descriptor2); d.endpoint_info[USB_CONTROL_EP].max_packet_size = 64; // Control ep0 d.endpoint_info[USB_CONTROL_EP].max_burst_size = 0; - d.endpoint_info[1].max_packet_size = 4; // In ep1 + d.endpoint_info[1].max_packet_size = 8; // In ep1 d.endpoint_info[1].max_burst_size = 0; } else { d.dev_descriptor = bx_keypad_dev_descriptor; @@ -854,6 +1240,39 @@ bool usb_hid_device_c::init() return 1; } +bool usb_hid_device_c::set_option(const char *option) +{ + if (!strncmp(option, "model:", 6)) { + s.report_use_id = 0; // assume no report id + // mice + if (!strcmp(option+6, "m228")) { + s.model = hid_mouse_2x2x8; + s.report_use_id = HID_REPORT_ID; // this model uses a report id + } else if (!strcmp(option+6, "m338")) { + s.model = hid_mouse_3x3x8; + } else if (!strcmp(option+6, "m33xDebug")) { + s.model = hid_mouse_3x3xDebug; + } else if (!strcmp(option+6, "m3312")) { + s.model = hid_mouse_3x3x12; + } else if (!strcmp(option+6, "m3316")) { + s.model = hid_mouse_3x3x16; + } else if (!strcmp(option+6, "m338phy")) { + s.model = hid_mouse_3x3x8phy; + if (d.speed > USB_SPEED_FULL) + BX_PANIC(("The Physical Descriptor model must be used on a Low- or Full-speed device only.")); + } + // keyboards + // only the default model (none) + // keypads + // only the default model (none) + // tablets + // only the default model (none) + return 1; + } + + return 0; +} + const char *usb_hid_device_c::get_info() { return d.devname; @@ -872,11 +1291,18 @@ void usb_hid_device_c::register_state_specific(bx_list_c *parent) BXRS_DEC_PARAM_FIELD(list, mouse_z, s.mouse_z); BXRS_HEX_PARAM_FIELD(list, b_state, s.b_state); BXRS_DEC_PARAM_FIELD(list, mouse_event_count, s.mouse_event_count); - new bx_shadow_data_c(list, "mouse_event_buf", (Bit8u*)s.mouse_event_buf, 6 * BX_KBD_ELEMENTS, 1); + new bx_shadow_data_c(list, "mouse_event_buf", (Bit8u *) s.mouse_event_buf, BX_KBD_ELEMENTS * BX_M_ELEMENTS_SIZE, 1); + new bx_shadow_data_c(list, "mouse_event_buf_len", (Bit8u *) s.mouse_event_buf_len, BX_KBD_ELEMENTS, 1); if ((d.type == USB_HID_TYPE_KEYPAD) || (d.type == USB_HID_TYPE_KEYBOARD)) { new bx_shadow_data_c(list, "kbd_packet", s.kbd_packet, 8, 1); + BXRS_HEX_PARAM_FIELD(list, kbd_packet_indx, s.kbd_packet_indx); BXRS_HEX_PARAM_FIELD(list, indicators, s.indicators); BXRS_DEC_PARAM_FIELD(list, kbd_event_count, s.kbd_event_count); + BXRS_DEC_PARAM_FIELD(list, report_use_id, s.report_use_id); + BXRS_DEC_PARAM_FIELD(list, report_id, s.report_id); + BXRS_DEC_PARAM_FIELD(list, bx_mouse_hid_report_descriptor_len, s.bx_mouse_hid_report_descriptor_len); + new bx_shadow_data_c(list, "bx_mouse_hid_report_descriptor", (Bit8u *) s.bx_mouse_hid_report_descriptor, sizeof(s.bx_mouse_hid_report_descriptor), 1); + new bx_shadow_data_c(list, "model", (Bit8u *) s.model, sizeof(s.model), 1); bx_list_c *evbuf = new bx_list_c(list, "kbd_event_buf", ""); char pname[16]; for (Bit8u i = 0; i < BX_KBD_ELEMENTS; i++) { @@ -888,12 +1314,14 @@ void usb_hid_device_c::register_state_specific(bx_list_c *parent) void usb_hid_device_c::handle_reset() { - memset((void *) &s, 0, sizeof(s)); + memset((void *) &s, 0, offsetof(struct HID_STATE, model)); BX_DEBUG(("Reset")); // HID 1.11, section 7.2.6, page 54(64): // "When initialized, all devices default to report protocol." s.boot_protocol = PROTOCOL_REPORT; + // next will be byte 2 in the 8 byte packet + s.kbd_packet_indx = 1; } int usb_hid_device_c::handle_control(int request, int value, int index, int length, Bit8u *data) @@ -922,10 +1350,10 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng switch(value >> 8) { case USB_DT_STRING: switch(value & 0xff) { - case 4: + case HID_CLASS_STR4: ret = set_usb_string(data, "HID Mouse"); break; - case 5: + case HID_CLASS_STR5: ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); break; default: @@ -947,9 +1375,15 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng BX_ERROR(("USB_REQ_GET_DESCRIPTOR: The Descriptor Index must be zero for this request.")); } if (d.type == USB_HID_TYPE_MOUSE) { - memcpy(data, bx_mouse_hid_descriptor, - sizeof(bx_mouse_hid_descriptor)); - ret = sizeof(bx_mouse_hid_descriptor); + if (s.model >= hid_mouse_3x3x8phy) { + memcpy(data, bx_mouse_hid_descriptor1, + sizeof(bx_mouse_hid_descriptor1)); + ret = sizeof(bx_mouse_hid_descriptor1); + } else { + memcpy(data, bx_mouse_hid_descriptor0, + sizeof(bx_mouse_hid_descriptor0)); + ret = sizeof(bx_mouse_hid_descriptor0); + } } else if (d.type == USB_HID_TYPE_TABLET) { memcpy(data, bx_tablet_hid_descriptor, sizeof(bx_tablet_hid_descriptor)); @@ -968,9 +1402,8 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng BX_ERROR(("USB HID handle_control: The Descriptor Index must be zero for this request.")); } if (d.type == USB_HID_TYPE_MOUSE) { - memcpy(data, bx_mouse_hid_report_descriptor, - sizeof(bx_mouse_hid_report_descriptor)); - ret = sizeof(bx_mouse_hid_report_descriptor); + memcpy(data, s.bx_mouse_hid_report_descriptor, s.bx_mouse_hid_report_descriptor_len); + ret = s.bx_mouse_hid_report_descriptor_len; } else if (d.type == USB_HID_TYPE_TABLET) { memcpy(data, bx_tablet_hid_report_descriptor, sizeof(bx_tablet_hid_report_descriptor)); @@ -983,10 +1416,23 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng } else { goto fail; } + // now the guest knows the report id, so we need to use it + s.report_id = s.report_use_id; break; case 0x23: // HID Physical Descriptor BX_ERROR(("USB HID handle_control: Host requested the HID Physical Descriptor")); - goto fail; + if (d.type == USB_HID_TYPE_MOUSE) { + int set = (value & 0xFF); + if ((set >= 0) && (set <= 2)) { + memcpy(data, bx_mouse_phys_descriptor + (set * HID_PHYS_DESC_SET_LEN), HID_PHYS_DESC_SET_LEN); + ret = HID_PHYS_DESC_SET_LEN; + } else { + goto fail; + } + } else { + goto fail; + } + break; default: // 0x24 -> 0x2F BX_ERROR(("USB HID handle_control: unknown HID descriptor 0x%02x", value >> 8)); goto fail; @@ -1000,20 +1446,34 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng break; case InterfaceInClassRequest | GET_REPORT: BX_DEBUG(("HID: GET_REPORT:")); - if ((d.type == USB_HID_TYPE_MOUSE) || - (d.type == USB_HID_TYPE_TABLET)) { - ret = mouse_poll(data, length, 1); - } else if ((d.type == USB_HID_TYPE_KEYPAD) || - (d.type == USB_HID_TYPE_KEYBOARD)) { - ret = keyboard_poll(data, length, 1); + if ((value >> 8) == 1) { // Input report + if ((value & 0xFF) == s.report_id) { + if ((d.type == USB_HID_TYPE_MOUSE) || + (d.type == USB_HID_TYPE_TABLET)) { + ret = mouse_poll(data, 1); + if (ret > length) + ret = length; + } else if ((d.type == USB_HID_TYPE_KEYPAD) || + (d.type == USB_HID_TYPE_KEYBOARD)) { + ret = keyboard_poll(data, 1); + if (ret > length) + ret = length; + } else { + goto fail; + } + } else { + BX_ERROR(("USB HID handle_control: Report ID (%d) doesn't match requested ID (%d)", s.report_id, value & 0xFF)); + goto fail; + } } else { + BX_ERROR(("USB HID handle_control: Requested report type (%d) must be Input(1)", (value >> 8) & 0xFF)); goto fail; } break; case InterfaceOutClassRequest | SET_REPORT: BX_DEBUG(("HID: SET_REPORT:")); if (((d.type == USB_HID_TYPE_KEYPAD) || - (d.type == USB_HID_TYPE_KEYBOARD)) && (value == 0x0200)) { // 0x02 = Report Type: Output, 0x00 = ID + (d.type == USB_HID_TYPE_KEYBOARD)) && (value == 0x0200)) { // 0x02 = Report Type: Output, 0x00 = ID (our keyboard/keypad use an ID of zero) modchange = (data[0] ^ s.indicators); if (modchange != 0) { if (modchange & 0x01) { @@ -1041,8 +1501,16 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng if (length != 1) { BX_ERROR(("USB HID handle_control: The wLength field should be 1 for this request.")); } - data[0] = s.idle; - ret = 1; + if ((value & 0xFF00) != 0) { + BX_ERROR(("USB HID handle_control: High byte of Value must be 0.")); + } + if ((value & 0xFF) == s.report_id) { + data[0] = s.idle; + ret = 1; + } else { + BX_ERROR(("USB HID handle_control: Report ID (%d) doesn't match requested ID (%d)", s.report_id, value & 0xFF)); + goto fail; + } break; case InterfaceOutClassRequest | SET_IDLE: BX_DEBUG(("HID: SET_IDLE:")); @@ -1050,9 +1518,14 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng if (length != 0) { BX_ERROR(("USB HID handle_control: The wLength field should be 0 for this request.")); } - s.idle = (value >> 8); - start_idle_timer(); - ret = 0; + if ((value & 0xFF) == s.report_id) { + s.idle = (value >> 8); + start_idle_timer(); + ret = 0; + } else { + BX_ERROR(("USB HID handle_control: Report ID (%d) doesn't match requested ID (%d)", s.report_id, value & 0xFF)); + goto fail; + } break; case InterfaceOutClassRequest | SET_PROTOCOL: BX_DEBUG(("HID: SET_PROTOCOL:")); @@ -1107,10 +1580,10 @@ int usb_hid_device_c::handle_data(USBPacket *p) if (p->devep == 1) { if ((d.type == USB_HID_TYPE_MOUSE) || (d.type == USB_HID_TYPE_TABLET)) { - ret = mouse_poll(p->data, p->len, 0); + ret = mouse_poll(p->data, 0); } else if ((d.type == USB_HID_TYPE_KEYPAD) || (d.type == USB_HID_TYPE_KEYBOARD)) { - ret = keyboard_poll(p->data, p->len, 0); + ret = keyboard_poll(p->data, 0); } else { goto fail; } @@ -1126,10 +1599,13 @@ int usb_hid_device_c::handle_data(USBPacket *p) ret = USB_RET_STALL; break; } + + if (ret > 0) usb_dump_packet(p->data, ret, 0, p->devaddr, p->devep, USB_TRANS_TYPE_BULK, false, true); + return ret; } -int usb_hid_device_c::mouse_poll(Bit8u *buf, int len, bool force) +int usb_hid_device_c::mouse_poll(Bit8u *buf, bool force) { int l = USB_RET_NAK; @@ -1140,9 +1616,9 @@ int usb_hid_device_c::mouse_poll(Bit8u *buf, int len, bool force) } if (s.has_events || force) { if (s.mouse_event_count > 0) { - l = get_mouse_packet(buf, len); + l = get_mouse_packet(buf); } else { - l = create_mouse_packet(buf, len); + l = create_mouse_packet(buf); } s.has_events = (s.mouse_event_count > 0); start_idle_timer(); @@ -1150,9 +1626,9 @@ int usb_hid_device_c::mouse_poll(Bit8u *buf, int len, bool force) } else if (d.type == USB_HID_TYPE_TABLET) { if (s.has_events || force) { if (s.mouse_event_count > 0) { - l = get_mouse_packet(buf, len); + l = get_mouse_packet(buf); } else { - l = create_mouse_packet(buf, len); + l = create_mouse_packet(buf); } s.has_events = (s.mouse_event_count > 0); start_idle_timer(); @@ -1161,66 +1637,137 @@ int usb_hid_device_c::mouse_poll(Bit8u *buf, int len, bool force) return l; } -int usb_hid_device_c::create_mouse_packet(Bit8u *buf, int len) +// must not return more than BX_M_ELEMENTS_SIZE bytes +int usb_hid_device_c::create_mouse_packet(Bit8u *buf) { int l = 0; - - if (d.type == USB_HID_TYPE_TABLET) { + + // The HID Boot Protocol report is only three bytes long + if (s.boot_protocol == PROTOCOL_BOOT) { buf[0] = (Bit8u) s.b_state; - buf[1] = (Bit8u)(s.mouse_x & 0xff); - buf[2] = (Bit8u)(s.mouse_x >> 8); - buf[3] = (Bit8u)(s.mouse_y & 0xff); - buf[4] = (Bit8u)(s.mouse_y >> 8); - buf[5] = (Bit8s) s.mouse_z; - l = 6; - } else { - // The HID Boot Protocol report is only three bytes long - if (s.boot_protocol == PROTOCOL_BOOT) { - buf[0] = (Bit8u) s.b_state; - buf[1] = (Bit8s) s.mouse_x; - buf[2] = (Bit8s) s.mouse_y; + buf[1] = (Bit8s) s.mouse_x; + buf[2] = (Bit8s) s.mouse_y; + l = 3; + } else { // do the Report Protocol + + // do we add a Report ID field? + if (s.report_id > 0) { + *buf++ = s.report_id; + l = 1; + } + + if (d.type == USB_HID_TYPE_TABLET) { + *buf++ = (Bit8u) s.b_state; + *buf++ = (Bit8u) (s.mouse_x & 0xff); + *buf++ = (Bit8u) (s.mouse_x >> 8); + *buf++ = (Bit8u) (s.mouse_y & 0xff); + *buf++ = (Bit8u) (s.mouse_y >> 8); + *buf++ = (Bit8s) s.mouse_z; + l += 6; + } else { + // USB_HID_TYPE_MOUSE + switch (s.model) { + // default 2-button, X and Y coords, 8-bit + // 000000BB + // XXXXXXXX + // YYYYYYYY + case hid_mouse_2x2x8: + *buf++ = (s.b_state & 3); + *buf++ = (Bit8s) s.mouse_x; + *buf++ = (Bit8s) s.mouse_y; + l += 3; + break; + + // 3-button, X, Y, and Wheel coords, 8-bit + // 00000BBB + // XXXXXXXX + // YYYYYYYY + // WWWWWWWW + case hid_mouse_3x3x8: + case hid_mouse_3x3x8phy: + *buf++ = s.b_state & 7; + *buf++ = (Bit8s) s.mouse_x; + *buf++ = (Bit8s) s.mouse_y; + *buf++ = (Bit8s) s.mouse_z; + l += 4; + break; + + // 3-button, 5-byte X, Y, and Wheel coords (debug model) + // YYYYYYY0 - 10 bit Y displacement + // WWWW0YYY - 8 bit W displacement + // 0B00WWWW - bit 6 is Button #2 (right button) + // XXXXX0B0 - 9 bit X displacement, bit 1 is Button #1 (left button) + // 0B00XXXX - bit 6 is Button #3 (middle button) + case hid_mouse_3x3xDebug: + *buf++ = (Bit8u) (((Bit16u) s.mouse_y & 0x7F) << 1); + *buf++ = (Bit8u) ((((Bit16u) s.mouse_y >> 7) & 0x07) | + (((Bit16u) s.mouse_z & 0x0F) << 4)); + *buf++ = (Bit8u) ((((Bit16u) s.mouse_z >> 4) & 0x0F) | + ( ((s.b_state & 2) >> 1) << 6)); + *buf++ = (Bit8u) (( ((s.b_state & 1) >> 0) << 1) | + (((Bit16u) s.mouse_x & 0x1F) << 3)); + *buf++ = (Bit8u) ((((Bit16u) s.mouse_x >> 5) & 0x0F) | + ( ((s.b_state & 4) >> 2) << 6)); + l += 5; + break; + + // 3-button, X, Y, and Wheel coords, 12-bit + // 00000BBB + // XXXXXXXX (lsb) + // YYYYXXXX (lsb of y, msb of x) + // YYYYYYYY (msb) + // WWWWWWWW + case hid_mouse_3x3x12: + *buf++ = s.b_state & 7; + *buf++ = (Bit8u) ((Bit16u) s.mouse_x & 0xFF); + *buf++ = (Bit8u) ((((Bit16u) s.mouse_x >> 8) & 0x0F) | + (((Bit16u) s.mouse_y & 0x0F) << 4)); + *buf++ = (Bit8u) (((Bit16u) s.mouse_y >> 4) & 0xFF); + *buf++ = (Bit8s) s.mouse_z; + l += 5; + break; + + // 3-button, X, Y, and Wheel coords, 16-bit + // 00000BBB + // XXXXXXXX (lsb) + // XXXXXXXX (msb) + // YYYYYYYY (lsb) + // YYYYYYYY (msb) + // WWWWWWWW + case hid_mouse_3x3x16: + *buf++ = s.b_state & 7; + *buf++ = (Bit8u) ((Bit16u) s.mouse_x & 0xFF); + *buf++ = (Bit8u) ((Bit16u) s.mouse_x >> 8) & 0xFF; + *buf++ = (Bit8u) ((Bit16u) s.mouse_y & 0xFF); + *buf++ = (Bit8u) ((Bit16u) s.mouse_y >> 8) & 0xFF; + *buf++ = (Bit8s) s.mouse_z; + l += 6; + break; + } s.mouse_x = 0; s.mouse_y = 0; - l = 3; - - // our HID report includes the first three Boot Protocol bytes, - // followed by the z corrd if a wheel mouse is present - } else { // PROTOCOL_REPORT - buf[0] = (Bit8u) s.b_state; - buf[1] = (Bit8s) s.mouse_x; - buf[2] = (Bit8s) s.mouse_y; - s.mouse_x = 0; - s.mouse_y = 0; - if (len >= 4) { - buf[3] = (Bit8s) s.mouse_z; // if wheel mouse - s.mouse_z = 0; - } else - buf[3] = 0; - l = 4; + s.mouse_z = 0; } } return l; } -int usb_hid_device_c::get_mouse_packet(Bit8u *buf, int len) +int usb_hid_device_c::get_mouse_packet(Bit8u *buf) { int l = USB_RET_NAK; if (s.mouse_event_count > 0) { - if (d.type == USB_HID_TYPE_TABLET) { - l = 6; - } else if (len >= 4) { - l = 4; - } else { - l = 3; - } - memcpy(buf, s.mouse_event_buf[0], l); + memcpy(buf, s.mouse_event_buf[0], s.mouse_event_buf_len[0]); + l = s.mouse_event_buf_len[0]; if (--s.mouse_event_count > 0) { memmove(s.mouse_event_buf[0], s.mouse_event_buf[1], - s.mouse_event_count * 6); + s.mouse_event_count * BX_M_ELEMENTS_SIZE); + memmove(&s.mouse_event_buf_len[0], &s.mouse_event_buf_len[1], + s.mouse_event_count * sizeof(s.mouse_event_buf_len[0])); } } + return l; } @@ -1284,7 +1831,9 @@ void usb_hid_device_c::mouse_enq(int delta_x, int delta_y, int delta_z, unsigned if ((s.mouse_x != 0) || (s.mouse_y != 0) || (s.mouse_z != 0) || (button_state != s.b_state)) { s.b_state = (Bit8u) button_state; if (s.mouse_event_count < BX_KBD_ELEMENTS) { - create_mouse_packet(s.mouse_event_buf[s.mouse_event_count++], 4); + s.mouse_event_buf_len[s.mouse_event_count] = + create_mouse_packet(s.mouse_event_buf[s.mouse_event_count]); + s.mouse_event_count++; } s.has_events = 1; } @@ -1308,7 +1857,9 @@ void usb_hid_device_c::mouse_enq(int delta_x, int delta_y, int delta_z, unsigned s.mouse_z = (Bit8s) delta_z; s.b_state = (Bit8u) button_state; if (s.mouse_event_count < BX_KBD_ELEMENTS) { - create_mouse_packet(s.mouse_event_buf[s.mouse_event_count++], 6); + s.mouse_event_buf_len[s.mouse_event_count] = + create_mouse_packet(s.mouse_event_buf[s.mouse_event_count]); + s.mouse_event_count++; } } s.has_events = 1; @@ -1316,14 +1867,14 @@ void usb_hid_device_c::mouse_enq(int delta_x, int delta_y, int delta_z, unsigned } } -int usb_hid_device_c::keyboard_poll(Bit8u *buf, int len, bool force) +int usb_hid_device_c::keyboard_poll(Bit8u *buf, bool force) { int l = USB_RET_NAK; if ((d.type == USB_HID_TYPE_KEYPAD) || (d.type == USB_HID_TYPE_KEYBOARD)) { if (s.has_events || force) { - memcpy(buf, s.kbd_packet, len); + memcpy(buf, s.kbd_packet, 8); l = 8; s.has_events = 0; if (s.kbd_event_count > 0) { @@ -1348,40 +1899,75 @@ bool usb_hid_device_c::gen_scancode_static(void *dev, Bit32u key) } } +// return 1 to indicate that we handled the key. +// return 0 to indicate that the underlining keyboard needs to handle the key. bool usb_hid_device_c::gen_scancode(Bit32u key) { - bool modkey, released = (key & BX_KEY_RELEASED) != 0; - Bit8u code; - - code = usbkbd_conv[key & ~BX_KEY_RELEASED].code; - modkey = usbkbd_conv[key & ~BX_KEY_RELEASED].modkey; + Bit8u released = (key & BX_KEY_RELEASED) != 0; + Bit8u code = usbkbd_conv[key & ~BX_KEY_RELEASED].code; + Bit8u modkey = usbkbd_conv[key & ~BX_KEY_RELEASED].modkey; + + // if the keypad, only process the numpad keys if (d.type == USB_HID_TYPE_KEYPAD) { + // else only allow the standard keypad keys if ((code < 0x53) || (code > 0x63)) { return 0; } - } else if (code == 0) { - return 1; } + // if we don't support this key, just return + if (code == 0) + return 1; + + // printed 'modkey' will bit the "modifying bit" position, else -1 + BX_DEBUG((" key: 0x%08X, code: 0x%02X, modkey = %i", + key, code, ((code & 0xF0) == 0xE0) ? (code & 0x0F) : -1)); + + // if we already have keys in the 'queue', add this one and return if (s.has_events) { if (s.kbd_event_count < BX_KBD_ELEMENTS) { s.kbd_event_buf[s.kbd_event_count++] = key; } return 1; } - if (modkey) { + + // was the previous packet a 'Phantom' packet? + // if so, reset the packet + if (s.kbd_packet_indx > 7) { + memset(s.kbd_packet, 0, 8); + s.kbd_packet_indx = 1; + } + + // was it a modifying key? + if (modkey != BX_MODS_NONE) { if (released) { - s.kbd_packet[0] &= ~code; + s.kbd_packet[0] &= ~modkey; } else { - s.kbd_packet[0] |= code; + s.kbd_packet[0] |= modkey; } + // else it was a normal key } else { + // if releasing a key, remove from the packet buffer if (released) { - if (code == s.kbd_packet[2]) { - s.kbd_packet[2] = 0; - s.has_events = 1; + for (int i=2; i<8; i++) { + if (s.kbd_packet[i] == code) { + for (int j=i; j<7; j++) + s.kbd_packet[j] = s.kbd_packet[j+1]; + s.kbd_packet[7] = 0; + if (s.kbd_packet_indx > 1) + s.kbd_packet_indx--; + s.has_events = 1; + break; + } } + // if pressing a key, add to the packet buffer } else { - s.kbd_packet[2] = code; + s.kbd_packet_indx++; + // if we overflow, create a 'Phantom' packet (0, 0, 1, 1, 1, 1, 1, 1) + if (s.kbd_packet_indx > 7) { + memset(&s.kbd_packet[0], 0, 2); + memset(&s.kbd_packet[2], 1, 6); + } else + s.kbd_packet[s.kbd_packet_indx] = code; s.has_events = 1; } } diff --git a/bochs/iodev/usb/usb_hid.h b/bochs/iodev/usb/usb_hid.h index edd9860bf..6ffca6f15 100644 --- a/bochs/iodev/usb/usb_hid.h +++ b/bochs/iodev/usb/usb_hid.h @@ -2,12 +2,12 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// USB HID emulation support (mouse and tablet) ported from QEMU -// USB keypad emulation based on code by Benjamin D Lunt (fys [at] fysnet [dot] net) -// USB keyboard emulation is an extension to the keypad based on the specs +// USB HID emulation support (mouse and tablet) originally ported from QEMU +// Current USB emulation based on code by Benjamin D Lunt (fys [at] fysnet [dot] net) // // Copyright (c) 2005 Fabrice Bellard // Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) +// Copyright (C) 2004-2023 Benjamin D Lunt (fys [at] fysnet [dot] net) // Copyright (C) 2009-2023 The Bochs Project // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -32,6 +32,73 @@ #ifndef BX_IODEV_USB_HID_H #define BX_IODEV_USB_HID_H +// Physical Descriptor Items +#define HID_PHYS_BIAS_NOT_APP 0 +#define HID_PHYS_BIAS_RIGHT_HAND 1 +#define HID_PHYS_BIAS_LEFT_HAND 2 +#define HID_PHYS_BIAS_BOTH_HANDS 3 +#define HID_PHYS_BIAS_EITHER_HAND 4 + +typedef enum +{ + None = 0, + Hand, Eyeball, Eyebrow, Eyelid, Ear, Nose, Mouth, UpperLip, LowerLip, + Jaw, Neck, UpperArm, Elbow, Forearm, Wrist, Palm, + Thumb, IndexFinger, MiddleFinger, RingFinger, LittleFinger, + Head, Shoulder, Hip, Waist, Thigh, Knee, Calf, Ankle, Foot, Heel, + BallofFoot, BigToe, SecondToe, ThirdToe, FourthToe, LittleToe, + Brow, Cheek, +} HID_PHYS_DESIGNATOR; + +typedef enum +{ + NotApp = 0, + Right, Left, Both, Either, Center +} HID_PHYS_QUALIFIER; + +// Device Model types +typedef enum +{ + // mice (w/o physical descriptor) + hid_mouse_2x2x8 = 0, // 2-button, 2-coords: X and Y coords, 8-bit + hid_mouse_3x3x8, // 3-button, 3-coords: X, Y, and Wheel coords, 8-bit (default) + hid_mouse_3x3x12, // 3-button, 3-coords: X, Y, and Wheel coords, 12-bit + hid_mouse_3x3xDebug, // 3-button, 3-coords: X, Y, and Wheel coords (debug) + hid_mouse_3x3x16, // 3-button, 3-coords: X, Y, and Wheel coords, 16-bit + // mice (w/ physical descriptor) + hid_mouse_3x3x8phy = 10, // 3-button, 3-coords: X, Y, and Wheel coords, 8-bit, Physical Descriptor included + + // keyboards + + // keypads + + // tablets + +} HID_MODEL; + +// one (or more) of our models uses the Report ID field. This is the ID value used. +#define HID_REPORT_ID 1 + +// our HID device(s) return two class specific strings, index 4 and index 5 +#define HID_CLASS_STR4 4 +#define HID_CLASS_STR5 5 + +#define BX_M_ELEMENTS_SIZE 8 + +struct USBKBD { + Bit8u code; + Bit8u modkey; +}; + +#define BX_MODS_NONE 0 +#define BX_MODS_LEFT_CTRL (1<<0) +#define BX_MODS_LEFT_SHIFT (1<<1) +#define BX_MODS_LEFT_ALT (1<<2) +#define BX_MODS_LEFT_GUI (1<<3) +#define BX_MODS_RIGHT_CTRL (1<<4) +#define BX_MODS_RIGHT_SHIFT (1<<5) +#define BX_MODS_RIGHT_ALT (1<<6) +#define BX_MODS_RIGHT_GUI (1<<7) class usb_hid_device_c : public usb_device_c { public: @@ -39,6 +106,7 @@ public: virtual ~usb_hid_device_c(); virtual bool init(); + virtual bool set_option(const char *option); virtual const char *get_info(); virtual void handle_reset(); virtual int handle_control(int request, int value, int index, int length, Bit8u *data); @@ -46,10 +114,9 @@ public: virtual void register_state_specific(bx_list_c *parent); private: - struct { + struct HID_STATE { bool has_events; Bit8u idle; - bool boot_protocol; // 0 = boot protocol, 1 = report protocol int mouse_delayed_dx; int mouse_delayed_dy; Bit16s mouse_x; @@ -57,11 +124,20 @@ private: Bit8s mouse_z; Bit8u b_state; Bit8u mouse_event_count; - Bit8u mouse_event_buf[BX_KBD_ELEMENTS][6]; + Bit8u mouse_event_buf[BX_KBD_ELEMENTS][BX_M_ELEMENTS_SIZE]; + int mouse_event_buf_len[BX_KBD_ELEMENTS]; Bit8u kbd_packet[8]; + int kbd_packet_indx; Bit8u indicators; Bit8u kbd_event_count; Bit32u kbd_event_buf[BX_KBD_ELEMENTS]; + // the remaining does not get cleared on a handle_reset() + HID_MODEL model; + Bit8u report_use_id; // id that we will use as soon as the HID report has been requested + Bit8u report_id; // id that we will use after the HID report has been requested + bool boot_protocol; // 0 = boot protocol, 1 = report protocol + int bx_mouse_hid_report_descriptor_len; + const Bit8u *bx_mouse_hid_report_descriptor; } s; int timer_index; @@ -73,10 +149,10 @@ private: static void mouse_enabled_changed(void *dev, bool enabled); static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state, bool absxy); void mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state, bool absxy); - int mouse_poll(Bit8u *buf, int len, bool force); - int create_mouse_packet(Bit8u *buf, int len); - int get_mouse_packet(Bit8u *buf, int len); - int keyboard_poll(Bit8u *buf, int len, bool force); + int mouse_poll(Bit8u *buf, bool force); + int create_mouse_packet(Bit8u *buf); + int get_mouse_packet(Bit8u *buf); + int keyboard_poll(Bit8u *buf, bool force); static void hid_timer_handler(void *); void start_idle_timer(void);