diff --git a/libusb/hid.c b/libusb/hid.c index abfeede43..74f59cf5e 100644 --- a/libusb/hid.c +++ b/libusb/hid.c @@ -143,6 +143,10 @@ struct hid_device_ { hidapi_error_ctx error; wchar_t *last_read_error_str; + + unsigned int write_timeout_ms; + unsigned int send_output_report_timeout_ms; + unsigned int send_feature_report_timeout_ms; }; static struct hid_api_version api_version = { @@ -165,6 +169,9 @@ static hid_device *new_hid_device(void) return NULL; dev->blocking = 1; + dev->write_timeout_ms = 1000; + dev->send_output_report_timeout_ms = 1000; + dev->send_feature_report_timeout_ms = 1000; hidapi_thread_state_init(&dev->thread_state); @@ -1577,6 +1584,61 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys return NULL; } +void HID_API_EXPORT hid_libusb_set_write_timeout(hid_device *dev, unsigned int timeout) +{ + dev->write_timeout_ms = timeout; +} + +void HID_API_EXPORT hid_libusb_set_send_output_report_timeout(hid_device *dev, unsigned int timeout) +{ + dev->send_output_report_timeout_ms = timeout; +} + +void HID_API_EXPORT hid_libusb_set_send_feature_report_timeout(hid_device *dev, unsigned int timeout) +{ + dev->send_feature_report_timeout_ms = timeout; +} + +static int hidapi_internal_send_output_report(hid_device *dev, const unsigned char *data, size_t length, unsigned int timeout_ms) +{ + int res = -1; + int skipped_report_id = 0; + int report_number; + + if (!data || !length) { + register_string_error(&dev->error, "Zero buffer/length"); + return -1; + } + + register_libusb_error(&dev->error, LIBUSB_SUCCESS, NULL); + + report_number = data[0]; + + if (report_number == 0x0) { + data++; + length--; + skipped_report_id = 1; + } + + res = libusb_control_transfer(dev->device_handle, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, + 0x09/*HID set_report*/, + (2/*HID output*/ << 8) | report_number, + dev->interface, + (unsigned char *)data, length, + timeout_ms); + + if (res < 0) { + register_libusb_error(&dev->error, res, "hidapi_internal_send_output_report"); + return -1; + } + + /* Account for the report ID */ + if (skipped_report_id) + length++; + + return (int)length; +} int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) { @@ -1586,7 +1648,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t if (dev->output_endpoint <= 0) { /* No interrupt out endpoint. Use the Control Endpoint */ - return hid_send_output_report(dev, data, length); + return hidapi_internal_send_output_report(dev, data, length, dev->write_timeout_ms); } if (!data || !length) { @@ -1610,7 +1672,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t dev->output_endpoint, (unsigned char*)data, (int)length, - &actual_length, 1000); + &actual_length, dev->write_timeout_ms); if (res < 0) { register_libusb_error(&dev->error, res, "hid_write"); @@ -1795,7 +1857,7 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char (3/*HID feature*/ << 8) | report_number, dev->interface, (unsigned char *)data, length, - 1000/*timeout millis*/); + dev->send_feature_report_timeout_ms); if (res < 0) { register_libusb_error(&dev->error, res, "hid_send_feature_report"); @@ -1852,43 +1914,7 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, int HID_API_EXPORT hid_send_output_report(hid_device *dev, const unsigned char *data, size_t length) { - int res = -1; - int skipped_report_id = 0; - int report_number; - - if (!data || !length) { - register_string_error(&dev->error, "Zero buffer/length"); - return -1; - } - - register_libusb_error(&dev->error, LIBUSB_SUCCESS, NULL); - - report_number = data[0]; - - if (report_number == 0x0) { - data++; - length--; - skipped_report_id = 1; - } - - res = libusb_control_transfer(dev->device_handle, - LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, - 0x09/*HID set_report*/, - (2/*HID output*/ << 8) | report_number, - dev->interface, - (unsigned char *)data, length, - 1000/*timeout millis*/); - - if (res < 0) { - register_libusb_error(&dev->error, res, "hid_send_output_report"); - return -1; - } - - /* Account for the report ID */ - if (skipped_report_id) - length++; - - return (int)length; + return hidapi_internal_send_output_report(dev, data, length, dev->send_output_report_timeout_ms); } int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) diff --git a/libusb/hidapi_libusb.h b/libusb/hidapi_libusb.h index 6e0ded4f7..417c0f985 100644 --- a/libusb/hidapi_libusb.h +++ b/libusb/hidapi_libusb.h @@ -49,22 +49,77 @@ extern "C" { */ HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys_dev, int interface_num); - /** @brief Similar to @ref hid_error but gives a libusb error code. + /** @brief Similar to @ref hid_error but gives a libusb error code. - Since version 0.15.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0) + Since version 0.15.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0) - If the error occurred is not immediately caused by a libusb function call, - the returned value is 1. @ref hid_error would still contain a valid and meaningful error message. + If the error occurred is not immediately caused by a libusb function call, + the returned value is 1. @ref hid_error would still contain a valid and meaningful error message. - @ingroup API - @param dev A device handle returned from hid_open(), - or NULL to get the last non-device-specific error - (e.g. for errors in hid_open() or hid_enumerate()). + @ingroup API + @param dev A device handle returned from hid_open(), + or NULL to get the last non-device-specific error + (e.g. for errors in hid_open() or hid_enumerate()). + + @returns + enum libusb_error value representing last error code. + */ + HID_API_EXPORT int HID_API_CALL hid_libusb_error(hid_device *dev); + + /** + * @brief Sets the timeout for hid_write operation. + * + * Since version 0.16.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 16, 0) + * + * The default timeout is 1sec for libusb backend. + * + * In case if 1sec is not enough, on in case of multi-platform development, + * the recommended value is 5sec, e.g. to match (unconfigurable) 5sec timeout + * set for hidraw (linux kernel) implementation. + * + * When the timeout is set to 0, the function will not exit, + * until the write operation is performed or an error occurred. + * + * @param timeout New timeout value in milliseconds. + */ + HID_API_EXPORT void HID_API_CALL hid_libusb_set_write_timeout(hid_device *dev, unsigned int timeout); + + /** + * @brief Sets the timeout for hid_send_output_report operation. + * + * Since version 0.16.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 16, 0) + * + * The default timeout is 1sec for libusb backend. + * + * In case if 1sec is not enough, on in case of multi-platform development, + * the recommended value is 5sec, e.g. to match (unconfigurable) 5sec timeout + * set for hidraw (linux kernel) implementation. + * + * When the timeout is set to 0, the function will not exit, + * until the write operation is performed or an error occurred. + * + * @param timeout New timeout value in milliseconds. + */ + HID_API_EXPORT void HID_API_CALL hid_libusb_set_send_output_report_timeout(hid_device *dev, unsigned int timeout); + + /** + * @brief Sets the timeout for hid_send_feature_report operation. + * + * Since version 0.16.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 16, 0) + * + * The default timeout is 1sec for libusb backend. + * + * In case if 1sec is not enough, on in case of multi-platform development, + * the recommended value is 5sec, e.g. to match (unconfigurable) 5sec timeout + * set for hidraw (linux kernel) implementation. + * + * When the timeout is set to 0, the function will not exit, + * until the write operation is performed or an error occurred. + * + * @param timeout New timeout value in milliseconds. + */ + HID_API_EXPORT void HID_API_CALL hid_libusb_set_send_feature_report_timeout(hid_device *dev, unsigned int timeout); - @returns - enum libusb_error value representing last error code. - */ - HID_API_EXPORT int HID_API_CALL hid_libusb_error(hid_device *dev); #ifdef __cplusplus }