switch-pico/usb_pairing_management.cpp

100 lines
3.5 KiB
C++

#include "usb_pairing_management.h"
#include <string.h>
#include "tusb.h"
#ifdef SWITCH_PICO_ADAPTER_FEASIBILITY
#include "adapter_host_probe.h"
#endif
namespace UsbPairingManagement {
size_t encode_snapshot(const Bluepad32PairingSnapshot& snapshot,
uint8_t* output, size_t output_size) {
const size_t required =
kResponseHeaderSize + snapshot.record_count * kRecordSize;
if (output == nullptr || output_size < required ||
snapshot.record_count > BLUEPAD32_PAIRING_RECORD_CAPACITY) {
return 0;
}
output[0] = 'S';
output[1] = 'P';
output[2] = 'P';
output[3] = 'M';
output[4] = kProtocolVersion;
output[5] = static_cast<uint8_t>(snapshot.status);
output[6] = snapshot.record_count;
output[7] = snapshot.overflow ? 1 : 0;
output[8] = static_cast<uint8_t>(snapshot.generation);
output[9] = static_cast<uint8_t>(snapshot.generation >> 8);
output[10] = static_cast<uint8_t>(snapshot.generation >> 16);
output[11] = static_cast<uint8_t>(snapshot.generation >> 24);
size_t offset = kResponseHeaderSize;
for (uint8_t index = 0; index < snapshot.record_count; ++index) {
const Bluepad32PairingRecord& record = snapshot.records[index];
output[offset] = static_cast<uint8_t>(record.transport);
output[offset + 1] = record.address_type;
memcpy(&output[offset + 2], record.address,
sizeof(record.address));
offset += kRecordSize;
}
return required;
}
} // namespace UsbPairingManagement
extern "C" bool tud_vendor_control_xfer_cb(
uint8_t rhport, uint8_t stage,
tusb_control_request_t const* request) {
#ifdef SWITCH_PICO_ADAPTER_FEASIBILITY
if (adapter_host_probe_vendor_control(rhport, stage, request)) {
return true;
}
#endif
if (stage != CONTROL_STAGE_SETUP) {
return true;
}
if (request == nullptr ||
request->bmRequestType_bit.recipient != TUSB_REQ_RCPT_DEVICE ||
request->wValue != UsbPairingManagement::kRequestValue ||
request->wIndex != UsbPairingManagement::kRequestIndex) {
return false;
}
switch (request->bRequest) {
case UsbPairingManagement::kRequestGet: {
if (request->bmRequestType_bit.direction != TUSB_DIR_IN) {
return false;
}
static uint8_t response[
UsbPairingManagement::kMaximumResponseSize];
Bluepad32PairingSnapshot snapshot{};
bluepad32_input_backend_pairing_snapshot(&snapshot);
const size_t response_size =
UsbPairingManagement::encode_snapshot(
snapshot, response, sizeof(response));
return response_size != 0 &&
tud_control_xfer(
rhport, request, response,
static_cast<uint16_t>(response_size));
}
case UsbPairingManagement::kRequestRefresh:
if (request->bmRequestType_bit.direction != TUSB_DIR_OUT ||
request->wLength != 0) {
return false;
}
bluepad32_input_backend_request_pairing_snapshot();
return tud_control_status(rhport, request);
case UsbPairingManagement::kRequestClear:
if (request->bmRequestType_bit.direction != TUSB_DIR_OUT ||
request->wLength != 0) {
return false;
}
bluepad32_input_backend_clear_pairings();
return tud_control_status(rhport, request);
default:
return false;
}
}