mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-15 22:20:59 +00:00
hid_device: rework get report handling
This commit is contained in:
parent
d74c876f55
commit
1002ad195b
@ -78,7 +78,7 @@ typedef struct hid_device {
|
||||
hid_report_type_t report_type;
|
||||
uint8_t report_id;
|
||||
uint16_t expected_report_size;
|
||||
uint16_t report_size;
|
||||
uint16_t response_size;
|
||||
uint8_t user_request_can_send_now;
|
||||
|
||||
hid_handshake_param_type_t report_status;
|
||||
@ -124,6 +124,7 @@ static void dummy_report_data(uint16_t hid_cid, hid_report_type_t report_type, u
|
||||
UNUSED(report_size);
|
||||
UNUSED(report);
|
||||
}
|
||||
|
||||
static uint16_t hid_device_get_next_cid(void){
|
||||
hid_device_cid++;
|
||||
if (!hid_device_cid){
|
||||
@ -353,6 +354,11 @@ static void hid_device_trigger_user_request_if_pending(const hid_device_t *hid_d
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_device_send_prepared_control_message(hid_device_t * hid_device, uint16_t message_len){
|
||||
l2cap_send_prepared(hid_device->control_cid, message_len);
|
||||
hid_device_trigger_user_request_if_pending(hid_device);
|
||||
}
|
||||
|
||||
static int hid_report_size_valid(uint16_t cid, int report_id, hid_report_type_t report_type, int report_size){
|
||||
if (!report_size) return 0;
|
||||
if (hid_device_in_boot_protocol_mode(cid)){
|
||||
@ -434,87 +440,88 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
|
||||
uint8_t param;
|
||||
bd_addr_t address;
|
||||
uint16_t local_cid;
|
||||
int pos = 0;
|
||||
uint16_t pos;
|
||||
int report_size;
|
||||
uint8_t report[48];
|
||||
uint8_t * outgoing_buffer;
|
||||
hid_message_type_t message_type;
|
||||
bool need_report_id;
|
||||
bool need_size;
|
||||
uint16_t response_size;
|
||||
uint16_t host_buffer_size;
|
||||
|
||||
switch (packet_type){
|
||||
case L2CAP_DATA_PACKET:
|
||||
device = hid_device_get_instance_for_l2cap_cid(channel);
|
||||
if (!device) {
|
||||
log_error("no device with cid 0x%02x", channel);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (packet_size < 1) break;
|
||||
|
||||
message_type = (hid_message_type_t)(packet[0] >> 4);
|
||||
switch (message_type){
|
||||
case HID_MESSAGE_TYPE_GET_REPORT:
|
||||
|
||||
pos = 0;
|
||||
device->report_type = (hid_report_type_t)(packet[pos++] & 0x03);
|
||||
device->report_id = 0;
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL;
|
||||
device->state = HID_DEVICE_W2_GET_REPORT;
|
||||
|
||||
// get and validate report id if needed
|
||||
need_report_id = false;
|
||||
switch (device->protocol_mode){
|
||||
case HID_PROTOCOL_MODE_BOOT:
|
||||
if (packet_size < 2){
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
device->report_id = packet[pos++];
|
||||
case HID_PROTOCOL_MODE_BOOT:
|
||||
need_report_id = true;
|
||||
break;
|
||||
case HID_PROTOCOL_MODE_REPORT:
|
||||
if (!btstack_hid_report_id_declared(hid_device_descriptor_len, hid_device_descriptor)) {
|
||||
if (packet_size < 2) break;
|
||||
if (packet[0] & 0x08){
|
||||
if (packet_size > 2) {
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
|
||||
}
|
||||
} else {
|
||||
if (packet_size > 1) {
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (packet_size < 2){
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
device->report_id = packet[pos++];
|
||||
need_report_id = btstack_hid_report_id_declared(hid_device_descriptor_len, hid_device_descriptor) != 0;
|
||||
break;
|
||||
default:
|
||||
btstack_assert(false);
|
||||
break;
|
||||
}
|
||||
if (need_report_id){
|
||||
if (packet_size >= (pos + 1)){
|
||||
device->report_id = packet[pos++];
|
||||
if (hid_report_id_status(device->cid, device->report_id) == HID_REPORT_ID_INVALID){
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
|
||||
}
|
||||
} else {
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
|
||||
}
|
||||
}
|
||||
if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL){
|
||||
l2cap_request_can_send_now_event(device->control_cid);
|
||||
break;
|
||||
}
|
||||
switch (hid_report_id_status(device->cid, device->report_id)){
|
||||
case HID_REPORT_ID_INVALID:
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// if size bit is set in header, next two bytes indicate host buffer size
|
||||
need_size = (packet[0] & 0x08) != 0;
|
||||
if (need_size){
|
||||
if (packet_size >= (pos + 2)) {
|
||||
host_buffer_size = little_endian_read_16(packet, pos);
|
||||
} else {
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
|
||||
l2cap_request_can_send_now_event(device->control_cid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate response size
|
||||
device->expected_report_size = hid_get_report_size_for_id(device->cid, device->report_id, device->report_type, hid_device_descriptor_len, hid_device_descriptor);
|
||||
report_size = device->expected_report_size + pos; // add 1 for header size and report id
|
||||
|
||||
if ((packet[0] & 0x08) && (packet_size >= (pos + 1))){
|
||||
device->report_size = btstack_min(btstack_min(little_endian_read_16(packet, pos), report_size), sizeof(report));
|
||||
} else {
|
||||
device->report_size = btstack_min(btstack_min(l2cap_max_mtu(), report_size), sizeof(report));
|
||||
response_size = device->expected_report_size + pos; // DATA + [ReportID]
|
||||
// host buffer size does not include the DATA header
|
||||
if (need_size){
|
||||
response_size = btstack_min(response_size, host_buffer_size + 1);
|
||||
}
|
||||
// we store total payload in report_size field
|
||||
device->response_size = response_size;
|
||||
|
||||
l2cap_request_can_send_now_event(device->control_cid);
|
||||
break;
|
||||
|
||||
case HID_MESSAGE_TYPE_SET_REPORT:
|
||||
device->state = HID_DEVICE_W2_SET_REPORT;
|
||||
device->report_size = l2cap_max_mtu();
|
||||
device->report_type = (hid_report_type_t)(packet[0] & 0x03);
|
||||
if (packet_size < 1){
|
||||
device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
|
||||
@ -742,24 +749,26 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
|
||||
case L2CAP_EVENT_CAN_SEND_NOW:
|
||||
local_cid = l2cap_event_can_send_now_get_local_cid(packet);
|
||||
device = hid_device_get_instance_for_l2cap_cid(local_cid);
|
||||
|
||||
if (!device) return;
|
||||
|
||||
outgoing_buffer = l2cap_get_outgoing_buffer();
|
||||
|
||||
switch (device->state){
|
||||
case HID_DEVICE_W2_GET_REPORT:{
|
||||
if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL) {
|
||||
report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_control_message(device->cid, &report[0], 1);
|
||||
outgoing_buffer[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_prepared_control_message(device, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
report[pos++] = (HID_MESSAGE_TYPE_DATA << 4) | device->report_type;
|
||||
if (device->report_id){
|
||||
report[pos++] = device->report_id;
|
||||
outgoing_buffer[pos++] = (HID_MESSAGE_TYPE_DATA << 4) | device->report_type;
|
||||
if (device->report_id != 0){
|
||||
outgoing_buffer[pos++] = device->report_id;
|
||||
}
|
||||
|
||||
report_size = 0;
|
||||
status = (*hci_device_get_report)(device->cid, device->report_type, device->report_id, &report_size, &report[pos]);
|
||||
status = (*hci_device_get_report)(device->cid, device->report_type, device->report_id, &report_size, &outgoing_buffer[pos]);
|
||||
|
||||
switch (status){
|
||||
case 0:
|
||||
@ -781,35 +790,32 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
|
||||
break;
|
||||
}
|
||||
if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL){
|
||||
report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_control_message(device->cid, &report[0], 1);
|
||||
outgoing_buffer[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_prepared_control_message(device, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
hid_device_send_control_message(device->cid, &report[0], device->report_size);
|
||||
|
||||
hid_device_send_prepared_control_message(device, device->response_size);
|
||||
break;
|
||||
}
|
||||
case HID_DEVICE_W2_SET_REPORT:
|
||||
case HID_DEVICE_W2_SET_PROTOCOL:
|
||||
report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_control_message(device->cid, &report[0], 1);
|
||||
outgoing_buffer[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_prepared_control_message(device, 1);
|
||||
break;
|
||||
case HID_DEVICE_W2_GET_PROTOCOL:
|
||||
if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL){
|
||||
report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_control_message(device->cid, &report[0], 1);
|
||||
outgoing_buffer[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
|
||||
hid_device_send_prepared_control_message(device, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
report[0] = (HID_MESSAGE_TYPE_DATA << 4);
|
||||
report[1] = device->protocol_mode;
|
||||
hid_device_send_control_message(device->cid, &report[0], 2);
|
||||
outgoing_buffer[0] = (HID_MESSAGE_TYPE_DATA << 4);
|
||||
outgoing_buffer[1] = device->protocol_mode;
|
||||
hid_device_send_prepared_control_message(device, 2);
|
||||
break;
|
||||
|
||||
|
||||
case HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST:
|
||||
report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST;
|
||||
hid_device_send_control_message(device->cid, &report[0], 1);
|
||||
outgoing_buffer[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST;
|
||||
hid_device_send_prepared_control_message(device, 1);
|
||||
break;
|
||||
default:
|
||||
if (device->user_request_can_send_now){
|
||||
|
Loading…
x
Reference in New Issue
Block a user