/* * This file is part of DeskHop (https://github.com/hrvach/deskhop). * Copyright (c) 2024 Hrvoje Cavrak * * This program 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, version 3. * * This program 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, see . */ #include "main.h" /**================================================== * * =========== TinyUSB Device Callbacks =========== * * ================================================== */ /* Invoked when we get GET_REPORT control request. * We are expected to fill buffer with the report content, update reqlen * and return its length. We return 0 to STALL the request. */ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t request_len) { return 0; } /** * Computer controls our LEDs by sending USB SetReport messages with a payload * of just 1 byte and report type output. It's type 0x21 (USB_REQ_DIR_OUT | * USB_REQ_TYP_CLASS | USB_REQ_REC_IFACE) Request code for SetReport is 0x09, * report type is 0x02 (HID_REPORT_TYPE_OUTPUT). We get a set_report callback * from TinyUSB device HID and then figure out what to do with the LEDs. */ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { if (report_id != REPORT_ID_KEYBOARD || bufsize != 1 || report_type != HID_REPORT_TYPE_OUTPUT) return; uint8_t leds = buffer[0]; /* If we are using caps lock LED to indicate the chosen output, that has priority */ if (KBD_LED_AS_INDICATOR) { leds = leds & 0xFD; /* 1111 1101 (Clear Caps Lock bit) */ if (global_state.active_output) leds |= KEYBOARD_LED_CAPSLOCK; } global_state.keyboard_leds[global_state.active_output] = leds; /* If the board doesn't have the keyboard hooked up directly, we need to relay this information to the other one that has (and LEDs you can turn on). */ if (global_state.keyboard_connected) restore_leds(&global_state); else send_value(leds, KBD_SET_REPORT_MSG); } /* Invoked when device is mounted */ void tud_mount_cb(void) { global_state.tud_connected = true; } /* Invoked when device is unmounted */ void tud_umount_cb(void) { global_state.tud_connected = false; } /**================================================== * * =============== USB HOST Section =============== * * ================================================== */ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); switch (itf_protocol) { case HID_ITF_PROTOCOL_KEYBOARD: global_state.keyboard_connected = false; break; case HID_ITF_PROTOCOL_MOUSE: global_state.mouse_connected = false; /* Clear this so reconnecting a mouse doesn't try to continue in HID REPORT protocol */ memset(&global_state.mouse_dev, 0, sizeof(global_state.mouse_dev)); break; } } void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); switch (itf_protocol) { case HID_ITF_PROTOCOL_KEYBOARD: /* Keeping this is required for setting leds from device set_report callback */ global_state.kbd_dev_addr = dev_addr; global_state.kbd_instance = instance; global_state.keyboard_connected = true; break; case HID_ITF_PROTOCOL_MOUSE: /* Switch to using protocol report instead of boot report, it's more complicated but at least we get all the information we need (looking at you, mouse wheel) */ if (tuh_hid_get_protocol(dev_addr, instance) == HID_PROTOCOL_BOOT) { tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_REPORT); } parse_report_descriptor(&global_state.mouse_dev, MAX_REPORTS, desc_report, desc_len); global_state.mouse_connected = true; break; } /* Flash local led to indicate a device was connected */ blink_led(&global_state); /* Also signal the other board to flash LED, to enable easy verification if serial works */ send_value(ENABLE, FLASH_LED_MSG); /* Kick off the report querying */ tuh_hid_receive_report(dev_addr, instance); } /* Invoked when received report from device via interrupt endpoint */ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); switch (itf_protocol) { case HID_ITF_PROTOCOL_KEYBOARD: process_keyboard_report((uint8_t *)report, len, &global_state); break; case HID_ITF_PROTOCOL_MOUSE: process_mouse_report((uint8_t *)report, len, &global_state); break; } /* Continue requesting reports */ tuh_hid_receive_report(dev_addr, instance); } /* Set protocol in a callback. If we were called, command succeeded. We're only doing this for the mouse for now, so we can only be called about the mouse */ void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol) { global_state.mouse_dev.protocol = protocol; }