diff --git a/include/libcasio/builtin.h b/include/libcasio/builtin.h
index 0287ad4..a75f2ed 100644
--- a/include/libcasio/builtin.h
+++ b/include/libcasio/builtin.h
@@ -70,6 +70,15 @@ CASIO_EXTERN int CASIO_EXPORT casio_opencom_windows
# define LIBCASIO_DISABLED_WINDOWS
# endif
/* ************************************************************************* */
+/* Built-in filesystems */
+/* ************************************************************************* */
+/* Make a local POSIX filesystem interface. */
+# if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
+/* TODO */
+# else
+# define LIBCASIO_DISABLED_POSIX_FS
+# endif
+/* ************************************************************************* */
/* Built-in serial devices listing */
/* ************************************************************************* */
/* List serial devices on Linux. */
diff --git a/include/libcasio/fs.h b/include/libcasio/fs.h
index e150b5b..caee8d7 100644
--- a/include/libcasio/fs.h
+++ b/include/libcasio/fs.h
@@ -45,6 +45,7 @@ typedef struct casio_stat_s casio_stat_t;
struct casio_pathnode_s {
casio_pathnode_t *casio_pathnode_next;
+ size_t casio_pathnode_size;
unsigned char casio_pathnode_name[2048];
};
@@ -61,21 +62,32 @@ struct casio_path_s {
/* ************************************************************************* */
/* Filesystem file entry */
/* ************************************************************************* */
-/* This structure defines file metadata. */
+/* This structure defines file metadata.
+ * Here are the flags: */
-# define CASIO_MODE_IFMT 0xF000
-# define CASIO_MODE_IFREG 0x1000
-# define CASIO_MODE_IFDIR 0x2000
+/* TODO */
-typedef unsigned long casio_mode_t;
+/* And here are the "file" types ("file" is between quotes as on Windows,
+ * directories are not files like on Unix) you can find: */
+
+# define CASIO_STAT_TYPE_REG 0x0001 /* Regular file. */
+# define CASIO_STAT_TYPE_DIR 0x0002 /* Directory. */
+# define CASIO_STAT_TYPE_LNK 0x0004 /* Symbolic link. */
+# define CASIO_STAT_TYPE_CHAR 0x0008 /* Character device. */
+# define CASIO_STAT_TYPE_BLK 0x0010 /* Block device. */
+# define CASIO_STAT_TYPE_SOCK 0x0020 /* Socket. */
+
+/* And here is the stat structure.
+ * The path is not in it. */
struct casio_stat_s {
- casio_mode_t casio_stat_mode;
+ unsigned int casio_stat_flags;
+ unsigned int casio_stat_type;
casio_off_t casio_stat_size;
};
typedef void casio_fs_list_func_t OF((void *casio__cookie,
- const void *casio__name, const casio_stat_t *casio__stat));
+ const casio_pathnode_t *casio__node, const casio_stat_t *casio__stat));
/* ************************************************************************* */
/* Filesystem description */
/* ************************************************************************* */
@@ -85,27 +97,25 @@ typedef void casio_fs_list_func_t OF((void *casio__cookie,
* directory. */
typedef int casio_fs_stat_t
- OF((void *casio__cookie, const char *casio__device,
- const void *casio__path[], casio_stat_t *casio__stat));
+ OF((void *casio__cookie, casio_path_t *casio__path,
+ casio_stat_t *casio__stat));
/* The `casio_fs_makedir` callback creates a directory. */
typedef int casio_fs_makedir_t
- OF((void *casio__cookie, const char *casio__device,
- const void *casio__path[]));
+ OF((void *casio__cookie, casio_path_t *casio__path));
/* The `casio_fs_del` callback deletes a file or directory. */
typedef int casio_fs_del_t
- OF((void *casio__cookie, const char *casio__device,
- const void *casio__path[]));
+ OF((void *casio__cookie, casio_path_t *casio__path));
/* The `casio_fs_move` callback renames/moves a file into an
* other directory, eventually with an other name. */
typedef int casio_fs_move_t
- OF((void *casio__cookie, const char *casio__device,
- const void *casio__orig[], const void *casio__new[]));
+ OF((void *casio__cookie, casio_path_t *casio__orig,
+ casio_path_t *casio__dest));
/* The `casio_fs_open` callback makes a stream out of a file with a path. */
@@ -116,8 +126,7 @@ typedef int casio_fs_open_t
/* The `casio_fs_list` callback lists files in a directory. */
typedef int casio_fs_list_t
- OF((void *casio__cookie, const char *casio__device,
- const void *casio__dirpath[],
+ OF((void *casio__cookie, casio_path_t *casio__path,
casio_fs_list_func_t *casio__callback, void *casio__cbcookie));
/* The `casio_fs_close` callback is called when the filesystem interface
diff --git a/src/fs/builtin/posix/path.c b/src/fs/builtin/posix/path.c
index 43a1f49..6fad6c9 100644
--- a/src/fs/builtin/posix/path.c
+++ b/src/fs/builtin/posix/path.c
@@ -17,6 +17,7 @@
* along with libcasio; if not, see .
* ************************************************************************* */
#include "posix.h"
+#ifndef LIBCASIO_DISABLED_POSIX_FS
/**
* makepathnode:
@@ -33,9 +34,65 @@ CASIO_LOCAL casio_pathnode_t *makepathnode(size_t size)
node = malloc(offsetof(casio_pathnode_t, casio_pathnode_name) + size);
if (!node) return (NULL);
node->casio_pathnode_next = NULL;
+ node->casio_pathnode_size = size;
return (node);
}
+/**
+ * casio_make_posix_path:
+ * Make a POSIX path from a platform-agnostic path.
+ *
+ * @arg ppath the path to make.
+ * @arg array the path array.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_make_posix_path(char **ppath, casio_path_t *array)
+{
+ size_t length; const casio_pathnode_t *node;
+ char *path;
+
+ /* Make up the length and validate. */
+ length = !(array->casio_path_flags & casio_pathflag_rel);
+ node = array->casio_path_nodes;
+ while (node) {
+ size_t nodesize = node->casio_pathnode_size;
+
+ /* Check that there is no forbidden characters. */
+ if (memchr(node->casio_pathnode_name, 0, nodesize)
+ || memchr(node->casio_pathnode_name, '/', nodesize))
+ return (casio_error_invalid);
+
+ /* Iterate on the node, add to the length. */
+ length += nodesize;
+ node = node->casio_pathnode_next;
+ if (node) length++; /* '/' */
+ }
+
+ /* Allocate the path. */
+ *ppath = malloc(length + 1);
+ path = *ppath; if (!path) return (casio_error_alloc);
+
+ /* Fill the path. */
+ if (~array->casio_path_flags & casio_pathflag_rel)
+ *path++ = '/';
+ node = array->casio_path_nodes;
+ while (node) {
+ size_t nodesize = node->casio_pathnode_size;
+
+ /* Copy the node data. */
+ memcpy(path, node->casio_pathnode_name, nodesize);
+ path += nodesize;
+
+ /* Iterate on the node, copy a slash if needed. */
+ node = node->casio_pathnode_next;
+ if (node) *path++ = '/';
+ }
+
+ /* No error has occured! */
+ return (0);
+}
+
/**
* casio_make_posix_path_array:
* Make a path array from a POSIX path.
@@ -98,3 +155,5 @@ fail:
}
return (casio_error_alloc);
}
+
+#endif
diff --git a/src/fs/builtin/posix/posix.h b/src/fs/builtin/posix/posix.h
index 98bdbda..c595a3c 100644
--- a/src/fs/builtin/posix/posix.h
+++ b/src/fs/builtin/posix/posix.h
@@ -19,8 +19,22 @@
#ifndef LOCAL_FS_BUILTIN_POSIX_H
# define LOCAL_FS_BUILTIN_POSIX_H 1
# include "../../../internals.h"
+# ifndef LIBCASIO_DISABLED_POSIX_FS
+# include
+# include
+/* Path conversions. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_make_posix_path
+ OF((char **casio__path, casio_path_t *casio__array));
CASIO_EXTERN int CASIO_EXPORT casio_make_posix_path_array
OF((casio_path_t **casio__path, const char *casio__rawpath));
+/* File information gathering. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_posix_stat
+ OF((void *casio__cookie, casio_path_t *casio__path,
+ casio_stat_t *casio__file_info));
+
+# endif
#endif /* LOCAL_FS_BUILTIN_POSIX_H */
diff --git a/src/fs/builtin/posix/stat.c b/src/fs/builtin/posix/stat.c
new file mode 100644
index 0000000..3abe359
--- /dev/null
+++ b/src/fs/builtin/posix/stat.c
@@ -0,0 +1,86 @@
+/* ****************************************************************************
+ * fs/builtin/posix/stat.c -- get file information from POSIX filesystem.
+ * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "posix.h"
+#ifndef LIBCASIO_DISABLED_POSIX_FS
+
+/**
+ * casio_posix_stat:
+ * POSIX stat.
+ *
+ * @arg cookie the POSIX cookie.
+ * @arg apath the path to get.
+ * @arg stat the file information to fill.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_posix_stat(void *cookie,
+ casio_path_t *apath, casio_stat_t *file_info)
+{
+ int err; char *path = NULL;
+ struct stat statbuf;
+
+ (void)cookie;
+ /* Make the POSIX path. */
+ err = casio_make_posix_path(&path, apath);
+ if (err) return (err);
+
+ /* Make the stat. */
+ if (lstat(path, &statbuf)) {
+ /* FIXME: different kinds of errnos? */
+ err = casio_error_unknown;
+ goto fail;
+ }
+
+ /* Gather the type. */
+ switch (statbuf.st_mode & S_IFMT) {
+ case S_IFIFO: /* FALLTHRU */
+ case S_IFCHR:
+ file_info->casio_stat_type = CASIO_STAT_TYPE_CHAR;
+ break;
+ case S_IFDIR:
+ file_info->casio_stat_type = CASIO_STAT_TYPE_DIR;
+ break;
+ case S_IFBLK:
+ file_info->casio_stat_type = CASIO_STAT_TYPE_BLK;
+ break;
+ case S_IFREG:
+ file_info->casio_stat_type = CASIO_STAT_TYPE_REG;
+ break;
+ case S_IFLNK:
+ file_info->casio_stat_type = CASIO_STAT_TYPE_LNK;
+ break;
+ case S_IFSOCK:
+ file_info->casio_stat_type = CASIO_STAT_TYPE_SOCK;
+ break;
+ default:
+ file_info->casio_stat_type = 0;
+ break;
+ }
+
+ /* Get the rest, and return. */
+ file_info->casio_stat_flags = 0;
+ file_info->casio_stat_size = statbuf.st_size;
+
+ err = 0;
+fail:
+ free(path);
+ return (err);
+}
+
+#endif
diff --git a/src/link/seven/datastream.c b/src/link/seven/datastream.c
index e0bbb24..4a0481b 100644
--- a/src/link/seven/datastream.c
+++ b/src/link/seven/datastream.c
@@ -312,7 +312,7 @@ int CASIO_EXPORT casio_seven_open_data_stream(casio_stream_t **stream,
void *dcookie)
{
seven_data_cookie_t *cookie = NULL;
- casio_mode_t mode;
+ casio_openmode_t mode;
/* make checks */
chk_handle(link);
diff --git a/src/stream/builtin/libusb.c b/src/stream/builtin/libusb.c
deleted file mode 100644
index fed95e2..0000000
--- a/src/stream/builtin/libusb.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/* ****************************************************************************
- * stream/builtin/libusb.c -- built-in libusb stream.
- * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
- *
- * This file is part of libcasio.
- * libcasio 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 3.0 of the License,
- * or (at your option) any later version.
- *
- * libcasio 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 libcasio; if not, see .
- * ************************************************************************* */
-#include "../../internals.h"
-#ifndef LIBCASIO_DISABLED_LIBUSB
-# include
-
-/* libusb cookie structure */
-# define BUFSIZE 2048
-typedef struct {
- libusb_context *_context;
- libusb_device_handle *_handle;
-
- /* timeouts */
- unsigned int tmread, tmwrite;
-
- /* buffer control */
- ssize_t _start, _end;
- unsigned char _buffer[BUFSIZE];
-} libusb_cookie_t;
-/* ************************************************************************* */
-/* Settings, close callbacks */
-/* ************************************************************************* */
-/**
- * casio_libusb_settm:
- * Set timeouts.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg timeouts the timeouts.
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_libusb_settm(void *vcookie,
- const casio_timeouts_t *timeouts)
-{
- libusb_cookie_t *cookie = (void*)vcookie;
-
- /* set the timeouts */
- cookie->tmread = timeouts->casio_timeouts_read;
- cookie->tmwrite = timeouts->casio_timeouts_write;
-
- /* no error! */
- return (0);
-}
-
-/**
- * casio_libusb_close:
- * Close libusb cookie.
- *
- * @arg vcookie the cookie (uncasted).
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_libusb_close(void *vcookie)
-{
- libusb_cookie_t *cookie = (libusb_cookie_t*)vcookie;
-
- if (cookie->_handle) libusb_close(cookie->_handle);
- if (cookie->_context) libusb_exit(cookie->_context);
- casio_free(vcookie);
- return (0);
-}
-/* ************************************************************************* */
-/* Character stream callbacks */
-/* ************************************************************************* */
-/**
- * casio_libusb_read:
- * Read using libusb cookie.
- *
- * @arg vcookie the cookie (voided)
- * @arg data the data pointer.
- * @arg size the data size.
- * @return the error code (0 if ok).
- */
-
-# define ENDPOINT_IN (LIBUSB_ENDPOINT_IN | LIBUSB_TRANSFER_TYPE_BULK)
-CASIO_LOCAL int casio_libusb_read(void *vcookie,
- unsigned char *dest, size_t size)
-{
- int libusberr; libusb_cookie_t *cookie = (libusb_cookie_t*)vcookie;
- size_t tocopy;
-
- /* transmit what's already in the buffer */
- if (cookie->_start <= cookie->_end) {
- tocopy = cookie->_end - cookie->_start + 1;
- if (tocopy > size) tocopy = size;
-
- memcpy(dest, &cookie->_buffer[cookie->_start], tocopy);
- cookie->_start += tocopy;
- dest += tocopy;
- size -= tocopy;
- }
-
- /* main receiving loop */
- while (size) {
- int recv;
-
- /* make the transfer. */
- libusberr = libusb_bulk_transfer(cookie->_handle, ENDPOINT_IN,
- cookie->_buffer, BUFSIZE, &recv, cookie->tmread);
- switch (libusberr) {
- case 0: break;
-
- case LIBUSB_ERROR_PIPE:
- case LIBUSB_ERROR_NO_DEVICE:
- case LIBUSB_ERROR_IO:
- msg((ll_error, "The calculator is not here anymore :("));
- return (casio_error_nocalc);
-
- case LIBUSB_ERROR_TIMEOUT:
- return (casio_error_timeout);
-
- default:
- msg((ll_fatal, "libusb error was %d: %s", libusberr,
- libusb_strerror(libusberr)));
- return (casio_error_unknown);
- }
-
- /* get the current size to copy */
- tocopy = (size_t)recv;
- if (tocopy > size) tocopy = size;
-
- /* copy to destination */
- memcpy(dest, cookie->_buffer, tocopy);
- dest += tocopy;
- size -= tocopy;
-
- /* correct start and end points */
- cookie->_start = tocopy;
- cookie->_end = (size_t)recv - 1;
- }
-
- /* no error */
- return (0);
-}
-
-/**
- * casio_libusb_write:
- * Write using libusb cookie.
- *
- * @arg vcookie the cookie (uncasted)
- * @arg data the source.
- * @arg size the source size.
- * @return the error code (0 if ok).
- */
-
-# define ENDPOINT_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
-CASIO_LOCAL int casio_libusb_write(void *vcookie,
- const unsigned char *data, size_t size)
-{
- libusb_cookie_t *cookie = (libusb_cookie_t*)vcookie;
- int sent, libusberr;
-
- /* Make the transfer. */
- libusberr = libusb_bulk_transfer(cookie->_handle, ENDPOINT_OUT,
- (unsigned char*)data, size, &sent, cookie->tmwrite);
- switch (libusberr) {
- case 0: break;
-
- case LIBUSB_ERROR_PIPE:
- case LIBUSB_ERROR_NO_DEVICE:
- msg((ll_error, "The calculator is not here anymore :("));
- return (casio_error_nocalc);
-
- default:
- msg((ll_fatal, "libusb error was %d: %s", libusberr,
- libusb_strerror(libusberr)));
- return (casio_error_unknown);
- }
-
- /* no error! */
- return (0);
-}
-/* ************************************************************************* */
-/* Main libusb function */
-/* ************************************************************************* */
-# include
-# include
-
-/* libusb callbacks. */
-CASIO_LOCAL const casio_streamfuncs_t casio_libusb_callbacks = {
- casio_libusb_close, casio_libusb_settm,
- casio_libusb_read, casio_libusb_write, NULL,
- NULL, NULL
-};
-
-/**
- * casio_openusb_libusb:
- * Initialize a stream with USB device using libusb.
- *
- * @arg handle the handle to create.
- * @arg flags the flags.
- * @return the error code (0 if you're a knoop).
- */
-
-int CASIO_EXPORT casio_openusb_libusb(casio_stream_t **stream)
-{
- int err = 0, uerr, id, device_count;
- libusb_context *context = NULL;
- libusb_device *calc = NULL, **device_list = NULL;
- libusb_device_handle *dhandle = NULL;
- libusb_cookie_t *cookie = NULL;
- casio_openmode_t openmode = CASIO_OPENMODE_USB;
-
- /* open up context */
- if (libusb_init(&context)) {
- msg((ll_fatal, "Couldn't create libusb context."));
- return (casio_error_nocalc);
- }
-
- /* get device list */
- device_count = libusb_get_device_list(context, &device_list);
- if (device_count < 0) {
- msg((ll_fatal, "couldn't get device list."));
- err = casio_error_nocalc;
- goto fail;
- }
-
- /* look for the calculator */
- for (id = 0; id < device_count; id++) {
- struct libusb_device_descriptor descriptor;
-
- /* get the device descriptor */
- if (libusb_get_device_descriptor(device_list[id], &descriptor))
- continue;
-
- /* check if is a CASIO Protocol 7.00 device */
- if (descriptor.idVendor == 0x07cf
- && descriptor.idProduct == 0x6101) {
- openmode |= CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE;
- calc = device_list[id];
- break;
- }
-
- /* check if is a CASIO SCSI device */
- if (descriptor.idVendor == 0x07cf
- && descriptor.idProduct == 0x6102) {
- openmode |= CASIO_OPENMODE_SCSI;
- calc = device_list[id];
- break;
- }
- }
-
- /* the calculator wasn't found */
- if (!calc) {
- libusb_free_device_list(device_list, 1);
- err = casio_error_nocalc;
- goto fail;
- }
-
- /* get calculator handle */
- msg((ll_info, "getting the device handle"));
- uerr = libusb_open(calc, &dhandle);
- libusb_free_device_list(device_list, 1);
-
- /* check if we have the handle */
- switch (uerr) {
- /* couldn't get access to the device */
- case LIBUSB_ERROR_ACCESS:
- err = casio_error_noaccess;
- goto fail;
-
- /* default cases */
- case 0: break;
- default:
- msg((ll_fatal, "libusb_open returned %d: %s",
- uerr, libusb_error_name(uerr)));
- err = casio_error_noaccess;
- goto fail;
- }
-
- /* disconnect any kernel driver */
- msg((ll_info, "Detaching kernel driver, if any."));
- uerr = libusb_detach_kernel_driver(dhandle, 0);
- switch (uerr) {
- /* cases where it's okay */
- case 0: case LIBUSB_ERROR_NOT_SUPPORTED:
- case LIBUSB_ERROR_NOT_FOUND: break;
-
- /* cases where it's not okay */
- case LIBUSB_ERROR_INVALID_PARAM:
- msg((ll_fatal, "Interface 0 doesn't exist...?"));
- err = casio_error_nocalc;
- goto fail;
- case LIBUSB_ERROR_NO_DEVICE:
- err = casio_error_nocalc;
- goto fail;
- default:
- msg((ll_fatal, "libusb returned %d: %s",
- uerr, libusb_error_name(uerr)));
- goto fail;
- }
-
- /* check if the interface is active */
- libusb_kernel_driver_active(dhandle, 0);
-
- /* claim the interface */
- msg((ll_info, "Claiming the interface."));
- uerr = libusb_claim_interface(dhandle, 0);
- switch (uerr) {
- /* cases where it's okay (not a lot) */
- case 0: break;
-
- /* cases where it's not okay */
- case LIBUSB_ERROR_NO_DEVICE:
- case LIBUSB_ERROR_NOT_FOUND:
- err = casio_error_nocalc;
- goto fail;
- case LIBUSB_ERROR_BUSY:
- msg((ll_info,
- "Another program/driver has claimed the interface..."));
- err = casio_error_noaccess;
- goto fail;
- default:
- msg((ll_info, "libusb returned %d: %s",
- uerr, libusb_error_name(uerr)));
- goto fail;
- }
-
- /* make the cookie */
- cookie = casio_alloc(1, sizeof(libusb_cookie_t));
- err = casio_error_alloc;
- if (!cookie) goto fail;
- cookie->_context = context;
- cookie->_handle = dhandle;
- cookie->_start = 0;
- cookie->_end = -1;
-
- /* final call. */
- return (casio_open(stream, openmode,
- cookie, &casio_libusb_callbacks));
-fail:
- if (cookie) casio_free(cookie);
- if (dhandle) libusb_close(dhandle);
- if (context) libusb_exit(context);
- return (err);
-}
-
-#endif
diff --git a/src/stream/builtin/libusb/close.c b/src/stream/builtin/libusb/close.c
new file mode 100644
index 0000000..d70983b
--- /dev/null
+++ b/src/stream/builtin/libusb/close.c
@@ -0,0 +1,38 @@
+/* ****************************************************************************
+ * stream/builtin/libusb/close.c -- close a libusb stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "libusb.h"
+#ifndef LIBCASIO_DISABLED_LIBUSB
+
+/**
+ * casio_libusb_close:
+ * Close libusb cookie.
+ *
+ * @arg cookie the cookie.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_libusb_close(cookie_libusb_t *cookie)
+{
+ if (cookie->_handle) libusb_close(cookie->_handle);
+ if (cookie->_context) libusb_exit(cookie->_context);
+ casio_free(cookie);
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/libusb/libusb.h b/src/stream/builtin/libusb/libusb.h
new file mode 100644
index 0000000..25d14f4
--- /dev/null
+++ b/src/stream/builtin/libusb/libusb.h
@@ -0,0 +1,56 @@
+/* ****************************************************************************
+ * stream/builtin/libusb/libusb.h -- libusb stream internals.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#ifndef LOCAL_STREAM_BUILTIN_LIBUSB_H
+# include "../../../internals.h"
+
+# ifndef LIBCASIO_DISABLED_LIBUSB
+# include
+
+# define BUFSIZE 2048
+typedef struct {
+ libusb_context *_context;
+ libusb_device_handle *_handle;
+
+ /* timeouts */
+ unsigned int tmread, tmwrite;
+
+ /* buffer control */
+ ssize_t _start, _end;
+ unsigned char _buffer[BUFSIZE];
+} cookie_libusb_t;
+
+/* General callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_libusb_close
+ OF((cookie_libusb_t *casio__cookie));
+CASIO_EXTERN int CASIO_EXPORT casio_libusb_settm
+ OF((cookie_libusb_t *casio__cookie,
+ const casio_timeouts_t *casio__timeouts));
+
+/* Character device callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_libusb_read
+ OF((cookie_libusb_t *casio__cookie,
+ unsigned char *casio__dest, size_t casio__size));
+CASIO_EXTERN int CASIO_EXPORT casio_libusb_write
+ OF((cookie_libusb_t *casio__cookie,
+ const unsigned char *casio__data, size_t casio__size));
+
+# endif
+#endif /* LOCAL_STREAM_BUILTIN_LIBUSB_H */
diff --git a/src/stream/builtin/libusb/open.c b/src/stream/builtin/libusb/open.c
new file mode 100644
index 0000000..c5b60cd
--- /dev/null
+++ b/src/stream/builtin/libusb/open.c
@@ -0,0 +1,183 @@
+/* ****************************************************************************
+ * stream/builtin/libusb/open.c -- open a libusb stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "libusb.h"
+#ifndef LIBCASIO_DISABLED_LIBUSB
+
+/* Stream callbacks. */
+CASIO_LOCAL const casio_streamfuncs_t casio_libusb_callbacks = {
+ (casio_stream_close_t*)&casio_libusb_close,
+ (casio_stream_settm_t*)&casio_libusb_settm,
+ (casio_stream_read_t*)&casio_libusb_read,
+ (casio_stream_write_t*)&casio_libusb_write,
+ NULL, NULL, NULL
+};
+
+/**
+ * casio_openusb_libusb:
+ * Initialize a stream with USB device using libusb.
+ *
+ * @arg handle the handle to create.
+ * @arg flags the flags.
+ * @return the error code (0 if you're a knoop).
+ */
+
+int CASIO_EXPORT casio_openusb_libusb(casio_stream_t **stream)
+{
+ int err = 0, uerr, id, device_count;
+ libusb_context *context = NULL;
+ libusb_device *calc = NULL, **device_list = NULL;
+ libusb_device_handle *dhandle = NULL;
+ cookie_libusb_t *cookie = NULL;
+ casio_openmode_t openmode = CASIO_OPENMODE_USB;
+
+ /* open up context */
+ if (libusb_init(&context)) {
+ msg((ll_fatal, "Couldn't create libusb context."));
+ return (casio_error_nocalc);
+ }
+
+ /* get device list */
+ device_count = libusb_get_device_list(context, &device_list);
+ if (device_count < 0) {
+ msg((ll_fatal, "couldn't get device list."));
+ err = casio_error_nocalc;
+ goto fail;
+ }
+
+ /* look for the calculator */
+ for (id = 0; id < device_count; id++) {
+ struct libusb_device_descriptor descriptor;
+
+ /* get the device descriptor */
+ if (libusb_get_device_descriptor(device_list[id], &descriptor))
+ continue;
+
+ /* check if is a CASIO Protocol 7.00 device */
+ if (descriptor.idVendor == 0x07cf
+ && descriptor.idProduct == 0x6101) {
+ openmode |= CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE;
+ calc = device_list[id];
+ break;
+ }
+
+ /* check if is a CASIO SCSI device */
+ if (descriptor.idVendor == 0x07cf
+ && descriptor.idProduct == 0x6102) {
+ openmode |= CASIO_OPENMODE_SCSI;
+ calc = device_list[id];
+ break;
+ }
+ }
+
+ /* the calculator wasn't found */
+ if (!calc) {
+ libusb_free_device_list(device_list, 1);
+ err = casio_error_nocalc;
+ goto fail;
+ }
+
+ /* get calculator handle */
+ msg((ll_info, "getting the device handle"));
+ uerr = libusb_open(calc, &dhandle);
+ libusb_free_device_list(device_list, 1);
+
+ /* check if we have the handle */
+ switch (uerr) {
+ /* couldn't get access to the device */
+ case LIBUSB_ERROR_ACCESS:
+ err = casio_error_noaccess;
+ goto fail;
+
+ /* default cases */
+ case 0: break;
+ default:
+ msg((ll_fatal, "libusb_open returned %d: %s",
+ uerr, libusb_error_name(uerr)));
+ err = casio_error_noaccess;
+ goto fail;
+ }
+
+ /* disconnect any kernel driver */
+ msg((ll_info, "Detaching kernel driver, if any."));
+ uerr = libusb_detach_kernel_driver(dhandle, 0);
+ switch (uerr) {
+ /* cases where it's okay */
+ case 0: case LIBUSB_ERROR_NOT_SUPPORTED:
+ case LIBUSB_ERROR_NOT_FOUND: break;
+
+ /* cases where it's not okay */
+ case LIBUSB_ERROR_INVALID_PARAM:
+ msg((ll_fatal, "Interface 0 doesn't exist...?"));
+ err = casio_error_nocalc;
+ goto fail;
+ case LIBUSB_ERROR_NO_DEVICE:
+ err = casio_error_nocalc;
+ goto fail;
+ default:
+ msg((ll_fatal, "libusb returned %d: %s",
+ uerr, libusb_error_name(uerr)));
+ goto fail;
+ }
+
+ /* check if the interface is active */
+ libusb_kernel_driver_active(dhandle, 0);
+
+ /* claim the interface */
+ msg((ll_info, "Claiming the interface."));
+ uerr = libusb_claim_interface(dhandle, 0);
+ switch (uerr) {
+ /* cases where it's okay (not a lot) */
+ case 0: break;
+
+ /* cases where it's not okay */
+ case LIBUSB_ERROR_NO_DEVICE:
+ case LIBUSB_ERROR_NOT_FOUND:
+ err = casio_error_nocalc;
+ goto fail;
+ case LIBUSB_ERROR_BUSY:
+ msg((ll_info,
+ "Another program/driver has claimed the interface..."));
+ err = casio_error_noaccess;
+ goto fail;
+ default:
+ msg((ll_info, "libusb returned %d: %s",
+ uerr, libusb_error_name(uerr)));
+ goto fail;
+ }
+
+ /* make the cookie */
+ cookie = casio_alloc(1, sizeof(cookie_libusb_t));
+ err = casio_error_alloc;
+ if (!cookie) goto fail;
+ cookie->_context = context;
+ cookie->_handle = dhandle;
+ cookie->_start = 0;
+ cookie->_end = -1;
+
+ /* final call. */
+ return (casio_open(stream, openmode,
+ cookie, &casio_libusb_callbacks));
+fail:
+ if (cookie) casio_free(cookie);
+ if (dhandle) libusb_close(dhandle);
+ if (context) libusb_exit(context);
+ return (err);
+}
+
+#endif
diff --git a/src/stream/builtin/libusb/read.c b/src/stream/builtin/libusb/read.c
new file mode 100644
index 0000000..c4eea8f
--- /dev/null
+++ b/src/stream/builtin/libusb/read.c
@@ -0,0 +1,93 @@
+/* ****************************************************************************
+ * stream/builtin/libusb/read.c -- read from a libusb stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "libusb.h"
+#ifndef LIBCASIO_DISABLED_LIBUSB
+
+/**
+ * casio_libusb_read:
+ * Read using libusb cookie.
+ *
+ * @arg vcookie the cookie (voided)
+ * @arg data the data pointer.
+ * @arg size the data size.
+ * @return the error code (0 if ok).
+ */
+
+# define ENDPOINT_IN (LIBUSB_ENDPOINT_IN | LIBUSB_TRANSFER_TYPE_BULK)
+int CASIO_EXPORT casio_libusb_read(cookie_libusb_t *cookie,
+ unsigned char *dest, size_t size)
+{
+ int libusberr;
+ size_t tocopy;
+
+ /* transmit what's already in the buffer */
+ if (cookie->_start <= cookie->_end) {
+ tocopy = cookie->_end - cookie->_start + 1;
+ if (tocopy > size) tocopy = size;
+
+ memcpy(dest, &cookie->_buffer[cookie->_start], tocopy);
+ cookie->_start += tocopy;
+ dest += tocopy;
+ size -= tocopy;
+ }
+
+ /* main receiving loop */
+ while (size) {
+ int recv;
+
+ /* make the transfer. */
+ libusberr = libusb_bulk_transfer(cookie->_handle, ENDPOINT_IN,
+ cookie->_buffer, BUFSIZE, &recv, cookie->tmread);
+ switch (libusberr) {
+ case 0: break;
+
+ case LIBUSB_ERROR_PIPE:
+ case LIBUSB_ERROR_NO_DEVICE:
+ case LIBUSB_ERROR_IO:
+ msg((ll_error, "The calculator is not here anymore :("));
+ return (casio_error_nocalc);
+
+ case LIBUSB_ERROR_TIMEOUT:
+ return (casio_error_timeout);
+
+ default:
+ msg((ll_fatal, "libusb error was %d: %s", libusberr,
+ libusb_strerror(libusberr)));
+ return (casio_error_unknown);
+ }
+
+ /* get the current size to copy */
+ tocopy = (size_t)recv;
+ if (tocopy > size) tocopy = size;
+
+ /* copy to destination */
+ memcpy(dest, cookie->_buffer, tocopy);
+ dest += tocopy;
+ size -= tocopy;
+
+ /* correct start and end points */
+ cookie->_start = tocopy;
+ cookie->_end = (size_t)recv - 1;
+ }
+
+ /* no error */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/libusb/settm.c b/src/stream/builtin/libusb/settm.c
new file mode 100644
index 0000000..3e1faba
--- /dev/null
+++ b/src/stream/builtin/libusb/settm.c
@@ -0,0 +1,42 @@
+/* ****************************************************************************
+ * stream/builtin/libusb/settm.c -- set timeouts of a libusb stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "libusb.h"
+#ifndef LIBCASIO_DISABLED_LIBUSB
+
+/**
+ * casio_libusb_settm:
+ * Set timeouts.
+ *
+ * @arg vcookie the cookie (uncasted).
+ * @arg timeouts the timeouts.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_libusb_settm(cookie_libusb_t *cookie,
+ const casio_timeouts_t *timeouts)
+{
+ /* set the timeouts */
+ cookie->tmread = timeouts->casio_timeouts_read;
+ cookie->tmwrite = timeouts->casio_timeouts_write;
+
+ /* no error! */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/libusb/write.c b/src/stream/builtin/libusb/write.c
new file mode 100644
index 0000000..1c95c19
--- /dev/null
+++ b/src/stream/builtin/libusb/write.c
@@ -0,0 +1,59 @@
+/* ****************************************************************************
+ * stream/builtin/libusb/write.c -- write to a libusb stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "libusb.h"
+#ifndef LIBCASIO_DISABLED_LIBUSB
+
+/**
+ * casio_libusb_write:
+ * Write using libusb cookie.
+ *
+ * @arg cookie the cookie.
+ * @arg data the source.
+ * @arg size the source size.
+ * @return the error code (0 if ok).
+ */
+
+# define ENDPOINT_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
+int CASIO_EXPORT casio_libusb_write(cookie_libusb_t *cookie,
+ const unsigned char *data, size_t size)
+{
+ int sent, libusberr;
+
+ /* Make the transfer. */
+ libusberr = libusb_bulk_transfer(cookie->_handle, ENDPOINT_OUT,
+ (unsigned char*)data, size, &sent, cookie->tmwrite);
+ switch (libusberr) {
+ case 0: break;
+
+ case LIBUSB_ERROR_PIPE:
+ case LIBUSB_ERROR_NO_DEVICE:
+ msg((ll_error, "The calculator is not here anymore :("));
+ return (casio_error_nocalc);
+
+ default:
+ msg((ll_fatal, "libusb error was %d: %s", libusberr,
+ libusb_strerror(libusberr)));
+ return (casio_error_unknown);
+ }
+
+ /* no error! */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/streams.c b/src/stream/builtin/streams.c
deleted file mode 100644
index faeb304..0000000
--- a/src/stream/builtin/streams.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/* ****************************************************************************
- * stream/builtin/streams.c -- built-in STREAMS stream.
- * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
- *
- * This file is part of libcasio.
- * libcasio 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 3.0 of the License,
- * or (at your option) any later version.
- *
- * libcasio 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 libcasio; if not, see .
- * ************************************************************************* */
-#include "../../internals.h"
-#ifndef LIBCASIO_DISABLED_STREAMS
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-
-/* the cookie type */
-# define BUFSIZE 2048
-typedef struct {
- int _readfd, _writefd;
- int _closeread, _closewrite;
-
- /* buffer [control] */
- ssize_t _start, _end;
- unsigned char _buffer[BUFSIZE];
-} streams_cookie_t;
-/* ************************************************************************* */
-/* Settings, close callbacks */
-/* ************************************************************************* */
-/**
- * setcomm_for_fd:
- * Set communication things for a STREAMS device.
- *
- * Some flags have the same effects as `cfmakeraw()` (see termios(3)).
- * Other effects are linked to the settings (see `libcasio/stream.h`).
- *
- * @arg fd the file descriptor.
- * @arg settings the settings to set.
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int setcomm_for_fd(const int fd,
- const casio_streamattrs_t *settings)
-{
- struct termios term;
- speed_t speed;
- unsigned int status, dtrflags, rtsflags;
-
- /* get the speed */
- switch (settings->casio_streamattrs_speed) {
- case CASIO_B1200: speed = B1200; break;
- case CASIO_B2400: speed = B2400; break;
- case CASIO_B4800: speed = B4800; break;
- case CASIO_B9600: speed = B9600; break;
- case CASIO_B19200: speed = B19200; break;
- case CASIO_B38400: speed = B38400; break;
- case CASIO_B57600: speed = B57600; break;
- case CASIO_B115200: speed = B115200; break;
- default:
- msg((ll_info, "Speed was unsupported by termios: %u",
- settings->casio_streamattrs_speed));
- return (casio_error_op);
- }
-
- /* get the current configuration */
- if (tcgetattr(fd, &term) < 0)
- return (casio_error_unknown);
-
- /* set the speed */
- cfsetispeed(&term, speed);
- cfsetospeed(&term, speed);
-
- /* input flags */
- term.c_iflag &= ~(IGNBRK | IGNCR | BRKINT | PARMRK | ISTRIP | INLCR
- | ICRNL | IGNPAR | IXON | IXOFF);
- if (settings->casio_streamattrs_flags & CASIO_XONMASK)
- term.c_iflag |= IXON;
- if (settings->casio_streamattrs_flags & CASIO_XOFFMASK)
- term.c_iflag |= IXOFF;
-
- /* output flags, local modes */
- term.c_oflag = 0;
- term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-
- /* control flags */
- term.c_cflag &= ~(PARENB | PARODD | CREAD | CSTOPB | CSIZE);
- term.c_cflag |= CREAD | CS8;
- if (settings->casio_streamattrs_flags & CASIO_TWOSTOPBITS)
- term.c_cflag |= CSTOPB;
- if (settings->casio_streamattrs_flags & CASIO_PARENB)
- term.c_cflag |= PARENB;
- if (settings->casio_streamattrs_flags & CASIO_PARODD)
- term.c_cflag |= PARODD;
-
- /* control characters */
- term.c_cc[VSTART] = settings->casio_streamattrs_cc[CASIO_XON];
- term.c_cc[VSTOP] = settings->casio_streamattrs_cc[CASIO_XOFF];
- term.c_cc[VMIN] = 0; /* ? */
-
- /* update the termios settings! */
- if (tcsetattr(fd, TCSANOW, &term))
- return (casio_error_unknown);
-
- /* get line status */
- if (ioctl(fd, TIOCMGET, &status) >= 0) status = 0;
- status &= ~(TIOCM_DTR | TIOCM_RTS);
-
- /* activate DTR and RTS */
- dtrflags = settings->casio_streamattrs_flags & CASIO_DTRMASK;
- rtsflags = settings->casio_streamattrs_flags & CASIO_RTSMASK;
- if (dtrflags == CASIO_DTRCTL_ENABLE || dtrflags == CASIO_DTRCTL_HANDSHAKE)
- status |= TIOCM_DTR;
- if (rtsflags == CASIO_RTSCTL_ENABLE || rtsflags == CASIO_RTSCTL_HANDSHAKE)
- status |= TIOCM_RTS;
- if (ioctl(fd, TIOCMSET, &status) < 0)
- return (casio_error_unknown);
-
- /* no error! */
- return (0);
-}
-
-/**
- * casio_streams_setcomm:
- * Set the communication status.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg settings the settings to set.
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_streams_setcomm(void *vcookie,
- const casio_streamattrs_t *settings)
-{
- int err; streams_cookie_t *cookie = (streams_cookie_t*)vcookie;
-
- /* set attributes */
- if (cookie->_readfd >= 0) {
- err = setcomm_for_fd(cookie->_readfd, settings);
- if (err) return (err);
- }
- if (cookie->_writefd >= 0 && cookie->_writefd != cookie->_readfd) {
- err = setcomm_for_fd(cookie->_writefd, settings);
- if (err) return (err);
- }
-
- /* no error */
- return (0);
-}
-
-/**
- * casio_streams_settm:
- * Set timeouts.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg timeouts the timeouts.
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_streams_settm(void *vcookie,
- const casio_timeouts_t *timeouts)
-{
- streams_cookie_t *cookie = (void*)vcookie;
- struct termios term;
-
- /* set on the read thing */
- if (!tcgetattr(cookie->_readfd, &term)) {
- /* set the timeout */
- term.c_cc[VTIME] = timeouts->casio_timeouts_read / 100;
-
- /* update */
- if (tcsetattr(cookie->_readfd, TCSANOW, &term))
- return (0);
- }
-
- /* set on the write thing */
- if (cookie->_readfd != cookie->_writefd
- && !tcgetattr(cookie->_writefd, &term)) {
- term.c_cc[VTIME] = timeouts->casio_timeouts_write / 100;
-
- /* update */
- if (tcsetattr(cookie->_writefd, TCSANOW, &term))
- return (0);
- }
-
- /* no error! */
- return (0);
-}
-
-/**
- * casio_streams_close:
- * Close the cookie.
- *
- * @arg vcookie the cookie (uncasted).
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_streams_close(void *vcookie)
-{
- streams_cookie_t *cookie = (streams_cookie_t*)vcookie;
-
- /* close the file descriptors. */
- if (cookie->_readfd >= 0 && cookie->_closeread)
- close(cookie->_readfd);
- if (cookie->_writefd >= 0 && cookie->_readfd != cookie->_writefd
- && cookie->_closewrite)
- close(cookie->_writefd);
-
- /* free the cookie. */
- casio_free(cookie);
- return (0);
-}
-/* ************************************************************************* */
-/* Character stream callbacks */
-/* ************************************************************************* */
-/**
- * casio_streams_read:
- * Read from a terminal.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg data the data pointer.
- * @arg size the data size.
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_streams_read(void *vcookie,
- unsigned char *dest, size_t size)
-{
- streams_cookie_t *cookie = (streams_cookie_t*)vcookie;
- int fd = cookie->_readfd;
-
- /* transmit what's already in the buffer */
- if (cookie->_start <= cookie->_end) {
- size_t tocopy = cookie->_end - cookie->_start + 1;
- if (tocopy > size) tocopy = size;
-
- memcpy(dest, &cookie->_buffer[cookie->_start], tocopy);
- cookie->_start += tocopy;
- dest += tocopy;
- size -= tocopy;
- }
-
- /* main receiving loop */
- while (size) {
- ssize_t recv;
- size_t tocopy;
-
- /* receive */
- recv = read(fd, cookie->_buffer, BUFSIZE);
- if (!recv) continue;
-
- /* check error */
- if (recv < 0) switch (errno) {
- case 0: continue;
- case ENODEV: case EIO:
- return (casio_error_nocalc);
- default:
- msg((ll_fatal, "error was %d: %s",
- errno, strerror(errno)));
- return (casio_error_unknown);
- }
-
- /* get the current size to copy */
- tocopy = (size_t)recv;
- if (tocopy > size) tocopy = size;
-
- /* copy to destination */
- memcpy(dest, cookie->_buffer, tocopy);
- dest += tocopy;
- size -= tocopy;
-
- /* correct start and end points */
- cookie->_start = tocopy;
- cookie->_end = (size_t)recv - 1;
- }
-
- /* no error */
- return (0);
-}
-
-/**
- * casio_streams_write:
- * Write to a terminal.
- *
- * @arg vcookie the cookie (uncasted)
- * @arg data the source.
- * @arg size the source size.
- * @return the error (0 if ok).
- */
-
-CASIO_LOCAL int casio_streams_write(void *vcookie,
- const unsigned char *data, size_t size)
-{
- streams_cookie_t *cookie = (streams_cookie_t*)vcookie;
- int fd = cookie->_writefd;
-
- /* send */
- while (size) {
- ssize_t wr = write(fd, data, size);
- if (wr < 0) break;
- size -= (size_t)wr;
- }
-
- /* be sure it's written, or check the error */
- if (size) switch (errno) {
- case ENODEV:
- return (casio_error_nocalc);
- default:
- msg((ll_fatal, "errno was %d: %s", errno, strerror(errno)));
- return (casio_error_unknown);
- }
-
- /* no error! */
- return (0);
-}
-/* ************************************************************************* */
-/* SCSI request callback */
-/* ************************************************************************* */
-# if 0 && defined(__linux__)
-# include
-
-/**
- * casio_streams_scsi_request:
- * Make an SCSI request using the SG interface.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg request the SCSI request.
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_streams_scsi_request(void *vcookie,
- casio_scsi_t *request)
-{
- streams_cookie_t *cookie = (streams_cookie_t*)vcookie;
-
- /* correct the request */
- int err = casio_scsi_correct(request);
- if (err) return (err);
-
- /* make an `sg_io_hdr_t` out of the request */
- sg_io_hdr_t h = {
- /* main input data */
- .interface_id = 'S', /* magic */
- .flags = 0, /* no special things, just normal SCSI */
- .dxfer_direction = request->direction, /* FIXME: macro to macro? */
- .cmd_len = request->cmd_len, .cmdp = request->cmd, /* command */
- .timeout = 0, /* FIXME (also, in ms) */
-
- /* data buffer */
- .iovec_count = 0,
- .dxfer_len = request->data_len,
- .dxferp = request->data, /* data buffer */
-
- /* sense buffer */
- .max_sb_len = request->slen, .sbp = request->sense, /* sense buffer */
- };
-
- /* make the request */
- if (ioctl(cookie->_writefd, SG_IO, &h) < 0) switch (errno) {
- case EACCES:
- log_error("Root perms required!");
- default:
- log_error("Errno: %s (0x%04X)", strerror(errno), errno);
- return (casio_error_unknown);
- }
-
- /* everything went well */
- return (0);
-}
-
-# endif
-/* ************************************************************************* */
-/* Stream initialization */
-/* ************************************************************************* */
-/* callbacks */
-CASIO_LOCAL const casio_streamfuncs_t casio_streams_callbacks =
-casio_stream_callbacks_for_serial(casio_streams_close,
- casio_streams_setcomm, casio_streams_settm,
- casio_streams_read, casio_streams_write);
-
-/**
- * casio_opencom_streams:
- * Callback for `opencom`.
- *
- * @arg stream the stream to make.
- * @arg path the path.
- * @return the error (0 if ok).
- */
-
-int CASIO_EXPORT casio_opencom_streams(casio_stream_t **stream,
- const char *path)
-{
- return (casio_open_stream_streams(stream, path,
- CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE));
-}
-
-/**
- * casio_open_stream_streams:
- * Initialize libcasio with char device.
- *
- * @arg stream the stream to make.
- * @arg path the path.
- * @arg mode the mode.
- * @return the error (0 if ok).
- */
-
-int CASIO_EXPORT casio_open_stream_streams(casio_stream_t **stream,
- const char *path, casio_openmode_t mode)
-{
- int openfd, readfd, writefd, flags;
-
- /* make up the flags */
- flags = O_NOCTTY;
- if ((mode & CASIO_OPENMODE_READ) && (mode & CASIO_OPENMODE_WRITE))
- flags |= O_RDWR;
- else if (mode & CASIO_OPENMODE_READ)
- flags |= O_RDONLY;
- else if (mode & CASIO_OPENMODE_WRITE)
- flags |= O_WRONLY;
- else return (casio_error_invalid);
-
- /* open the stream */
- openfd = open(path, flags);
- if (openfd < 0) switch (errno) {
- /* no such device */
- case ENODEV: case ENOENT: case ENXIO:
- case EPIPE: case ESPIPE:
- msg((ll_error, "couldn't open calculator: %s",
- strerror(errno)));
- return (casio_error_nocalc);
-
- /* no access */
- case EACCES:
- msg((ll_error, "permission denied"));
- return (casio_error_noaccess);
-
- /* default */
- default:
- msg((ll_error, "unknown error: %s (0x%X)",
- strerror(errno), errno));
- return (casio_error_unknown);
- }
-
- /* make the file descriptors */
- readfd = mode & CASIO_OPENMODE_READ ? openfd : -1;
- writefd = mode & CASIO_OPENMODE_WRITE ? openfd : -1;
-
- /* make the final stream */
- return (casio_open_stream_fd(stream, readfd, writefd, 1, 1));
-}
-
-/**
- * casio_open_stream_fd:
- * Initialize libcasio with file descriptors.
- *
- * @arg stream the stream to make.
- * @arg readfd the read file descriptor.
- * @arg writefd the write file descriptor.
- * @arg closeread close the read file descriptor?
- * @arg closewrite close the write file descriptor?
- * @return the error (0 if ok)
- */
-
-int CASIO_EXPORT casio_open_stream_fd(casio_stream_t **stream,
- int readfd, int writefd, int closeread, int closewrite)
-{
- int err; streams_cookie_t *cookie = NULL;
- casio_openmode_t mode =
- CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE | CASIO_OPENMODE_SERIAL;
-
- /* check if the devices are valid. */
- if ( readfd < 0 || read(readfd, NULL, 0) < 0)
- mode &= ~CASIO_OPENMODE_READ;
- if (writefd < 0 || write(writefd, NULL, 0) < 0)
- mode &= ~CASIO_OPENMODE_WRITE;
-
- /* check if we have at least read/write file descriptors. */
- if (!mode) { err = casio_error_invalid; goto fail; }
-
- /* allocate cookie */
- cookie = casio_alloc(1, sizeof(streams_cookie_t));
- if (!cookie) { err = casio_error_alloc; goto fail; }
- cookie->_readfd = readfd;
- cookie->_writefd = writefd;
- cookie->_closeread = closeread;
- cookie->_closewrite = closewrite;
- cookie->_start = 0;
- cookie->_end = -1;
-
- /* init for real */
- msg((ll_info, "Initializing STREAMS stream with fds: (%d, %d)",
- readfd, writefd));
-
- /* final call */
- return (casio_open(stream, mode, cookie,
- &casio_streams_callbacks));
-fail:
- if (readfd >= 0 && closeread)
- close(readfd);
- if (writefd >= 0 && writefd != readfd && closewrite)
- close(writefd);
- return (err);
-}
-
-#endif
diff --git a/src/stream/builtin/streams/close.c b/src/stream/builtin/streams/close.c
new file mode 100644
index 0000000..bfc8e40
--- /dev/null
+++ b/src/stream/builtin/streams/close.c
@@ -0,0 +1,44 @@
+/* ****************************************************************************
+ * stream/builtin/streams/close.c -- close a STREAMS stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#ifndef LIBCASIO_DISABLED_STREAMS
+
+/**
+ * casio_streams_close:
+ * Close the cookie.
+ *
+ * @arg cookie the cookie.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_streams_close(streams_cookie_t *cookie)
+{
+ /* close the file descriptors. */
+ if (cookie->_readfd >= 0 && cookie->_closeread)
+ close(cookie->_readfd);
+ if (cookie->_writefd >= 0 && cookie->_readfd != cookie->_writefd
+ && cookie->_closewrite)
+ close(cookie->_writefd);
+
+ /* free the cookie. */
+ casio_free(cookie);
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/streams/open.c b/src/stream/builtin/streams/open.c
new file mode 100644
index 0000000..58adae0
--- /dev/null
+++ b/src/stream/builtin/streams/open.c
@@ -0,0 +1,152 @@
+/* ****************************************************************************
+ * stream/builtin/streams/open.c -- open a STREAMS stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#ifndef LIBCASIO_DISABLED_STREAMS
+
+/* Callbacks. */
+CASIO_LOCAL const casio_streamfuncs_t casio_streams_callbacks =
+casio_stream_callbacks_for_serial(casio_streams_close,
+ casio_streams_setattrs, casio_streams_settm,
+ casio_streams_read, casio_streams_write);
+
+/**
+ * casio_opencom_streams:
+ * Callback for `opencom`.
+ *
+ * @arg stream the stream to make.
+ * @arg path the path.
+ * @return the error (0 if ok).
+ */
+
+int CASIO_EXPORT casio_opencom_streams(casio_stream_t **stream,
+ const char *path)
+{
+ return (casio_open_stream_streams(stream, path,
+ CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE));
+}
+
+/**
+ * casio_open_stream_streams:
+ * Initialize libcasio with char device.
+ *
+ * @arg stream the stream to make.
+ * @arg path the path.
+ * @arg mode the mode.
+ * @return the error (0 if ok).
+ */
+
+int CASIO_EXPORT casio_open_stream_streams(casio_stream_t **stream,
+ const char *path, casio_openmode_t mode)
+{
+ int openfd, readfd, writefd, flags;
+
+ /* make up the flags */
+ flags = O_NOCTTY;
+ if ((mode & CASIO_OPENMODE_READ) && (mode & CASIO_OPENMODE_WRITE))
+ flags |= O_RDWR;
+ else if (mode & CASIO_OPENMODE_READ)
+ flags |= O_RDONLY;
+ else if (mode & CASIO_OPENMODE_WRITE)
+ flags |= O_WRONLY;
+ else return (casio_error_invalid);
+
+ /* open the stream */
+ openfd = open(path, flags);
+ if (openfd < 0) switch (errno) {
+ /* no such device */
+ case ENODEV: case ENOENT: case ENXIO:
+ case EPIPE: case ESPIPE:
+ msg((ll_error, "couldn't open calculator: %s",
+ strerror(errno)));
+ return (casio_error_nocalc);
+
+ /* no access */
+ case EACCES:
+ msg((ll_error, "permission denied"));
+ return (casio_error_noaccess);
+
+ /* default */
+ default:
+ msg((ll_error, "unknown error: %s (0x%X)",
+ strerror(errno), errno));
+ return (casio_error_unknown);
+ }
+
+ /* make the file descriptors */
+ readfd = mode & CASIO_OPENMODE_READ ? openfd : -1;
+ writefd = mode & CASIO_OPENMODE_WRITE ? openfd : -1;
+
+ /* make the final stream */
+ return (casio_open_stream_fd(stream, readfd, writefd, 1, 1));
+}
+
+/**
+ * casio_open_stream_fd:
+ * Initialize libcasio with file descriptors.
+ *
+ * @arg stream the stream to make.
+ * @arg readfd the read file descriptor.
+ * @arg writefd the write file descriptor.
+ * @arg closeread close the read file descriptor?
+ * @arg closewrite close the write file descriptor?
+ * @return the error (0 if ok)
+ */
+
+int CASIO_EXPORT casio_open_stream_fd(casio_stream_t **stream,
+ int readfd, int writefd, int closeread, int closewrite)
+{
+ int err; streams_cookie_t *cookie = NULL;
+ casio_openmode_t mode =
+ CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE | CASIO_OPENMODE_SERIAL;
+
+ /* check if the devices are valid. */
+ if ( readfd < 0 || read(readfd, NULL, 0) < 0)
+ mode &= ~CASIO_OPENMODE_READ;
+ if (writefd < 0 || write(writefd, NULL, 0) < 0)
+ mode &= ~CASIO_OPENMODE_WRITE;
+
+ /* check if we have at least read/write file descriptors. */
+ if (!mode) { err = casio_error_invalid; goto fail; }
+
+ /* allocate cookie */
+ cookie = casio_alloc(1, sizeof(streams_cookie_t));
+ if (!cookie) { err = casio_error_alloc; goto fail; }
+ cookie->_readfd = readfd;
+ cookie->_writefd = writefd;
+ cookie->_closeread = closeread;
+ cookie->_closewrite = closewrite;
+ cookie->_start = 0;
+ cookie->_end = -1;
+
+ /* init for real */
+ msg((ll_info, "Initializing STREAMS stream with fds: (%d, %d)",
+ readfd, writefd));
+
+ /* final call */
+ return (casio_open(stream, mode, cookie,
+ &casio_streams_callbacks));
+fail:
+ if (readfd >= 0 && closeread)
+ close(readfd);
+ if (writefd >= 0 && writefd != readfd && closewrite)
+ close(writefd);
+ return (err);
+}
+
+#endif
diff --git a/src/stream/builtin/streams/read.c b/src/stream/builtin/streams/read.c
new file mode 100644
index 0000000..7bfcd7b
--- /dev/null
+++ b/src/stream/builtin/streams/read.c
@@ -0,0 +1,86 @@
+/* ****************************************************************************
+ * stream/builtin/streams/read.c -- read from a STREAMS stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#ifndef LIBCASIO_DISABLED_STREAMS
+
+/**
+ * casio_streams_read:
+ * Read from a terminal.
+ *
+ * @arg cookie the cookie.
+ * @arg data the data pointer.
+ * @arg size the data size.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_streams_read(streams_cookie_t *cookie,
+ unsigned char *dest, size_t size)
+{
+ int fd = cookie->_readfd;
+
+ /* transmit what's already in the buffer */
+ if (cookie->_start <= cookie->_end) {
+ size_t tocopy = cookie->_end - cookie->_start + 1;
+ if (tocopy > size) tocopy = size;
+
+ memcpy(dest, &cookie->_buffer[cookie->_start], tocopy);
+ cookie->_start += tocopy;
+ dest += tocopy;
+ size -= tocopy;
+ }
+
+ /* main receiving loop */
+ while (size) {
+ ssize_t recv;
+ size_t tocopy;
+
+ /* receive */
+ recv = read(fd, cookie->_buffer, BUFSIZE);
+ if (!recv) continue;
+
+ /* check error */
+ if (recv < 0) switch (errno) {
+ case 0: continue;
+ case ENODEV: case EIO:
+ return (casio_error_nocalc);
+ default:
+ msg((ll_fatal, "error was %d: %s",
+ errno, strerror(errno)));
+ return (casio_error_unknown);
+ }
+
+ /* get the current size to copy */
+ tocopy = (size_t)recv;
+ if (tocopy > size) tocopy = size;
+
+ /* copy to destination */
+ memcpy(dest, cookie->_buffer, tocopy);
+ dest += tocopy;
+ size -= tocopy;
+
+ /* correct start and end points */
+ cookie->_start = tocopy;
+ cookie->_end = (size_t)recv - 1;
+ }
+
+ /* no error */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/streams/scsi.c b/src/stream/builtin/streams/scsi.c
new file mode 100644
index 0000000..5407ef8
--- /dev/null
+++ b/src/stream/builtin/streams/scsi.c
@@ -0,0 +1,72 @@
+/* ****************************************************************************
+ * stream/builtin/streams/scsi.c -- make an SCSI request on a STREAMS device.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#if 0 && !defined(LIBCASIO_DISABLED_STREAMS)
+# include
+
+/**
+ * casio_streams_scsi_request:
+ * Make an SCSI request using the SG interface.
+ *
+ * @arg vcookie the cookie (uncasted).
+ * @arg request the SCSI request.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_streams_scsi_request(void *vcookie,
+ casio_scsi_t *request)
+{
+ streams_cookie_t *cookie = (streams_cookie_t*)vcookie;
+
+ /* correct the request */
+ int err = casio_scsi_correct(request);
+ if (err) return (err);
+
+ /* make an `sg_io_hdr_t` out of the request */
+ sg_io_hdr_t h = {
+ /* main input data */
+ .interface_id = 'S', /* magic */
+ .flags = 0, /* no special things, just normal SCSI */
+ .dxfer_direction = request->direction, /* FIXME: macro to macro? */
+ .cmd_len = request->cmd_len, .cmdp = request->cmd, /* command */
+ .timeout = 0, /* FIXME (also, in ms) */
+
+ /* data buffer */
+ .iovec_count = 0,
+ .dxfer_len = request->data_len,
+ .dxferp = request->data, /* data buffer */
+
+ /* sense buffer */
+ .max_sb_len = request->slen, .sbp = request->sense, /* sense buffer */
+ };
+
+ /* make the request */
+ if (ioctl(cookie->_writefd, SG_IO, &h) < 0) switch (errno) {
+ case EACCES:
+ log_error("Root perms required!");
+ default:
+ log_error("Errno: %s (0x%04X)", strerror(errno), errno);
+ return (casio_error_unknown);
+ }
+
+ /* everything went well */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/streams/setattrs.c b/src/stream/builtin/streams/setattrs.c
new file mode 100644
index 0000000..2fbcffe
--- /dev/null
+++ b/src/stream/builtin/streams/setattrs.c
@@ -0,0 +1,142 @@
+/* ****************************************************************************
+ * stream/builtin/streams/setattrs.c -- STREAMS attributes.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#ifndef LIBCASIO_DISABLED_STREAMS
+
+/**
+ * set_attrs_for_fd:
+ * Set communication things for a STREAMS device.
+ *
+ * Some flags have the same effects as `cfmakeraw()` (see termios(3)).
+ * Other effects are linked to the settings (see `libcasio/stream.h`).
+ *
+ * @arg fd the file descriptor.
+ * @arg settings the settings to set.
+ * @return the error code (0 if ok).
+ */
+
+CASIO_LOCAL int set_attrs_for_fd(const int fd,
+ const casio_streamattrs_t *settings)
+{
+ struct termios term;
+ speed_t speed;
+ unsigned int status, dtrflags, rtsflags;
+
+ /* get the speed */
+ switch (settings->casio_streamattrs_speed) {
+ case CASIO_B1200: speed = B1200; break;
+ case CASIO_B2400: speed = B2400; break;
+ case CASIO_B4800: speed = B4800; break;
+ case CASIO_B9600: speed = B9600; break;
+ case CASIO_B19200: speed = B19200; break;
+ case CASIO_B38400: speed = B38400; break;
+ case CASIO_B57600: speed = B57600; break;
+ case CASIO_B115200: speed = B115200; break;
+ default:
+ msg((ll_info, "Speed was unsupported by termios: %u",
+ settings->casio_streamattrs_speed));
+ return (casio_error_op);
+ }
+
+ /* get the current configuration */
+ if (tcgetattr(fd, &term) < 0)
+ return (casio_error_unknown);
+
+ /* set the speed */
+ cfsetispeed(&term, speed);
+ cfsetospeed(&term, speed);
+
+ /* input flags */
+ term.c_iflag &= ~(IGNBRK | IGNCR | BRKINT | PARMRK | ISTRIP | INLCR
+ | ICRNL | IGNPAR | IXON | IXOFF);
+ if (settings->casio_streamattrs_flags & CASIO_XONMASK)
+ term.c_iflag |= IXON;
+ if (settings->casio_streamattrs_flags & CASIO_XOFFMASK)
+ term.c_iflag |= IXOFF;
+
+ /* output flags, local modes */
+ term.c_oflag = 0;
+ term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+
+ /* control flags */
+ term.c_cflag &= ~(PARENB | PARODD | CREAD | CSTOPB | CSIZE);
+ term.c_cflag |= CREAD | CS8;
+ if (settings->casio_streamattrs_flags & CASIO_TWOSTOPBITS)
+ term.c_cflag |= CSTOPB;
+ if (settings->casio_streamattrs_flags & CASIO_PARENB)
+ term.c_cflag |= PARENB;
+ if (settings->casio_streamattrs_flags & CASIO_PARODD)
+ term.c_cflag |= PARODD;
+
+ /* control characters */
+ term.c_cc[VSTART] = settings->casio_streamattrs_cc[CASIO_XON];
+ term.c_cc[VSTOP] = settings->casio_streamattrs_cc[CASIO_XOFF];
+ term.c_cc[VMIN] = 0; /* ? */
+
+ /* update the termios settings! */
+ if (tcsetattr(fd, TCSANOW, &term))
+ return (casio_error_unknown);
+
+ /* get line status */
+ if (ioctl(fd, TIOCMGET, &status) >= 0) status = 0;
+ status &= ~(TIOCM_DTR | TIOCM_RTS);
+
+ /* activate DTR and RTS */
+ dtrflags = settings->casio_streamattrs_flags & CASIO_DTRMASK;
+ rtsflags = settings->casio_streamattrs_flags & CASIO_RTSMASK;
+ if (dtrflags == CASIO_DTRCTL_ENABLE || dtrflags == CASIO_DTRCTL_HANDSHAKE)
+ status |= TIOCM_DTR;
+ if (rtsflags == CASIO_RTSCTL_ENABLE || rtsflags == CASIO_RTSCTL_HANDSHAKE)
+ status |= TIOCM_RTS;
+ if (ioctl(fd, TIOCMSET, &status) < 0)
+ return (casio_error_unknown);
+
+ /* no error! */
+ return (0);
+}
+
+/**
+ * casio_streams_setattrs:
+ * Set the communication status.
+ *
+ * @arg cookie the cookie.
+ * @arg settings the settings to set.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_streams_setattrs(streams_cookie_t *cookie,
+ const casio_streamattrs_t *settings)
+{
+ int err;
+
+ /* set attributes */
+ if (cookie->_readfd >= 0) {
+ err = set_attrs_for_fd(cookie->_readfd, settings);
+ if (err) return (err);
+ }
+ if (cookie->_writefd >= 0 && cookie->_writefd != cookie->_readfd) {
+ err = set_attrs_for_fd(cookie->_writefd, settings);
+ if (err) return (err);
+ }
+
+ /* no error */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/streams/settm.c b/src/stream/builtin/streams/settm.c
new file mode 100644
index 0000000..4b7a21d
--- /dev/null
+++ b/src/stream/builtin/streams/settm.c
@@ -0,0 +1,60 @@
+/* ****************************************************************************
+ * stream/builtin/streams/settm.c -- set timeouts for a STREAMS stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#ifndef LIBCASIO_DISABLED_STREAMS
+
+/**
+ * casio_streams_settm:
+ * Set timeouts.
+ *
+ * @arg cookie the cookie.
+ * @arg timeouts the timeouts.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_streams_settm(streams_cookie_t *cookie,
+ const casio_timeouts_t *timeouts)
+{
+ struct termios term;
+
+ /* set on the read thing */
+ if (!tcgetattr(cookie->_readfd, &term)) {
+ /* set the timeout */
+ term.c_cc[VTIME] = timeouts->casio_timeouts_read / 100;
+
+ /* update */
+ if (tcsetattr(cookie->_readfd, TCSANOW, &term))
+ return (0);
+ }
+
+ /* set on the write thing */
+ if (cookie->_readfd != cookie->_writefd
+ && !tcgetattr(cookie->_writefd, &term)) {
+ term.c_cc[VTIME] = timeouts->casio_timeouts_write / 100;
+
+ /* update */
+ if (tcsetattr(cookie->_writefd, TCSANOW, &term))
+ return (0);
+ }
+
+ /* no error! */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/streams/streams.h b/src/stream/builtin/streams/streams.h
new file mode 100644
index 0000000..443b205
--- /dev/null
+++ b/src/stream/builtin/streams/streams.h
@@ -0,0 +1,72 @@
+/* ****************************************************************************
+ * stream/builtin/streams/streams.h -- built-in STREAMS stream internals.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#ifndef LOCAL_STREAM_BUILTIN_STREAMS_H
+# define LOCAL_STREAM_BUILTIN_STREAMS_H 1
+# include "../../../internals.h"
+# ifndef LIBCASIO_DISABLED_STREAMS
+# include
+# include
+# include
+# include
+# include
+# include
+
+/* the cookie type */
+# define BUFSIZE 2048
+typedef struct {
+ int _readfd, _writefd;
+ int _closeread, _closewrite;
+
+ /* buffer [control] */
+ ssize_t _start, _end;
+ unsigned char _buffer[BUFSIZE];
+} streams_cookie_t;
+
+/* General callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_streams_close
+ OF((streams_cookie_t *casio__cookie));
+CASIO_EXTERN int CASIO_EXPORT casio_streams_settm
+ OF((streams_cookie_t *casio__cookie,
+ const casio_timeouts_t *casio__timeouts));
+
+/* Character device callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_streams_read
+ OF((streams_cookie_t *casio__cookie,
+ unsigned char *casio__dest, size_t casio__size));
+CASIO_EXTERN int CASIO_EXPORT casio_streams_write
+ OF((streams_cookie_t *casio__cookie,
+ const unsigned char *casio__data, size_t casio__size));
+
+/* Serial callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_streams_setattrs
+ OF((streams_cookie_t *casio__cookie,
+ const casio_streamattrs_t *casio__settings));
+
+/* SCSI callbacks. */
+
+# if 0
+CASIO_EXTERN int CASIO_EXPORT casio_streams_scsi_request
+ OF((streams_cookie_t *casio__cookie, casio_scsi_t *casio__request));
+# endif
+
+# endif
+#endif /* LOCAL_STREAM_BUILTIN_STREAMS_H */
diff --git a/src/stream/builtin/streams/write.c b/src/stream/builtin/streams/write.c
new file mode 100644
index 0000000..55c1282
--- /dev/null
+++ b/src/stream/builtin/streams/write.c
@@ -0,0 +1,57 @@
+/* ****************************************************************************
+ * stream/builtin/streams/write.c -- write to a STREAMS stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "streams.h"
+#ifndef LIBCASIO_DISABLED_STREAMS
+
+/**
+ * casio_streams_write:
+ * Write to a terminal.
+ *
+ * @arg cookie the cookie.
+ * @arg data the source.
+ * @arg size the source size.
+ * @return the error (0 if ok).
+ */
+
+int CASIO_EXPORT casio_streams_write(streams_cookie_t *cookie,
+ const unsigned char *data, size_t size)
+{
+ int fd = cookie->_writefd;
+
+ /* send */
+ while (size) {
+ ssize_t wr = write(fd, data, size);
+ if (wr < 0) break;
+ size -= (size_t)wr;
+ }
+
+ /* be sure it's written, or check the error */
+ if (size) switch (errno) {
+ case ENODEV:
+ return (casio_error_nocalc);
+ default:
+ msg((ll_fatal, "errno was %d: %s", errno, strerror(errno)));
+ return (casio_error_unknown);
+ }
+
+ /* no error! */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows.c b/src/stream/builtin/windows.c
deleted file mode 100644
index ad4d346..0000000
--- a/src/stream/builtin/windows.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/* ****************************************************************************
- * stream/builtin/windows.c -- built-in Windows API stream.
- * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
- *
- * This file is part of libcasio.
- * libcasio 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 3.0 of the License,
- * or (at your option) any later version.
- *
- * libcasio 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 libcasio; if not, see .
- * ************************************************************************* */
-#include "../../internals.h"
-#ifndef LIBCASIO_DISABLED_WINDOWS
-
-/* only works because I redefined the version at the beginning
- * of `internals.h`! */
-# include
-# include
-# include
-# include
-
-/* Here is the structure of a cookie, used by the stream callbacks.
- * PSP_COOKIE is just there to take the piss out of Microsoft :p */
-# define BUFSIZE 2048
-typedef struct {
- HANDLE _handle;
-
- long _start, _end;
- unsigned char _buf[BUFSIZE];
-} win_cookie_t, *PSP_COOKIE;
-/* ************************************************************************* */
-/* Find USB devices */
-/* ************************************************************************* */
-/**
- * wfind:
- * Find the Microsoft Windows device path.
- *
- * @arg vid the vendor ID (0x0000 to 0xffff)
- * @arg pid the product ID (0x0000 to 0xffff)
- * @return the allocated path of the device if found, NULL otherwise
- */
-
-CASIO_LOCAL char *wfind(unsigned int vid, unsigned int pid)
-{
- int i; DWORD werr;
- char *devpath = NULL, vidpid[20];
- HDEVINFO DeviceInfoSet;
- SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
-
- /* make the vid/pid string */
- sprintf(vidpid, "#vid_%04x&pid_%04x", vid, pid);
-
- /* get the device information set (chained list) */
- msg((ll_info, "Getting the device info set"));
- DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE,
- NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
- werr = GetLastError();
- msg((ll_fatal, "Device info gathering failed! Error 0x%08lX", werr));
- return (NULL);
- }
-
-
- /* browse this set, setup */
- DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- msg((ll_info, "Enumerating interfaces"));
- for (i = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL,
- &GUID_DEVINTERFACE_USB_DEVICE, i, &DeviceInterfaceData); i++) {
- /* make the local variables */
- DWORD RequiredSize = 0; const char *Path;
- PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
-
- /* get the detail size */
- msg((ll_info, "Getting interface information detail size"));
- if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
- &DeviceInterfaceData, NULL, 0, &RequiredSize, NULL) &&
- (werr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) {
- msg((ll_error, "Error getting this size: 0x%08lX", werr));
- continue;
- }
-
- /* allocate detail space */
- msg((ll_info,
- "Allocating space for interface information detail (%luo)",
- RequiredSize));
- DeviceInterfaceDetailData = casio_alloc(RequiredSize, 1);
- if (!DeviceInterfaceDetailData) {
- msg((ll_error, "Memory allocation failed. Oh well."));
- break ;
- }
- DeviceInterfaceDetailData->cbSize =
- sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
-
- /* get the detail */
- msg((ll_info, "Getting interface information detail"));
- if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
- &DeviceInterfaceData, DeviceInterfaceDetailData, RequiredSize,
- NULL, NULL)) {
- werr = GetLastError();
- msg((ll_error, "Error getting the interface information detail: "
- "0x%08lX", werr));
- continue;
- }
-
- /* check if it corresponds */
- Path = DeviceInterfaceDetailData->DevicePath;
- msg((ll_info, "Stumbled across: %s", Path));
- if (strstr(Path, vidpid)) {
- devpath = casio_alloc(strlen(Path) + 1, 1);
- if (!devpath) break;
- strcpy(devpath, Path);
- }
-
- /* free the allocated detail */
- casio_free(DeviceInterfaceDetailData);
- if (devpath) break ;
- }
-
- /* destroy the device information set */
- msg((ll_info, "Destroying the device information set"));
- SetupDiDestroyDeviceInfoList(DeviceInfoSet);
- return (devpath);
-}
-/* ************************************************************************* */
-/* Settings, close callbacks */
-/* ************************************************************************* */
-/**
- * casio_win_setcomm:
- * Set communication status of a Microsoft Windows stream.
- *
- * This is accomplished by getting, updating and setting the DCB.
- * Yay, a Windows API thingy.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg settings the settings to apply.
- * @return the error (0 if ok)
- */
-
-CASIO_LOCAL int casio_win_setcomm(void *vcookie,
- const casio_streamattrs_t *settings)
-{
- win_cookie_t *cookie = (win_cookie_t*)vcookie;
- DWORD wsuccess, spd; DCB dcb;
-
- /* get speed */
- switch (settings->casio_streamattrs_speed) {
- case CASIO_B1200: spd = CBR_1200; break;
- case CASIO_B2400: spd = CBR_2400; break;
- case CASIO_B4800: spd = CBR_4800; break;
- case CASIO_B9600: spd = CBR_9600; break;
- case CASIO_B19200: spd = CBR_19200; break;
- case CASIO_B38400: spd = CBR_38400; break;
- case CASIO_B57600: spd = CBR_57600; break;
- case CASIO_B115200: spd = CBR_115200; break;
- default:
- msg((ll_info, "Speed was unsupported by the Windows API: %u",
- settings->casio_streamattrs_speed));
- return (casio_error_op);
- }
-
- /* gather stream properties */
- SecureZeroMemory(&dcb, sizeof(DCB));
- dcb.DCBlength = sizeof(DCB);
- if (!GetCommState(cookie->_handle, &dcb)) {
- msg((ll_warn, "Failed gathering the DCB (0x%08lX), nevermind.",
- GetLastError()));
- return (0);
- }
-
- /* set normal things */
- dcb.BaudRate = spd;
- dcb.ByteSize = 8;
- dcb.fParity = !!(settings->casio_streamattrs_flags & CASIO_PARENB);
- dcb.Parity = (~settings->casio_streamattrs_flags & CASIO_PARENB)
- ? NOPARITY : (settings->casio_streamattrs_flags & CASIO_PARODD)
- ? ODDPARITY : EVENPARITY;
- dcb.StopBits = (settings->casio_streamattrs_flags & CASIO_TWOSTOPBITS)
- ? TWOSTOPBITS : ONESTOPBIT;
-
- /* set the DTR control mode */
- switch (settings->casio_streamattrs_flags & CASIO_DTRMASK) {
- case CASIO_DTRCTL_ENABLE:
- dcb.fDtrControl = DTR_CONTROL_ENABLE;
- break;
- case CASIO_DTRCTL_HANDSHAKE:
- dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
- break;
- default:
- dcb.fDtrControl = DTR_CONTROL_DISABLE;
- break;
- }
-
- /* set the RTS control mode */
- switch (settings->casio_streamattrs_flags & CASIO_RTSMASK) {
- case CASIO_RTSCTL_ENABLE:
- dcb.fRtsControl = RTS_CONTROL_ENABLE;
- break;
- case CASIO_RTSCTL_HANDSHAKE:
- dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
- break;
- default:
- dcb.fRtsControl = RTS_CONTROL_DISABLE;
- break;
- }
-
- /* set the XON/XOFF control mode on input */
- dcb.fInX = !!(settings->casio_streamattrs_flags & CASIO_XONCTL_ENABLE);
- dcb.XonChar = settings->casio_streamattrs_cc[CASIO_XON];
-
- /* set the XON/XOFF control mode on output */
- dcb.fOutX = !!(settings->casio_streamattrs_flags & CASIO_XOFFCTL_ENABLE);
- dcb.XoffChar = settings->casio_streamattrs_cc[CASIO_XOFF];
-
- /* set buffer limits (TODO: find out why non-zero values cause
- * ERROR_INVALID_PARAMETER when using `SetCommState`) */
- dcb.XonLim = 0x0000;
- dcb.XoffLim = 0x0000;
-
- /* save new state */
- msg((ll_info, "Updating the DCB."));
- wsuccess = SetCommState(cookie->_handle, &dcb);
- if (!wsuccess) {
- msg((ll_warn, "SetCommState: Error 0x%08lX occured.", GetLastError()));
- return (casio_error_unknown);
- }
-
- /* no error! */
- return (0);
-}
-
-/**
- * casio_win_settm:
- * Set timeouts.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg timeouts the timeouts to apply.
- * @return the error (0 if ok).
- */
-
-CASIO_LOCAL int casio_win_settm(void *vcookie,
- const casio_timeouts_t *timeouts)
-{
- win_cookie_t *cookie = (void*)vcookie;
-
- /* set the timeouts */
- COMMTIMEOUTS tm;
- tm.ReadIntervalTimeout = timeouts->casio_timeouts_read_bw;
- tm.ReadTotalTimeoutConstant = timeouts->casio_timeouts_read;
- tm.WriteTotalTimeoutConstant = timeouts->casio_timeouts_write;
- SetCommTimeouts(cookie->_handle, &tm);
-
- /* no error */
- return (0);
-}
-
-/**
- * casio_win_close:
- * Close a MS-Windows stream.
- *
- * @arg vcookie the cookie (uncasted).
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_win_close(void *vcookie)
-{
- win_cookie_t *cookie = (win_cookie_t*)vcookie;
- CloseHandle(cookie->_handle);
- casio_free(cookie);
- return (0);
-}
-/* ************************************************************************* */
-/* Character stream callbacks */
-/* ************************************************************************* */
-/**
- * casio_win_read:
- * Read from an MS-Windows stream.
- *
- * @arg vcookie the cookie (uncasted).
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_win_read(void *vcookie, unsigned char *dest, size_t size)
-{
- win_cookie_t *cookie = (win_cookie_t*)vcookie;
- DWORD werr, wsuccess, recv; size_t tocopy;
-
- /* transmit what's already in the buffer */
- if (cookie->_start <= cookie->_end) {
- tocopy = cookie->_end - cookie->_start + 1;
- if (tocopy > size) tocopy = size;
-
- memcpy(dest, &cookie->_buf[cookie->_start], tocopy);
- cookie->_start += tocopy;
- dest += tocopy;
- size -= tocopy;
- }
-
- /* main receiving loop */
- while (size) {
- /* receive */
- wsuccess = ReadFile(cookie->_handle,
- cookie->_buf, size, &recv, NULL);
-
- /* check error */
- if (!wsuccess) switch ((werr = GetLastError())) {
- case ERROR_DEV_NOT_EXIST:
- msg((ll_error, "Device has been disconnected!"));
- return (casio_error_nocalc);
-
- default:
- msg((ll_fatal, "Encountered error 0x%08lX", werr));
- return (casio_error_unknown);
- }
-
- /* get the current size to copy */
- tocopy = (size_t)recv;
- if (tocopy > size) tocopy = size;
-
- /* copy to destination */
- memcpy(dest, cookie->_buf, tocopy);
- dest += tocopy;
- size -= tocopy;
-
- /* correct start and end points */
- cookie->_start = tocopy;
- cookie->_end = (size_t)recv - 1;
- }
-
- /* no error */
- return (0);
-}
-
-/**
- * casio_win_seek:
- * Seek within an MS-Windows stream.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg
- */
-
-CASIO_LOCAL int casio_win_seek(void *vcookie, casio_off_t *offset,
- casio_whence_t whence)
-{
- win_cookie_t *cookie = (win_cookie_t*)vcookie;
- DWORD ret;
-
- /* get the move method */
- DWORD MoveMethod;
- switch (whence) {
- case CASIO_SEEK_CUR: MoveMethod = FILE_CURRENT; break;
- case CASIO_SEEK_END: MoveMethod = FILE_END; break;
- default /* CASIO_SEEK_SET */: MoveMethod = FILE_BEGIN; break; }
-
- ret = SetFilePointer(cookie->_handle, (LONG)*offset, NULL, MoveMethod);
- if (ret == INVALID_SET_FILE_POINTER)
- return (casio_error_op); /* TODO: check error with `GetLastError`? */
-
- *offset = (casio_off_t)ret;
- return (0);
-}
-
-/**
- * casio_win_write:
- * Write to an MS-Windows stream.
- *
- * @arg vcookie the cookie (uncasted).
- * @arg data the source
- * @arg size the source size
- * @return the error code (0 if ok).
- */
-
-CASIO_LOCAL int casio_win_write(void *vcookie,
- const unsigned char *data, size_t size)
-{
- win_cookie_t *cookie = (win_cookie_t*)vcookie;
- BOOL wsuccess, werr;
-
- /* make the I/O request */
- wsuccess = TRUE;
- do {
- /* write */
- DWORD wrt;
- wsuccess = WriteFile(cookie->_handle, data, size, &wrt, NULL);
- if (!wsuccess) break;
-
- /* go forward */
- data += wrt;
- size -= wrt;
- } while (size);
-
- /* check error */
- if (!wsuccess) switch ((werr = GetLastError())) {
- case ERROR_DEV_NOT_EXIST:
- msg((ll_error, "Device has been disconnected!"));
- return (casio_error_nocalc);
-
- default:
- msg((ll_fatal, "Encountered error 0x%08lx", werr));
- return (casio_error_unknown);
- }
-
- /* success! */
- return (0);
-}
-/* ************************************************************************* */
-/* Initialization function */
-/* ************************************************************************* */
-/* Callbacks */
-CASIO_LOCAL const casio_streamfuncs_t casio_windows_callbacks = {
- casio_win_close,
- casio_win_setcomm, casio_win_settm,
- casio_win_read, casio_win_write, casio_win_seek,
- NULL
-};
-
-/**
- * casio_openusb_windows:
- * Open a Microsoft Windows API stream.
- *
- * @arg stream the stream to make.
- * @return the error code (0 if you're ugly).
- */
-
-int CASIO_EXPORT casio_openusb_windows(casio_stream_t **stream)
-{
- int err; char *p = NULL;
-
- p = wfind(0x07cf, 0x6101);
- if (!p) return (casio_error_nocalc);
-
- err = casio_opencom_windows(stream, p);
- casio_free(p);
- return (err);
-}
-
-/**
- * casio_opencom_windows:
- * Open a Microsoft Windows API stream.
- *
- * @arg stream the stream to make.
- * @arg path the Windows device path (NULL if we should find it).
- * @return the error code (0 if you're a psychopath).
- */
-
-int CASIO_EXPORT casio_opencom_windows(casio_stream_t **stream,
- const char *path)
-{
- int err = 0; DWORD werr;
- HANDLE fhandle = INVALID_HANDLE_VALUE;
- win_cookie_t *cookie = NULL;
-
- /* open the file handle - my god, this function is so complex. */
- msg((ll_info, "Opening the stream"));
- fhandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (fhandle == INVALID_HANDLE_VALUE) switch ((werr = GetLastError())) {
- case ERROR_FILE_NOT_FOUND:
- case ERROR_DEV_NOT_EXIST:
- err = casio_error_nocalc; goto fail;
- case ERROR_ACCESS_DENIED:
- err = casio_error_noaccess; goto fail;
- default:
- msg((ll_fatal, "Error 0x%08lx encountered.", werr));
- err = casio_error_noaccess; goto fail;
- }
-
- /* make cookie */
- msg((ll_info, "Making the cookie"));
- cookie = casio_alloc(1, sizeof(win_cookie_t));
- err = casio_error_alloc;
- if (!cookie) goto fail;
-
- /* fill cookie */
- cookie->_handle = fhandle;
- cookie->_start = 0;
- cookie->_end = 1;
-
- /* initialize for real */
- return (casio_open(stream, CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE,
- casio_streamtype_serial, cookie, &casio_windows_callbacks));
-fail:
- if (fhandle != INVALID_HANDLE_VALUE) CloseHandle(fhandle);
- if (cookie) casio_free(cookie);
- return (err);
-}
-
-#endif
diff --git a/src/stream/builtin/windows/close.c b/src/stream/builtin/windows/close.c
new file mode 100644
index 0000000..dc0d430
--- /dev/null
+++ b/src/stream/builtin/windows/close.c
@@ -0,0 +1,37 @@
+/* ****************************************************************************
+ * stream/builtin/windows/close.c -- close a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_close:
+ * Close a MS-Windows stream.
+ *
+ * @arg cookie the cookie.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_windows_close(win_cookie_t *cookie)
+{
+ CloseHandle(cookie->_handle);
+ casio_free(cookie);
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/find.c b/src/stream/builtin/windows/find.c
new file mode 100644
index 0000000..06d769d
--- /dev/null
+++ b/src/stream/builtin/windows/find.c
@@ -0,0 +1,116 @@
+/* ****************************************************************************
+ * stream/builtin/windows/find.c -- find a Windows API USB stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_find_usb:
+ * Find the Microsoft Windows device path.
+ *
+ * @arg path the path to allocate.
+ * @arg vid the vendor ID (0x0000 to 0xffff)
+ * @arg pid the product ID (0x0000 to 0xffff)
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_windows_find_usb(char **path,
+ unsigned int vid, unsigned int pid)
+{
+ int i; DWORD werr;
+ char *devpath = NULL, vidpid[20];
+ HDEVINFO DeviceInfoSet;
+ SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
+
+ /* make the vid/pid string */
+ sprintf(vidpid, "#vid_%04x&pid_%04x", vid, pid);
+
+ /* get the device information set (chained list) */
+ msg((ll_info, "Getting the device info set"));
+ DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE,
+ NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
+ werr = GetLastError();
+ msg((ll_fatal, "Device info gathering failed! Error 0x%08lX", werr));
+ return (casio_error_notfound);
+ }
+
+ /* browse this set, setup */
+ DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ msg((ll_info, "Enumerating interfaces"));
+ for (i = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL,
+ &GUID_DEVINTERFACE_USB_DEVICE, i, &DeviceInterfaceData); i++) {
+ /* make the local variables */
+ DWORD RequiredSize = 0; const char *Path;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
+
+ /* get the detail size */
+ msg((ll_info, "Getting interface information detail size"));
+ if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
+ &DeviceInterfaceData, NULL, 0, &RequiredSize, NULL) &&
+ (werr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) {
+ msg((ll_error, "Error getting this size: 0x%08lX", werr));
+ continue;
+ }
+
+ /* allocate detail space */
+ msg((ll_info,
+ "Allocating space for interface information detail (%luo)",
+ RequiredSize));
+ DeviceInterfaceDetailData = casio_alloc(RequiredSize, 1);
+ if (!DeviceInterfaceDetailData) {
+ msg((ll_error, "Memory allocation failed. Oh well."));
+ break ;
+ }
+ DeviceInterfaceDetailData->cbSize =
+ sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+
+ /* get the detail */
+ msg((ll_info, "Getting interface information detail"));
+ if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
+ &DeviceInterfaceData, DeviceInterfaceDetailData, RequiredSize,
+ NULL, NULL)) {
+ werr = GetLastError();
+ msg((ll_error, "Error getting the interface information detail: "
+ "0x%08lX", werr));
+ continue;
+ }
+
+ /* check if it corresponds */
+ Path = DeviceInterfaceDetailData->DevicePath;
+ msg((ll_info, "Stumbled across: %s", Path));
+ if (strstr(Path, vidpid)) {
+ devpath = casio_alloc(strlen(Path) + 1, 1);
+ if (!devpath) break;
+ strcpy(devpath, Path);
+ }
+
+ /* free the allocated detail */
+ casio_free(DeviceInterfaceDetailData);
+ if (devpath) break ;
+ }
+
+ /* destroy the device information set */
+ msg((ll_info, "Destroying the device information set"));
+ SetupDiDestroyDeviceInfoList(DeviceInfoSet);
+ if (!devpath) return (casio_error_notfound);
+ *path = devpath;
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/open.c b/src/stream/builtin/windows/open.c
new file mode 100644
index 0000000..04f91df
--- /dev/null
+++ b/src/stream/builtin/windows/open.c
@@ -0,0 +1,104 @@
+/* ****************************************************************************
+ * stream/builtin/windows/open.c -- open a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/* Callbacks */
+CASIO_LOCAL const casio_streamfuncs_t casio_windows_callbacks = {
+ (casio_stream_close_t*)&casio_windows_close,
+ (casio_stream_settm_t*)&casio_windows_settm,
+ (casio_stream_read_t*)&casio_windows_read,
+ (casio_stream_write_t*)&casio_windows_write,
+ (casio_stream_seek_t*)&casio_windows_seek,
+ (casio_stream_setattrs_t*)&casio_windows_setattrs, NULL
+};
+
+/**
+ * casio_openusb_windows:
+ * Open a Microsoft Windows API stream.
+ *
+ * @arg stream the stream to make.
+ * @return the error code (0 if you're ugly).
+ */
+
+int CASIO_EXPORT casio_openusb_windows(casio_stream_t **stream)
+{
+ int err; char *p = NULL;
+
+ err = casio_windows_find_usb(&p, 0x07cf, 0x6101);
+ if (err) return (err);
+
+ err = casio_opencom_windows(stream, p);
+ casio_free(p);
+ return (err);
+}
+
+/**
+ * casio_opencom_windows:
+ * Open a Microsoft Windows API stream.
+ *
+ * @arg stream the stream to make.
+ * @arg path the Windows device path (NULL if we should find it).
+ * @return the error code (0 if you're a psychopath).
+ */
+
+int CASIO_EXPORT casio_opencom_windows(casio_stream_t **stream,
+ const char *path)
+{
+ int err = 0; DWORD werr;
+ HANDLE fhandle = INVALID_HANDLE_VALUE;
+ win_cookie_t *cookie = NULL;
+ casio_openmode_t mode;
+
+ /* open the file handle - my god, this function is so complex. */
+ msg((ll_info, "Opening the stream"));
+ fhandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fhandle == INVALID_HANDLE_VALUE) switch ((werr = GetLastError())) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_DEV_NOT_EXIST:
+ err = casio_error_nocalc; goto fail;
+ case ERROR_ACCESS_DENIED:
+ err = casio_error_noaccess; goto fail;
+ default:
+ msg((ll_fatal, "Error 0x%08lx encountered.", werr));
+ err = casio_error_noaccess; goto fail;
+ }
+
+ /* make cookie */
+ msg((ll_info, "Making the cookie"));
+ cookie = casio_alloc(1, sizeof(win_cookie_t));
+ err = casio_error_alloc;
+ if (!cookie) goto fail;
+
+ /* fill cookie */
+ cookie->_handle = fhandle;
+ cookie->_start = 0;
+ cookie->_end = 1;
+
+ /* initialize for real */
+ mode = CASIO_OPENMODE_READ | CASIO_OPENMODE_WRITE | CASIO_OPENMODE_SERIAL;
+ return (casio_open(stream, mode, cookie, &casio_windows_callbacks));
+fail:
+ if (fhandle != INVALID_HANDLE_VALUE) CloseHandle(fhandle);
+ if (cookie) casio_free(cookie);
+ return (err);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/read.c b/src/stream/builtin/windows/read.c
new file mode 100644
index 0000000..3ea6311
--- /dev/null
+++ b/src/stream/builtin/windows/read.c
@@ -0,0 +1,81 @@
+/* ****************************************************************************
+ * stream/builtin/windows/read.c -- read from a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_read:
+ * Read from an MS-Windows stream.
+ *
+ * @arg cookie the cookie.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_windows_read(win_cookie_t *cookie,
+ unsigned char *dest, size_t size)
+{
+ DWORD werr, wsuccess, recv; size_t tocopy;
+
+ /* transmit what's already in the buffer */
+ if (cookie->_start <= cookie->_end) {
+ tocopy = cookie->_end - cookie->_start + 1;
+ if (tocopy > size) tocopy = size;
+
+ memcpy(dest, &cookie->_buf[cookie->_start], tocopy);
+ cookie->_start += tocopy;
+ dest += tocopy;
+ size -= tocopy;
+ }
+
+ /* main receiving loop */
+ while (size) {
+ /* receive */
+ wsuccess = ReadFile(cookie->_handle,
+ cookie->_buf, size, &recv, NULL);
+
+ /* check error */
+ if (!wsuccess) switch ((werr = GetLastError())) {
+ case ERROR_DEV_NOT_EXIST:
+ msg((ll_error, "Device has been disconnected!"));
+ return (casio_error_nocalc);
+
+ default:
+ msg((ll_fatal, "Encountered error 0x%08lX", werr));
+ return (casio_error_unknown);
+ }
+
+ /* get the current size to copy */
+ tocopy = (size_t)recv;
+ if (tocopy > size) tocopy = size;
+
+ /* copy to destination */
+ memcpy(dest, cookie->_buf, tocopy);
+ dest += tocopy;
+ size -= tocopy;
+
+ /* correct start and end points */
+ cookie->_start = tocopy;
+ cookie->_end = (size_t)recv - 1;
+ }
+
+ /* no error */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/seek.c b/src/stream/builtin/windows/seek.c
new file mode 100644
index 0000000..7535bf1
--- /dev/null
+++ b/src/stream/builtin/windows/seek.c
@@ -0,0 +1,52 @@
+/* ****************************************************************************
+ * stream/builtin/windows/seek.c -- seek within a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_seek:
+ * Seek within an MS-Windows stream.
+ *
+ * @arg cookie the cookie.
+ * @arg offset the offset to seek to, and the final offset.
+ * @arg whence the whence.
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_windows_seek(win_cookie_t *cookie,
+ casio_off_t *offset, casio_whence_t whence)
+{
+ DWORD ret;
+
+ /* get the move method */
+ DWORD MoveMethod;
+ switch (whence) {
+ case CASIO_SEEK_CUR: MoveMethod = FILE_CURRENT; break;
+ case CASIO_SEEK_END: MoveMethod = FILE_END; break;
+ default /* CASIO_SEEK_SET */: MoveMethod = FILE_BEGIN; break; }
+
+ ret = SetFilePointer(cookie->_handle, (LONG)*offset, NULL, MoveMethod);
+ if (ret == INVALID_SET_FILE_POINTER)
+ return (casio_error_op); /* TODO: check error with `GetLastError`? */
+
+ *offset = (casio_off_t)ret;
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/setattrs.c b/src/stream/builtin/windows/setattrs.c
new file mode 100644
index 0000000..7809ada
--- /dev/null
+++ b/src/stream/builtin/windows/setattrs.c
@@ -0,0 +1,125 @@
+/* ****************************************************************************
+ * stream/builtin/windows/setattrs.c -- set attrs of a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_setattrs:
+ * Set communication status of a Microsoft Windows stream.
+ *
+ * This is accomplished by getting, updating and setting the DCB.
+ * Yay, a Windows API thingy.
+ *
+ * @arg cookie the cookie.
+ * @arg settings the settings to apply.
+ * @return the error (0 if ok)
+ */
+
+int CASIO_EXPORT casio_windows_setattrs(win_cookie_t *cookie,
+ const casio_streamattrs_t *settings)
+{
+ DWORD wsuccess, spd; DCB dcb;
+
+ /* get speed */
+ switch (settings->casio_streamattrs_speed) {
+ case CASIO_B1200: spd = CBR_1200; break;
+ case CASIO_B2400: spd = CBR_2400; break;
+ case CASIO_B4800: spd = CBR_4800; break;
+ case CASIO_B9600: spd = CBR_9600; break;
+ case CASIO_B19200: spd = CBR_19200; break;
+ case CASIO_B38400: spd = CBR_38400; break;
+ case CASIO_B57600: spd = CBR_57600; break;
+ case CASIO_B115200: spd = CBR_115200; break;
+ default:
+ msg((ll_info, "Speed was unsupported by the Windows API: %u",
+ settings->casio_streamattrs_speed));
+ return (casio_error_op);
+ }
+
+ /* gather stream properties */
+ SecureZeroMemory(&dcb, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!GetCommState(cookie->_handle, &dcb)) {
+ msg((ll_warn, "Failed gathering the DCB (0x%08lX), nevermind.",
+ GetLastError()));
+ return (0);
+ }
+
+ /* set normal things */
+ dcb.BaudRate = spd;
+ dcb.ByteSize = 8;
+ dcb.fParity = !!(settings->casio_streamattrs_flags & CASIO_PARENB);
+ dcb.Parity = (~settings->casio_streamattrs_flags & CASIO_PARENB)
+ ? NOPARITY : (settings->casio_streamattrs_flags & CASIO_PARODD)
+ ? ODDPARITY : EVENPARITY;
+ dcb.StopBits = (settings->casio_streamattrs_flags & CASIO_TWOSTOPBITS)
+ ? TWOSTOPBITS : ONESTOPBIT;
+
+ /* set the DTR control mode */
+ switch (settings->casio_streamattrs_flags & CASIO_DTRMASK) {
+ case CASIO_DTRCTL_ENABLE:
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;
+ break;
+ case CASIO_DTRCTL_HANDSHAKE:
+ dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
+ break;
+ default:
+ dcb.fDtrControl = DTR_CONTROL_DISABLE;
+ break;
+ }
+
+ /* set the RTS control mode */
+ switch (settings->casio_streamattrs_flags & CASIO_RTSMASK) {
+ case CASIO_RTSCTL_ENABLE:
+ dcb.fRtsControl = RTS_CONTROL_ENABLE;
+ break;
+ case CASIO_RTSCTL_HANDSHAKE:
+ dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+ break;
+ default:
+ dcb.fRtsControl = RTS_CONTROL_DISABLE;
+ break;
+ }
+
+ /* set the XON/XOFF control mode on input */
+ dcb.fInX = !!(settings->casio_streamattrs_flags & CASIO_XONCTL_ENABLE);
+ dcb.XonChar = settings->casio_streamattrs_cc[CASIO_XON];
+
+ /* set the XON/XOFF control mode on output */
+ dcb.fOutX = !!(settings->casio_streamattrs_flags & CASIO_XOFFCTL_ENABLE);
+ dcb.XoffChar = settings->casio_streamattrs_cc[CASIO_XOFF];
+
+ /* set buffer limits (TODO: find out why non-zero values cause
+ * ERROR_INVALID_PARAMETER when using `SetCommState`) */
+ dcb.XonLim = 0x0000;
+ dcb.XoffLim = 0x0000;
+
+ /* save new state */
+ msg((ll_info, "Updating the DCB."));
+ wsuccess = SetCommState(cookie->_handle, &dcb);
+ if (!wsuccess) {
+ msg((ll_warn, "SetCommState: Error 0x%08lX occured.", GetLastError()));
+ return (casio_error_unknown);
+ }
+
+ /* no error! */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/settm.c b/src/stream/builtin/windows/settm.c
new file mode 100644
index 0000000..0b88b53
--- /dev/null
+++ b/src/stream/builtin/windows/settm.c
@@ -0,0 +1,45 @@
+/* ****************************************************************************
+ * stream/builtin/windows/settm.c -- set timeouts of a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_settm:
+ * Set timeouts.
+ *
+ * @arg cookie the cookie.
+ * @arg timeouts the timeouts to apply.
+ * @return the error (0 if ok).
+ */
+
+int CASIO_EXPORT casio_windows_settm(win_cookie_t *cookie,
+ const casio_timeouts_t *timeouts)
+{
+ /* set the timeouts */
+ COMMTIMEOUTS tm;
+ tm.ReadIntervalTimeout = timeouts->casio_timeouts_read_bw;
+ tm.ReadTotalTimeoutConstant = timeouts->casio_timeouts_read;
+ tm.WriteTotalTimeoutConstant = timeouts->casio_timeouts_write;
+ SetCommTimeouts(cookie->_handle, &tm);
+
+ /* no error */
+ return (0);
+}
+
+#endif
diff --git a/src/stream/builtin/windows/windows.h b/src/stream/builtin/windows/windows.h
new file mode 100644
index 0000000..b19422b
--- /dev/null
+++ b/src/stream/builtin/windows/windows.h
@@ -0,0 +1,69 @@
+/* ****************************************************************************
+ * stream/builtin/windows/windows.h -- Windows API stream internals.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#ifndef LOCAL_STREAM_BUILTIN_WINDOWS_H
+# define LOCAL_STREAM_BUILTIN_WINDOWS_H 1
+# include "../../../internals.h"
+# ifndef LIBCASIO_DISABLED_WINDOWS
+# include
+# include
+# include
+# include
+# define BUFSIZE 2048
+
+/* Here is the structure of a cookie, used by the stream callbacks.
+ * PSP_COOKIE is just there to take the piss out of Microsoft :p */
+
+typedef struct {
+ HANDLE _handle;
+
+ long _start, _end;
+ unsigned char _buf[BUFSIZE];
+} win_cookie_t, *PSP_COOKIE;
+
+/* Find a USB device. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_windows_find_usb
+ OF((char **path, unsigned int vid, unsigned int pid));
+
+/* General callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_windows_close
+ OF((win_cookie_t *cookie));
+CASIO_EXTERN int CASIO_EXPORT casio_windows_settm
+ OF((win_cookie_t *cookie, const casio_timeouts_t *timeouts));
+
+/* Character device callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_windows_read
+ OF((win_cookie_t *cookie, unsigned char *dest, size_t size));
+CASIO_EXTERN int CASIO_EXPORT casio_windows_write
+ OF((win_cookie_t *cookie, const unsigned char *data, size_t size));
+
+/* Seek callback. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_windows_seek
+ OF((win_cookie_t *cookie, casio_off_t *offset, casio_whence_t whence));
+
+/* Serial callbacks. */
+
+CASIO_EXTERN int CASIO_EXPORT casio_windows_setattrs
+ OF((win_cookie_t *cookie, const casio_streamattrs_t *settings));
+
+# endif
+#endif /* LOCAL_STREAM_BUILTIN_WINDOWS_H */
diff --git a/src/stream/builtin/windows/write.c b/src/stream/builtin/windows/write.c
new file mode 100644
index 0000000..4689721
--- /dev/null
+++ b/src/stream/builtin/windows/write.c
@@ -0,0 +1,65 @@
+/* ****************************************************************************
+ * stream/builtin/windows/write.c -- write to a Windows API stream.
+ * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey
+ *
+ * This file is part of libcasio.
+ * libcasio 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 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 libcasio; if not, see .
+ * ************************************************************************* */
+#include "windows.h"
+#ifndef LIBCASIO_DISABLED_WINDOWS
+
+/**
+ * casio_windows_write:
+ * Write to an MS-Windows stream.
+ *
+ * @arg cookie the cookie.
+ * @arg data the source
+ * @arg size the source size
+ * @return the error code (0 if ok).
+ */
+
+int CASIO_EXPORT casio_windows_write(win_cookie_t *cookie,
+ const unsigned char *data, size_t size)
+{
+ BOOL wsuccess, werr;
+
+ /* make the I/O request */
+ wsuccess = TRUE;
+ do {
+ /* write */
+ DWORD wrt;
+ wsuccess = WriteFile(cookie->_handle, data, size, &wrt, NULL);
+ if (!wsuccess) break;
+
+ /* go forward */
+ data += wrt;
+ size -= wrt;
+ } while (size);
+
+ /* check error */
+ if (!wsuccess) switch ((werr = GetLastError())) {
+ case ERROR_DEV_NOT_EXIST:
+ msg((ll_error, "Device has been disconnected!"));
+ return (casio_error_nocalc);
+
+ default:
+ msg((ll_fatal, "Encountered error 0x%08lx", werr));
+ return (casio_error_unknown);
+ }
+
+ /* success! */
+ return (0);
+}
+
+#endif