Skip to content

Commit

Permalink
Adding current state
Browse files Browse the repository at this point in the history
  • Loading branch information
janweinstock committed Feb 23, 2024
1 parent 72ac1eb commit f94fcea
Show file tree
Hide file tree
Showing 8 changed files with 443 additions and 126 deletions.
1 change: 1 addition & 0 deletions include/vcml/models/usb/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct endpoint_desc {
u8 interval;
u8 refresh;
u8 sync_address;
vector<u8> extra;
};

struct interface_desc {
Expand Down
7 changes: 7 additions & 0 deletions include/vcml/models/usb/keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ class keyboard : public device
{
private:
u8 m_leds;
vector<u8> m_keys;

ui::keyboard m_keyboard;
ui::console m_console;

void poll_modifier_keys(u8& data);
void poll_standard_keys(u8* data, size_t len);
void poll_keys(u8* data, size_t len);

public:
enum led_type {
LED_NUM_LOCK = bit(0),
Expand All @@ -52,6 +58,7 @@ class keyboard : public device
property<string> manufacturer;
property<string> product;
property<string> serialno;
property<string> keymap;

usb_target_socket usb_in;

Expand Down
9 changes: 7 additions & 2 deletions include/vcml/models/usb/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class xhci : public peripheral, public usb_host_if

struct devslot {
u64 context;
size_t irq;
size_t port;
u32 intr;
u32 port;
bool enabled;
bool addressed;
endpoint endpoints[32];
Expand Down Expand Up @@ -127,6 +127,10 @@ class xhci : public peripheral, public usb_host_if
bool get_transfer(u32& slotid, u32& epid);
void run_transfer(u32 slotid, u32 epid);

u32 enable_endpoint(u32 slot, u32 epid, u64 context, u64 input);
u32 update_endpoint(u32 slot, u32 epid, u32 state);
void kick_endpoint(u32 slot, u32 epid);

u32 cmd_noop(trb& cmd);
u32 cmd_enable_slot(trb& cmd, u32& slotid);
u32 cmd_disable_slot(trb& cmd, u32& slotid);
Expand All @@ -136,6 +140,7 @@ class xhci : public peripheral, public usb_host_if
u32 cmd_reset_endpoint(trb& cmd, u32& slotid);
u32 cmd_stop_endpoint(trb& cmd, u32& slotid);
u32 cmd_set_tr_dequeue_pointer(trb& cmd, u32& slotid);
u32 cmd_reset_device(trb& cmd, u32& slotid);

bool fetch_command(trb& cmd, u64& addr);
void execute_command(trb& cmd, u64 addr);
Expand Down
12 changes: 12 additions & 0 deletions include/vcml/ui/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,25 @@ class input
class keyboard : public input
{
private:
bool m_ctrl_l;
bool m_ctrl_r;
bool m_shift_l;
bool m_shift_r;
bool m_capsl;
bool m_alt_l;
bool m_alt_r;
bool m_meta_l;
bool m_meta_r;
u32 m_prev_sym;
string m_layout;

static unordered_map<string, keyboard*> s_keyboards;

public:
bool ctrl_l() const { return m_ctrl_l; }
bool ctrl_r() const { return m_ctrl_r; }
bool ctrl() const { return m_ctrl_l || m_ctrl_r; }

bool shift_l() const { return m_shift_l; }
bool shift_r() const { return m_shift_r; }
bool shift() const { return m_shift_l || m_shift_r; }
Expand All @@ -102,6 +110,10 @@ class keyboard : public input
bool alt_r() const { return m_alt_r; }
bool alt() const { return m_alt_l || m_alt_r; }

bool meta_l() const { return m_meta_l; }
bool meta_r() const { return m_meta_r; }
bool meta() const { return m_meta_l || m_meta_r; }

bool capslock() const { return m_capsl; }

const char* layout() const { return m_layout.c_str(); }
Expand Down
10 changes: 7 additions & 3 deletions src/vcml/models/usb/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,18 @@ void write_data(u8*& ptr, size_t& size, const endpoint_desc& desc) {
write_data<u8>(ptr, size, desc.interval);
write_data<u8>(ptr, size, desc.refresh);
write_data<u8>(ptr, size, desc.sync_address);

for (auto ch : desc.extra)
write_data<u8>(ptr, size, ch);
}

static size_t total_length(const config_desc& desc) {
size_t length = sizeof(usb_config_desc);
for (auto& ifx : desc.interfaces) {
length += sizeof(usb_interface_desc);
length += sizeof(usb_endpoint_desc) * ifx.endpoints.size();
length += ifx.extra.size();
for (auto& ep : ifx.endpoints)
length += sizeof(usb_endpoint_desc) + ep.extra.size();
}

return length;
Expand Down Expand Up @@ -379,12 +383,12 @@ usb_result device::handle_data(usb_packet& p) {
}

void device::usb_reset_device() {
log_info("usb reset device");
log_debug("usb reset device");
usb_reset_endpoint(0);
}

void device::usb_reset_endpoint(int ep) {
log_info("usb reset endpoint %d", ep);
log_debug("usb reset endpoint %d", ep);
switch (ep) {
case 0:
m_ep0.req = 0;
Expand Down
138 changes: 123 additions & 15 deletions src/vcml/models/usb/keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ static const device_desc KEYBOARD_DESC{
} },
};

static const u8 USB3_ENDPOINT_COMPANION_DT[] = {
0x06, // length
USB_DT_ENDPOINT_COMPANION,
0x00, // max burst
0x00, // attributes
0x08, // bytes per interval (lo)
0x00 // bytes per interval (hi)
};

// USB-HID: Appendix B (Boot Interface Descriptors)
// - input reports (i.e. reports from device to host)
// - 1x8 bits for modifier keys
Expand Down Expand Up @@ -104,6 +113,41 @@ static const u8 KEYBOARD_REPORT_DESCRIPTOR[] = {
0xc0, // end collection
};

static const u8 USB_HID_KEYCODE_TABLE[256] = {
0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, // [0..7]
0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, // [8..15]
0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, // [16..23]
0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, // [24..31]
0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, // [32..39]
0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, // [40..47]
0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, // [48..55]
0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, // [56..63]
0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, // [64..71]
0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, // [72..79]
0x5a, 0x5b, 0x62, 0x63, 0xff, 0x94, 0x64, 0x44, // [80..87]
0x45, 0x87, 0x92, 0x93, 0x8a, 0x88, 0x8b, 0x8c, // [88..95]
0x58, 0xe4, 0x54, 0x46, 0xe6, 0x00, 0x4a, 0x52, // [96..103]
0x4b, 0x50, 0x4f, 0x4d, 0x51, 0x4e, 0x49, 0x4c, // [104..111]
0x00, 0x7f, 0x81, 0x80, 0x66, 0x67, 0x00, 0x48, // [112..119]
0x00, 0x85, 0x90, 0x91, 0x89, 0xe3, 0xe7, 0x65, // [120..127]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [128..135]
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, // [136..143]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [144..151]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [152..159]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [160..167]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [168..175]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [176..183]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [184..191]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [192..199]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [200..207]
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, // [208..215]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [216..223]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [224..231]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [232..239]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [240..247]
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // [248..255]
};

enum usb_hid_request : u16 {
USB_REQ_GET_REPORT = 0x01,
USB_REQ_GET_IDLE = 0x02,
Expand All @@ -113,6 +157,64 @@ enum usb_hid_request : u16 {
USB_REQ_SET_PROTOCOL = 0x0b,
};

void keyboard::poll_modifier_keys(u8& data) {
data = 0;
if (m_keyboard.ctrl_l())
data |= bit(0);
if (m_keyboard.shift_l())
data |= bit(1);
if (m_keyboard.alt_l())
data |= bit(2);
if (m_keyboard.meta_l())
data |= bit(3);
if (m_keyboard.ctrl_r())
data |= bit(4);
if (m_keyboard.shift_r())
data |= bit(5);
if (m_keyboard.alt_r())
data |= bit(6);
if (m_keyboard.meta_r())
data |= bit(7);
}

void keyboard::poll_standard_keys(u8* data, size_t length) {
ui::input_event ev;
vector<u8> release;

while (m_keyboard.has_events()) {
m_keyboard.pop_event(ev);
if (!ev.is_key()) {
log_warn("invalid input event on keyboard");
continue;
}

u8 hid = USB_HID_KEYCODE_TABLE[ev.key.code & 0xff];

if (ev.key.state == ui::VCML_KEY_UP)
stl_add_unique(release, hid);
else
stl_add_unique(m_keys, hid);
}

if (m_keys.size() <= length) {
memcpy(data, m_keys.data(), m_keys.size());
memset(data + m_keys.size(), 0, length - m_keys.size());
} else {
memcpy(data, m_keys.data(), length - 1);
data[length - 1] = 1; // rollover
}

for (auto hid : release)
stl_remove(m_keys, hid);
}

void keyboard::poll_keys(u8* data, size_t length) {
VCML_ERROR_ON(length < 8, "insufficient buffer size to poll keys");
poll_modifier_keys(data[0]);
data[1] = 0; // reserved
poll_standard_keys(data + 2, length - 2);
}

keyboard::keyboard(const sc_module_name& nm):
device(nm, KEYBOARD_DESC),
m_leds(),
Expand All @@ -124,21 +226,30 @@ keyboard::keyboard(const sc_module_name& nm):
manufacturer("manufacturer", "MachineWare GmbH"),
product("product", "VCML Keyboard"),
serialno("serialno", VCML_GIT_REV_SHORT),
keymap("keymap", "us"),
usb_in("usb_in") {
if (usb3) {
m_desc.bcd_usb = 0x300;
m_desc.max_packet_size0 = 9;
auto& extra = m_desc.configs[0].interfaces[0].endpoints[0].extra;
for (auto ch : USB3_ENDPOINT_COMPANION_DT)
extra.push_back(ch);
} else {
m_desc.bcd_usb = 0x200;
m_desc.max_packet_size0 = 8;
}

m_keyboard.set_layout(keymap);
}

keyboard::~keyboard() {
// nothing to do
}

void keyboard::start_of_simulation() {
if (m_console.has_display())
m_console.notify(m_keyboard);

if (usb3)
usb_in.attach(USB_SPEED_SUPER);
else
Expand All @@ -156,20 +267,7 @@ usb_result keyboard::get_report(u8* data, size_t length) {
return USB_RESULT_STALL;
}

data[0] = 0; // TODO: modifier state
data[1] = 0; // TODO: reserved
data[2] = 0; // TODO: keycode 1
data[3] = 0; // TODO: keycode 2
data[4] = 0; // TODO: keycode 3
data[5] = 0; // TODO: keycode 4
data[6] = 0; // TODO: keycode 5
data[7] = 0; // TODO: keycode 6

log_debug(
"get_report(%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx)",
data[0], data[1], data[2], data[3], data[4], data[5], data[6],
data[7]);

poll_keys(data, length);
return USB_RESULT_SUCCESS;
}

Expand Down Expand Up @@ -197,7 +295,17 @@ usb_result keyboard::set_report(u8* data, size_t length) {
}

usb_result keyboard::get_data(u32 ep, u8* data, size_t len) {
log_info("ep%u get_data (%zu bytes)", ep, len);
if (ep != 2) {
log_error("invalid endpoint contacted: %u", ep);
return USB_RESULT_NACK;
}

if (len != 8) {
log_error("invalid data packet length: %zu, expected 8", len);
return USB_RESULT_STALL;
}

poll_keys(data, len);
return USB_RESULT_SUCCESS;
}

Expand Down
Loading

0 comments on commit f94fcea

Please sign in to comment.