mirror of
https://github.com/openharmony/third_party_sane-airscan.git
synced 2026-06-30 21:17:55 -04:00
442 lines
11 KiB
C
442 lines
11 KiB
C
/* AirScan (a.k.a. eSCL) backend for SANE
|
|
*
|
|
* Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
|
|
* See LICENSE for license terms and conditions
|
|
*
|
|
* SANE API
|
|
*/
|
|
|
|
#include "airscan.h"
|
|
|
|
/* Static variables
|
|
*/
|
|
static const SANE_Device **sane_device_list;
|
|
|
|
/* Initialize the backend
|
|
*/
|
|
SANE_Status
|
|
sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize)
|
|
{
|
|
SANE_Status status;
|
|
|
|
if (version_code != NULL) {
|
|
*version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR,
|
|
SANE_CURRENT_MINOR, 0);
|
|
}
|
|
|
|
(void) authorize;
|
|
|
|
status = airscan_init(0, "API: sane_init(): called");
|
|
if (status == SANE_STATUS_GOOD) {
|
|
status = device_management_init();
|
|
}
|
|
|
|
if (status != SANE_STATUS_GOOD) {
|
|
log_debug(NULL, "API: sane_init(): %s", sane_strstatus(status));
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Exit the backend
|
|
*/
|
|
void
|
|
sane_exit (void)
|
|
{
|
|
log_debug(NULL, "API: sane_exit(): called");
|
|
|
|
eloop_thread_stop();
|
|
device_management_cleanup();
|
|
airscan_cleanup("API: sane_exit(): OK");
|
|
}
|
|
|
|
/* Get list of devices
|
|
*/
|
|
SANE_Status
|
|
sane_get_devices (const SANE_Device ***device_list, SANE_Bool local_only)
|
|
{
|
|
log_debug(NULL, "API: sane_get_devices(): called");
|
|
|
|
if (local_only && !conf.pretend_local) {
|
|
/* Note, all our devices are non-local */
|
|
static const SANE_Device *empty_devlist[1] = {0};
|
|
*device_list = empty_devlist;
|
|
} else {
|
|
eloop_mutex_lock();
|
|
|
|
zeroconf_device_list_free(sane_device_list);
|
|
sane_device_list = zeroconf_device_list_get();
|
|
*device_list = sane_device_list;
|
|
|
|
eloop_mutex_unlock();
|
|
}
|
|
|
|
log_debug(NULL, "API: sane_get_devices(): done");
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/* Open the device
|
|
*/
|
|
SANE_Status
|
|
sane_open (SANE_String_Const name, SANE_Handle *handle)
|
|
{
|
|
SANE_Status status;
|
|
device *dev;
|
|
const SANE_Device **dev_list = NULL;
|
|
|
|
log_debug(NULL, "API: sane_open(\"%s\"): called", name ? name : "");
|
|
|
|
eloop_mutex_lock();
|
|
|
|
/* If name is not set, open the first device
|
|
*/
|
|
if (name == NULL || *name == '\0') {
|
|
dev_list = zeroconf_device_list_get();
|
|
if (dev_list[0] != NULL) {
|
|
name = dev_list[0]->name;
|
|
}
|
|
}
|
|
|
|
dev = device_open(name, &status);
|
|
|
|
eloop_mutex_unlock();
|
|
|
|
if (dev != NULL) {
|
|
*handle = (SANE_Handle) dev;
|
|
}
|
|
|
|
log_debug(device_log_ctx(dev), "API: sane_open(\"%s\"): %s",
|
|
name ? name : "", sane_strstatus(status));
|
|
|
|
zeroconf_device_list_free(dev_list);
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Close the device
|
|
*/
|
|
void
|
|
sane_close (SANE_Handle handle)
|
|
{
|
|
device *dev = (device*) handle;
|
|
|
|
log_debug(device_log_ctx(dev), "API: sane_close(): called");
|
|
|
|
eloop_mutex_lock();
|
|
device_close((device*) handle, "API: sane_close(): done");
|
|
eloop_mutex_unlock();
|
|
}
|
|
|
|
/* Get option descriptor
|
|
*/
|
|
const SANE_Option_Descriptor *
|
|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
|
{
|
|
device *dev = (device*) handle;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
const SANE_Option_Descriptor *desc;
|
|
|
|
log_debug(log, "API: device_get_option_descriptor(): called");
|
|
|
|
eloop_mutex_lock();
|
|
desc = device_get_option_descriptor(dev, option);
|
|
eloop_mutex_unlock();
|
|
|
|
log_debug(log, "API: device_get_option_descriptor(): done");
|
|
|
|
return desc;
|
|
}
|
|
|
|
/* Write sane_control_option operation to the log
|
|
*/
|
|
static void
|
|
sane_control_option_log (log_ctx *log, const SANE_Option_Descriptor *desc,
|
|
SANE_Int option, SANE_Action action, void *value, SANE_Int info)
|
|
{
|
|
char vbuf[128];
|
|
char ibuf[128] = "";
|
|
bool get;
|
|
|
|
switch (action) {
|
|
case SANE_ACTION_GET_VALUE:
|
|
get = true;
|
|
break;
|
|
|
|
case SANE_ACTION_SET_VALUE:
|
|
get = false;
|
|
break;
|
|
|
|
case SANE_ACTION_SET_AUTO:
|
|
default:
|
|
/* Not supported here */
|
|
return;
|
|
}
|
|
|
|
switch (desc->type) {
|
|
case SANE_TYPE_BOOL:
|
|
strcpy(vbuf, *((SANE_Word*) value) ? "true" : "false");
|
|
break;
|
|
|
|
case SANE_TYPE_INT:
|
|
sprintf(vbuf, "%d", *((SANE_Word*) value));
|
|
break;
|
|
|
|
case SANE_TYPE_FIXED:
|
|
sprintf(vbuf, "%g", SANE_UNFIX(*((SANE_Fixed*) value)));
|
|
break;
|
|
|
|
case SANE_TYPE_STRING:
|
|
snprintf(vbuf, sizeof(vbuf), "\"%s\"", (char*) value);
|
|
break;
|
|
|
|
case SANE_TYPE_BUTTON:
|
|
case SANE_TYPE_GROUP:
|
|
default:
|
|
/* Not supported here */
|
|
return;
|
|
}
|
|
|
|
if (action == SANE_ACTION_SET_VALUE && info != 0) {
|
|
strcat(ibuf, " info: ");
|
|
|
|
if ((info & SANE_INFO_INEXACT) != 0) {
|
|
strcat(ibuf, "inexact");
|
|
info &= ~SANE_INFO_INEXACT;
|
|
if (info != 0) {
|
|
strcat(ibuf, ", ");
|
|
}
|
|
}
|
|
|
|
if ((info & (SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS)) != 0) {
|
|
strcat(ibuf, "reload:");
|
|
|
|
if ((info & SANE_INFO_RELOAD_OPTIONS) != 0) {
|
|
strcat(ibuf, " options");
|
|
}
|
|
|
|
if ((info & SANE_INFO_RELOAD_PARAMS) != 0) {
|
|
strcat(ibuf, " params");
|
|
}
|
|
}
|
|
}
|
|
|
|
log_debug(log, "API: %s %s: %s %s",
|
|
get ? "get" : "set", option ? desc->name : "(0)", vbuf, ibuf);
|
|
}
|
|
|
|
/* Get or set option value
|
|
*/
|
|
SANE_Status
|
|
sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
|
|
void *value, SANE_Int *info)
|
|
{
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
|
device *dev = (device*) handle;
|
|
const SANE_Option_Descriptor *desc;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
|
|
eloop_mutex_lock();
|
|
|
|
/* Roughly validate arguments */
|
|
if (dev == NULL || value == NULL) {
|
|
goto DONE;
|
|
}
|
|
|
|
desc = device_get_option_descriptor(dev, option);
|
|
if (desc == NULL) {
|
|
goto DONE;
|
|
}
|
|
|
|
if (action == SANE_ACTION_SET_VALUE && !SANE_OPTION_IS_SETTABLE(desc->cap)){
|
|
goto DONE;
|
|
}
|
|
|
|
/* Get/set the option */
|
|
if (action == SANE_ACTION_GET_VALUE) {
|
|
status = device_get_option(dev, option, value);
|
|
} else {
|
|
status = device_set_option(dev, option, value, info);
|
|
}
|
|
|
|
DONE:
|
|
eloop_mutex_unlock();
|
|
|
|
if (status == SANE_STATUS_GOOD) {
|
|
sane_control_option_log(log, desc, option, action, value,
|
|
info ? *info : 0);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Get current scan parameters
|
|
*/
|
|
SANE_Status
|
|
sane_get_parameters (SANE_Handle handle, SANE_Parameters *params)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
device *dev = (device*) handle;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
|
|
log_debug(log, "API: sane_get_params(): called");
|
|
|
|
if (params != NULL) {
|
|
eloop_mutex_lock();
|
|
status = device_get_parameters(dev, params);
|
|
eloop_mutex_unlock();
|
|
}
|
|
|
|
log_debug(log, "API: sane_get_params(): done");
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Start scanning operation
|
|
*/
|
|
SANE_Status
|
|
sane_start (SANE_Handle handle)
|
|
{
|
|
SANE_Status status;
|
|
device *dev = (device*) handle;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
|
|
log_debug(log, "API: sane_start(): called");
|
|
|
|
eloop_mutex_lock();
|
|
status = device_start(dev);
|
|
eloop_mutex_unlock();
|
|
|
|
log_debug(log, "API: sane_start(): %s", sane_strstatus(status));
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Read scanned image
|
|
*/
|
|
SANE_Status
|
|
sane_read (SANE_Handle handle, SANE_Byte *data, SANE_Int max_len, SANE_Int *len)
|
|
{
|
|
SANE_Status status;
|
|
device *dev = (device*) handle;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
|
|
eloop_mutex_lock();
|
|
status = device_read(dev, data, max_len, len);
|
|
eloop_mutex_unlock();
|
|
|
|
/* Note, as a special exception, we don't log every successful
|
|
* call of sane_read(), because during loading of image there
|
|
* are a lot of them
|
|
*/
|
|
if (status != SANE_STATUS_GOOD) {
|
|
log_debug(log, "API: sane_read(): %s", sane_strstatus(status));
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Cancel scanning operation
|
|
*/
|
|
void
|
|
sane_cancel (SANE_Handle handle)
|
|
{
|
|
device *dev = handle;
|
|
|
|
/* Note, no mutex lock here and no logging. We can be called from
|
|
* signal handler. device_cancel() properly handles it
|
|
*/
|
|
device_cancel(dev);
|
|
}
|
|
|
|
/* Set I/O mode
|
|
*/
|
|
SANE_Status
|
|
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
|
|
{
|
|
SANE_Status status;
|
|
device *dev = (device*) handle;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
const char *mode = non_blocking ? "true" : "false";
|
|
|
|
log_debug(log, "API: sane_set_io_mode(%s): called", mode);
|
|
|
|
eloop_mutex_lock();
|
|
status = device_set_io_mode(dev, non_blocking);
|
|
eloop_mutex_unlock();
|
|
|
|
log_debug(log, "API: sane_set_io_mode(%s): %s", mode,
|
|
sane_strstatus(status));
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Get select file descriptor
|
|
*/
|
|
SANE_Status
|
|
sane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
|
|
{
|
|
SANE_Status status;
|
|
device *dev = (device*) handle;
|
|
log_ctx *log = device_log_ctx(dev);
|
|
|
|
log_debug(log, "API: sane_get_select_fd(): called");
|
|
|
|
eloop_mutex_lock();
|
|
status = device_get_select_fd(dev, fd);
|
|
eloop_mutex_unlock();
|
|
|
|
if (status == SANE_STATUS_GOOD) {
|
|
log_debug(log, "API: sane_get_select_fd(): fd = %d", *fd);
|
|
} else {
|
|
log_debug(log, "API: sane_get_select_fd(): %s", sane_strstatus(status));
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/******************** API aliases for libsane-dll ********************/
|
|
SANE_Status __attribute__ ((alias ("sane_init")))
|
|
sane_airscan_init (SANE_Int *version_code, SANE_Auth_Callback authorize);
|
|
|
|
void __attribute__ ((alias ("sane_exit")))
|
|
sane_airscan_exit (void);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_get_devices")))
|
|
sane_airscan_get_devices (const SANE_Device ***device_list, SANE_Bool local_only);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_open")))
|
|
sane_airscan_open (SANE_String_Const devicename, SANE_Handle *handle);
|
|
|
|
void __attribute__ ((alias ("sane_close")))
|
|
sane_airscan_close (SANE_Handle handle);
|
|
|
|
const SANE_Option_Descriptor * __attribute__ ((alias ("sane_get_option_descriptor")))
|
|
sane_airscan_get_option_descriptor (SANE_Handle handle, SANE_Int option);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_control_option")))
|
|
sane_airscan_control_option (SANE_Handle handle, SANE_Int option,
|
|
SANE_Action action, void *value, SANE_Int *info);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_get_parameters")))
|
|
sane_airscan_get_parameters (SANE_Handle handle, SANE_Parameters *params);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_start")))
|
|
sane_airscan_start (SANE_Handle handle);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_read")))
|
|
sane_airscan_read (SANE_Handle handle, SANE_Byte *data,
|
|
SANE_Int max_length, SANE_Int *length);
|
|
|
|
void __attribute__ ((alias ("sane_cancel")))
|
|
sane_airscan_cancel (SANE_Handle handle);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_set_io_mode")))
|
|
sane_airscan_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking);
|
|
|
|
SANE_Status __attribute__ ((alias ("sane_get_select_fd")))
|
|
sane_airscan_get_select_fd (SANE_Handle handle, SANE_Int * fd);
|
|
|
|
/* vim:ts=8:sw=4:et
|
|
*/
|