|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
println("control callback (hid)"); |
|
|
println("control callback (hid)"); |
|
|
print_hexbytes(transfer->buffer, transfer->length); |
|
|
print_hexbytes(transfer->buffer, transfer->length); |
|
|
|
|
|
// To decode hex dump to human readable HID report summary: |
|
|
|
|
|
// http://eleccelerator.com/usbdescreqparser/ |
|
|
uint32_t mesg = transfer->setup.word1; |
|
|
uint32_t mesg = transfer->setup.word1; |
|
|
//println(" mesg = ", mesg, HEX); |
|
|
//println(" mesg = ", mesg, HEX); |
|
|
if (mesg == 0x22000681 && transfer->length == descsize) { // HID report descriptor |
|
|
if (mesg == 0x22000681 && transfer->length == descsize) { // HID report descriptor |
|
|
println(" got report descriptor"); |
|
|
println(" got report descriptor"); |
|
|
|
|
|
parse(); |
|
|
queue_Data_Transfer(in_pipe, report, in_size, this); |
|
|
queue_Data_Transfer(in_pipe, report, in_size, this); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
print("HID: "); |
|
|
print("HID: "); |
|
|
print_hexbytes(transfer->buffer, transfer->length); |
|
|
print_hexbytes(transfer->buffer, transfer->length); |
|
|
parse(0x0100, (const uint8_t *)transfer->buffer, transfer->length); |
|
|
|
|
|
|
|
|
const uint8_t *buf = (const uint8_t *)transfer->buffer; |
|
|
|
|
|
uint32_t len = transfer->length; |
|
|
|
|
|
if (use_report_id == false) { |
|
|
|
|
|
parse(0x0100, buf, len); |
|
|
|
|
|
} else { |
|
|
|
|
|
if (len > 1) { |
|
|
|
|
|
parse(0x0100 | buf[0], buf + 1, len - 1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
queue_Data_Transfer(in_pipe, report, in_size, this); |
|
|
queue_Data_Transfer(in_pipe, report, in_size, this); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 0xA0: // Collection |
|
|
case 0xA0: // Collection |
|
|
if (collection_level == 0 && topusage_count < TOPUSAGE_LIST_LEN) { |
|
|
if (collection_level == 0 && topusage_count < TOPUSAGE_LIST_LEN) { |
|
|
uint32_t topusage = ((uint32_t)usage_page << 16) | usage; |
|
|
uint32_t topusage = ((uint32_t)usage_page << 16) | usage; |
|
|
|
|
|
println("Found top level collection ", topusage, HEX); |
|
|
//topusage_list[topusage_count] = topusage; |
|
|
//topusage_list[topusage_count] = topusage; |
|
|
topusage_drivers[topusage_count] = find_driver(topusage); |
|
|
topusage_drivers[topusage_count] = find_driver(topusage); |
|
|
topusage_count++; |
|
|
topusage_count++; |
|
|
|
|
|
|
|
|
uint8_t collection_level = 0; |
|
|
uint8_t collection_level = 0; |
|
|
uint8_t usage[USAGE_LIST_LEN] = {0, 0}; |
|
|
uint8_t usage[USAGE_LIST_LEN] = {0, 0}; |
|
|
uint8_t usage_count = 0; |
|
|
uint8_t usage_count = 0; |
|
|
|
|
|
uint8_t report_id = 0; |
|
|
uint16_t report_size = 0; |
|
|
uint16_t report_size = 0; |
|
|
uint16_t report_count = 0; |
|
|
uint16_t report_count = 0; |
|
|
uint16_t usage_page = 0; |
|
|
uint16_t usage_page = 0; |
|
|
|
|
|
|
|
|
report_count = val; |
|
|
report_count = val; |
|
|
break; |
|
|
break; |
|
|
case 0x84: // Report ID (global) |
|
|
case 0x84: // Report ID (global) |
|
|
// TODO |
|
|
|
|
|
|
|
|
report_id = val; |
|
|
break; |
|
|
break; |
|
|
case 0x08: // Usage (local) |
|
|
case 0x08: // Usage (local) |
|
|
if (usage_count < USAGE_LIST_LEN) { |
|
|
if (usage_count < USAGE_LIST_LEN) { |
|
|
|
|
|
|
|
|
driver = topusage_drivers[topusage_index++]; |
|
|
driver = topusage_drivers[topusage_index++]; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
// discard collection info if not top level, hopefully that's ok? |
|
|
collection_level++; |
|
|
collection_level++; |
|
|
reset_local = true; |
|
|
reset_local = true; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
reset_local = true; |
|
|
reset_local = true; |
|
|
break; |
|
|
break; |
|
|
case 0x80: // Input |
|
|
case 0x80: // Input |
|
|
if ((val & 1) == 0) { |
|
|
|
|
|
|
|
|
if (use_report_id && (report_id != (type_and_report_id & 0xFF))) { |
|
|
|
|
|
// completely ignore and do not advance bitindex |
|
|
|
|
|
// for descriptors of other report IDs |
|
|
|
|
|
reset_local = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
if ((val & 1) || (driver == NULL)) { |
|
|
|
|
|
// skip past constant fields or when no driver is listening |
|
|
|
|
|
bitindex += report_count * report_size; |
|
|
|
|
|
} else { |
|
|
println("begin, usage=", topusage, HEX); |
|
|
println("begin, usage=", topusage, HEX); |
|
|
println(" type= ", val, HEX); |
|
|
println(" type= ", val, HEX); |
|
|
println(" min= ", logical_min); |
|
|
println(" min= ", logical_min); |
|
|
println(" max= ", logical_max); |
|
|
println(" max= ", logical_max); |
|
|
if (driver) { |
|
|
|
|
|
driver->hid_input_begin(topusage, val, |
|
|
|
|
|
logical_min, logical_max); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
driver->hid_input_begin(topusage, val, logical_min, logical_max); |
|
|
println("Input, total bits=", report_count * report_size); |
|
|
println("Input, total bits=", report_count * report_size); |
|
|
if ((val & 2)) { |
|
|
if ((val & 2)) { |
|
|
// ordinary variable format |
|
|
// ordinary variable format |
|
|
|
|
|
|
|
|
uint32_t n = bitfield(data, bitindex, report_size); |
|
|
uint32_t n = bitfield(data, bitindex, report_size); |
|
|
if (logical_min >= 0) { |
|
|
if (logical_min >= 0) { |
|
|
println(" data = ", n); |
|
|
println(" data = ", n); |
|
|
if (driver) driver->hid_input_data(u, n); |
|
|
|
|
|
|
|
|
driver->hid_input_data(u, n); |
|
|
} else { |
|
|
} else { |
|
|
int32_t sn = signext(n, report_size); |
|
|
int32_t sn = signext(n, report_size); |
|
|
println(" sdata = ", sn); |
|
|
println(" sdata = ", sn); |
|
|
if (driver) driver->hid_input_data(u, sn); |
|
|
|
|
|
|
|
|
driver->hid_input_data(u, sn); |
|
|
} |
|
|
} |
|
|
bitindex += report_size; |
|
|
bitindex += report_size; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
u |= (uint32_t)usage_page << 16; |
|
|
u |= (uint32_t)usage_page << 16; |
|
|
print(" usage = ", u, HEX); |
|
|
print(" usage = ", u, HEX); |
|
|
println(" data = 1"); |
|
|
println(" data = 1"); |
|
|
if (driver) driver->hid_input_data(u, 1); |
|
|
|
|
|
|
|
|
driver->hid_input_data(u, 1); |
|
|
} |
|
|
} |
|
|
bitindex += report_size; |
|
|
bitindex += report_size; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
|
|
|
// skip past constant fields |
|
|
|
|
|
bitindex += report_count * report_size; |
|
|
|
|
|
} |
|
|
} |
|
|
reset_local = true; |
|
|
reset_local = true; |
|
|
break; |
|
|
break; |