Merge branch 'usbhid'
This commit is contained in:
commit
c3039b4aab
19
configure.ac
19
configure.ac
@ -73,6 +73,8 @@ esac
|
||||
AC_MSG_RESULT([$os_win32])
|
||||
AM_CONDITIONAL([OS_WIN32], [test "$os_win32" = "yes"])
|
||||
|
||||
DEPENDENCIES=""
|
||||
|
||||
# Checks for USB support.
|
||||
AC_ARG_WITH([libusb],
|
||||
[AS_HELP_STRING([--without-libusb],
|
||||
@ -82,10 +84,25 @@ AS_IF([test "x$with_libusb" != "xno"], [
|
||||
PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], [have_libusb=yes], [have_libusb=no])
|
||||
AS_IF([test "x$have_libusb" = "xyes"], [
|
||||
AC_DEFINE([HAVE_LIBUSB], [1], [libusb library])
|
||||
AC_SUBST([DEPENDENCIES], [libusb-1.0])
|
||||
DEPENDENCIES="$DEPENDENCIES libusb-1.0"
|
||||
])
|
||||
])
|
||||
|
||||
# Checks for HIDAPI support.
|
||||
AC_ARG_WITH([hidapi],
|
||||
[AS_HELP_STRING([--without-hidapi],
|
||||
[Build without the hidapi library])],
|
||||
[], [with_hidapi=auto])
|
||||
AS_IF([test "x$with_hidapi" != "xno"], [
|
||||
PKG_CHECK_MODULES([HIDAPI], [hidapi], [have_hidapi=yes], [have_hidapi=no])
|
||||
AS_IF([test "x$have_hidapi" = "xyes"], [
|
||||
AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library])
|
||||
DEPENDENCIES="$DEPENDENCIES hidapi"
|
||||
])
|
||||
])
|
||||
|
||||
AC_SUBST([DEPENDENCIES])
|
||||
|
||||
# Checks for IrDA support.
|
||||
AC_CHECK_HEADERS([winsock2.h af_irda.h], [irda_win32=yes], [irda_win32=no], [
|
||||
#if HAVE_WINSOCK2_H
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
AM_CFLAGS = $(LIBUSB_CFLAGS) -DENABLE_DEPRECATED
|
||||
AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) -DENABLE_DEPRECATED
|
||||
|
||||
lib_LTLIBRARIES = libdivecomputer.la
|
||||
|
||||
libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) -lm
|
||||
libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(HIDAPI_LIBS) -lm
|
||||
libdivecomputer_la_LDFLAGS = \
|
||||
-version-info $(DC_VERSION_LIBTOOL) \
|
||||
-no-undefined \
|
||||
@ -83,6 +83,8 @@ else
|
||||
libdivecomputer_la_SOURCES += irda.h irda_dummy.c
|
||||
endif
|
||||
|
||||
libdivecomputer_la_SOURCES += usbhid.h usbhid.c
|
||||
|
||||
if OS_WIN32
|
||||
libdivecomputer_la_SOURCES += libdivecomputer.rc
|
||||
endif
|
||||
|
||||
@ -23,6 +23,12 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
#define USBHID
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
#define USBHID
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -80,7 +86,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D},
|
||||
{"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E},
|
||||
/* Suunto EON Steel */
|
||||
#ifdef HAVE_LIBUSB
|
||||
#ifdef USBHID
|
||||
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0},
|
||||
#endif
|
||||
/* Uwatec Aladin */
|
||||
|
||||
@ -19,10 +19,6 @@
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -32,24 +28,15 @@
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "array.h"
|
||||
#include "usbhid.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOGDI
|
||||
#endif
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
typedef struct suunto_eonsteel_device_t {
|
||||
dc_device_t base;
|
||||
|
||||
libusb_context *ctx;
|
||||
libusb_device_handle *handle;
|
||||
dc_usbhid_t *usbhid;
|
||||
unsigned int magic;
|
||||
unsigned short seq;
|
||||
unsigned char version[0x30];
|
||||
@ -143,13 +130,13 @@ static void put_le32(unsigned int val, unsigned char *p)
|
||||
static int receive_packet(suunto_eonsteel_device_t *eon, unsigned char *buffer, int size)
|
||||
{
|
||||
unsigned char buf[64];
|
||||
const int InEndpoint = 0x82;
|
||||
int rc, transferred, len;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
size_t transferred = 0;
|
||||
int len;
|
||||
|
||||
/* 5000 = 5s timeout */
|
||||
rc = libusb_interrupt_transfer(eon->handle, InEndpoint, buf, PACKET_SIZE, &transferred, 5000);
|
||||
if (rc) {
|
||||
ERROR(eon->base.context, "read interrupt transfer failed (%s)", libusb_error_name(rc));
|
||||
rc = dc_usbhid_read(eon->usbhid, buf, PACKET_SIZE, &transferred);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR(eon->base.context, "read interrupt transfer failed");
|
||||
return -1;
|
||||
}
|
||||
if (transferred != PACKET_SIZE) {
|
||||
@ -179,11 +166,11 @@ static int send_cmd(suunto_eonsteel_device_t *eon,
|
||||
unsigned int len,
|
||||
const unsigned char *buffer)
|
||||
{
|
||||
const int OutEndpoint = 0x02;
|
||||
unsigned char buf[64];
|
||||
int transferred, rc;
|
||||
unsigned short seq = eon->seq;
|
||||
unsigned int magic = eon->magic;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
size_t transferred = 0;
|
||||
|
||||
// Two-byte packet header, followed by 12 bytes of extended header
|
||||
if (len > sizeof(buf)-2-12) {
|
||||
@ -213,8 +200,8 @@ static int send_cmd(suunto_eonsteel_device_t *eon,
|
||||
memcpy(buf+14, buffer, len);
|
||||
}
|
||||
|
||||
rc = libusb_interrupt_transfer(eon->handle, OutEndpoint, buf, sizeof(buf), &transferred, 5000);
|
||||
if (rc < 0) {
|
||||
rc = dc_usbhid_write(eon->usbhid, buf, sizeof(buf), &transferred);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR(eon->base.context, "write interrupt transfer failed");
|
||||
return -1;
|
||||
}
|
||||
@ -525,22 +512,25 @@ static int get_file_list(suunto_eonsteel_device_t *eon, struct directory_entry *
|
||||
|
||||
static int initialize_eonsteel(suunto_eonsteel_device_t *eon)
|
||||
{
|
||||
const int InEndpoint = 0x82;
|
||||
const unsigned char init[] = {0x02, 0x00, 0x2a, 0x00};
|
||||
unsigned char buf[64];
|
||||
struct eon_hdr hdr;
|
||||
|
||||
dc_usbhid_set_timeout(eon->usbhid, 10);
|
||||
|
||||
/* Get rid of any pending stale input first */
|
||||
for (;;) {
|
||||
int transferred;
|
||||
size_t transferred = 0;
|
||||
|
||||
int rc = libusb_interrupt_transfer(eon->handle, InEndpoint, buf, sizeof(buf), &transferred, 10);
|
||||
if (rc < 0)
|
||||
dc_status_t rc = dc_usbhid_read(eon->usbhid, buf, sizeof(buf), &transferred);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
break;
|
||||
if (!transferred)
|
||||
break;
|
||||
}
|
||||
|
||||
dc_usbhid_set_timeout(eon->usbhid, 5000);
|
||||
|
||||
if (send_cmd(eon, INIT_CMD, sizeof(init), init)) {
|
||||
ERROR(eon->base.context, "Failed to send initialization command");
|
||||
return -1;
|
||||
@ -576,39 +566,24 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char
|
||||
memset (eon->version, 0, sizeof (eon->version));
|
||||
memset (eon->fingerprint, 0, sizeof (eon->fingerprint));
|
||||
|
||||
if (libusb_init(&eon->ctx)) {
|
||||
ERROR(context, "libusb_init() failed");
|
||||
status = DC_STATUS_IO;
|
||||
status = dc_usbhid_open(&eon->usbhid, context, 0x1493, 0x0030);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR(context, "unable to open device");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
eon->handle = libusb_open_device_with_vid_pid(eon->ctx, 0x1493, 0x0030);
|
||||
if (!eon->handle) {
|
||||
ERROR(context, "unable to open device");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_usb_exit;
|
||||
}
|
||||
|
||||
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)
|
||||
libusb_set_auto_detach_kernel_driver(eon->handle, 1);
|
||||
#endif
|
||||
|
||||
libusb_claim_interface(eon->handle, 0);
|
||||
|
||||
if (initialize_eonsteel(eon) < 0) {
|
||||
ERROR(context, "unable to initialize device");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_usb_close;
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
*out = (dc_device_t *) eon;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_usb_close:
|
||||
libusb_close(eon->handle);
|
||||
error_usb_exit:
|
||||
libusb_exit(eon->ctx);
|
||||
error_close:
|
||||
dc_usbhid_close(eon->usbhid);
|
||||
error_free:
|
||||
free(eon);
|
||||
return status;
|
||||
@ -732,19 +707,7 @@ suunto_eonsteel_device_close(dc_device_t *abstract)
|
||||
{
|
||||
suunto_eonsteel_device_t *eon = (suunto_eonsteel_device_t *) abstract;
|
||||
|
||||
libusb_close(eon->handle);
|
||||
libusb_exit(eon->ctx);
|
||||
dc_usbhid_close(eon->usbhid);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#else // no LIBUSB support
|
||||
|
||||
dc_status_t
|
||||
suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
|
||||
{
|
||||
ERROR(context, "The Suunto EON Steel backend needs libusb-1.0");
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
420
src/usbhid.c
Normal file
420
src/usbhid.c
Normal file
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2016 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it 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.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
#define USBHID
|
||||
#ifdef _WIN32
|
||||
#define NOGDI
|
||||
#endif
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
#define USBHID
|
||||
#include <hidapi/hidapi.h>
|
||||
#endif
|
||||
|
||||
#include "usbhid.h"
|
||||
#include "common-private.h"
|
||||
#include "context-private.h"
|
||||
|
||||
struct dc_usbhid_t {
|
||||
/* Library context. */
|
||||
dc_context_t *context;
|
||||
/* Internal state. */
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
libusb_context *ctx;
|
||||
libusb_device_handle *handle;
|
||||
int interface;
|
||||
unsigned char endpoint_in;
|
||||
unsigned char endpoint_out;
|
||||
unsigned int timeout;
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
hid_device *handle;
|
||||
int timeout;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
static dc_status_t
|
||||
syserror(int errcode)
|
||||
{
|
||||
switch (errcode) {
|
||||
case LIBUSB_ERROR_INVALID_PARAM:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
case LIBUSB_ERROR_NO_MEM:
|
||||
return DC_STATUS_NOMEMORY;
|
||||
case LIBUSB_ERROR_NO_DEVICE:
|
||||
case LIBUSB_ERROR_NOT_FOUND:
|
||||
return DC_STATUS_NODEVICE;
|
||||
case LIBUSB_ERROR_ACCESS:
|
||||
case LIBUSB_ERROR_BUSY:
|
||||
return DC_STATUS_NOACCESS;
|
||||
case LIBUSB_ERROR_TIMEOUT:
|
||||
return DC_STATUS_TIMEOUT;
|
||||
default:
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
dc_status_t
|
||||
dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsigned int pid)
|
||||
{
|
||||
#ifdef USBHID
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_usbhid_t *usbhid = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
INFO (context, "Open: vid=%04x, pid=%04x", vid, pid);
|
||||
|
||||
// Allocate memory.
|
||||
usbhid = (dc_usbhid_t *) malloc (sizeof (dc_usbhid_t));
|
||||
if (usbhid == NULL) {
|
||||
ERROR (context, "Out of memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Library context.
|
||||
usbhid->context = context;
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
struct libusb_device **devices = NULL;
|
||||
struct libusb_config_descriptor *config = NULL;
|
||||
|
||||
// Initialize the libusb library.
|
||||
rc = libusb_init (&usbhid->ctx);
|
||||
if (rc != LIBUSB_SUCCESS) {
|
||||
ERROR (context, "Failed to initialize usb support (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Enumerate the USB devices.
|
||||
ssize_t ndevices = libusb_get_device_list (usbhid->ctx, &devices);
|
||||
if (ndevices < 0) {
|
||||
ERROR (context, "Failed to enumerate the usb devices (%s).",
|
||||
libusb_error_name (ndevices));
|
||||
status = syserror (ndevices);
|
||||
goto error_usb_exit;
|
||||
}
|
||||
|
||||
// Find the first device matching the VID/PID.
|
||||
struct libusb_device *device = NULL;
|
||||
for (size_t i = 0; i < ndevices; i++) {
|
||||
struct libusb_device_descriptor desc;
|
||||
rc = libusb_get_device_descriptor (devices[i], &desc);
|
||||
if (rc < 0) {
|
||||
ERROR (context, "Failed to get the device descriptor (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto error_usb_free_list;
|
||||
}
|
||||
|
||||
if (desc.idVendor == vid && desc.idProduct == pid) {
|
||||
device = devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (device == NULL) {
|
||||
ERROR (context, "No matching USB device found.");
|
||||
status = DC_STATUS_NODEVICE;
|
||||
goto error_usb_free_list;
|
||||
}
|
||||
|
||||
// Get the active configuration descriptor.
|
||||
rc = libusb_get_active_config_descriptor (device, &config);
|
||||
if (rc != LIBUSB_SUCCESS) {
|
||||
ERROR (context, "Failed to get the configuration descriptor (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto error_usb_free_list;
|
||||
}
|
||||
|
||||
// Find the first HID interface.
|
||||
const struct libusb_interface_descriptor *interface = NULL;
|
||||
for (unsigned int i = 0; i < config->bNumInterfaces; i++) {
|
||||
const struct libusb_interface *iface = &config->interface[i];
|
||||
for (unsigned int j = 0; j < iface->num_altsetting; j++) {
|
||||
const struct libusb_interface_descriptor *desc = &iface->altsetting[j];
|
||||
if (desc->bInterfaceClass == LIBUSB_CLASS_HID && interface == NULL) {
|
||||
interface = desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interface == NULL) {
|
||||
ERROR (context, "No HID interface found.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_usb_free_config;
|
||||
}
|
||||
|
||||
// Find the first input and output interrupt endpoints.
|
||||
const struct libusb_endpoint_descriptor *ep_in = NULL, *ep_out = NULL;
|
||||
for (unsigned int i = 0; i < interface->bNumEndpoints; i++) {
|
||||
const struct libusb_endpoint_descriptor *desc = &interface->endpoint[i];
|
||||
|
||||
unsigned int type = desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK;
|
||||
unsigned int direction = desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK;
|
||||
|
||||
if (type != LIBUSB_TRANSFER_TYPE_INTERRUPT)
|
||||
continue;
|
||||
|
||||
if (direction == LIBUSB_ENDPOINT_IN && ep_in == NULL) {
|
||||
ep_in = desc;
|
||||
}
|
||||
|
||||
if (direction == LIBUSB_ENDPOINT_OUT && ep_out == NULL) {
|
||||
ep_out = desc;
|
||||
}
|
||||
}
|
||||
|
||||
if (ep_in == NULL || ep_out == NULL) {
|
||||
ERROR (context, "No interrupt endpoints found.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_usb_free_config;
|
||||
}
|
||||
|
||||
usbhid->interface = interface->bInterfaceNumber;
|
||||
usbhid->endpoint_in = ep_in->bEndpointAddress;
|
||||
usbhid->endpoint_out = ep_out->bEndpointAddress;
|
||||
usbhid->timeout = 0;
|
||||
|
||||
INFO (context, "Open: interface=%u, endpoints=%02x,%02x",
|
||||
usbhid->interface, usbhid->endpoint_in, usbhid->endpoint_out);
|
||||
|
||||
// Open the USB device.
|
||||
rc = libusb_open (device, &usbhid->handle);
|
||||
if (rc != LIBUSB_SUCCESS) {
|
||||
ERROR (context, "Failed to open the usb device (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto error_usb_free_config;
|
||||
}
|
||||
|
||||
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)
|
||||
libusb_set_auto_detach_kernel_driver (usbhid->handle, 1);
|
||||
#endif
|
||||
|
||||
// Claim the HID interface.
|
||||
rc = libusb_claim_interface (usbhid->handle, usbhid->interface);
|
||||
if (rc != LIBUSB_SUCCESS) {
|
||||
ERROR (context, "Failed to claim the usb interface (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto error_usb_close;
|
||||
}
|
||||
|
||||
libusb_free_config_descriptor (config);
|
||||
libusb_free_device_list (devices, 1);
|
||||
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
|
||||
// Initialize the hidapi library.
|
||||
rc = hid_init();
|
||||
if (rc < 0) {
|
||||
ERROR (context, "Failed to initialize usb support.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Open the USB device.
|
||||
usbhid->handle = hid_open (vid, pid, NULL);
|
||||
if (usbhid->handle == NULL) {
|
||||
ERROR (context, "Failed to open the usb device.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_hid_exit;
|
||||
}
|
||||
|
||||
usbhid->timeout = -1;
|
||||
#endif
|
||||
|
||||
*out = usbhid;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
error_usb_close:
|
||||
libusb_close (usbhid->handle);
|
||||
error_usb_free_config:
|
||||
libusb_free_config_descriptor (config);
|
||||
error_usb_free_list:
|
||||
libusb_free_device_list (devices, 1);
|
||||
error_usb_exit:
|
||||
libusb_exit (usbhid->ctx);
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
error_hid_exit:
|
||||
hid_exit ();
|
||||
#endif
|
||||
error_free:
|
||||
free (usbhid);
|
||||
return status;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_usbhid_close (dc_usbhid_t *usbhid)
|
||||
{
|
||||
#ifdef USBHID
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
if (usbhid == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
libusb_release_interface (usbhid->handle, usbhid->interface);
|
||||
libusb_close (usbhid->handle);
|
||||
libusb_exit (usbhid->ctx);
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
hid_close(usbhid->handle);
|
||||
hid_exit();
|
||||
#endif
|
||||
free (usbhid);
|
||||
|
||||
return status;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout)
|
||||
{
|
||||
#ifdef USBHID
|
||||
if (usbhid == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
INFO (usbhid->context, "Timeout: value=%i", timeout);
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
if (timeout < 0) {
|
||||
usbhid->timeout = 0;
|
||||
} else if (timeout == 0) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
} else {
|
||||
usbhid->timeout = timeout;
|
||||
}
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
if (timeout < 0) {
|
||||
usbhid->timeout = -1;
|
||||
} else {
|
||||
usbhid->timeout = timeout;
|
||||
}
|
||||
#endif
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual)
|
||||
{
|
||||
#ifdef USBHID
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
int nbytes = 0;
|
||||
|
||||
if (usbhid == NULL) {
|
||||
status = DC_STATUS_INVALIDARGS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
int rc = libusb_interrupt_transfer (usbhid->handle, usbhid->endpoint_in, data, size, &nbytes, usbhid->timeout);
|
||||
if (rc != LIBUSB_SUCCESS) {
|
||||
ERROR (usbhid->context, "Usb read interrupt transfer failed (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto out;
|
||||
}
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
nbytes = hid_read_timeout(usbhid->handle, data, size, usbhid->timeout);
|
||||
if (nbytes < 0) {
|
||||
ERROR (usbhid->context, "Usb read interrupt transfer failed.");
|
||||
status = DC_STATUS_IO;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
|
||||
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
|
||||
return status;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *actual)
|
||||
{
|
||||
#ifdef USBHID
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
int nbytes = 0;
|
||||
|
||||
if (usbhid == NULL) {
|
||||
status = DC_STATUS_INVALIDARGS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
int rc = libusb_interrupt_transfer (usbhid->handle, usbhid->endpoint_out, (void *) data, size, &nbytes, 0);
|
||||
if (rc != LIBUSB_SUCCESS) {
|
||||
ERROR (usbhid->context, "Usb write interrupt transfer failed (%s).",
|
||||
libusb_error_name (rc));
|
||||
status = syserror (rc);
|
||||
goto out;
|
||||
}
|
||||
#elif defined(HAVE_HIDAPI)
|
||||
nbytes = hid_write(usbhid->handle, data, size);
|
||||
if (nbytes < 0) {
|
||||
ERROR (usbhid->context, "Usb write interrupt transfer failed.");
|
||||
status = DC_STATUS_IO;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
|
||||
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
|
||||
return status;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
122
src/usbhid.h
Normal file
122
src/usbhid.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2016 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it 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.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DC_USBHID_H
|
||||
#define DC_USBHID_H
|
||||
|
||||
#include <libdivecomputer/common.h>
|
||||
#include <libdivecomputer/context.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB HID connection.
|
||||
*/
|
||||
typedef struct dc_usbhid_t dc_usbhid_t;
|
||||
|
||||
/**
|
||||
* Open a USB HID connection.
|
||||
*
|
||||
* @param[out] usbhid A location to store the USB HID connection.
|
||||
* @param[in] context A valid context object.
|
||||
* @param[in] vid The USB Vendor ID of the device.
|
||||
* @param[in] pid The USB Product ID of the device.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_usbhid_open (dc_usbhid_t **usbhid, dc_context_t *context, unsigned int vid, unsigned int pid);
|
||||
|
||||
/**
|
||||
* Close the connection and free all resources.
|
||||
*
|
||||
* @param[in] usbhid A valid USB HID connection.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_usbhid_close (dc_usbhid_t *usbhid);
|
||||
|
||||
/**
|
||||
* Set the read timeout.
|
||||
*
|
||||
* There are three distinct modes available:
|
||||
*
|
||||
* 1. Blocking (timeout < 0):
|
||||
*
|
||||
* The read operation is blocked until all the requested bytes have
|
||||
* been received. If the requested number of bytes does not arrive,
|
||||
* the operation will block forever.
|
||||
*
|
||||
* 2. Non-blocking (timeout == 0):
|
||||
*
|
||||
* The read operation returns immediately with the bytes that have
|
||||
* already been received, even if no bytes have been received.
|
||||
*
|
||||
* 3. Timeout (timeout > 0):
|
||||
*
|
||||
* The read operation is blocked until all the requested bytes have
|
||||
* been received. If the requested number of bytes does not arrive
|
||||
* within the specified amount of time, the operation will return
|
||||
* with the bytes that have already been received.
|
||||
*
|
||||
* @param[in] usbhid A valid USB HID connection.
|
||||
* @param[in] timeout The timeout in milliseconds.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout);
|
||||
|
||||
/**
|
||||
* Read data from the USB HID connection.
|
||||
*
|
||||
* @param[in] usbhid A valid USB HID connection.
|
||||
* @param[out] data The memory buffer to read the data into.
|
||||
* @param[in] size The number of bytes to read.
|
||||
* @param[out] actual An (optional) location to store the actual
|
||||
* number of bytes transferred.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual);
|
||||
|
||||
/**
|
||||
* Write data to the USB HID connection.
|
||||
*
|
||||
* @param[in] usbhid A valid USB HID connection.
|
||||
* @param[in] data The memory buffer to write the data from.
|
||||
* @param[in] size The number of bytes to write.
|
||||
* @param[out] actual An (optional) location to store the actual
|
||||
* number of bytes transferred.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *actual);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_USBHID_H */
|
||||
Loading…
x
Reference in New Issue
Block a user