From 99c2ca72053d418a7b96fb281aed441d1dcdb44c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 7 May 2020 12:42:14 -0700 Subject: [PATCH] Add 'usbstorage' iostream This ends up being just a file interface for dive computers that expose their data as a filesystem that can be mounted. Right now that's only the Garmin Descent Mk1, although technically the Uemis Zurich also did that (but oddly, and the backend was never merged into libdivecomputer). Signed-off-by: Linus Torvalds --- examples/common.c | 3 + include/libdivecomputer/common.h | 6 +- include/libdivecomputer/iostream.h | 3 + src/Makefile.am | 1 + src/context.c | 1 + src/libdivecomputer.symbols | 2 + src/usb_storage.c | 109 +++++++++++++++++++++++++++++ 7 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/usb_storage.c diff --git a/examples/common.c b/examples/common.c index d8c7262..ba22eaf 100644 --- a/examples/common.c +++ b/examples/common.c @@ -99,6 +99,7 @@ static const transport_table_t g_transports[] = { {"irda", DC_TRANSPORT_IRDA}, {"bluetooth", DC_TRANSPORT_BLUETOOTH}, {"ble", DC_TRANSPORT_BLE}, + {"usbstorage",DC_TRANSPORT_USBSTORAGE}, }; const char * @@ -537,6 +538,8 @@ dctool_iostream_open (dc_iostream_t **iostream, dc_context_t *context, dc_descri return dctool_irda_open (iostream, context, descriptor, devname); case DC_TRANSPORT_BLUETOOTH: return dctool_bluetooth_open (iostream, context, descriptor, devname); + case DC_TRANSPORT_USBSTORAGE: + return dc_usb_storage_open (iostream, context, devname); default: return DC_STATUS_UNSUPPORTED; } diff --git a/include/libdivecomputer/common.h b/include/libdivecomputer/common.h index 7f94f14..154bf12 100644 --- a/include/libdivecomputer/common.h +++ b/include/libdivecomputer/common.h @@ -48,9 +48,13 @@ typedef enum dc_transport_t { DC_TRANSPORT_USBHID = (1 << 2), DC_TRANSPORT_IRDA = (1 << 3), DC_TRANSPORT_BLUETOOTH = (1 << 4), - DC_TRANSPORT_BLE = (1 << 5) + DC_TRANSPORT_BLE = (1 << 5), + DC_TRANSPORT_USBSTORAGE= (1 << 6), } dc_transport_t; +// Idiotic enums can't be queried +#define DC_TRANSPORT_USBSTORAGE DC_TRANSPORT_USBSTORAGE + typedef enum dc_family_t { DC_FAMILY_NULL = 0, /* Suunto */ diff --git a/include/libdivecomputer/iostream.h b/include/libdivecomputer/iostream.h index b09cba1..7e60a73 100644 --- a/include/libdivecomputer/iostream.h +++ b/include/libdivecomputer/iostream.h @@ -310,6 +310,9 @@ dc_iostream_sleep (dc_iostream_t *iostream, unsigned int milliseconds); dc_status_t dc_iostream_close (dc_iostream_t *iostream); +dc_status_t +dc_usb_storage_open (dc_iostream_t **out, dc_context_t *context, const char *name); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/Makefile.am b/src/Makefile.am index b21ef3b..cc71d1a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,7 @@ libdivecomputer_la_SOURCES = \ irda.c \ usbhid.c \ bluetooth.c \ + usb_storage.c \ custom.c if OS_WIN32 diff --git a/src/context.c b/src/context.c index 63824a5..1e77d83 100644 --- a/src/context.c +++ b/src/context.c @@ -334,6 +334,7 @@ dc_context_get_transports (dc_context_t *context) #elif defined(HAVE_LIBUSB) && !defined(__APPLE__) | DC_TRANSPORT_USBHID #endif + | DC_TRANSPORT_USBSTORAGE #ifdef _WIN32 #ifdef HAVE_AF_IRDA_H | DC_TRANSPORT_IRDA diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index b17d60b..96fe6fe 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -76,6 +76,8 @@ dc_usbhid_device_free dc_usbhid_iterator_new dc_usbhid_open +dc_usb_storage_open + dc_custom_open dc_parser_new diff --git a/src/usb_storage.c b/src/usb_storage.c new file mode 100644 index 0000000..c667673 --- /dev/null +++ b/src/usb_storage.c @@ -0,0 +1,109 @@ +/* + * Dummy "stream" operations for USB storage + * + * Copyright (C) 2018 Linus Torvalds + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "common-private.h" +#include "context-private.h" +#include "iostream-private.h" +#include "iterator-private.h" +#include "descriptor-private.h" +#include "timer.h" + +// Fake "device" that just contains the directory name that +// you can read out of the iostream. All the actual IO is +// up to you. +typedef struct dc_usbstorage_t { + dc_iostream_t base; + char pathname[PATH_MAX]; +} dc_usbstorage_t; + +static dc_status_t +dc_usb_storage_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); + +static const dc_iostream_vtable_t dc_usbstorage_vtable = { + sizeof(dc_usbstorage_t), + NULL, /* set_timeout */ + NULL, /* set_latency */ + NULL, /* set_break */ + NULL, /* set_dtr */ + NULL, /* set_rts */ + NULL, /* get_lines */ + NULL, /* get_available */ + NULL, /* configure */ + dc_usb_storage_read, /* read */ + NULL, /* write */ + NULL, /* flush */ + NULL, /* purge */ + NULL, /* sleep */ + NULL, /* close */ +}; + +dc_status_t +dc_usb_storage_open (dc_iostream_t **out, dc_context_t *context, const char *name) +{ + dc_usbstorage_t *device = NULL; + struct stat st; + + if (out == NULL || name == NULL) + return DC_STATUS_INVALIDARGS; + + INFO (context, "Open: name=%s", name); + if (stat(name, &st) < 0 || !S_ISDIR(st.st_mode)) + return DC_STATUS_NODEVICE; + + // Allocate memory. + device = (dc_usbstorage_t *) dc_iostream_allocate (context, &dc_usbstorage_vtable, DC_TRANSPORT_USBSTORAGE); + if (device == NULL) { + SYSERROR (context, ENOMEM); + return DC_STATUS_NOMEMORY; + } + + strncpy(device->pathname, name, PATH_MAX); + device->pathname[PATH_MAX-1] = 0; + + *out = (dc_iostream_t *) device; + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dc_usb_storage_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual) +{ + dc_usbstorage_t *device = (dc_usbstorage_t *) iostream; + size_t len = strlen(device->pathname); + + if (size <= len) + return DC_STATUS_IO; + memcpy(data, device->pathname, len+1); + if (actual) + *actual = len; + return DC_STATUS_SUCCESS; +}