Reorganized, continued experiments on filesystems
This commit is contained in:
parent
04c7cbd9d7
commit
089863770d
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* along with libcasio; if not, see <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
||||
|
|
|
@ -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 <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
|
||||
/* 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 */
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* ****************************************************************************
|
||||
* fs/builtin/posix/stat.c -- get file information from POSIX filesystem.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -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);
|
||||
|
|
|
@ -1,354 +0,0 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb.c -- built-in libusb stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#include "../../internals.h"
|
||||
#ifndef LIBCASIO_DISABLED_LIBUSB
|
||||
# include <libusb.h>
|
||||
|
||||
/* 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 <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
/* 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
|
|
@ -0,0 +1,38 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb/close.c -- close a libusb stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,56 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb/libusb.h -- libusb stream internals.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#ifndef LOCAL_STREAM_BUILTIN_LIBUSB_H
|
||||
# include "../../../internals.h"
|
||||
|
||||
# ifndef LIBCASIO_DISABLED_LIBUSB
|
||||
# include <libusb.h>
|
||||
|
||||
# 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 */
|
|
@ -0,0 +1,183 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb/open.c -- open a libusb stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,93 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb/read.c -- read from a libusb stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,42 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb/settm.c -- set timeouts of a libusb stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,59 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/libusb/write.c -- write to a libusb stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -1,517 +0,0 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams.c -- built-in STREAMS stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#include "../../internals.h"
|
||||
#ifndef LIBCASIO_DISABLED_STREAMS
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <termios.h>
|
||||
|
||||
/* 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 <scsi/sg.h>
|
||||
|
||||
/**
|
||||
* 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
|
|
@ -0,0 +1,44 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/close.c -- close a STREAMS stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,152 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/open.c -- open a STREAMS stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,86 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/read.c -- read from a STREAMS stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,72 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/scsi.c -- make an SCSI request on a STREAMS device.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#include "streams.h"
|
||||
#if 0 && !defined(LIBCASIO_DISABLED_STREAMS)
|
||||
# include <scsi/sg.h>
|
||||
|
||||
/**
|
||||
* 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
|
|
@ -0,0 +1,142 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/setattrs.c -- STREAMS attributes.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,60 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/settm.c -- set timeouts for a STREAMS stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,72 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/streams.h -- built-in STREAMS stream internals.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#ifndef LOCAL_STREAM_BUILTIN_STREAMS_H
|
||||
# define LOCAL_STREAM_BUILTIN_STREAMS_H 1
|
||||
# include "../../../internals.h"
|
||||
# ifndef LIBCASIO_DISABLED_STREAMS
|
||||
# include <sys/stat.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
# include <termios.h>
|
||||
|
||||
/* 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 */
|
|
@ -0,0 +1,57 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/streams/write.c -- write to a STREAMS stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -1,494 +0,0 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows.c -- built-in Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#include "../../internals.h"
|
||||
#ifndef LIBCASIO_DISABLED_WINDOWS
|
||||
|
||||
/* only works because I redefined the version at the beginning
|
||||
* of `internals.h`! */
|
||||
# include <windows.h>
|
||||
# include <setupapi.h>
|
||||
# include <usbiodef.h>
|
||||
# include <winerror.h>
|
||||
|
||||
/* 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
|
|
@ -0,0 +1,37 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/close.c -- close a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,116 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/find.c -- find a Windows API USB stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,104 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/open.c -- open a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,81 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/read.c -- read from a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,52 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/seek.c -- seek within a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,125 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/setattrs.c -- set attrs of a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,45 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/settm.c -- set timeouts of a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
|
@ -0,0 +1,69 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/windows.h -- Windows API stream internals.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#ifndef LOCAL_STREAM_BUILTIN_WINDOWS_H
|
||||
# define LOCAL_STREAM_BUILTIN_WINDOWS_H 1
|
||||
# include "../../../internals.h"
|
||||
# ifndef LIBCASIO_DISABLED_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <setupapi.h>
|
||||
# include <usbiodef.h>
|
||||
# include <winerror.h>
|
||||
# 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 */
|
|
@ -0,0 +1,65 @@
|
|||
/* ****************************************************************************
|
||||
* stream/builtin/windows/write.c -- write to a Windows API stream.
|
||||
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************* */
|
||||
#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
|
Loading…
Reference in New Issue