diff options
Diffstat (limited to 'backend/dmc.c')
-rw-r--r-- | backend/dmc.c | 1404 |
1 files changed, 1404 insertions, 0 deletions
diff --git a/backend/dmc.c b/backend/dmc.c new file mode 100644 index 0000000..96f9186 --- /dev/null +++ b/backend/dmc.c @@ -0,0 +1,1404 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1998 David F. Skoll + Heavily based on "hp.c" driver for HP Scanners, by + David Mosberger-Tang. + + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + + This file implements a SANE backend for the Polaroid Digital + Microscope Camera. */ + +/* $Id$ */ + +#include "../include/sane/config.h" + +#include <limits.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "../include/_stdint.h" + +#include "../include/sane/sane.h" +#include "../include/sane/saneopts.h" +#include "../include/sane/sanei_scsi.h" + +#define BACKEND_NAME dmc +#include "../include/sane/sanei_backend.h" + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +#include "../include/sane/sanei_config.h" +#define DMC_CONFIG_FILE "dmc.conf" + +#include "dmc.h" + +/* A linked-list of attached devices and handles */ +static DMC_Device *FirstDevice = NULL; +static DMC_Camera *FirstHandle = NULL; +static int NumDevices = 0; + +static SANE_String_Const ValidModes[] = { "Full frame", "Viewfinder", + "Raw", "Thumbnail", + "Super-Resolution", + NULL }; + +static SANE_String_Const ValidBalances[] = { "Daylight", "Incandescent", + "Fluorescent", NULL }; + +static SANE_Word ValidASAs[] = { 3, 25, 50, 100 }; + +/* Convert between 32-us ticks and milliseconds */ +#define MS_TO_TICKS(x) (((x) * 1000 + 16) / 32) +#define TICKS_TO_MS(x) (((x) * 32) / 1000) + +/* Macros for stepping along the raw lines for super-resolution mode + They are very ugly because they handle boundary conditions at + the edges of the image. Yuck... */ + +#define PREV_RED(i) (((i)/3)*3) +#define NEXT_RED(i) (((i) >= BYTES_PER_RAW_LINE-3) ? BYTES_PER_RAW_LINE-3 : \ + PREV_RED(i)+3) +#define PREV_GREEN(i) ((i)<1 ? 1 : PREV_RED((i)-1)+1) +#define NEXT_GREEN(i) ((i)<1 ? 1 : ((i) >= BYTES_PER_RAW_LINE-2) ? \ + BYTES_PER_RAW_LINE-2 : PREV_GREEN(i)+3) +#define PREV_BLUE(i) ((i)<2 ? 2 : PREV_RED((i)-2)+2) +#define NEXT_BLUE(i) ((i)<2 ? 2 : ((i) >= BYTES_PER_RAW_LINE-1) ? \ + BYTES_PER_RAW_LINE-1 : PREV_BLUE(i)+3) + +#define ADVANCE_COEFF(i) (((i)==1) ? 3 : (i)-1); + +/********************************************************************** +//%FUNCTION: DMCRead +//%ARGUMENTS: +// fd -- file descriptor +// typecode -- data type code +// qualifier -- data type qualifier +// maxlen -- tranfer length +// buf -- buffer to store data in +// len -- set to actual length of data +//%RETURNS: +// A SANE status code +//%DESCRIPTION: +// Reads the particular data selected by typecode and qualifier +// *********************************************************************/ +static SANE_Status +DMCRead(int fd, unsigned int typecode, unsigned int qualifier, + SANE_Byte *buf, size_t maxlen, size_t *len) +{ + uint8_t readCmd[10]; + SANE_Status status; + + readCmd[0] = 0x28; + readCmd[1] = 0; + readCmd[2] = typecode; + readCmd[3] = 0; + readCmd[4] = (qualifier >> 8) & 0xFF; + readCmd[5] = qualifier & 0xFF; + readCmd[6] = (maxlen >> 16) & 0xFF; + readCmd[7] = (maxlen >> 8) & 0xFF; + readCmd[8] = maxlen & 0xFF; + readCmd[9] = 0; + DBG(3, "DMCRead: typecode=%x, qualifier=%x, maxlen=%lu\n", + typecode, qualifier, (u_long) maxlen); + + *len = maxlen; + status = sanei_scsi_cmd(fd, readCmd, sizeof(readCmd), buf, len); + DBG(3, "DMCRead: Read %lu bytes\n", (u_long) *len); + return status; +} + +/********************************************************************** +//%FUNCTION: DMCWrite +//%ARGUMENTS: +// fd -- file descriptor +// typecode -- data type code +// qualifier -- data type qualifier +// maxlen -- tranfer length +// buf -- buffer to store data in +//%RETURNS: +// A SANE status code +//%DESCRIPTION: +// Writes the particular data selected by typecode and qualifier +// *********************************************************************/ +static SANE_Status +DMCWrite(int fd, unsigned int typecode, unsigned int qualifier, + SANE_Byte *buf, size_t maxlen) +{ + uint8_t *writeCmd; + SANE_Status status; + + writeCmd = malloc(maxlen + 10); + if (!writeCmd) return SANE_STATUS_NO_MEM; + + writeCmd[0] = 0x2A; + writeCmd[1] = 0; + writeCmd[2] = typecode; + writeCmd[3] = 0; + writeCmd[4] = (qualifier >> 8) & 0xFF; + writeCmd[5] = qualifier & 0xFF; + writeCmd[6] = (maxlen >> 16) & 0xFF; + writeCmd[7] = (maxlen >> 8) & 0xFF; + writeCmd[8] = maxlen & 0xFF; + writeCmd[9] = 0; + memcpy(writeCmd+10, buf, maxlen); + + DBG(3, "DMCWrite: typecode=%x, qualifier=%x, maxlen=%lu\n", + typecode, qualifier, (u_long) maxlen); + + status = sanei_scsi_cmd(fd, writeCmd, 10+maxlen, NULL, NULL); + free(writeCmd); + return status; +} + +/********************************************************************** +//%FUNCTION: DMCAttach +//%ARGUMENTS: +// devname -- name of device file to open +// devp -- a DMC_Device structure which we fill in if it's not NULL. +//%RETURNS: +// SANE_STATUS_GOOD -- We have a Polaroid DMC attached and all looks good. +// SANE_STATUS_INVAL -- There's a problem. +//%DESCRIPTION: +// Verifies that a Polaroid DMC is attached. Sets up device options in +// DMC_Device structure. +// *********************************************************************/ +#define INQ_LEN 255 +static SANE_Status +DMCAttach(char const *devname, DMC_Device **devp) +{ + DMC_Device *dev; + SANE_Status status; + int fd; + size_t size; + char result[INQ_LEN]; + + uint8_t exposureCalculationResults[16]; + uint8_t userInterfaceSettings[16]; + + static uint8_t const inquiry[] = + { 0x12, 0x00, 0x00, 0x00, INQ_LEN, 0x00 }; + + static uint8_t const test_unit_ready[] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + static uint8_t const no_viewfinder[] = + { 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + /* If we're already attached, do nothing */ + + for (dev = FirstDevice; dev; dev = dev->next) { + if (!strcmp(dev->sane.name, devname)) { + if (devp) *devp = dev; + return SANE_STATUS_GOOD; + } + } + + DBG(3, "DMCAttach: opening `%s'\n", devname); + status = sanei_scsi_open(devname, &fd, 0, 0); + if (status != SANE_STATUS_GOOD) { + DBG(1, "DMCAttach: open failed (%s)\n", sane_strstatus(status)); + return status; + } + + DBG(3, "DMCAttach: sending INQUIRY\n"); + size = sizeof(result); + status = sanei_scsi_cmd(fd, inquiry, sizeof(inquiry), result, &size); + if (status != SANE_STATUS_GOOD || size < 32) { + if (status == SANE_STATUS_GOOD) status = SANE_STATUS_INVAL; + DBG(1, "DMCAttach: inquiry failed (%s)\n", sane_strstatus(status)); + sanei_scsi_close(fd); + return status; + } + + /* Verify that we have a Polaroid DMC */ + + if (result[0] != 6 || + strncmp(result+8, "POLAROID", 8) || + strncmp(result+16, "DMC ", 8)) { + sanei_scsi_close(fd); + DBG(1, "DMCAttach: Device does not look like a Polaroid DMC\n"); + return SANE_STATUS_INVAL; + } + + DBG(3, "DMCAttach: sending TEST_UNIT_READY\n"); + status = sanei_scsi_cmd(fd, test_unit_ready, sizeof(test_unit_ready), + NULL, NULL); + if (status != SANE_STATUS_GOOD) { + DBG(1, "DMCAttach: test unit ready failed (%s)\n", + sane_strstatus(status)); + sanei_scsi_close(fd); + return status; + } + + /* Read current ASA and shutter speed settings */ + status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults, + sizeof(exposureCalculationResults), &size); + if (status != SANE_STATUS_GOOD || + size < sizeof(exposureCalculationResults)) { + DBG(1, "DMCAttach: Couldn't read exposure calculation results (%s)\n", + sane_strstatus(status)); + sanei_scsi_close(fd); + if (status == SANE_STATUS_GOOD) status = SANE_STATUS_IO_ERROR; + return status; + } + + /* Read current white balance settings */ + status = DMCRead(fd, 0x82, 0x0, userInterfaceSettings, + sizeof(userInterfaceSettings), &size); + if (status != SANE_STATUS_GOOD || + size < sizeof(userInterfaceSettings)) { + DBG(1, "DMCAttach: Couldn't read user interface settings (%s)\n", + sane_strstatus(status)); + sanei_scsi_close(fd); + if (status == SANE_STATUS_GOOD) status = SANE_STATUS_IO_ERROR; + return status; + } + + /* Shut off viewfinder mode */ + status = sanei_scsi_cmd(fd, no_viewfinder, sizeof(no_viewfinder), + NULL, NULL); + if (status != SANE_STATUS_GOOD) { + sanei_scsi_close(fd); + return status; + } + sanei_scsi_close(fd); + + DBG(3, "DMCAttach: Looks like we have a Polaroid DMC\n"); + + dev = malloc(sizeof(*dev)); + if (!dev) return SANE_STATUS_NO_MEM; + memset(dev, 0, sizeof(*dev)); + + dev->sane.name = strdup(devname); + dev->sane.vendor = "Polaroid"; + dev->sane.model = "DMC"; + dev->sane.type = "still camera"; + dev->next = FirstDevice; + dev->whiteBalance = userInterfaceSettings[5]; + if (dev->whiteBalance > WHITE_BALANCE_FLUORESCENT) { + dev->whiteBalance = WHITE_BALANCE_FLUORESCENT; + } + + /* Bright Eyes documentation gives these as shutter speed ranges (ms) */ + /* dev->shutterSpeedRange.min = 8; */ + /* dev->shutterSpeedRange.max = 320; */ + + /* User's manual says these are shutter speed ranges (ms) */ + dev->shutterSpeedRange.min = 8; + dev->shutterSpeedRange.max = 1000; + dev->shutterSpeedRange.quant = 2; + dev->shutterSpeed = + (exposureCalculationResults[10] << 8) + + exposureCalculationResults[11]; + + /* Convert from ticks to ms */ + dev->shutterSpeed = TICKS_TO_MS(dev->shutterSpeed); + + dev->asa = exposureCalculationResults[13]; + if (dev->asa > ASA_100) dev->asa = ASA_100; + dev->asa = ValidASAs[dev->asa + 1]; + FirstDevice = dev; + NumDevices++; + if (devp) *devp = dev; + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: ValidateHandle +//%ARGUMENTS: +// handle -- a handle for an opened camera +//%RETURNS: +// A validated pointer to the camera or NULL if handle is not valid. +// *********************************************************************/ +static DMC_Camera * +ValidateHandle(SANE_Handle handle) +{ + DMC_Camera *c; + for (c = FirstHandle; c; c = c->next) { + if (c == handle) return c; + } + DBG(1, "ValidateHandle: invalid handle %p\n", handle); + return NULL; +} + +/********************************************************************** +//%FUNCTION: DMCInitOptions +//%ARGUMENTS: +// c -- a DMC camera device +//%RETURNS: +// SANE_STATUS_GOOD -- OK +// SANE_STATUS_INVAL -- There's a problem. +//%DESCRIPTION: +// Initializes the options in the DMC_Camera structure +// *********************************************************************/ +static SANE_Status +DMCInitOptions(DMC_Camera *c) +{ + int i; + + /* Image is initially 801x600 */ + c->tl_x_range.min = 0; + c->tl_x_range.max = c->tl_x_range.min; + c->tl_x_range.quant = 1; + c->tl_y_range.min = 0; + c->tl_y_range.max = c->tl_y_range.min; + c->tl_y_range.quant = 1; + + c->br_x_range.min = 800; + c->br_x_range.max = c->br_x_range.min; + c->br_x_range.quant = 1; + c->br_y_range.min = 599; + c->br_y_range.max = c->br_y_range.min; + c->br_y_range.quant = 1; + + memset(c->opt, 0, sizeof(c->opt)); + memset(c->val, 0, sizeof(c->val)); + + for (i=0; i<NUM_OPTIONS; i++) { + c->opt[i].type = SANE_TYPE_INT; + c->opt[i].size = sizeof(SANE_Word); + c->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + c->opt[i].unit = SANE_UNIT_NONE; + } + + c->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; + c->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; + c->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; + c->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; + c->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; + c->opt[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE; + c->val[OPT_NUM_OPTS].w = NUM_OPTIONS; + + c->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; + c->opt[OPT_GEOMETRY_GROUP].name = ""; + c->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; + c->opt[OPT_GEOMETRY_GROUP].desc = ""; + c->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; + c->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* top-left x */ + c->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; + c->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; + c->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; + c->opt[OPT_TL_X].type = SANE_TYPE_INT; + c->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL; + c->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + c->opt[OPT_TL_X].constraint.range = &c->tl_x_range; + c->val[OPT_TL_X].w = c->tl_x_range.min; + + /* top-left y */ + c->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; + c->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + c->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + c->opt[OPT_TL_Y].type = SANE_TYPE_INT; + c->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL; + c->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + c->opt[OPT_TL_Y].constraint.range = &c->tl_y_range; + c->val[OPT_TL_Y].w = c->tl_y_range.min; + + /* bottom-right x */ + c->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; + c->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; + c->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; + c->opt[OPT_BR_X].type = SANE_TYPE_INT; + c->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL; + c->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + c->opt[OPT_BR_X].constraint.range = &c->br_x_range; + c->val[OPT_BR_X].w = c->br_x_range.min; + + /* bottom-right y */ + c->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; + c->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + c->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + c->opt[OPT_BR_Y].type = SANE_TYPE_INT; + c->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL; + c->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + c->opt[OPT_BR_Y].constraint.range = &c->br_y_range; + c->val[OPT_BR_Y].w = c->br_y_range.min; + + c->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; + c->opt[OPT_MODE_GROUP].name = ""; + c->opt[OPT_MODE_GROUP].title = "Imaging Mode"; + c->opt[OPT_MODE_GROUP].desc = ""; + c->opt[OPT_MODE_GROUP].cap = SANE_CAP_ADVANCED; + c->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + c->opt[OPT_IMAGE_MODE].name = "imagemode"; + c->opt[OPT_IMAGE_MODE].title = "Image Mode"; + c->opt[OPT_IMAGE_MODE].desc = "Selects image mode: 800x600 full frame, 270x201 viewfinder mode, 1599x600 \"raw\" image, 80x60 thumbnail image or 1599x1200 \"super-resolution\" image"; + c->opt[OPT_IMAGE_MODE].type = SANE_TYPE_STRING; + c->opt[OPT_IMAGE_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + c->opt[OPT_IMAGE_MODE].constraint.string_list = ValidModes; + c->opt[OPT_IMAGE_MODE].size = 16; + c->val[OPT_IMAGE_MODE].s = "Full frame"; + + c->opt[OPT_ASA].name = "asa"; + c->opt[OPT_ASA].title = "ASA Setting"; + c->opt[OPT_ASA].desc = "Equivalent ASA setting"; + c->opt[OPT_ASA].constraint_type = SANE_CONSTRAINT_WORD_LIST; + c->opt[OPT_ASA].constraint.word_list = ValidASAs; + c->val[OPT_ASA].w = c->hw->asa; + + c->opt[OPT_SHUTTER_SPEED].name = "shutterspeed"; + c->opt[OPT_SHUTTER_SPEED].title = "Shutter Speed (ms)"; + c->opt[OPT_SHUTTER_SPEED].desc = "Shutter Speed in milliseconds"; + c->opt[OPT_SHUTTER_SPEED].constraint_type = SANE_CONSTRAINT_RANGE; + c->opt[OPT_SHUTTER_SPEED].constraint.range = &c->hw->shutterSpeedRange; + c->val[OPT_SHUTTER_SPEED].w = c->hw->shutterSpeed; + + c->opt[OPT_WHITE_BALANCE].name = "whitebalance"; + c->opt[OPT_WHITE_BALANCE].title = "White Balance"; + c->opt[OPT_WHITE_BALANCE].desc = "Selects white balance"; + c->opt[OPT_WHITE_BALANCE].type = SANE_TYPE_STRING; + c->opt[OPT_WHITE_BALANCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + c->opt[OPT_WHITE_BALANCE].constraint.string_list = ValidBalances; + c->opt[OPT_WHITE_BALANCE].size = 16; + c->val[OPT_WHITE_BALANCE].s = (SANE_String) ValidBalances[c->hw->whiteBalance]; + + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: DMCSetMode +//%ARGUMENTS: +// c -- a DMC camera device +// mode -- Imaging mode +//%RETURNS: +// SANE_STATUS_GOOD -- OK +// SANE_STATUS_INVAL -- There's a problem. +//%DESCRIPTION: +// Sets the camera's imaging mode. +// *********************************************************************/ +static SANE_Status +DMCSetMode(DMC_Camera *c, int mode) +{ + switch(mode) { + case IMAGE_MFI: + c->tl_x_range.min = 0; + c->tl_x_range.max = c->tl_x_range.max; + c->tl_y_range.min = 0; + c->tl_y_range.max = c->tl_y_range.max; + c->br_x_range.min = 800; + c->br_x_range.max = c->br_x_range.max; + c->br_y_range.min = 599; + c->br_y_range.max = c->br_y_range.max; + break; + case IMAGE_VIEWFINDER: + c->tl_x_range.min = 0; + c->tl_x_range.max = c->tl_x_range.max; + c->tl_y_range.min = 0; + c->tl_y_range.max = c->tl_y_range.max; + c->br_x_range.min = 269; + c->br_x_range.max = c->br_x_range.max; + c->br_y_range.min = 200; + c->br_y_range.max = c->br_y_range.max; + break; + case IMAGE_RAW: + c->tl_x_range.min = 0; + c->tl_x_range.max = c->tl_x_range.max; + c->tl_y_range.min = 0; + c->tl_y_range.max = c->tl_y_range.max; + c->br_x_range.min = 1598; + c->br_x_range.max = c->br_x_range.max; + c->br_y_range.min = 599; + c->br_y_range.max = c->br_y_range.max; + break; + case IMAGE_THUMB: + c->tl_x_range.min = 0; + c->tl_x_range.max = c->tl_x_range.max; + c->tl_y_range.min = 0; + c->tl_y_range.max = c->tl_y_range.max; + c->br_x_range.min = 79; + c->br_x_range.max = c->br_x_range.max; + c->br_y_range.min = 59; + c->br_y_range.max = c->br_y_range.max; + break; + case IMAGE_SUPER_RES: + c->tl_x_range.min = 0; + c->tl_x_range.max = c->tl_x_range.max; + c->tl_y_range.min = 0; + c->tl_y_range.max = c->tl_y_range.max; + c->br_x_range.min = 1598; + c->br_x_range.max = c->br_x_range.max; + c->br_y_range.min = 1199; + c->br_y_range.max = c->br_y_range.max; + break; + default: + return SANE_STATUS_INVAL; + } + c->imageMode = mode; + c->val[OPT_TL_X].w = c->tl_x_range.min; + c->val[OPT_TL_Y].w = c->tl_y_range.min; + c->val[OPT_BR_X].w = c->br_x_range.min; + c->val[OPT_BR_Y].w = c->br_y_range.min; + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: DMCCancel +//%ARGUMENTS: +// c -- a DMC camera device +//%RETURNS: +// SANE_STATUS_CANCELLED +//%DESCRIPTION: +// Cancels DMC image acquisition +// *********************************************************************/ +static SANE_Status +DMCCancel(DMC_Camera *c) +{ + if (c->fd >= 0) { + sanei_scsi_close(c->fd); + c->fd = -1; + } + return SANE_STATUS_CANCELLED; +} + +/********************************************************************** +//%FUNCTION: DMCSetASA +//%ARGUMENTS: +// fd -- SCSI file descriptor +// asa -- the ASA to set +//%RETURNS: +// A sane status value +//%DESCRIPTION: +// Sets the equivalent ASA setting of the camera. +// *********************************************************************/ +static SANE_Status +DMCSetASA(int fd, unsigned int asa) +{ + uint8_t exposureCalculationResults[16]; + SANE_Status status; + size_t len; + int i; + + DBG(3, "DMCSetAsa: %d\n", asa); + for (i=1; i<=ASA_100+1; i++) { + if (asa == (unsigned int) ValidASAs[i]) break; + } + + if (i > ASA_100+1) return SANE_STATUS_INVAL; + + status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults, + sizeof(exposureCalculationResults), &len); + if (status != SANE_STATUS_GOOD) return status; + if (len < sizeof(exposureCalculationResults)) return SANE_STATUS_IO_ERROR; + + exposureCalculationResults[13] = (uint8_t) i - 1; + + return DMCWrite(fd, 0x87, 0x4, exposureCalculationResults, + sizeof(exposureCalculationResults)); +} + +/********************************************************************** +//%FUNCTION: DMCSetWhiteBalance +//%ARGUMENTS: +// fd -- SCSI file descriptor +// mode -- white balance mode +//%RETURNS: +// A sane status value +//%DESCRIPTION: +// Sets the equivalent ASA setting of the camera. +// *********************************************************************/ +static SANE_Status +DMCSetWhiteBalance(int fd, int mode) +{ + uint8_t userInterfaceSettings[16]; + SANE_Status status; + size_t len; + + DBG(3, "DMCSetWhiteBalance: %d\n", mode); + status = DMCRead(fd, 0x82, 0x0, userInterfaceSettings, + sizeof(userInterfaceSettings), &len); + if (status != SANE_STATUS_GOOD) return status; + if (len < sizeof(userInterfaceSettings)) return SANE_STATUS_IO_ERROR; + + userInterfaceSettings[5] = (uint8_t) mode; + + return DMCWrite(fd, 0x82, 0x0, userInterfaceSettings, + sizeof(userInterfaceSettings)); +} + +/********************************************************************** +//%FUNCTION: DMCSetShutterSpeed +//%ARGUMENTS: +// fd -- SCSI file descriptor +// speed -- shutter speed in ms +//%RETURNS: +// A sane status value +//%DESCRIPTION: +// Sets the shutter speed of the camera +// *********************************************************************/ +static SANE_Status +DMCSetShutterSpeed(int fd, unsigned int speed) +{ + uint8_t exposureCalculationResults[16]; + SANE_Status status; + size_t len; + + DBG(3, "DMCSetShutterSpeed: %u\n", speed); + /* Convert from ms to ticks */ + speed = MS_TO_TICKS(speed); + + status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults, + sizeof(exposureCalculationResults), &len); + if (status != SANE_STATUS_GOOD) return status; + if (len < sizeof(exposureCalculationResults)) return SANE_STATUS_IO_ERROR; + + exposureCalculationResults[10] = (speed >> 8) & 0xFF; + exposureCalculationResults[11] = speed & 0xFF; + + return DMCWrite(fd, 0x87, 0x4, exposureCalculationResults, + sizeof(exposureCalculationResults)); +} + +/********************************************************************** +//%FUNCTION: DMCReadTwoSuperResolutionLines +//%ARGUMENTS: +// c -- DMC Camera +// buf -- where to put output. +// lastLine -- if true, these are the last two lines in the super-resolution +// image to read. +//%RETURNS: +// Nothing +//%DESCRIPTION: +// Reads a single "raw" line from the camera (if needed) and constructs +// two "super-resolution" output lines in "buf" +// *********************************************************************/ +static SANE_Status +DMCReadTwoSuperResolutionLines(DMC_Camera *c, SANE_Byte *buf, int lastLine) +{ + SANE_Status status; + size_t len; + + SANE_Byte *output, *prev; + int redCoeff, greenCoeff, blueCoeff; + int red, green, blue; + int i; + + if (c->nextRawLineValid) { + memcpy(c->currentRawLine, c->nextRawLine, BYTES_PER_RAW_LINE); + } else { + status = DMCRead(c->fd, 0x00, IMAGE_RAW, + c->currentRawLine, BYTES_PER_RAW_LINE, &len); + if (status != SANE_STATUS_GOOD) return status; + } + if (!lastLine) { + status = DMCRead(c->fd, 0x00, IMAGE_RAW, + c->nextRawLine, BYTES_PER_RAW_LINE, &len); + if (status != SANE_STATUS_GOOD) return status; + c->nextRawLineValid = 1; + } + + redCoeff = 3; + greenCoeff = 1; + blueCoeff = 2; + + /* Do the first super-resolution line */ + output = buf; + for (i=0; i<BYTES_PER_RAW_LINE; i++) { + red = redCoeff * c->currentRawLine[PREV_RED(i)] + + (3-redCoeff) * c->currentRawLine[NEXT_RED(i)]; + green = greenCoeff * c->currentRawLine[PREV_GREEN(i)] + + (3-greenCoeff) * c->currentRawLine[NEXT_GREEN(i)]; + blue = blueCoeff * c->currentRawLine[PREV_BLUE(i)] + + (3-blueCoeff) * c->currentRawLine[NEXT_BLUE(i)]; + *output++ = red/3; + *output++ = green/3; + *output++ = blue/3; + redCoeff = ADVANCE_COEFF(redCoeff); + greenCoeff = ADVANCE_COEFF(greenCoeff); + blueCoeff = ADVANCE_COEFF(blueCoeff); + } + + /* Do the next super-resolution line and interpolate vertically */ + if (lastLine) { + memcpy(buf+BYTES_PER_RAW_LINE*3, buf, BYTES_PER_RAW_LINE*3); + return SANE_STATUS_GOOD; + } + redCoeff = 3; + greenCoeff = 1; + blueCoeff = 2; + + prev = buf; + for (i=0; i<BYTES_PER_RAW_LINE; i++) { + red = redCoeff * c->nextRawLine[PREV_RED(i)] + + (3-redCoeff) * c->nextRawLine[NEXT_RED(i)]; + green = greenCoeff * c->nextRawLine[PREV_GREEN(i)] + + (3-greenCoeff) * c->nextRawLine[NEXT_GREEN(i)]; + blue = blueCoeff * c->nextRawLine[PREV_BLUE(i)] + + (3-blueCoeff) * c->nextRawLine[NEXT_BLUE(i)]; + *output++ = (red/3 + *prev++) / 2; + *output++ = (green/3 + *prev++) / 2; + *output++ = (blue/3 + *prev++) / 2; + redCoeff = ADVANCE_COEFF(redCoeff); + greenCoeff = ADVANCE_COEFF(greenCoeff); + blueCoeff = ADVANCE_COEFF(blueCoeff); + } + return SANE_STATUS_GOOD; +} + +/*********************************************************************** +//%FUNCTION: attach_one (static function) +//%ARGUMENTS: +// dev -- device to attach +//%RETURNS: +// SANE_STATUS_GOOD +//%DESCRIPTION: +// tries to attach a device found by sanei_config_attach_matching_devices +// *********************************************************************/ +static SANE_Status +attach_one (const char *dev) +{ + DMCAttach (dev, 0); + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_init +//%ARGUMENTS: +// version_code -- pointer to where we stick our version code +// authorize -- authorization function +//%RETURNS: +// A sane status value +//%DESCRIPTION: +// Initializes DMC sane system. +// *********************************************************************/ +SANE_Status +sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) +{ + char dev_name[PATH_MAX]; + size_t len; + FILE *fp; + + authorize = authorize; + + DBG_INIT(); + if (version_code) { + *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0); + } + + fp = sanei_config_open(DMC_CONFIG_FILE); + if (!fp) { + /* default to /dev/camera instead of insisting on config file */ + if (DMCAttach ("/dev/camera", NULL) != SANE_STATUS_GOOD) { + /* OK, try /dev/scanner */ + DMCAttach("/dev/scanner", NULL); + } + return SANE_STATUS_GOOD; + } + + while (sanei_config_read (dev_name, sizeof (dev_name), fp)) { + if (dev_name[0] == '#') { /* ignore line comments */ + continue; + } + len = strlen (dev_name); + + if (!len) continue; /* ignore empty lines */ + + sanei_config_attach_matching_devices(dev_name, attach_one); + } + fclose (fp); + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_exit +//%ARGUMENTS: +// None +//%RETURNS: +// Nothing +//%DESCRIPTION: +// Cleans up all the SANE information +// *********************************************************************/ +void +sane_exit(void) +{ + DMC_Device *dev, *next; + + /* Close all handles */ + while(FirstHandle) { + sane_close(FirstHandle); + } + + /* Free all devices */ + dev = FirstDevice; + while(dev) { + next = dev->next; + free((char *) dev->sane.model); + free(dev); + dev = next; + } +} + +/********************************************************************** +//%FUNCTION: sane_get_devices +//%ARGUMENTS: +// device_list -- set to allocated list of devices +// local_only -- ignored +//%RETURNS: +// A SANE status +//%DESCRIPTION: +// Returns a list of all known DMC devices +// *********************************************************************/ +SANE_Status +sane_get_devices(SANE_Device const ***device_list, SANE_Bool local_only) +{ + static SANE_Device const **devlist = 0; + DMC_Device *dev; + int i = 0; + + local_only = local_only; + + if (devlist) free(devlist); + devlist = malloc((NumDevices+1) * sizeof(devlist[0])); + if (!devlist) return SANE_STATUS_NO_MEM; + + for (dev=FirstDevice; dev; dev = dev->next) { + devlist[i++] = &dev->sane; + } + devlist[i] = NULL; + + if (device_list) *device_list = devlist; + + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_open +//%ARGUMENTS: +// name -- name of device to open +// handle -- set to a handle for the opened device +//%RETURNS: +// A SANE status +//%DESCRIPTION: +// Opens a DMC camera device +// *********************************************************************/ +SANE_Status +sane_open(SANE_String_Const name, SANE_Handle *handle) +{ + SANE_Status status; + DMC_Device *dev; + DMC_Camera *c; + + /* If we're given a device name, search for it */ + if (*name) { + for (dev = FirstDevice; dev; dev = dev->next) { + if (!strcmp(dev->sane.name, name)) { + break; + } + } + if (!dev) { + status = DMCAttach(name, &dev); + if (status != SANE_STATUS_GOOD) return status; + } + } else { + dev = FirstDevice; + } + + if (!dev) return SANE_STATUS_INVAL; + + c = malloc(sizeof(*c)); + if (!c) return SANE_STATUS_NO_MEM; + + memset(c, 0, sizeof(*c)); + + c->fd = -1; + c->hw = dev; + c->readBuffer = NULL; + c->readPtr = NULL; + c->imageMode = IMAGE_MFI; + c->inViewfinderMode = 0; + c->nextRawLineValid = 0; + + DMCInitOptions(c); + + c->next = FirstHandle; + FirstHandle = c; + if (handle) *handle = c; + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_close +//%ARGUMENTS: +// handle -- handle of device to close +//%RETURNS: +// A SANE status +//%DESCRIPTION: +// Closes a DMC camera device +// *********************************************************************/ +void +sane_close(SANE_Handle handle) +{ + DMC_Camera *prev, *c; + prev = NULL; + for (c = FirstHandle; c; c = c->next) { + if (c == handle) break; + prev = c; + } + if (!c) { + DBG(1, "close: invalid handle %p\n", handle); + return; + } + DMCCancel(c); + + if (prev) prev->next = c->next; + else FirstHandle = c->next; + + if (c->readBuffer) { + free(c->readBuffer); + } + free(c); +} + +/********************************************************************** +//%FUNCTION: sane_get_option_descriptor +//%ARGUMENTS: +// handle -- handle of device +// option -- option number to retrieve +//%RETURNS: +// An option descriptor or NULL on error +// *********************************************************************/ +SANE_Option_Descriptor const * +sane_get_option_descriptor(SANE_Handle handle, SANE_Int option) +{ + DMC_Camera *c = ValidateHandle(handle); + if (!c) return NULL; + + if ((unsigned) option >= NUM_OPTIONS) return NULL; + return c->opt + option; +} + +/********************************************************************** +//%FUNCTION: sane_control_option +//%ARGUMENTS: +// handle -- handle of device +// option -- option number to retrieve +// action -- what to do with the option +// val -- value to set option to +// info -- returned info flags +//%RETURNS: +// SANE status +//%DESCRIPTION: +// Sets or queries option values +// *********************************************************************/ +SANE_Status +sane_control_option(SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int *info) +{ + DMC_Camera *c; + SANE_Word cap; + SANE_Status status; + int i; + + if (info) *info = 0; + + c = ValidateHandle(handle); + if (!c) return SANE_STATUS_INVAL; + + if (c->fd >= 0) return SANE_STATUS_DEVICE_BUSY; + + if (option >= NUM_OPTIONS) return SANE_STATUS_INVAL; + + cap = c->opt[option].cap; + if (!SANE_OPTION_IS_ACTIVE(cap)) return SANE_STATUS_INVAL; + + if (action == SANE_ACTION_GET_VALUE) { + switch(c->opt[option].type) { + case SANE_TYPE_INT: + * (SANE_Int *) val = c->val[option].w; + return SANE_STATUS_GOOD; + + case SANE_TYPE_STRING: + strcpy(val, c->val[option].s); + return SANE_STATUS_GOOD; + + default: + DBG(3, "impossible option type!\n"); + return SANE_STATUS_INVAL; + } + } + + if (action == SANE_ACTION_SET_AUTO) { + return SANE_STATUS_UNSUPPORTED; + } + + switch(option) { + case OPT_IMAGE_MODE: + for (i=0; i<NUM_IMAGE_MODES; i++) { + if (!strcmp(val, ValidModes[i])) { + status = DMCSetMode(c, i); + c->val[OPT_IMAGE_MODE].s = (SANE_String) ValidModes[i]; + if (info) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + return SANE_STATUS_GOOD; + } + } + break; + case OPT_WHITE_BALANCE: + for (i=0; i<=WHITE_BALANCE_FLUORESCENT; i++) { + if (!strcmp(val, ValidBalances[i])) { + c->val[OPT_WHITE_BALANCE].s = (SANE_String) ValidBalances[i]; + return SANE_STATUS_GOOD; + } + } + break; + case OPT_ASA: + for (i=1; i<= ASA_100+1; i++) { + if (* ((SANE_Int *) val) == ValidASAs[i]) { + c->val[OPT_ASA].w = ValidASAs[i]; + return SANE_STATUS_GOOD; + } + } + break; + case OPT_SHUTTER_SPEED: + if (* (SANE_Int *) val < c->hw->shutterSpeedRange.min || + * (SANE_Int *) val > c->hw->shutterSpeedRange.max) { + return SANE_STATUS_INVAL; + } + c->val[OPT_SHUTTER_SPEED].w = * (SANE_Int *) val; + /* Do any roundoff */ + c->val[OPT_SHUTTER_SPEED].w = + TICKS_TO_MS(MS_TO_TICKS(c->val[OPT_SHUTTER_SPEED].w)); + if (c->val[OPT_SHUTTER_SPEED].w != * (SANE_Int *) val) { + if (info) *info |= SANE_INFO_INEXACT; + } + + return SANE_STATUS_GOOD; + + default: + /* Should really be INVAL, but just bit-bucket set requests... */ + return SANE_STATUS_GOOD; + } + + return SANE_STATUS_INVAL; +} + +/********************************************************************** +//%FUNCTION: sane_get_parameters +//%ARGUMENTS: +// handle -- handle of device +// params -- set to device parameters +//%RETURNS: +// SANE status +//%DESCRIPTION: +// Returns parameters for current or next image. +// *********************************************************************/ +SANE_Status +sane_get_parameters(SANE_Handle handle, SANE_Parameters *params) +{ + DMC_Camera *c = ValidateHandle(handle); + if (!c) return SANE_STATUS_INVAL; + + if (c->fd < 0) { + int width, height; + memset(&c->params, 0, sizeof(c->params)); + + width = c->val[OPT_BR_X].w - c->val[OPT_TL_X].w; + height = c->val[OPT_BR_Y].w - c->val[OPT_TL_Y].w; + c->params.pixels_per_line = width + 1; + c->params.lines = height+1; + c->params.depth = 8; + c->params.last_frame = SANE_TRUE; + switch(c->imageMode) { + case IMAGE_SUPER_RES: + case IMAGE_MFI: + case IMAGE_THUMB: + c->params.format = SANE_FRAME_RGB; + c->params.bytes_per_line = c->params.pixels_per_line * 3; + break; + case IMAGE_RAW: + case IMAGE_VIEWFINDER: + c->params.format = SANE_FRAME_GRAY; + c->params.bytes_per_line = c->params.pixels_per_line; + break; + } + } + if (params) *params = c->params; + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_start +//%ARGUMENTS: +// handle -- handle of device +//%RETURNS: +// SANE status +//%DESCRIPTION: +// Starts acquisition +// *********************************************************************/ +SANE_Status +sane_start(SANE_Handle handle) +{ + static uint8_t const acquire[] = + { 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + static uint8_t const viewfinder[] = + { 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + static uint8_t const no_viewfinder[] = + { 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + DMC_Camera *c = ValidateHandle(handle); + SANE_Status status; + int i; + + if (!c) return SANE_STATUS_INVAL; + + /* If we're already open, barf -- not sure this is the best status */ + if (c->fd >= 0) return SANE_STATUS_DEVICE_BUSY; + + /* Get rid of old read buffers */ + if (c->readBuffer) { + free(c->readBuffer); + c->readBuffer = NULL; + c->readPtr = NULL; + } + + c->nextRawLineValid = 0; + + /* Refresh parameter list */ + status = sane_get_parameters(c, NULL); + if (status != SANE_STATUS_GOOD) return status; + + status = sanei_scsi_open(c->hw->sane.name, &c->fd, NULL, NULL); + if (status != SANE_STATUS_GOOD) { + c->fd = -1; + DBG(1, "DMC: Open of `%s' failed: %s\n", + c->hw->sane.name, sane_strstatus(status)); + return status; + } + + /* Set ASA and shutter speed if they're no longer current */ + if (c->val[OPT_ASA].w != c->hw->asa) { + status = DMCSetASA(c->fd, c->val[OPT_ASA].w); + if (status != SANE_STATUS_GOOD) { + DMCCancel(c); + return status; + } + c->hw->asa = c->val[OPT_ASA].w; + } + + if ((unsigned int) c->val[OPT_SHUTTER_SPEED].w != c->hw->shutterSpeed) { + status = DMCSetShutterSpeed(c->fd, c->val[OPT_SHUTTER_SPEED].w); + if (status != SANE_STATUS_GOOD) { + DMCCancel(c); + return status; + } + c->hw->shutterSpeed = c->val[OPT_SHUTTER_SPEED].w; + } + + /* Set white balance mode if needed */ + for (i=0; i<=WHITE_BALANCE_FLUORESCENT; i++) { + if (!strcmp(ValidBalances[i], c->val[OPT_WHITE_BALANCE].s)) { + if (i != c->hw->whiteBalance) { + status = DMCSetWhiteBalance(c->fd, i); + if (status != SANE_STATUS_GOOD) { + DMCCancel(c); + return status; + } + c->hw->whiteBalance = i; + } + } + } + + /* Flip into viewfinder mode if needed */ + if (c->imageMode == IMAGE_VIEWFINDER && !c->inViewfinderMode) { + status = sanei_scsi_cmd(c->fd, viewfinder, sizeof(viewfinder), + NULL, NULL); + if (status != SANE_STATUS_GOOD) { + DMCCancel(c); + return status; + } + c->inViewfinderMode = 1; + } + + /* Flip out of viewfinder mode if needed */ + if (c->imageMode != IMAGE_VIEWFINDER && c->inViewfinderMode) { + status = sanei_scsi_cmd(c->fd, no_viewfinder, sizeof(no_viewfinder), + NULL, NULL); + if (status != SANE_STATUS_GOOD) { + DMCCancel(c); + return status; + } + c->inViewfinderMode = 0; + } + + + status = sanei_scsi_cmd(c->fd, acquire, sizeof(acquire), NULL, NULL); + if (status != SANE_STATUS_GOOD) { + DMCCancel(c); + return status; + } + c->bytes_to_read = c->params.bytes_per_line * c->params.lines; + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_read +//%ARGUMENTS: +// handle -- handle of device +// buf -- destination for data +// max_len -- maximum amount of data to store +// len -- set to actual amount of data stored. +//%RETURNS: +// SANE status +//%DESCRIPTION: +// Reads image data from the camera +// *********************************************************************/ +SANE_Status +sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len) +{ + SANE_Status status; + DMC_Camera *c = ValidateHandle(handle); + size_t size; + SANE_Int i; + + if (!c) return SANE_STATUS_INVAL; + + if (c->fd < 0) return SANE_STATUS_INVAL; + + if (c->bytes_to_read == 0) { + if (c->readBuffer) { + free(c->readBuffer); + c->readBuffer = NULL; + c->readPtr = NULL; + } + DMCCancel(c); + return SANE_STATUS_EOF; + } + + if (max_len == 0) { + return SANE_STATUS_GOOD; + } + + if (c->imageMode == IMAGE_SUPER_RES) { + /* We have to read *two* complete rows... */ + max_len = (max_len / (2*c->params.bytes_per_line)) * + (2*c->params.bytes_per_line); + /* If user is trying to read less than two complete lines, fail */ + if (max_len == 0) return SANE_STATUS_INVAL; + if ((unsigned int) max_len > c->bytes_to_read) max_len = c->bytes_to_read; + for (i=0; i<max_len; i += 2*c->params.bytes_per_line) { + c->bytes_to_read -= 2*c->params.bytes_per_line; + status = DMCReadTwoSuperResolutionLines(c, buf+i, + !c->bytes_to_read); + if (status != SANE_STATUS_GOOD) return status; + } + *len = max_len; + return SANE_STATUS_GOOD; + } + + if (c->imageMode == IMAGE_MFI || c->imageMode == IMAGE_RAW) { + /* We have to read complete rows... */ + max_len = (max_len / c->params.bytes_per_line) * c->params.bytes_per_line; + + /* If user is trying to read less than one complete row, fail */ + if (max_len == 0) return SANE_STATUS_INVAL; + if ((unsigned int) max_len > c->bytes_to_read) max_len = c->bytes_to_read; + c->bytes_to_read -= (unsigned int) max_len; + status = DMCRead(c->fd, 0x00, c->imageMode, buf, max_len, &size); + *len = size; + return status; + } + + if ((unsigned int) max_len > c->bytes_to_read) max_len = c->bytes_to_read; + if (c->readPtr) { + *len = max_len; + memcpy(buf, c->readPtr, max_len); + c->readPtr += max_len; + c->bytes_to_read -= max_len; + return SANE_STATUS_GOOD; + } + + /* Fill the read buffer completely */ + c->readBuffer = malloc(c->bytes_to_read); + if (!c->readBuffer) return SANE_STATUS_NO_MEM; + c->readPtr = c->readBuffer; + status = DMCRead(c->fd, 0x00, c->imageMode, (SANE_Byte *) c->readBuffer, + c->bytes_to_read, &size); + *len = size; + if (status != SANE_STATUS_GOOD) return status; + if ((unsigned int) *len != c->bytes_to_read) return SANE_STATUS_IO_ERROR; + + /* Now copy */ + *len = max_len; + memcpy(buf, c->readPtr, max_len); + c->readPtr += max_len; + c->bytes_to_read -= max_len; + return SANE_STATUS_GOOD; +} + +/********************************************************************** +//%FUNCTION: sane_cancel +//%ARGUMENTS: +// handle -- handle of device +//%RETURNS: +// Nothing +//%DESCRIPTION: +// A quick cancellation of the scane +// *********************************************************************/ +void +sane_cancel (SANE_Handle handle) +{ + DMC_Camera *c = ValidateHandle(handle); + if (!c) return; + + DMCCancel(c); +} + +SANE_Status +sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) +{ + handle = handle; + non_blocking = non_blocking; + + return SANE_STATUS_UNSUPPORTED; +} + +SANE_Status +sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) +{ + handle = handle; + fd = fd; + + return SANE_STATUS_UNSUPPORTED; +} |