From 089863770ded91bf4a4a336c70bb66a671900e15 Mon Sep 17 00:00:00 2001 From: "Thomas \"Cakeisalie5\" Touhey" Date: Fri, 30 Jun 2017 20:15:15 +0200 Subject: [PATCH] Reorganized, continued experiments on filesystems --- include/libcasio/builtin.h | 9 + include/libcasio/fs.h | 43 ++- src/fs/builtin/posix/path.c | 59 +++ src/fs/builtin/posix/posix.h | 14 + src/fs/builtin/posix/stat.c | 86 +++++ src/link/seven/datastream.c | 2 +- src/stream/builtin/libusb.c | 354 ------------------ src/stream/builtin/libusb/close.c | 38 ++ src/stream/builtin/libusb/libusb.h | 56 +++ src/stream/builtin/libusb/open.c | 183 +++++++++ src/stream/builtin/libusb/read.c | 93 +++++ src/stream/builtin/libusb/settm.c | 42 +++ src/stream/builtin/libusb/write.c | 59 +++ src/stream/builtin/streams.c | 517 -------------------------- src/stream/builtin/streams/close.c | 44 +++ src/stream/builtin/streams/open.c | 152 ++++++++ src/stream/builtin/streams/read.c | 86 +++++ src/stream/builtin/streams/scsi.c | 72 ++++ src/stream/builtin/streams/setattrs.c | 142 +++++++ src/stream/builtin/streams/settm.c | 60 +++ src/stream/builtin/streams/streams.h | 72 ++++ src/stream/builtin/streams/write.c | 57 +++ src/stream/builtin/windows.c | 494 ------------------------ src/stream/builtin/windows/close.c | 37 ++ src/stream/builtin/windows/find.c | 116 ++++++ src/stream/builtin/windows/open.c | 104 ++++++ src/stream/builtin/windows/read.c | 81 ++++ src/stream/builtin/windows/seek.c | 52 +++ src/stream/builtin/windows/setattrs.c | 125 +++++++ src/stream/builtin/windows/settm.c | 45 +++ src/stream/builtin/windows/windows.h | 69 ++++ src/stream/builtin/windows/write.c | 65 ++++ 32 files changed, 2045 insertions(+), 1383 deletions(-) create mode 100644 src/fs/builtin/posix/stat.c delete mode 100644 src/stream/builtin/libusb.c create mode 100644 src/stream/builtin/libusb/close.c create mode 100644 src/stream/builtin/libusb/libusb.h create mode 100644 src/stream/builtin/libusb/open.c create mode 100644 src/stream/builtin/libusb/read.c create mode 100644 src/stream/builtin/libusb/settm.c create mode 100644 src/stream/builtin/libusb/write.c delete mode 100644 src/stream/builtin/streams.c create mode 100644 src/stream/builtin/streams/close.c create mode 100644 src/stream/builtin/streams/open.c create mode 100644 src/stream/builtin/streams/read.c create mode 100644 src/stream/builtin/streams/scsi.c create mode 100644 src/stream/builtin/streams/setattrs.c create mode 100644 src/stream/builtin/streams/settm.c create mode 100644 src/stream/builtin/streams/streams.h create mode 100644 src/stream/builtin/streams/write.c delete mode 100644 src/stream/builtin/windows.c create mode 100644 src/stream/builtin/windows/close.c create mode 100644 src/stream/builtin/windows/find.c create mode 100644 src/stream/builtin/windows/open.c create mode 100644 src/stream/builtin/windows/read.c create mode 100644 src/stream/builtin/windows/seek.c create mode 100644 src/stream/builtin/windows/setattrs.c create mode 100644 src/stream/builtin/windows/settm.c create mode 100644 src/stream/builtin/windows/windows.h create mode 100644 src/stream/builtin/windows/write.c 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