1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 1998 David F. Skoll
3141cc406Sopenharmony_ci   Heavily based on "hp.c" driver for HP Scanners, by
4141cc406Sopenharmony_ci   David Mosberger-Tang.
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci   This file implements a SANE backend for the Polaroid Digital
43141cc406Sopenharmony_ci   Microscope Camera. */
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci#include "../include/sane/config.h"
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#include <limits.h>
48141cc406Sopenharmony_ci#include <stdlib.h>
49141cc406Sopenharmony_ci#include <stdarg.h>
50141cc406Sopenharmony_ci#include <string.h>
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci#include "../include/_stdint.h"
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci#include "../include/sane/sane.h"
55141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
56141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#define BACKEND_NAME	dmc
59141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci#ifndef PATH_MAX
62141cc406Sopenharmony_ci# define PATH_MAX	1024
63141cc406Sopenharmony_ci#endif
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
66141cc406Sopenharmony_ci#define DMC_CONFIG_FILE "dmc.conf"
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci#include "dmc.h"
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci/* A linked-list of attached devices and handles */
71141cc406Sopenharmony_cistatic DMC_Device *FirstDevice = NULL;
72141cc406Sopenharmony_cistatic DMC_Camera *FirstHandle = NULL;
73141cc406Sopenharmony_cistatic int NumDevices = 0;
74141cc406Sopenharmony_cistatic SANE_Device const **devlist = NULL;
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_cistatic SANE_String_Const ValidModes[] = { "Full frame", "Viewfinder",
77141cc406Sopenharmony_ci					  "Raw", "Thumbnail",
78141cc406Sopenharmony_ci					  "Super-Resolution",
79141cc406Sopenharmony_ci					  NULL };
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_cistatic SANE_String_Const ValidBalances[] = { "Daylight", "Incandescent",
82141cc406Sopenharmony_ci					     "Fluorescent", NULL };
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_cistatic SANE_Word ValidASAs[] = { 3, 25, 50, 100 };
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci/* Convert between 32-us ticks and milliseconds */
87141cc406Sopenharmony_ci#define MS_TO_TICKS(x) (((x) * 1000 + 16) / 32)
88141cc406Sopenharmony_ci#define TICKS_TO_MS(x) (((x) * 32) / 1000)
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci/* Macros for stepping along the raw lines for super-resolution mode
91141cc406Sopenharmony_ci   They are very ugly because they handle boundary conditions at
92141cc406Sopenharmony_ci   the edges of the image.  Yuck... */
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_ci#define PREV_RED(i) (((i)/3)*3)
95141cc406Sopenharmony_ci#define NEXT_RED(i) (((i) >= BYTES_PER_RAW_LINE-3) ? BYTES_PER_RAW_LINE-3 : \
96141cc406Sopenharmony_ci		     PREV_RED(i)+3)
97141cc406Sopenharmony_ci#define PREV_GREEN(i) ((i)<1 ? 1 : PREV_RED((i)-1)+1)
98141cc406Sopenharmony_ci#define NEXT_GREEN(i) ((i)<1 ? 1 : ((i) >= BYTES_PER_RAW_LINE-2) ? \
99141cc406Sopenharmony_ci		       BYTES_PER_RAW_LINE-2 : PREV_GREEN(i)+3)
100141cc406Sopenharmony_ci#define PREV_BLUE(i) ((i)<2 ? 2 : PREV_RED((i)-2)+2)
101141cc406Sopenharmony_ci#define NEXT_BLUE(i) ((i)<2 ? 2 : ((i) >= BYTES_PER_RAW_LINE-1) ? \
102141cc406Sopenharmony_ci		      BYTES_PER_RAW_LINE-1 : PREV_BLUE(i)+3)
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci#define ADVANCE_COEFF(i) (((i)==1) ? 3 : (i)-1);
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci/**********************************************************************
107141cc406Sopenharmony_ci//%FUNCTION: DMCRead
108141cc406Sopenharmony_ci//%ARGUMENTS:
109141cc406Sopenharmony_ci// fd -- file descriptor
110141cc406Sopenharmony_ci// typecode -- data type code
111141cc406Sopenharmony_ci// qualifier -- data type qualifier
112141cc406Sopenharmony_ci// maxlen -- transfer length
113141cc406Sopenharmony_ci// buf -- buffer to store data in
114141cc406Sopenharmony_ci// len -- set to actual length of data
115141cc406Sopenharmony_ci//%RETURNS:
116141cc406Sopenharmony_ci// A SANE status code
117141cc406Sopenharmony_ci//%DESCRIPTION:
118141cc406Sopenharmony_ci// Reads the particular data selected by typecode and qualifier
119141cc406Sopenharmony_ci// *********************************************************************/
120141cc406Sopenharmony_cistatic SANE_Status
121141cc406Sopenharmony_ciDMCRead(int fd, unsigned int typecode, unsigned int qualifier,
122141cc406Sopenharmony_ci	SANE_Byte *buf, size_t maxlen, size_t *len)
123141cc406Sopenharmony_ci{
124141cc406Sopenharmony_ci    uint8_t readCmd[10];
125141cc406Sopenharmony_ci    SANE_Status status;
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci    readCmd[0] = 0x28;
128141cc406Sopenharmony_ci    readCmd[1] = 0;
129141cc406Sopenharmony_ci    readCmd[2] = typecode;
130141cc406Sopenharmony_ci    readCmd[3] = 0;
131141cc406Sopenharmony_ci    readCmd[4] = (qualifier >> 8) & 0xFF;
132141cc406Sopenharmony_ci    readCmd[5] = qualifier & 0xFF;
133141cc406Sopenharmony_ci    readCmd[6] = (maxlen >> 16) & 0xFF;
134141cc406Sopenharmony_ci    readCmd[7] = (maxlen >> 8) & 0xFF;
135141cc406Sopenharmony_ci    readCmd[8] = maxlen & 0xFF;
136141cc406Sopenharmony_ci    readCmd[9] = 0;
137141cc406Sopenharmony_ci    DBG(3, "DMCRead: typecode=%x, qualifier=%x, maxlen=%lu\n",
138141cc406Sopenharmony_ci	typecode, qualifier, (u_long) maxlen);
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_ci    *len = maxlen;
141141cc406Sopenharmony_ci    status = sanei_scsi_cmd(fd, readCmd, sizeof(readCmd), buf, len);
142141cc406Sopenharmony_ci    DBG(3, "DMCRead: Read %lu bytes\n", (u_long) *len);
143141cc406Sopenharmony_ci    return status;
144141cc406Sopenharmony_ci}
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_ci/**********************************************************************
147141cc406Sopenharmony_ci//%FUNCTION: DMCWrite
148141cc406Sopenharmony_ci//%ARGUMENTS:
149141cc406Sopenharmony_ci// fd -- file descriptor
150141cc406Sopenharmony_ci// typecode -- data type code
151141cc406Sopenharmony_ci// qualifier -- data type qualifier
152141cc406Sopenharmony_ci// maxlen -- transfer length
153141cc406Sopenharmony_ci// buf -- buffer to store data in
154141cc406Sopenharmony_ci//%RETURNS:
155141cc406Sopenharmony_ci// A SANE status code
156141cc406Sopenharmony_ci//%DESCRIPTION:
157141cc406Sopenharmony_ci// Writes the particular data selected by typecode and qualifier
158141cc406Sopenharmony_ci// *********************************************************************/
159141cc406Sopenharmony_cistatic SANE_Status
160141cc406Sopenharmony_ciDMCWrite(int fd, unsigned int typecode, unsigned int qualifier,
161141cc406Sopenharmony_ci	SANE_Byte *buf, size_t maxlen)
162141cc406Sopenharmony_ci{
163141cc406Sopenharmony_ci    uint8_t *writeCmd;
164141cc406Sopenharmony_ci    SANE_Status status;
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci    writeCmd = malloc(maxlen + 10);
167141cc406Sopenharmony_ci    if (!writeCmd) return SANE_STATUS_NO_MEM;
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci    writeCmd[0] = 0x2A;
170141cc406Sopenharmony_ci    writeCmd[1] = 0;
171141cc406Sopenharmony_ci    writeCmd[2] = typecode;
172141cc406Sopenharmony_ci    writeCmd[3] = 0;
173141cc406Sopenharmony_ci    writeCmd[4] = (qualifier >> 8) & 0xFF;
174141cc406Sopenharmony_ci    writeCmd[5] = qualifier & 0xFF;
175141cc406Sopenharmony_ci    writeCmd[6] = (maxlen >> 16) & 0xFF;
176141cc406Sopenharmony_ci    writeCmd[7] = (maxlen >> 8) & 0xFF;
177141cc406Sopenharmony_ci    writeCmd[8] = maxlen & 0xFF;
178141cc406Sopenharmony_ci    writeCmd[9] = 0;
179141cc406Sopenharmony_ci    memcpy(writeCmd+10, buf, maxlen);
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci    DBG(3, "DMCWrite: typecode=%x, qualifier=%x, maxlen=%lu\n",
182141cc406Sopenharmony_ci	typecode, qualifier, (u_long) maxlen);
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci    status = sanei_scsi_cmd(fd, writeCmd, 10+maxlen, NULL, NULL);
185141cc406Sopenharmony_ci    free(writeCmd);
186141cc406Sopenharmony_ci    return status;
187141cc406Sopenharmony_ci}
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_ci/**********************************************************************
190141cc406Sopenharmony_ci//%FUNCTION: DMCAttach
191141cc406Sopenharmony_ci//%ARGUMENTS:
192141cc406Sopenharmony_ci// devname -- name of device file to open
193141cc406Sopenharmony_ci// devp -- a DMC_Device structure which we fill in if it's not NULL.
194141cc406Sopenharmony_ci//%RETURNS:
195141cc406Sopenharmony_ci// SANE_STATUS_GOOD -- We have a Polaroid DMC attached and all looks good.
196141cc406Sopenharmony_ci// SANE_STATUS_INVAL -- There's a problem.
197141cc406Sopenharmony_ci//%DESCRIPTION:
198141cc406Sopenharmony_ci// Verifies that a Polaroid DMC is attached.  Sets up device options in
199141cc406Sopenharmony_ci// DMC_Device structure.
200141cc406Sopenharmony_ci// *********************************************************************/
201141cc406Sopenharmony_ci#define INQ_LEN 255
202141cc406Sopenharmony_cistatic SANE_Status
203141cc406Sopenharmony_ciDMCAttach(char const *devname, DMC_Device **devp)
204141cc406Sopenharmony_ci{
205141cc406Sopenharmony_ci    DMC_Device *dev;
206141cc406Sopenharmony_ci    SANE_Status status;
207141cc406Sopenharmony_ci    int fd;
208141cc406Sopenharmony_ci    size_t size;
209141cc406Sopenharmony_ci    char result[INQ_LEN];
210141cc406Sopenharmony_ci
211141cc406Sopenharmony_ci    uint8_t exposureCalculationResults[16];
212141cc406Sopenharmony_ci    uint8_t userInterfaceSettings[16];
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci    static uint8_t const inquiry[] =
215141cc406Sopenharmony_ci    { 0x12, 0x00, 0x00, 0x00, INQ_LEN, 0x00 };
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci    static uint8_t const test_unit_ready[] =
218141cc406Sopenharmony_ci    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci    static uint8_t const no_viewfinder[] =
221141cc406Sopenharmony_ci    { 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ci    /* If we're already attached, do nothing */
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci    for (dev = FirstDevice; dev; dev = dev->next) {
226141cc406Sopenharmony_ci	if (!strcmp(dev->sane.name, devname)) {
227141cc406Sopenharmony_ci	    if (devp) *devp = dev;
228141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
229141cc406Sopenharmony_ci	}
230141cc406Sopenharmony_ci    }
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci    DBG(3, "DMCAttach: opening `%s'\n", devname);
233141cc406Sopenharmony_ci    status = sanei_scsi_open(devname, &fd, 0, 0);
234141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
235141cc406Sopenharmony_ci	DBG(1, "DMCAttach: open failed (%s)\n", sane_strstatus(status));
236141cc406Sopenharmony_ci	return status;
237141cc406Sopenharmony_ci    }
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ci    DBG(3, "DMCAttach: sending INQUIRY\n");
240141cc406Sopenharmony_ci    size = sizeof(result);
241141cc406Sopenharmony_ci    status = sanei_scsi_cmd(fd, inquiry, sizeof(inquiry), result, &size);
242141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD || size < 32) {
243141cc406Sopenharmony_ci	if (status == SANE_STATUS_GOOD) status = SANE_STATUS_INVAL;
244141cc406Sopenharmony_ci	DBG(1, "DMCAttach: inquiry failed (%s)\n", sane_strstatus(status));
245141cc406Sopenharmony_ci	sanei_scsi_close(fd);
246141cc406Sopenharmony_ci	return status;
247141cc406Sopenharmony_ci    }
248141cc406Sopenharmony_ci
249141cc406Sopenharmony_ci    /* Verify that we have a Polaroid DMC */
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci    if (result[0] != 6 ||
252141cc406Sopenharmony_ci	strncmp(result+8, "POLAROID", 8) ||
253141cc406Sopenharmony_ci	strncmp(result+16, "DMC     ", 8)) {
254141cc406Sopenharmony_ci	sanei_scsi_close(fd);
255141cc406Sopenharmony_ci	DBG(1, "DMCAttach: Device does not look like a Polaroid DMC\n");
256141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
257141cc406Sopenharmony_ci    }
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci    DBG(3, "DMCAttach: sending TEST_UNIT_READY\n");
260141cc406Sopenharmony_ci    status = sanei_scsi_cmd(fd, test_unit_ready, sizeof(test_unit_ready),
261141cc406Sopenharmony_ci			    NULL, NULL);
262141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
263141cc406Sopenharmony_ci	DBG(1, "DMCAttach: test unit ready failed (%s)\n",
264141cc406Sopenharmony_ci	    sane_strstatus(status));
265141cc406Sopenharmony_ci	sanei_scsi_close(fd);
266141cc406Sopenharmony_ci	return status;
267141cc406Sopenharmony_ci    }
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci    /* Read current ASA and shutter speed settings */
270141cc406Sopenharmony_ci    status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults,
271141cc406Sopenharmony_ci		     sizeof(exposureCalculationResults), &size);
272141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD ||
273141cc406Sopenharmony_ci	size < sizeof(exposureCalculationResults)) {
274141cc406Sopenharmony_ci	DBG(1, "DMCAttach: Couldn't read exposure calculation results (%s)\n",
275141cc406Sopenharmony_ci	    sane_strstatus(status));
276141cc406Sopenharmony_ci	sanei_scsi_close(fd);
277141cc406Sopenharmony_ci	if (status == SANE_STATUS_GOOD) status = SANE_STATUS_IO_ERROR;
278141cc406Sopenharmony_ci	return status;
279141cc406Sopenharmony_ci    }
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci    /* Read current white balance settings */
282141cc406Sopenharmony_ci    status = DMCRead(fd, 0x82, 0x0, userInterfaceSettings,
283141cc406Sopenharmony_ci		     sizeof(userInterfaceSettings), &size);
284141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD ||
285141cc406Sopenharmony_ci	size < sizeof(userInterfaceSettings)) {
286141cc406Sopenharmony_ci	DBG(1, "DMCAttach: Couldn't read user interface settings (%s)\n",
287141cc406Sopenharmony_ci	    sane_strstatus(status));
288141cc406Sopenharmony_ci	sanei_scsi_close(fd);
289141cc406Sopenharmony_ci	if (status == SANE_STATUS_GOOD) status = SANE_STATUS_IO_ERROR;
290141cc406Sopenharmony_ci	return status;
291141cc406Sopenharmony_ci    }
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci    /* Shut off viewfinder mode */
294141cc406Sopenharmony_ci    status = sanei_scsi_cmd(fd, no_viewfinder, sizeof(no_viewfinder),
295141cc406Sopenharmony_ci			    NULL, NULL);
296141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
297141cc406Sopenharmony_ci	sanei_scsi_close(fd);
298141cc406Sopenharmony_ci	return status;
299141cc406Sopenharmony_ci    }
300141cc406Sopenharmony_ci    sanei_scsi_close(fd);
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci    DBG(3, "DMCAttach: Looks like we have a Polaroid DMC\n");
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci    dev = malloc(sizeof(*dev));
305141cc406Sopenharmony_ci    if (!dev) return SANE_STATUS_NO_MEM;
306141cc406Sopenharmony_ci    memset(dev, 0, sizeof(*dev));
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci    dev->sane.name = strdup(devname);
309141cc406Sopenharmony_ci    dev->sane.vendor = "Polaroid";
310141cc406Sopenharmony_ci    dev->sane.model = "DMC";
311141cc406Sopenharmony_ci    dev->sane.type = "still camera";
312141cc406Sopenharmony_ci    dev->next = FirstDevice;
313141cc406Sopenharmony_ci    dev->whiteBalance = userInterfaceSettings[5];
314141cc406Sopenharmony_ci    if (dev->whiteBalance > WHITE_BALANCE_FLUORESCENT) {
315141cc406Sopenharmony_ci	dev->whiteBalance = WHITE_BALANCE_FLUORESCENT;
316141cc406Sopenharmony_ci    }
317141cc406Sopenharmony_ci
318141cc406Sopenharmony_ci    /* Bright Eyes documentation gives these as shutter speed ranges (ms) */
319141cc406Sopenharmony_ci    /* dev->shutterSpeedRange.min = 8; */
320141cc406Sopenharmony_ci    /* dev->shutterSpeedRange.max = 320; */
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci    /* User's manual says these are shutter speed ranges (ms) */
323141cc406Sopenharmony_ci    dev->shutterSpeedRange.min = 8;
324141cc406Sopenharmony_ci    dev->shutterSpeedRange.max = 1000;
325141cc406Sopenharmony_ci    dev->shutterSpeedRange.quant = 2;
326141cc406Sopenharmony_ci    dev->shutterSpeed =
327141cc406Sopenharmony_ci	(exposureCalculationResults[10] << 8) +
328141cc406Sopenharmony_ci	exposureCalculationResults[11];
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci    /* Convert from ticks to ms */
331141cc406Sopenharmony_ci    dev->shutterSpeed = TICKS_TO_MS(dev->shutterSpeed);
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ci    dev->asa = exposureCalculationResults[13];
334141cc406Sopenharmony_ci    if (dev->asa > ASA_100) dev->asa = ASA_100;
335141cc406Sopenharmony_ci    dev->asa = ValidASAs[dev->asa + 1];
336141cc406Sopenharmony_ci    FirstDevice = dev;
337141cc406Sopenharmony_ci    NumDevices++;
338141cc406Sopenharmony_ci    if (devp) *devp = dev;
339141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
340141cc406Sopenharmony_ci}
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci/**********************************************************************
343141cc406Sopenharmony_ci//%FUNCTION: ValidateHandle
344141cc406Sopenharmony_ci//%ARGUMENTS:
345141cc406Sopenharmony_ci// handle -- a handle for an opened camera
346141cc406Sopenharmony_ci//%RETURNS:
347141cc406Sopenharmony_ci// A validated pointer to the camera or NULL if handle is not valid.
348141cc406Sopenharmony_ci// *********************************************************************/
349141cc406Sopenharmony_cistatic DMC_Camera *
350141cc406Sopenharmony_ciValidateHandle(SANE_Handle handle)
351141cc406Sopenharmony_ci{
352141cc406Sopenharmony_ci    DMC_Camera *c;
353141cc406Sopenharmony_ci    for (c = FirstHandle; c; c = c->next) {
354141cc406Sopenharmony_ci	if (c == handle) return c;
355141cc406Sopenharmony_ci    }
356141cc406Sopenharmony_ci    DBG(1, "ValidateHandle: invalid handle %p\n", handle);
357141cc406Sopenharmony_ci    return NULL;
358141cc406Sopenharmony_ci}
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_ci/**********************************************************************
361141cc406Sopenharmony_ci//%FUNCTION: DMCInitOptions
362141cc406Sopenharmony_ci//%ARGUMENTS:
363141cc406Sopenharmony_ci// c -- a DMC camera device
364141cc406Sopenharmony_ci//%RETURNS:
365141cc406Sopenharmony_ci// SANE_STATUS_GOOD -- OK
366141cc406Sopenharmony_ci// SANE_STATUS_INVAL -- There's a problem.
367141cc406Sopenharmony_ci//%DESCRIPTION:
368141cc406Sopenharmony_ci// Initializes the options in the DMC_Camera structure
369141cc406Sopenharmony_ci// *********************************************************************/
370141cc406Sopenharmony_cistatic SANE_Status
371141cc406Sopenharmony_ciDMCInitOptions(DMC_Camera *c)
372141cc406Sopenharmony_ci{
373141cc406Sopenharmony_ci    int i;
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_ci    /* Image is initially 801x600 */
376141cc406Sopenharmony_ci    c->tl_x_range.min = 0;
377141cc406Sopenharmony_ci    c->tl_x_range.max = c->tl_x_range.min;
378141cc406Sopenharmony_ci    c->tl_x_range.quant = 1;
379141cc406Sopenharmony_ci    c->tl_y_range.min = 0;
380141cc406Sopenharmony_ci    c->tl_y_range.max = c->tl_y_range.min;
381141cc406Sopenharmony_ci    c->tl_y_range.quant = 1;
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci    c->br_x_range.min = 800;
384141cc406Sopenharmony_ci    c->br_x_range.max = c->br_x_range.min;
385141cc406Sopenharmony_ci    c->br_x_range.quant = 1;
386141cc406Sopenharmony_ci    c->br_y_range.min = 599;
387141cc406Sopenharmony_ci    c->br_y_range.max = c->br_y_range.min;
388141cc406Sopenharmony_ci    c->br_y_range.quant = 1;
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci    memset(c->opt, 0, sizeof(c->opt));
391141cc406Sopenharmony_ci    memset(c->val, 0, sizeof(c->val));
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci    for (i=0; i<NUM_OPTIONS; i++) {
394141cc406Sopenharmony_ci	c->opt[i].type = SANE_TYPE_INT;
395141cc406Sopenharmony_ci	c->opt[i].size = sizeof(SANE_Word);
396141cc406Sopenharmony_ci	c->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
397141cc406Sopenharmony_ci	c->opt[i].unit = SANE_UNIT_NONE;
398141cc406Sopenharmony_ci    }
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci    c->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
401141cc406Sopenharmony_ci    c->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
402141cc406Sopenharmony_ci    c->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
403141cc406Sopenharmony_ci    c->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
404141cc406Sopenharmony_ci    c->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
405141cc406Sopenharmony_ci    c->opt[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
406141cc406Sopenharmony_ci    c->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci    c->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
409141cc406Sopenharmony_ci    c->opt[OPT_GEOMETRY_GROUP].name = "";
410141cc406Sopenharmony_ci    c->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
411141cc406Sopenharmony_ci    c->opt[OPT_GEOMETRY_GROUP].desc = "";
412141cc406Sopenharmony_ci    c->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
413141cc406Sopenharmony_ci    c->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci    /* top-left x */
416141cc406Sopenharmony_ci    c->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
417141cc406Sopenharmony_ci    c->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
418141cc406Sopenharmony_ci    c->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
419141cc406Sopenharmony_ci    c->opt[OPT_TL_X].type = SANE_TYPE_INT;
420141cc406Sopenharmony_ci    c->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL;
421141cc406Sopenharmony_ci    c->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
422141cc406Sopenharmony_ci    c->opt[OPT_TL_X].constraint.range = &c->tl_x_range;
423141cc406Sopenharmony_ci    c->val[OPT_TL_X].w = c->tl_x_range.min;
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci    /* top-left y */
426141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
427141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
428141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
429141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].type = SANE_TYPE_INT;
430141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL;
431141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
432141cc406Sopenharmony_ci    c->opt[OPT_TL_Y].constraint.range = &c->tl_y_range;
433141cc406Sopenharmony_ci    c->val[OPT_TL_Y].w = c->tl_y_range.min;
434141cc406Sopenharmony_ci
435141cc406Sopenharmony_ci    /* bottom-right x */
436141cc406Sopenharmony_ci    c->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
437141cc406Sopenharmony_ci    c->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
438141cc406Sopenharmony_ci    c->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
439141cc406Sopenharmony_ci    c->opt[OPT_BR_X].type = SANE_TYPE_INT;
440141cc406Sopenharmony_ci    c->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL;
441141cc406Sopenharmony_ci    c->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
442141cc406Sopenharmony_ci    c->opt[OPT_BR_X].constraint.range = &c->br_x_range;
443141cc406Sopenharmony_ci    c->val[OPT_BR_X].w = c->br_x_range.min;
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci    /* bottom-right y */
446141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
447141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
448141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
449141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].type = SANE_TYPE_INT;
450141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL;
451141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
452141cc406Sopenharmony_ci    c->opt[OPT_BR_Y].constraint.range = &c->br_y_range;
453141cc406Sopenharmony_ci    c->val[OPT_BR_Y].w = c->br_y_range.min;
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci    c->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
456141cc406Sopenharmony_ci    c->opt[OPT_MODE_GROUP].name = "";
457141cc406Sopenharmony_ci    c->opt[OPT_MODE_GROUP].title = "Imaging Mode";
458141cc406Sopenharmony_ci    c->opt[OPT_MODE_GROUP].desc = "";
459141cc406Sopenharmony_ci    c->opt[OPT_MODE_GROUP].cap = SANE_CAP_ADVANCED;
460141cc406Sopenharmony_ci    c->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci    c->opt[OPT_IMAGE_MODE].name = "imagemode";
463141cc406Sopenharmony_ci    c->opt[OPT_IMAGE_MODE].title = "Image Mode";
464141cc406Sopenharmony_ci    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";
465141cc406Sopenharmony_ci    c->opt[OPT_IMAGE_MODE].type = SANE_TYPE_STRING;
466141cc406Sopenharmony_ci    c->opt[OPT_IMAGE_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
467141cc406Sopenharmony_ci    c->opt[OPT_IMAGE_MODE].constraint.string_list = ValidModes;
468141cc406Sopenharmony_ci    c->opt[OPT_IMAGE_MODE].size = 16;
469141cc406Sopenharmony_ci    c->val[OPT_IMAGE_MODE].s = "Full frame";
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci    c->opt[OPT_ASA].name = "asa";
472141cc406Sopenharmony_ci    c->opt[OPT_ASA].title = "ASA Setting";
473141cc406Sopenharmony_ci    c->opt[OPT_ASA].desc = "Equivalent ASA setting";
474141cc406Sopenharmony_ci    c->opt[OPT_ASA].constraint_type = SANE_CONSTRAINT_WORD_LIST;
475141cc406Sopenharmony_ci    c->opt[OPT_ASA].constraint.word_list = ValidASAs;
476141cc406Sopenharmony_ci    c->val[OPT_ASA].w = c->hw->asa;
477141cc406Sopenharmony_ci
478141cc406Sopenharmony_ci    c->opt[OPT_SHUTTER_SPEED].name = "shutterspeed";
479141cc406Sopenharmony_ci    c->opt[OPT_SHUTTER_SPEED].title = "Shutter Speed (ms)";
480141cc406Sopenharmony_ci    c->opt[OPT_SHUTTER_SPEED].desc = "Shutter Speed in milliseconds";
481141cc406Sopenharmony_ci    c->opt[OPT_SHUTTER_SPEED].constraint_type = SANE_CONSTRAINT_RANGE;
482141cc406Sopenharmony_ci    c->opt[OPT_SHUTTER_SPEED].constraint.range = &c->hw->shutterSpeedRange;
483141cc406Sopenharmony_ci    c->val[OPT_SHUTTER_SPEED].w = c->hw->shutterSpeed;
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].name = "whitebalance";
486141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].title = "White Balance";
487141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].desc = "Selects white balance";
488141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].type = SANE_TYPE_STRING;
489141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
490141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].constraint.string_list = ValidBalances;
491141cc406Sopenharmony_ci    c->opt[OPT_WHITE_BALANCE].size = 16;
492141cc406Sopenharmony_ci    c->val[OPT_WHITE_BALANCE].s = (SANE_String) ValidBalances[c->hw->whiteBalance];
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
495141cc406Sopenharmony_ci}
496141cc406Sopenharmony_ci
497141cc406Sopenharmony_ci/**********************************************************************
498141cc406Sopenharmony_ci//%FUNCTION: DMCSetMode
499141cc406Sopenharmony_ci//%ARGUMENTS:
500141cc406Sopenharmony_ci// c -- a DMC camera device
501141cc406Sopenharmony_ci// mode -- Imaging mode
502141cc406Sopenharmony_ci//%RETURNS:
503141cc406Sopenharmony_ci// SANE_STATUS_GOOD -- OK
504141cc406Sopenharmony_ci// SANE_STATUS_INVAL -- There's a problem.
505141cc406Sopenharmony_ci//%DESCRIPTION:
506141cc406Sopenharmony_ci// Sets the camera's imaging mode.
507141cc406Sopenharmony_ci// *********************************************************************/
508141cc406Sopenharmony_cistatic SANE_Status
509141cc406Sopenharmony_ciDMCSetMode(DMC_Camera *c, int mode)
510141cc406Sopenharmony_ci{
511141cc406Sopenharmony_ci  switch (mode)
512141cc406Sopenharmony_ci    {
513141cc406Sopenharmony_ci    case IMAGE_MFI:
514141cc406Sopenharmony_ci      c->tl_x_range.min = 0;
515141cc406Sopenharmony_ci      c->tl_x_range.max = 800;
516141cc406Sopenharmony_ci      c->tl_y_range.min = 0;
517141cc406Sopenharmony_ci      c->tl_y_range.max = 599;
518141cc406Sopenharmony_ci      c->br_x_range.min = c->tl_x_range.min;
519141cc406Sopenharmony_ci      c->br_x_range.max = c->tl_x_range.max;
520141cc406Sopenharmony_ci      c->br_y_range.min = c->tl_y_range.min;
521141cc406Sopenharmony_ci      c->br_y_range.max = c->tl_y_range.max;
522141cc406Sopenharmony_ci      break;
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_ci    case IMAGE_VIEWFINDER:
525141cc406Sopenharmony_ci      c->tl_x_range.min = 0;
526141cc406Sopenharmony_ci      c->tl_x_range.max = 269;
527141cc406Sopenharmony_ci      c->tl_y_range.min = 0;
528141cc406Sopenharmony_ci      c->tl_y_range.max = 200;
529141cc406Sopenharmony_ci      c->br_x_range.min = c->tl_x_range.min;
530141cc406Sopenharmony_ci      c->br_x_range.max = c->tl_x_range.max;
531141cc406Sopenharmony_ci      c->br_y_range.min = c->tl_y_range.min;
532141cc406Sopenharmony_ci      c->br_y_range.max = c->tl_y_range.max;
533141cc406Sopenharmony_ci      break;
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci    case IMAGE_RAW:
536141cc406Sopenharmony_ci      c->tl_x_range.min = 0;
537141cc406Sopenharmony_ci      c->tl_x_range.max = 1598;
538141cc406Sopenharmony_ci      c->tl_y_range.min = 0;
539141cc406Sopenharmony_ci      c->tl_y_range.max = 599;
540141cc406Sopenharmony_ci      c->br_x_range.min = c->tl_x_range.min;
541141cc406Sopenharmony_ci      c->br_x_range.max = c->tl_x_range.max;
542141cc406Sopenharmony_ci      c->br_y_range.min = c->tl_y_range.min;
543141cc406Sopenharmony_ci      c->br_y_range.max = c->tl_y_range.max;
544141cc406Sopenharmony_ci      break;
545141cc406Sopenharmony_ci
546141cc406Sopenharmony_ci    case IMAGE_THUMB:
547141cc406Sopenharmony_ci      c->tl_x_range.min = 0;
548141cc406Sopenharmony_ci      c->tl_x_range.max = 79;
549141cc406Sopenharmony_ci      c->tl_y_range.min = 0;
550141cc406Sopenharmony_ci      c->tl_y_range.max = 59;
551141cc406Sopenharmony_ci      c->br_x_range.min = c->tl_x_range.min;
552141cc406Sopenharmony_ci      c->br_x_range.max = c->tl_x_range.max;
553141cc406Sopenharmony_ci      c->br_y_range.min = c->tl_y_range.min;
554141cc406Sopenharmony_ci      c->br_y_range.max = c->tl_y_range.max;
555141cc406Sopenharmony_ci      break;
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci    case IMAGE_SUPER_RES:
558141cc406Sopenharmony_ci      c->tl_x_range.min = 0;
559141cc406Sopenharmony_ci      c->tl_x_range.max = 1598;
560141cc406Sopenharmony_ci      c->tl_y_range.min = 0;
561141cc406Sopenharmony_ci      c->tl_y_range.max = 1199;
562141cc406Sopenharmony_ci      c->br_x_range.min = c->tl_x_range.min;
563141cc406Sopenharmony_ci      c->br_x_range.max = c->tl_x_range.max;
564141cc406Sopenharmony_ci      c->br_y_range.min = c->tl_y_range.min;
565141cc406Sopenharmony_ci      c->br_y_range.max = c->tl_y_range.max;
566141cc406Sopenharmony_ci      break;
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci    default:
569141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
570141cc406Sopenharmony_ci    }
571141cc406Sopenharmony_ci    c->imageMode = mode;
572141cc406Sopenharmony_ci    c->val[OPT_TL_X].w = c->tl_x_range.min;
573141cc406Sopenharmony_ci    c->val[OPT_TL_Y].w = c->tl_y_range.min;
574141cc406Sopenharmony_ci    c->val[OPT_BR_X].w = c->br_x_range.min;
575141cc406Sopenharmony_ci    c->val[OPT_BR_Y].w = c->br_y_range.min;
576141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
577141cc406Sopenharmony_ci}
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci/**********************************************************************
580141cc406Sopenharmony_ci//%FUNCTION: DMCCancel
581141cc406Sopenharmony_ci//%ARGUMENTS:
582141cc406Sopenharmony_ci// c -- a DMC camera device
583141cc406Sopenharmony_ci//%RETURNS:
584141cc406Sopenharmony_ci// SANE_STATUS_CANCELLED
585141cc406Sopenharmony_ci//%DESCRIPTION:
586141cc406Sopenharmony_ci// Cancels DMC image acquisition
587141cc406Sopenharmony_ci// *********************************************************************/
588141cc406Sopenharmony_cistatic SANE_Status
589141cc406Sopenharmony_ciDMCCancel(DMC_Camera *c)
590141cc406Sopenharmony_ci{
591141cc406Sopenharmony_ci    if (c->fd >= 0) {
592141cc406Sopenharmony_ci	sanei_scsi_close(c->fd);
593141cc406Sopenharmony_ci	c->fd = -1;
594141cc406Sopenharmony_ci    }
595141cc406Sopenharmony_ci    return SANE_STATUS_CANCELLED;
596141cc406Sopenharmony_ci}
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci/**********************************************************************
599141cc406Sopenharmony_ci//%FUNCTION: DMCSetASA
600141cc406Sopenharmony_ci//%ARGUMENTS:
601141cc406Sopenharmony_ci// fd -- SCSI file descriptor
602141cc406Sopenharmony_ci// asa -- the ASA to set
603141cc406Sopenharmony_ci//%RETURNS:
604141cc406Sopenharmony_ci// A sane status value
605141cc406Sopenharmony_ci//%DESCRIPTION:
606141cc406Sopenharmony_ci// Sets the equivalent ASA setting of the camera.
607141cc406Sopenharmony_ci// *********************************************************************/
608141cc406Sopenharmony_cistatic SANE_Status
609141cc406Sopenharmony_ciDMCSetASA(int fd, unsigned int asa)
610141cc406Sopenharmony_ci{
611141cc406Sopenharmony_ci    uint8_t exposureCalculationResults[16];
612141cc406Sopenharmony_ci    SANE_Status status;
613141cc406Sopenharmony_ci    size_t len;
614141cc406Sopenharmony_ci    int i;
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_ci    DBG(3, "DMCSetAsa: %d\n", asa);
617141cc406Sopenharmony_ci    for (i=1; i<=ASA_100+1; i++) {
618141cc406Sopenharmony_ci	if (asa == (unsigned int) ValidASAs[i]) break;
619141cc406Sopenharmony_ci    }
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci    if (i > ASA_100+1) return SANE_STATUS_INVAL;
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci    status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults,
624141cc406Sopenharmony_ci		     sizeof(exposureCalculationResults), &len);
625141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
626141cc406Sopenharmony_ci    if (len < sizeof(exposureCalculationResults)) return SANE_STATUS_IO_ERROR;
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci    exposureCalculationResults[13] = (uint8_t) i - 1;
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci    return DMCWrite(fd, 0x87, 0x4, exposureCalculationResults,
631141cc406Sopenharmony_ci		    sizeof(exposureCalculationResults));
632141cc406Sopenharmony_ci}
633141cc406Sopenharmony_ci
634141cc406Sopenharmony_ci/**********************************************************************
635141cc406Sopenharmony_ci//%FUNCTION: DMCSetWhiteBalance
636141cc406Sopenharmony_ci//%ARGUMENTS:
637141cc406Sopenharmony_ci// fd -- SCSI file descriptor
638141cc406Sopenharmony_ci// mode -- white balance mode
639141cc406Sopenharmony_ci//%RETURNS:
640141cc406Sopenharmony_ci// A sane status value
641141cc406Sopenharmony_ci//%DESCRIPTION:
642141cc406Sopenharmony_ci// Sets the equivalent ASA setting of the camera.
643141cc406Sopenharmony_ci// *********************************************************************/
644141cc406Sopenharmony_cistatic SANE_Status
645141cc406Sopenharmony_ciDMCSetWhiteBalance(int fd, int mode)
646141cc406Sopenharmony_ci{
647141cc406Sopenharmony_ci    uint8_t userInterfaceSettings[16];
648141cc406Sopenharmony_ci    SANE_Status status;
649141cc406Sopenharmony_ci    size_t len;
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ci    DBG(3, "DMCSetWhiteBalance: %d\n", mode);
652141cc406Sopenharmony_ci    status = DMCRead(fd, 0x82, 0x0, userInterfaceSettings,
653141cc406Sopenharmony_ci		     sizeof(userInterfaceSettings), &len);
654141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
655141cc406Sopenharmony_ci    if (len < sizeof(userInterfaceSettings)) return SANE_STATUS_IO_ERROR;
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci    userInterfaceSettings[5] = (uint8_t) mode;
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci    return DMCWrite(fd, 0x82, 0x0, userInterfaceSettings,
660141cc406Sopenharmony_ci		    sizeof(userInterfaceSettings));
661141cc406Sopenharmony_ci}
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci/**********************************************************************
664141cc406Sopenharmony_ci//%FUNCTION: DMCSetShutterSpeed
665141cc406Sopenharmony_ci//%ARGUMENTS:
666141cc406Sopenharmony_ci// fd -- SCSI file descriptor
667141cc406Sopenharmony_ci// speed -- shutter speed in ms
668141cc406Sopenharmony_ci//%RETURNS:
669141cc406Sopenharmony_ci// A sane status value
670141cc406Sopenharmony_ci//%DESCRIPTION:
671141cc406Sopenharmony_ci// Sets the shutter speed of the camera
672141cc406Sopenharmony_ci// *********************************************************************/
673141cc406Sopenharmony_cistatic SANE_Status
674141cc406Sopenharmony_ciDMCSetShutterSpeed(int fd, unsigned int speed)
675141cc406Sopenharmony_ci{
676141cc406Sopenharmony_ci    uint8_t exposureCalculationResults[16];
677141cc406Sopenharmony_ci    SANE_Status status;
678141cc406Sopenharmony_ci    size_t len;
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci    DBG(3, "DMCSetShutterSpeed: %u\n", speed);
681141cc406Sopenharmony_ci    /* Convert from ms to ticks */
682141cc406Sopenharmony_ci    speed = MS_TO_TICKS(speed);
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci    status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults,
685141cc406Sopenharmony_ci		     sizeof(exposureCalculationResults), &len);
686141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
687141cc406Sopenharmony_ci    if (len < sizeof(exposureCalculationResults)) return SANE_STATUS_IO_ERROR;
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci    exposureCalculationResults[10] = (speed >> 8) & 0xFF;
690141cc406Sopenharmony_ci    exposureCalculationResults[11] = speed & 0xFF;
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci    return DMCWrite(fd, 0x87, 0x4, exposureCalculationResults,
693141cc406Sopenharmony_ci		    sizeof(exposureCalculationResults));
694141cc406Sopenharmony_ci}
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci/**********************************************************************
697141cc406Sopenharmony_ci//%FUNCTION: DMCReadTwoSuperResolutionLines
698141cc406Sopenharmony_ci//%ARGUMENTS:
699141cc406Sopenharmony_ci// c -- DMC Camera
700141cc406Sopenharmony_ci// buf -- where to put output.
701141cc406Sopenharmony_ci// lastLine -- if true, these are the last two lines in the super-resolution
702141cc406Sopenharmony_ci//             image to read.
703141cc406Sopenharmony_ci//%RETURNS:
704141cc406Sopenharmony_ci// Nothing
705141cc406Sopenharmony_ci//%DESCRIPTION:
706141cc406Sopenharmony_ci// Reads a single "raw" line from the camera (if needed) and constructs
707141cc406Sopenharmony_ci// two "super-resolution" output lines in "buf"
708141cc406Sopenharmony_ci// *********************************************************************/
709141cc406Sopenharmony_cistatic SANE_Status
710141cc406Sopenharmony_ciDMCReadTwoSuperResolutionLines(DMC_Camera *c, SANE_Byte *buf, int lastLine)
711141cc406Sopenharmony_ci{
712141cc406Sopenharmony_ci    SANE_Status status;
713141cc406Sopenharmony_ci    size_t len;
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci    SANE_Byte *output, *prev;
716141cc406Sopenharmony_ci    int redCoeff, greenCoeff, blueCoeff;
717141cc406Sopenharmony_ci    int red, green, blue;
718141cc406Sopenharmony_ci    int i;
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci    if (c->nextRawLineValid) {
721141cc406Sopenharmony_ci	memcpy(c->currentRawLine, c->nextRawLine, BYTES_PER_RAW_LINE);
722141cc406Sopenharmony_ci    } else {
723141cc406Sopenharmony_ci	status = DMCRead(c->fd, 0x00, IMAGE_RAW,
724141cc406Sopenharmony_ci			 c->currentRawLine, BYTES_PER_RAW_LINE, &len);
725141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) return status;
726141cc406Sopenharmony_ci    }
727141cc406Sopenharmony_ci    if (!lastLine) {
728141cc406Sopenharmony_ci	status = DMCRead(c->fd, 0x00, IMAGE_RAW,
729141cc406Sopenharmony_ci			 c->nextRawLine, BYTES_PER_RAW_LINE, &len);
730141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) return status;
731141cc406Sopenharmony_ci	c->nextRawLineValid = 1;
732141cc406Sopenharmony_ci    }
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci    redCoeff = 3;
735141cc406Sopenharmony_ci    greenCoeff = 1;
736141cc406Sopenharmony_ci    blueCoeff = 2;
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci    /* Do the first super-resolution line */
739141cc406Sopenharmony_ci    output = buf;
740141cc406Sopenharmony_ci    for (i=0; i<BYTES_PER_RAW_LINE; i++) {
741141cc406Sopenharmony_ci	red = redCoeff * c->currentRawLine[PREV_RED(i)] +
742141cc406Sopenharmony_ci	    (3-redCoeff) * c->currentRawLine[NEXT_RED(i)];
743141cc406Sopenharmony_ci	green = greenCoeff * c->currentRawLine[PREV_GREEN(i)] +
744141cc406Sopenharmony_ci	    (3-greenCoeff) * c->currentRawLine[NEXT_GREEN(i)];
745141cc406Sopenharmony_ci	blue = blueCoeff * c->currentRawLine[PREV_BLUE(i)] +
746141cc406Sopenharmony_ci	    (3-blueCoeff) * c->currentRawLine[NEXT_BLUE(i)];
747141cc406Sopenharmony_ci	*output++ = red/3;
748141cc406Sopenharmony_ci	*output++ = green/3;
749141cc406Sopenharmony_ci	*output++ = blue/3;
750141cc406Sopenharmony_ci	redCoeff = ADVANCE_COEFF(redCoeff);
751141cc406Sopenharmony_ci	greenCoeff = ADVANCE_COEFF(greenCoeff);
752141cc406Sopenharmony_ci	blueCoeff = ADVANCE_COEFF(blueCoeff);
753141cc406Sopenharmony_ci    }
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ci    /* Do the next super-resolution line and interpolate vertically */
756141cc406Sopenharmony_ci    if (lastLine) {
757141cc406Sopenharmony_ci	memcpy(buf+BYTES_PER_RAW_LINE*3, buf, BYTES_PER_RAW_LINE*3);
758141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
759141cc406Sopenharmony_ci    }
760141cc406Sopenharmony_ci    redCoeff = 3;
761141cc406Sopenharmony_ci    greenCoeff = 1;
762141cc406Sopenharmony_ci    blueCoeff = 2;
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_ci    prev = buf;
765141cc406Sopenharmony_ci    for (i=0; i<BYTES_PER_RAW_LINE; i++) {
766141cc406Sopenharmony_ci	red = redCoeff * c->nextRawLine[PREV_RED(i)] +
767141cc406Sopenharmony_ci	    (3-redCoeff) * c->nextRawLine[NEXT_RED(i)];
768141cc406Sopenharmony_ci	green = greenCoeff * c->nextRawLine[PREV_GREEN(i)] +
769141cc406Sopenharmony_ci	    (3-greenCoeff) * c->nextRawLine[NEXT_GREEN(i)];
770141cc406Sopenharmony_ci	blue = blueCoeff * c->nextRawLine[PREV_BLUE(i)] +
771141cc406Sopenharmony_ci	    (3-blueCoeff) * c->nextRawLine[NEXT_BLUE(i)];
772141cc406Sopenharmony_ci	*output++ = (red/3 + *prev++) / 2;
773141cc406Sopenharmony_ci	*output++ = (green/3 + *prev++) / 2;
774141cc406Sopenharmony_ci	*output++ = (blue/3 + *prev++) / 2;
775141cc406Sopenharmony_ci	redCoeff = ADVANCE_COEFF(redCoeff);
776141cc406Sopenharmony_ci	greenCoeff = ADVANCE_COEFF(greenCoeff);
777141cc406Sopenharmony_ci	blueCoeff = ADVANCE_COEFF(blueCoeff);
778141cc406Sopenharmony_ci    }
779141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
780141cc406Sopenharmony_ci}
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci/***********************************************************************
783141cc406Sopenharmony_ci//%FUNCTION: attach_one (static function)
784141cc406Sopenharmony_ci//%ARGUMENTS:
785141cc406Sopenharmony_ci// dev -- device to attach
786141cc406Sopenharmony_ci//%RETURNS:
787141cc406Sopenharmony_ci// SANE_STATUS_GOOD
788141cc406Sopenharmony_ci//%DESCRIPTION:
789141cc406Sopenharmony_ci// tries to attach a device found by sanei_config_attach_matching_devices
790141cc406Sopenharmony_ci// *********************************************************************/
791141cc406Sopenharmony_cistatic SANE_Status
792141cc406Sopenharmony_ciattach_one (const char *dev)
793141cc406Sopenharmony_ci{
794141cc406Sopenharmony_ci  DMCAttach (dev, 0);
795141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
796141cc406Sopenharmony_ci}
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci/**********************************************************************
799141cc406Sopenharmony_ci//%FUNCTION: sane_init
800141cc406Sopenharmony_ci//%ARGUMENTS:
801141cc406Sopenharmony_ci// version_code -- pointer to where we stick our version code
802141cc406Sopenharmony_ci// authorize -- authorization function
803141cc406Sopenharmony_ci//%RETURNS:
804141cc406Sopenharmony_ci// A sane status value
805141cc406Sopenharmony_ci//%DESCRIPTION:
806141cc406Sopenharmony_ci// Initializes DMC sane system.
807141cc406Sopenharmony_ci// *********************************************************************/
808141cc406Sopenharmony_ciSANE_Status
809141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
810141cc406Sopenharmony_ci{
811141cc406Sopenharmony_ci    char dev_name[PATH_MAX];
812141cc406Sopenharmony_ci    size_t len;
813141cc406Sopenharmony_ci    FILE *fp;
814141cc406Sopenharmony_ci
815141cc406Sopenharmony_ci    (void) authorize;
816141cc406Sopenharmony_ci
817141cc406Sopenharmony_ci    DBG_INIT();
818141cc406Sopenharmony_ci    if (version_code) {
819141cc406Sopenharmony_ci	*version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
820141cc406Sopenharmony_ci    }
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci    fp = sanei_config_open(DMC_CONFIG_FILE);
823141cc406Sopenharmony_ci    if (!fp) {
824141cc406Sopenharmony_ci	/* default to /dev/camera instead of insisting on config file */
825141cc406Sopenharmony_ci	if (DMCAttach ("/dev/camera", NULL) != SANE_STATUS_GOOD) {
826141cc406Sopenharmony_ci	    /* OK, try /dev/scanner */
827141cc406Sopenharmony_ci	    DMCAttach("/dev/scanner", NULL);
828141cc406Sopenharmony_ci	}
829141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
830141cc406Sopenharmony_ci    }
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci    while (sanei_config_read (dev_name, sizeof (dev_name), fp)) {
833141cc406Sopenharmony_ci	if (dev_name[0] == '#')	{	/* ignore line comments */
834141cc406Sopenharmony_ci	    continue;
835141cc406Sopenharmony_ci	}
836141cc406Sopenharmony_ci	len = strlen (dev_name);
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci	if (!len) continue;			/* ignore empty lines */
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci	sanei_config_attach_matching_devices(dev_name, attach_one);
841141cc406Sopenharmony_ci    }
842141cc406Sopenharmony_ci    fclose (fp);
843141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
844141cc406Sopenharmony_ci}
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ci/**********************************************************************
847141cc406Sopenharmony_ci//%FUNCTION: sane_exit
848141cc406Sopenharmony_ci//%ARGUMENTS:
849141cc406Sopenharmony_ci// None
850141cc406Sopenharmony_ci//%RETURNS:
851141cc406Sopenharmony_ci// Nothing
852141cc406Sopenharmony_ci//%DESCRIPTION:
853141cc406Sopenharmony_ci// Cleans up all the SANE information
854141cc406Sopenharmony_ci// *********************************************************************/
855141cc406Sopenharmony_civoid
856141cc406Sopenharmony_cisane_exit(void)
857141cc406Sopenharmony_ci{
858141cc406Sopenharmony_ci    DMC_Device *dev, *next;
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci    /* Close all handles */
861141cc406Sopenharmony_ci    while(FirstHandle) {
862141cc406Sopenharmony_ci	sane_close(FirstHandle);
863141cc406Sopenharmony_ci    }
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ci    /* Free all devices */
866141cc406Sopenharmony_ci    dev = FirstDevice;
867141cc406Sopenharmony_ci    while(dev) {
868141cc406Sopenharmony_ci	next = dev->next;
869141cc406Sopenharmony_ci	free((char *) dev->sane.model);
870141cc406Sopenharmony_ci	free(dev);
871141cc406Sopenharmony_ci	dev = next;
872141cc406Sopenharmony_ci    }
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_ci    if (devlist)
875141cc406Sopenharmony_ci      free (devlist);
876141cc406Sopenharmony_ci}
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci/**********************************************************************
879141cc406Sopenharmony_ci//%FUNCTION: sane_get_devices
880141cc406Sopenharmony_ci//%ARGUMENTS:
881141cc406Sopenharmony_ci// device_list -- set to allocated list of devices
882141cc406Sopenharmony_ci// local_only -- ignored
883141cc406Sopenharmony_ci//%RETURNS:
884141cc406Sopenharmony_ci// A SANE status
885141cc406Sopenharmony_ci//%DESCRIPTION:
886141cc406Sopenharmony_ci// Returns a list of all known DMC devices
887141cc406Sopenharmony_ci// *********************************************************************/
888141cc406Sopenharmony_ciSANE_Status
889141cc406Sopenharmony_cisane_get_devices(SANE_Device const ***device_list, SANE_Bool local_only)
890141cc406Sopenharmony_ci{
891141cc406Sopenharmony_ci    DMC_Device *dev;
892141cc406Sopenharmony_ci    int i = 0;
893141cc406Sopenharmony_ci
894141cc406Sopenharmony_ci    (void) local_only;
895141cc406Sopenharmony_ci
896141cc406Sopenharmony_ci    if (devlist) free(devlist);
897141cc406Sopenharmony_ci    devlist = malloc((NumDevices+1) * sizeof(devlist[0]));
898141cc406Sopenharmony_ci    if (!devlist) return SANE_STATUS_NO_MEM;
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci    for (dev=FirstDevice; dev; dev = dev->next) {
901141cc406Sopenharmony_ci	devlist[i++] = &dev->sane;
902141cc406Sopenharmony_ci    }
903141cc406Sopenharmony_ci    devlist[i] = NULL;
904141cc406Sopenharmony_ci
905141cc406Sopenharmony_ci    if (device_list) *device_list = devlist;
906141cc406Sopenharmony_ci
907141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
908141cc406Sopenharmony_ci}
909141cc406Sopenharmony_ci
910141cc406Sopenharmony_ci/**********************************************************************
911141cc406Sopenharmony_ci//%FUNCTION: sane_open
912141cc406Sopenharmony_ci//%ARGUMENTS:
913141cc406Sopenharmony_ci// name -- name of device to open
914141cc406Sopenharmony_ci// handle -- set to a handle for the opened device
915141cc406Sopenharmony_ci//%RETURNS:
916141cc406Sopenharmony_ci// A SANE status
917141cc406Sopenharmony_ci//%DESCRIPTION:
918141cc406Sopenharmony_ci// Opens a DMC camera device
919141cc406Sopenharmony_ci// *********************************************************************/
920141cc406Sopenharmony_ciSANE_Status
921141cc406Sopenharmony_cisane_open(SANE_String_Const name, SANE_Handle *handle)
922141cc406Sopenharmony_ci{
923141cc406Sopenharmony_ci    SANE_Status status;
924141cc406Sopenharmony_ci    DMC_Device *dev;
925141cc406Sopenharmony_ci    DMC_Camera *c;
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci    /* If we're given a device name, search for it */
928141cc406Sopenharmony_ci    if (*name) {
929141cc406Sopenharmony_ci	for (dev = FirstDevice; dev; dev = dev->next) {
930141cc406Sopenharmony_ci	    if (!strcmp(dev->sane.name, name)) {
931141cc406Sopenharmony_ci		break;
932141cc406Sopenharmony_ci	    }
933141cc406Sopenharmony_ci	}
934141cc406Sopenharmony_ci	if (!dev) {
935141cc406Sopenharmony_ci	    status = DMCAttach(name, &dev);
936141cc406Sopenharmony_ci	    if (status != SANE_STATUS_GOOD) return status;
937141cc406Sopenharmony_ci	}
938141cc406Sopenharmony_ci    } else {
939141cc406Sopenharmony_ci	dev = FirstDevice;
940141cc406Sopenharmony_ci    }
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci    if (!dev) return SANE_STATUS_INVAL;
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci    c = malloc(sizeof(*c));
945141cc406Sopenharmony_ci    if (!c) return SANE_STATUS_NO_MEM;
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci    memset(c, 0, sizeof(*c));
948141cc406Sopenharmony_ci
949141cc406Sopenharmony_ci    c->fd = -1;
950141cc406Sopenharmony_ci    c->hw = dev;
951141cc406Sopenharmony_ci    c->readBuffer = NULL;
952141cc406Sopenharmony_ci    c->readPtr = NULL;
953141cc406Sopenharmony_ci    c->imageMode = IMAGE_MFI;
954141cc406Sopenharmony_ci    c->inViewfinderMode = 0;
955141cc406Sopenharmony_ci    c->nextRawLineValid = 0;
956141cc406Sopenharmony_ci
957141cc406Sopenharmony_ci    DMCInitOptions(c);
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci    c->next = FirstHandle;
960141cc406Sopenharmony_ci    FirstHandle = c;
961141cc406Sopenharmony_ci    if (handle) *handle = c;
962141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
963141cc406Sopenharmony_ci}
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci/**********************************************************************
966141cc406Sopenharmony_ci//%FUNCTION: sane_close
967141cc406Sopenharmony_ci//%ARGUMENTS:
968141cc406Sopenharmony_ci// handle -- handle of device to close
969141cc406Sopenharmony_ci//%RETURNS:
970141cc406Sopenharmony_ci// A SANE status
971141cc406Sopenharmony_ci//%DESCRIPTION:
972141cc406Sopenharmony_ci// Closes a DMC camera device
973141cc406Sopenharmony_ci// *********************************************************************/
974141cc406Sopenharmony_civoid
975141cc406Sopenharmony_cisane_close(SANE_Handle handle)
976141cc406Sopenharmony_ci{
977141cc406Sopenharmony_ci    DMC_Camera *prev, *c;
978141cc406Sopenharmony_ci    prev = NULL;
979141cc406Sopenharmony_ci    for (c = FirstHandle; c; c = c->next) {
980141cc406Sopenharmony_ci	if (c == handle) break;
981141cc406Sopenharmony_ci	prev = c;
982141cc406Sopenharmony_ci    }
983141cc406Sopenharmony_ci    if (!c) {
984141cc406Sopenharmony_ci	DBG(1, "close: invalid handle %p\n", handle);
985141cc406Sopenharmony_ci	return;
986141cc406Sopenharmony_ci    }
987141cc406Sopenharmony_ci    DMCCancel(c);
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_ci    if (prev) prev->next = c->next;
990141cc406Sopenharmony_ci    else FirstHandle = c->next;
991141cc406Sopenharmony_ci
992141cc406Sopenharmony_ci    if (c->readBuffer) {
993141cc406Sopenharmony_ci	free(c->readBuffer);
994141cc406Sopenharmony_ci    }
995141cc406Sopenharmony_ci    free(c);
996141cc406Sopenharmony_ci}
997141cc406Sopenharmony_ci
998141cc406Sopenharmony_ci/**********************************************************************
999141cc406Sopenharmony_ci//%FUNCTION: sane_get_option_descriptor
1000141cc406Sopenharmony_ci//%ARGUMENTS:
1001141cc406Sopenharmony_ci// handle -- handle of device
1002141cc406Sopenharmony_ci// option -- option number to retrieve
1003141cc406Sopenharmony_ci//%RETURNS:
1004141cc406Sopenharmony_ci// An option descriptor or NULL on error
1005141cc406Sopenharmony_ci// *********************************************************************/
1006141cc406Sopenharmony_ciSANE_Option_Descriptor const *
1007141cc406Sopenharmony_cisane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
1008141cc406Sopenharmony_ci{
1009141cc406Sopenharmony_ci    DMC_Camera *c = ValidateHandle(handle);
1010141cc406Sopenharmony_ci    if (!c) return NULL;
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci    if ((unsigned) option >= NUM_OPTIONS) return NULL;
1013141cc406Sopenharmony_ci    return c->opt + option;
1014141cc406Sopenharmony_ci}
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci/**********************************************************************
1017141cc406Sopenharmony_ci//%FUNCTION: sane_control_option
1018141cc406Sopenharmony_ci//%ARGUMENTS:
1019141cc406Sopenharmony_ci// handle -- handle of device
1020141cc406Sopenharmony_ci// option -- option number to retrieve
1021141cc406Sopenharmony_ci// action -- what to do with the option
1022141cc406Sopenharmony_ci// val -- value to set option to
1023141cc406Sopenharmony_ci// info -- returned info flags
1024141cc406Sopenharmony_ci//%RETURNS:
1025141cc406Sopenharmony_ci// SANE status
1026141cc406Sopenharmony_ci//%DESCRIPTION:
1027141cc406Sopenharmony_ci// Sets or queries option values
1028141cc406Sopenharmony_ci// *********************************************************************/
1029141cc406Sopenharmony_ciSANE_Status
1030141cc406Sopenharmony_cisane_control_option(SANE_Handle handle, SANE_Int option,
1031141cc406Sopenharmony_ci		    SANE_Action action, void *val, SANE_Int *info)
1032141cc406Sopenharmony_ci{
1033141cc406Sopenharmony_ci    DMC_Camera *c;
1034141cc406Sopenharmony_ci    SANE_Word cap;
1035141cc406Sopenharmony_ci    int i;
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci    if (info) *info = 0;
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci    c = ValidateHandle(handle);
1040141cc406Sopenharmony_ci    if (!c) return SANE_STATUS_INVAL;
1041141cc406Sopenharmony_ci
1042141cc406Sopenharmony_ci    if (c->fd >= 0) return SANE_STATUS_DEVICE_BUSY;
1043141cc406Sopenharmony_ci
1044141cc406Sopenharmony_ci    if (option >= NUM_OPTIONS) return SANE_STATUS_INVAL;
1045141cc406Sopenharmony_ci
1046141cc406Sopenharmony_ci    cap = c->opt[option].cap;
1047141cc406Sopenharmony_ci    if (!SANE_OPTION_IS_ACTIVE(cap)) return SANE_STATUS_INVAL;
1048141cc406Sopenharmony_ci
1049141cc406Sopenharmony_ci    if (action == SANE_ACTION_GET_VALUE) {
1050141cc406Sopenharmony_ci	switch(c->opt[option].type) {
1051141cc406Sopenharmony_ci	case SANE_TYPE_INT:
1052141cc406Sopenharmony_ci	    * (SANE_Int *) val = c->val[option].w;
1053141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci	case SANE_TYPE_STRING:
1056141cc406Sopenharmony_ci	    strcpy(val, c->val[option].s);
1057141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_ci	default:
1060141cc406Sopenharmony_ci	    DBG(3, "impossible option type!\n");
1061141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1062141cc406Sopenharmony_ci	}
1063141cc406Sopenharmony_ci    }
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ci    if (action == SANE_ACTION_SET_AUTO) {
1066141cc406Sopenharmony_ci	return SANE_STATUS_UNSUPPORTED;
1067141cc406Sopenharmony_ci    }
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci    switch(option) {
1070141cc406Sopenharmony_ci    case OPT_IMAGE_MODE:
1071141cc406Sopenharmony_ci	for (i=0; i<NUM_IMAGE_MODES; i++) {
1072141cc406Sopenharmony_ci	    if (!strcmp(val, ValidModes[i])) {
1073141cc406Sopenharmony_ci		DMCSetMode(c, i);
1074141cc406Sopenharmony_ci		c->val[OPT_IMAGE_MODE].s = (SANE_String) ValidModes[i];
1075141cc406Sopenharmony_ci		if (info) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
1076141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
1077141cc406Sopenharmony_ci	    }
1078141cc406Sopenharmony_ci	}
1079141cc406Sopenharmony_ci	break;
1080141cc406Sopenharmony_ci    case OPT_WHITE_BALANCE:
1081141cc406Sopenharmony_ci	for (i=0; i<=WHITE_BALANCE_FLUORESCENT; i++) {
1082141cc406Sopenharmony_ci	    if (!strcmp(val, ValidBalances[i])) {
1083141cc406Sopenharmony_ci		c->val[OPT_WHITE_BALANCE].s = (SANE_String) ValidBalances[i];
1084141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
1085141cc406Sopenharmony_ci	    }
1086141cc406Sopenharmony_ci	}
1087141cc406Sopenharmony_ci	break;
1088141cc406Sopenharmony_ci    case OPT_ASA:
1089141cc406Sopenharmony_ci	for (i=1; i<= ASA_100+1; i++) {
1090141cc406Sopenharmony_ci	    if (* ((SANE_Int *) val) == ValidASAs[i]) {
1091141cc406Sopenharmony_ci		c->val[OPT_ASA].w = ValidASAs[i];
1092141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
1093141cc406Sopenharmony_ci	    }
1094141cc406Sopenharmony_ci	}
1095141cc406Sopenharmony_ci	break;
1096141cc406Sopenharmony_ci    case OPT_SHUTTER_SPEED:
1097141cc406Sopenharmony_ci	if (* (SANE_Int *) val < c->hw->shutterSpeedRange.min ||
1098141cc406Sopenharmony_ci	    * (SANE_Int *) val > c->hw->shutterSpeedRange.max) {
1099141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
1100141cc406Sopenharmony_ci	}
1101141cc406Sopenharmony_ci	c->val[OPT_SHUTTER_SPEED].w = * (SANE_Int *) val;
1102141cc406Sopenharmony_ci	/* Do any roundoff */
1103141cc406Sopenharmony_ci	c->val[OPT_SHUTTER_SPEED].w =
1104141cc406Sopenharmony_ci	    TICKS_TO_MS(MS_TO_TICKS(c->val[OPT_SHUTTER_SPEED].w));
1105141cc406Sopenharmony_ci	if (c->val[OPT_SHUTTER_SPEED].w != * (SANE_Int *) val) {
1106141cc406Sopenharmony_ci	    if (info) *info |= SANE_INFO_INEXACT;
1107141cc406Sopenharmony_ci	}
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1110141cc406Sopenharmony_ci
1111141cc406Sopenharmony_ci    default:
1112141cc406Sopenharmony_ci	/* Should really be INVAL, but just bit-bucket set requests... */
1113141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1114141cc406Sopenharmony_ci    }
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1117141cc406Sopenharmony_ci}
1118141cc406Sopenharmony_ci
1119141cc406Sopenharmony_ci/**********************************************************************
1120141cc406Sopenharmony_ci//%FUNCTION: sane_get_parameters
1121141cc406Sopenharmony_ci//%ARGUMENTS:
1122141cc406Sopenharmony_ci// handle -- handle of device
1123141cc406Sopenharmony_ci// params -- set to device parameters
1124141cc406Sopenharmony_ci//%RETURNS:
1125141cc406Sopenharmony_ci// SANE status
1126141cc406Sopenharmony_ci//%DESCRIPTION:
1127141cc406Sopenharmony_ci// Returns parameters for current or next image.
1128141cc406Sopenharmony_ci// *********************************************************************/
1129141cc406Sopenharmony_ciSANE_Status
1130141cc406Sopenharmony_cisane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
1131141cc406Sopenharmony_ci{
1132141cc406Sopenharmony_ci    DMC_Camera *c = ValidateHandle(handle);
1133141cc406Sopenharmony_ci    if (!c) return SANE_STATUS_INVAL;
1134141cc406Sopenharmony_ci
1135141cc406Sopenharmony_ci    if (c->fd < 0) {
1136141cc406Sopenharmony_ci	int width, height;
1137141cc406Sopenharmony_ci	memset(&c->params, 0, sizeof(c->params));
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci	width = c->val[OPT_BR_X].w - c->val[OPT_TL_X].w;
1140141cc406Sopenharmony_ci	height = c->val[OPT_BR_Y].w - c->val[OPT_TL_Y].w;
1141141cc406Sopenharmony_ci	c->params.pixels_per_line = width + 1;
1142141cc406Sopenharmony_ci	c->params.lines = height+1;
1143141cc406Sopenharmony_ci	c->params.depth = 8;
1144141cc406Sopenharmony_ci	c->params.last_frame = SANE_TRUE;
1145141cc406Sopenharmony_ci	switch(c->imageMode) {
1146141cc406Sopenharmony_ci	case IMAGE_SUPER_RES:
1147141cc406Sopenharmony_ci	case IMAGE_MFI:
1148141cc406Sopenharmony_ci	case IMAGE_THUMB:
1149141cc406Sopenharmony_ci	    c->params.format = SANE_FRAME_RGB;
1150141cc406Sopenharmony_ci	    c->params.bytes_per_line = c->params.pixels_per_line * 3;
1151141cc406Sopenharmony_ci	    break;
1152141cc406Sopenharmony_ci	case IMAGE_RAW:
1153141cc406Sopenharmony_ci	case IMAGE_VIEWFINDER:
1154141cc406Sopenharmony_ci	    c->params.format = SANE_FRAME_GRAY;
1155141cc406Sopenharmony_ci	    c->params.bytes_per_line = c->params.pixels_per_line;
1156141cc406Sopenharmony_ci	    break;
1157141cc406Sopenharmony_ci	}
1158141cc406Sopenharmony_ci    }
1159141cc406Sopenharmony_ci    if (params) *params = c->params;
1160141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1161141cc406Sopenharmony_ci}
1162141cc406Sopenharmony_ci
1163141cc406Sopenharmony_ci/**********************************************************************
1164141cc406Sopenharmony_ci//%FUNCTION: sane_start
1165141cc406Sopenharmony_ci//%ARGUMENTS:
1166141cc406Sopenharmony_ci// handle -- handle of device
1167141cc406Sopenharmony_ci//%RETURNS:
1168141cc406Sopenharmony_ci// SANE status
1169141cc406Sopenharmony_ci//%DESCRIPTION:
1170141cc406Sopenharmony_ci// Starts acquisition
1171141cc406Sopenharmony_ci// *********************************************************************/
1172141cc406Sopenharmony_ciSANE_Status
1173141cc406Sopenharmony_cisane_start(SANE_Handle handle)
1174141cc406Sopenharmony_ci{
1175141cc406Sopenharmony_ci    static uint8_t const acquire[] =
1176141cc406Sopenharmony_ci    { 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci    static uint8_t const viewfinder[] =
1179141cc406Sopenharmony_ci    { 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1180141cc406Sopenharmony_ci
1181141cc406Sopenharmony_ci    static uint8_t const no_viewfinder[] =
1182141cc406Sopenharmony_ci    { 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1183141cc406Sopenharmony_ci
1184141cc406Sopenharmony_ci    DMC_Camera *c = ValidateHandle(handle);
1185141cc406Sopenharmony_ci    SANE_Status status;
1186141cc406Sopenharmony_ci    int i;
1187141cc406Sopenharmony_ci
1188141cc406Sopenharmony_ci    if (!c) return SANE_STATUS_INVAL;
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci    /* If we're already open, barf -- not sure this is the best status */
1191141cc406Sopenharmony_ci    if (c->fd >= 0) return SANE_STATUS_DEVICE_BUSY;
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci    /* Get rid of old read buffers */
1194141cc406Sopenharmony_ci    if (c->readBuffer) {
1195141cc406Sopenharmony_ci	free(c->readBuffer);
1196141cc406Sopenharmony_ci	c->readBuffer = NULL;
1197141cc406Sopenharmony_ci	c->readPtr = NULL;
1198141cc406Sopenharmony_ci    }
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci    c->nextRawLineValid = 0;
1201141cc406Sopenharmony_ci
1202141cc406Sopenharmony_ci    /* Refresh parameter list */
1203141cc406Sopenharmony_ci    status = sane_get_parameters(c, NULL);
1204141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci    status = sanei_scsi_open(c->hw->sane.name, &c->fd, NULL, NULL);
1207141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
1208141cc406Sopenharmony_ci	c->fd = -1;
1209141cc406Sopenharmony_ci	DBG(1, "DMC: Open of `%s' failed: %s\n",
1210141cc406Sopenharmony_ci	    c->hw->sane.name, sane_strstatus(status));
1211141cc406Sopenharmony_ci	return status;
1212141cc406Sopenharmony_ci    }
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci    /* Set ASA and shutter speed if they're no longer current */
1215141cc406Sopenharmony_ci    if (c->val[OPT_ASA].w != c->hw->asa) {
1216141cc406Sopenharmony_ci	status = DMCSetASA(c->fd, c->val[OPT_ASA].w);
1217141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1218141cc406Sopenharmony_ci	    DMCCancel(c);
1219141cc406Sopenharmony_ci	    return status;
1220141cc406Sopenharmony_ci	}
1221141cc406Sopenharmony_ci	c->hw->asa = c->val[OPT_ASA].w;
1222141cc406Sopenharmony_ci    }
1223141cc406Sopenharmony_ci
1224141cc406Sopenharmony_ci    if ((unsigned int) c->val[OPT_SHUTTER_SPEED].w != c->hw->shutterSpeed) {
1225141cc406Sopenharmony_ci	status = DMCSetShutterSpeed(c->fd, c->val[OPT_SHUTTER_SPEED].w);
1226141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1227141cc406Sopenharmony_ci	    DMCCancel(c);
1228141cc406Sopenharmony_ci	    return status;
1229141cc406Sopenharmony_ci	}
1230141cc406Sopenharmony_ci	c->hw->shutterSpeed = c->val[OPT_SHUTTER_SPEED].w;
1231141cc406Sopenharmony_ci    }
1232141cc406Sopenharmony_ci
1233141cc406Sopenharmony_ci    /* Set white balance mode if needed */
1234141cc406Sopenharmony_ci    for (i=0; i<=WHITE_BALANCE_FLUORESCENT; i++) {
1235141cc406Sopenharmony_ci	if (!strcmp(ValidBalances[i], c->val[OPT_WHITE_BALANCE].s)) {
1236141cc406Sopenharmony_ci	    if (i != c->hw->whiteBalance) {
1237141cc406Sopenharmony_ci		status = DMCSetWhiteBalance(c->fd, i);
1238141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD) {
1239141cc406Sopenharmony_ci		    DMCCancel(c);
1240141cc406Sopenharmony_ci		    return status;
1241141cc406Sopenharmony_ci		}
1242141cc406Sopenharmony_ci		c->hw->whiteBalance = i;
1243141cc406Sopenharmony_ci	    }
1244141cc406Sopenharmony_ci	}
1245141cc406Sopenharmony_ci    }
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci    /* Flip into viewfinder mode if needed */
1248141cc406Sopenharmony_ci    if (c->imageMode == IMAGE_VIEWFINDER && !c->inViewfinderMode) {
1249141cc406Sopenharmony_ci	status = sanei_scsi_cmd(c->fd, viewfinder, sizeof(viewfinder),
1250141cc406Sopenharmony_ci				NULL, NULL);
1251141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1252141cc406Sopenharmony_ci	    DMCCancel(c);
1253141cc406Sopenharmony_ci	    return status;
1254141cc406Sopenharmony_ci	}
1255141cc406Sopenharmony_ci	c->inViewfinderMode = 1;
1256141cc406Sopenharmony_ci    }
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci    /* Flip out of viewfinder mode if needed */
1259141cc406Sopenharmony_ci    if (c->imageMode != IMAGE_VIEWFINDER && c->inViewfinderMode) {
1260141cc406Sopenharmony_ci	status = sanei_scsi_cmd(c->fd, no_viewfinder, sizeof(no_viewfinder),
1261141cc406Sopenharmony_ci				NULL, NULL);
1262141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1263141cc406Sopenharmony_ci	    DMCCancel(c);
1264141cc406Sopenharmony_ci	    return status;
1265141cc406Sopenharmony_ci	}
1266141cc406Sopenharmony_ci	c->inViewfinderMode = 0;
1267141cc406Sopenharmony_ci    }
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci    status = sanei_scsi_cmd(c->fd, acquire, sizeof(acquire), NULL, NULL);
1271141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
1272141cc406Sopenharmony_ci	DMCCancel(c);
1273141cc406Sopenharmony_ci	return status;
1274141cc406Sopenharmony_ci    }
1275141cc406Sopenharmony_ci    c->bytes_to_read = c->params.bytes_per_line * c->params.lines;
1276141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1277141cc406Sopenharmony_ci}
1278141cc406Sopenharmony_ci
1279141cc406Sopenharmony_ci/**********************************************************************
1280141cc406Sopenharmony_ci//%FUNCTION: sane_read
1281141cc406Sopenharmony_ci//%ARGUMENTS:
1282141cc406Sopenharmony_ci// handle -- handle of device
1283141cc406Sopenharmony_ci// buf -- destination for data
1284141cc406Sopenharmony_ci// max_len -- maximum amount of data to store
1285141cc406Sopenharmony_ci// len -- set to actual amount of data stored.
1286141cc406Sopenharmony_ci//%RETURNS:
1287141cc406Sopenharmony_ci// SANE status
1288141cc406Sopenharmony_ci//%DESCRIPTION:
1289141cc406Sopenharmony_ci// Reads image data from the camera
1290141cc406Sopenharmony_ci// *********************************************************************/
1291141cc406Sopenharmony_ciSANE_Status
1292141cc406Sopenharmony_cisane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)
1293141cc406Sopenharmony_ci{
1294141cc406Sopenharmony_ci    SANE_Status status;
1295141cc406Sopenharmony_ci    DMC_Camera *c = ValidateHandle(handle);
1296141cc406Sopenharmony_ci    size_t size;
1297141cc406Sopenharmony_ci    SANE_Int i;
1298141cc406Sopenharmony_ci
1299141cc406Sopenharmony_ci    if (!c) return SANE_STATUS_INVAL;
1300141cc406Sopenharmony_ci
1301141cc406Sopenharmony_ci    if (c->fd < 0) return SANE_STATUS_INVAL;
1302141cc406Sopenharmony_ci
1303141cc406Sopenharmony_ci    if (c->bytes_to_read == 0) {
1304141cc406Sopenharmony_ci	if (c->readBuffer) {
1305141cc406Sopenharmony_ci	    free(c->readBuffer);
1306141cc406Sopenharmony_ci	    c->readBuffer = NULL;
1307141cc406Sopenharmony_ci	    c->readPtr = NULL;
1308141cc406Sopenharmony_ci	}
1309141cc406Sopenharmony_ci	DMCCancel(c);
1310141cc406Sopenharmony_ci	return SANE_STATUS_EOF;
1311141cc406Sopenharmony_ci    }
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci    if (max_len == 0) {
1314141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1315141cc406Sopenharmony_ci    }
1316141cc406Sopenharmony_ci
1317141cc406Sopenharmony_ci    if (c->imageMode == IMAGE_SUPER_RES) {
1318141cc406Sopenharmony_ci	/* We have to read *two* complete rows... */
1319141cc406Sopenharmony_ci	max_len = (max_len / (2*c->params.bytes_per_line)) *
1320141cc406Sopenharmony_ci	    (2*c->params.bytes_per_line);
1321141cc406Sopenharmony_ci	/* If user is trying to read less than two complete lines, fail */
1322141cc406Sopenharmony_ci	if (max_len == 0) return SANE_STATUS_INVAL;
1323141cc406Sopenharmony_ci	if ((unsigned int) max_len > c->bytes_to_read) max_len = c->bytes_to_read;
1324141cc406Sopenharmony_ci	for (i=0; i<max_len; i += 2*c->params.bytes_per_line) {
1325141cc406Sopenharmony_ci	    c->bytes_to_read -= 2*c->params.bytes_per_line;
1326141cc406Sopenharmony_ci	    status = DMCReadTwoSuperResolutionLines(c, buf+i,
1327141cc406Sopenharmony_ci						    !c->bytes_to_read);
1328141cc406Sopenharmony_ci	    if (status != SANE_STATUS_GOOD) return status;
1329141cc406Sopenharmony_ci	}
1330141cc406Sopenharmony_ci	*len = max_len;
1331141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1332141cc406Sopenharmony_ci    }
1333141cc406Sopenharmony_ci
1334141cc406Sopenharmony_ci    if (c->imageMode == IMAGE_MFI || c->imageMode == IMAGE_RAW) {
1335141cc406Sopenharmony_ci	/* We have to read complete rows... */
1336141cc406Sopenharmony_ci	max_len = (max_len / c->params.bytes_per_line) * c->params.bytes_per_line;
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci	/* If user is trying to read less than one complete row, fail */
1339141cc406Sopenharmony_ci	if (max_len == 0) return SANE_STATUS_INVAL;
1340141cc406Sopenharmony_ci	if ((unsigned int) max_len > c->bytes_to_read) max_len = c->bytes_to_read;
1341141cc406Sopenharmony_ci	c->bytes_to_read -= (unsigned int) max_len;
1342141cc406Sopenharmony_ci	status = DMCRead(c->fd, 0x00, c->imageMode, buf, max_len, &size);
1343141cc406Sopenharmony_ci	*len = size;
1344141cc406Sopenharmony_ci	return status;
1345141cc406Sopenharmony_ci    }
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_ci    if ((unsigned int) max_len > c->bytes_to_read) max_len = c->bytes_to_read;
1348141cc406Sopenharmony_ci    if (c->readPtr) {
1349141cc406Sopenharmony_ci	*len = max_len;
1350141cc406Sopenharmony_ci	memcpy(buf, c->readPtr, max_len);
1351141cc406Sopenharmony_ci	c->readPtr += max_len;
1352141cc406Sopenharmony_ci	c->bytes_to_read -= max_len;
1353141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1354141cc406Sopenharmony_ci    }
1355141cc406Sopenharmony_ci
1356141cc406Sopenharmony_ci    /* Fill the read buffer completely */
1357141cc406Sopenharmony_ci    c->readBuffer = malloc(c->bytes_to_read);
1358141cc406Sopenharmony_ci    if (!c->readBuffer) return SANE_STATUS_NO_MEM;
1359141cc406Sopenharmony_ci    c->readPtr = c->readBuffer;
1360141cc406Sopenharmony_ci    status = DMCRead(c->fd, 0x00, c->imageMode, (SANE_Byte *) c->readBuffer,
1361141cc406Sopenharmony_ci		     c->bytes_to_read, &size);
1362141cc406Sopenharmony_ci    *len = size;
1363141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
1364141cc406Sopenharmony_ci    if ((unsigned int) *len != c->bytes_to_read) return SANE_STATUS_IO_ERROR;
1365141cc406Sopenharmony_ci
1366141cc406Sopenharmony_ci    /* Now copy */
1367141cc406Sopenharmony_ci    *len = max_len;
1368141cc406Sopenharmony_ci    memcpy(buf, c->readPtr, max_len);
1369141cc406Sopenharmony_ci    c->readPtr += max_len;
1370141cc406Sopenharmony_ci    c->bytes_to_read -= max_len;
1371141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1372141cc406Sopenharmony_ci}
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci/**********************************************************************
1375141cc406Sopenharmony_ci//%FUNCTION: sane_cancel
1376141cc406Sopenharmony_ci//%ARGUMENTS:
1377141cc406Sopenharmony_ci// handle -- handle of device
1378141cc406Sopenharmony_ci//%RETURNS:
1379141cc406Sopenharmony_ci// Nothing
1380141cc406Sopenharmony_ci//%DESCRIPTION:
1381141cc406Sopenharmony_ci// A quick cancellation of the scane
1382141cc406Sopenharmony_ci// *********************************************************************/
1383141cc406Sopenharmony_civoid
1384141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
1385141cc406Sopenharmony_ci{
1386141cc406Sopenharmony_ci    DMC_Camera *c = ValidateHandle(handle);
1387141cc406Sopenharmony_ci    if (!c) return;
1388141cc406Sopenharmony_ci
1389141cc406Sopenharmony_ci    DMCCancel(c);
1390141cc406Sopenharmony_ci}
1391141cc406Sopenharmony_ci
1392141cc406Sopenharmony_ciSANE_Status
1393141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1394141cc406Sopenharmony_ci{
1395141cc406Sopenharmony_ci  (void) handle;
1396141cc406Sopenharmony_ci  (void) non_blocking;
1397141cc406Sopenharmony_ci
1398141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1399141cc406Sopenharmony_ci}
1400141cc406Sopenharmony_ci
1401141cc406Sopenharmony_ciSANE_Status
1402141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
1403141cc406Sopenharmony_ci{
1404141cc406Sopenharmony_ci  (void) handle;
1405141cc406Sopenharmony_ci  (void) fd;
1406141cc406Sopenharmony_ci
1407141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1408141cc406Sopenharmony_ci}
1409