Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement hid_error #690

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 141 additions & 4 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ struct hid_device_ {
#ifdef DETACH_KERNEL_DRIVER
int is_driver_detached;
#endif

int error;
Youw marked this conversation as resolved.
Show resolved Hide resolved
const char *error_context;
};

static struct hid_api_version api_version = {
Expand All @@ -140,6 +143,8 @@ static hid_device *new_hid_device(void)
{
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
dev->blocking = 1;
dev->error = LIBUSB_SUCCESS;
dev->error_context = NULL;

hidapi_thread_state_init(&dev->thread_state);

Expand Down Expand Up @@ -340,6 +345,88 @@ static int is_language_supported(libusb_device_handle *dev, uint16_t lang)
return 0;
}

static wchar_t *utf8_to_wchar(char *s)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have a similar routine (using iconv) - would be great to have a common implementation if possible

{
wchar_t *w = NULL;

/* we don't use iconv on Android, or when it is explicitly disabled */
#if defined(__ANDROID__) || defined(NO_ICONV)

w = wcsdup(L"not implemented");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but we need a fallback implementation anyway


#else
size_t slen = strlen(s);
wchar_t *wbuf = malloc((slen + 1) * sizeof(wchar_t));
if (!wbuf) { goto err; }
/* iconv variables */
iconv_t ic;
size_t inbytes;
size_t outbytes;
size_t res;
char ** restrict inptr;
char *outptr;
/* buf does not need to be explicitly NULL-terminated because
it is only passed into iconv() which does not need it. */

/* Initialize iconv. */
ic = iconv_open("WCHAR_T", "UTF-8");
if (ic == (iconv_t)-1) {
LOG("iconv_open() failed\n");
return NULL;
}

/* Convert to native wchar_t (UTF-32 on glibc/BSD systems). */
inptr = &s;
inbytes = slen;
outptr = (char*) wbuf;
outbytes = slen * sizeof(wchar_t);
res = iconv(ic, inptr, &inbytes, &outptr, &outbytes);
if (res == (size_t)-1) {
LOG("iconv() failed\n");
goto err;
}

/* Write the terminating NULL. */
wbuf[slen] = 0;

w = wbuf;

err:
iconv_close(ic);

#endif

return w;
}

static wchar_t *libusb_error_wchar(int e, const char * (*f)(int))
{
const char *cs;
char *s;
wchar_t *w;

cs = f(e);
s = strdup(cs);
w = utf8_to_wchar(s);

free(s);

return w;
}

static wchar_t *libusb_error_name_wchar(int error) {
return libusb_error_wchar(error, libusb_error_name);
}

static wchar_t *libusb_strerror_wchar(int error) {
return libusb_error_wchar(error, libusb_strerror);
}
Comment on lines +417 to +423
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't look like it is being used


static void set_error(hid_device *dev, int error, const char *error_context)
{
dev->error = error;
dev->error_context = error_context;
}

/* This function returns a newly allocated wide string containing the USB
device string numbered by the index. The returned string must be freed
Expand Down Expand Up @@ -1582,8 +1669,31 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char
(unsigned char *)data, length,
1000/*timeout millis*/);

if (res < 0)
if (res < 0) {
const char *context = NULL;

switch (res) {
case LIBUSB_ERROR_TIMEOUT:
context = "Transfer timed out";
break;
case LIBUSB_ERROR_PIPE:
context = "Control request not supported by device";
break;
case LIBUSB_ERROR_NO_DEVICE:
context = "Device has disconnected";
break;
case LIBUSB_ERROR_BUSY:
context = "Called from event handling context";
break;
case LIBUSB_ERROR_INVALID_PARAM:
context = "Transfer size larger than supported";
break;
}
Comment on lines +1675 to +1691
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if these are documented by libusb itself - even stronger reason not to have it here at all


set_error(dev, res, context);

return -1;
}

/* Account for the report ID */
if (skipped_report_id)
Expand Down Expand Up @@ -1778,11 +1888,38 @@ int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char
return hid_get_report_descriptor_libusb(dev->device_handle, dev->interface, dev->report_descriptor_size, buf, buf_size);
}


HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
{
(void)dev;
return L"hid_error is not implemented yet";
static const char format_simple[] = "%s: %s";
static const char format_context[] = "%s: %s (%s)";
const char *name, *message, *context, *format;
char *buffer;
wchar_t *w;
size_t len;

if (dev->error == LIBUSB_SUCCESS) {
return NULL;
}

name = libusb_error_name(dev->error);
message = libusb_strerror(dev->error);
context = dev->error_context;
format = context? format_context : format_simple;

len = 1 + snprintf(NULL, 0, format, name, message, context);

buffer = malloc(len);
if (!buffer) {
return NULL;
}

snprintf(buffer, len, format, name, message, context);

w = utf8_to_wchar(buffer);

free(buffer);

return w;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this is a memory leak - by the documentation what is returned by hid_error - is owned by HIDAPI

}


Expand Down
Loading