/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2021 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include #include #include "log.h" #include "bitfield.h" #include "io_usb.h" const unsigned char usbHidItemLengths[] = {0, 1, 2, 4}; const UsbHidDescriptor * usbHidDescriptor (UsbDevice *device) { const UsbDescriptor *descriptor = NULL; while (usbNextDescriptor(device, &descriptor)) if (descriptor->endpoint.bDescriptorType == UsbDescriptorType_HID) return &descriptor->hid; logMessage(LOG_WARNING, "USB: HID descriptor not found"); errno = ENOENT; return NULL; } ssize_t usbHidGetItems ( UsbDevice *device, unsigned char interface, unsigned char number, unsigned char **items, int timeout ) { const UsbHidDescriptor *hid = usbHidDescriptor(device); if (hid) { if (number < hid->bNumDescriptors) { const UsbClassDescriptor *descriptor = &hid->descriptors[number]; uint16_t length = getLittleEndian16(descriptor->wDescriptorLength); void *buffer = malloc(length); if (buffer) { ssize_t result = usbControlRead(device, UsbControlRecipient_Interface, UsbControlType_Standard, UsbStandardRequest_GetDescriptor, (descriptor->bDescriptorType << 8) | interface, number, buffer, length, timeout); if (result != -1) { *items = buffer; return result; } free(buffer); } else { logMallocError(); } } else { logMessage(LOG_WARNING, "USB report descriptor not found: %u[%u]", interface, number); } } return -1; } int usbHidFillReportDescription ( const unsigned char *items, size_t size, unsigned char identifier, UsbHidReportDescription *description ) { int found = 0; int index = 0; while (index < size) { unsigned char item = items[index++]; UsbHidItemType type = USB_HID_ITEM_TYPE(item); unsigned char length = usbHidItemLengths[USB_HID_ITEM_LENGTH(item)]; uint32_t value = 0; if (length) { unsigned char shift = 0; do { if (index == size) return 0; value |= items[index++] << shift; shift += 8; } while (--length); } switch (type) { case UsbHidItemType_ReportID: if (!found && (value == identifier)) { memset(description, 0, sizeof(*description)); description->reportIdentifier = identifier; found = 1; continue; } break; case UsbHidItemType_ReportCount: if (found) { description->reportCount = value; goto defined; } break; case UsbHidItemType_ReportSize: if (found) { description->reportSize = value; goto defined; } break; case UsbHidItemType_LogicalMinimum: if (found) { description->logicalMinimum = value; goto defined; } break; case UsbHidItemType_LogicalMaximum: if (found) { description->logicalMaximum = value; goto defined; } break; defined: description->defined |= USB_HID_ITEM_BIT(type); continue; default: break; } if (found) break; } return found; } int usbHidGetReportSize ( const unsigned char *items, size_t length, unsigned char identifier, size_t *size ) { UsbHidReportDescription description; *size = 0; if (usbHidFillReportDescription(items, length, identifier, &description)) { if (description.defined & USB_HID_ITEM_BIT(UsbHidItemType_ReportCount)) { if (description.defined & USB_HID_ITEM_BIT(UsbHidItemType_ReportSize)) { uint32_t bytes = ((description.reportCount * description.reportSize) + 7) / 8; logMessage(LOG_CATEGORY(USB_IO), "HID report size: %02X = %"PRIu32, identifier, bytes); *size = 1 + bytes; return 1; } else { logMessage(LOG_WARNING, "HID report size not defined: %02X", identifier); } } else { logMessage(LOG_WARNING, "HID report count not defined: %02X", identifier); } } else { logMessage(LOG_WARNING, "HID report not found: %02X", identifier); } return 0; } ssize_t usbHidGetReport ( UsbDevice *device, unsigned char interface, unsigned char report, void *buffer, uint16_t length, int timeout ) { return usbControlRead(device, UsbControlRecipient_Interface, UsbControlType_Class, UsbHidRequest_GetReport, (UsbHidReportType_Input << 8) | report, interface, buffer, length, timeout); } ssize_t usbHidSetReport ( UsbDevice *device, unsigned char interface, unsigned char report, const void *buffer, uint16_t length, int timeout ) { return usbControlWrite(device, UsbControlRecipient_Interface, UsbControlType_Class, UsbHidRequest_SetReport, (UsbHidReportType_Output << 8) | report, interface, buffer, length, timeout); } ssize_t usbHidGetFeature ( UsbDevice *device, unsigned char interface, unsigned char report, void *buffer, uint16_t length, int timeout ) { return usbControlRead(device, UsbControlRecipient_Interface, UsbControlType_Class, UsbHidRequest_GetReport, (UsbHidReportType_Feature << 8) | report, interface, buffer, length, timeout); } ssize_t usbHidSetFeature ( UsbDevice *device, unsigned char interface, unsigned char report, const void *buffer, uint16_t length, int timeout ) { return usbControlWrite(device, UsbControlRecipient_Interface, UsbControlType_Class, UsbHidRequest_SetReport, (UsbHidReportType_Feature << 8) | report, interface, buffer, length, timeout); }