1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru>
4141cc406Sopenharmony_ci   Copyright (C) 2002 - 2007 Henning Geinitz <sane@geinitz.org>
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
43141cc406Sopenharmony_ci/** @file
44141cc406Sopenharmony_ci * @brief Implementation of the low-level scanner interface functions.
45141cc406Sopenharmony_ci */
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#include "gt68xx_low.h"
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci#include "../include/sane/sane.h"
50141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
51141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci#include <stdlib.h>
54141cc406Sopenharmony_ci#include <string.h>
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci#ifdef USE_FORK
57141cc406Sopenharmony_ci#include <sys/wait.h>
58141cc406Sopenharmony_ci#include <unistd.h>
59141cc406Sopenharmony_ci#include "gt68xx_shm_channel.c"
60141cc406Sopenharmony_ci#endif
61141cc406Sopenharmony_ci
62141cc406Sopenharmony_ci/** Check that the device pointer is not NULL.
63141cc406Sopenharmony_ci *
64141cc406Sopenharmony_ci * @param dev       Pointer to the device object (GT68xx_Device).
65141cc406Sopenharmony_ci * @param func_name Function name (for use in debug messages).
66141cc406Sopenharmony_ci */
67141cc406Sopenharmony_ci#define CHECK_DEV_NOT_NULL(dev, func_name)                              \
68141cc406Sopenharmony_ci  do {                                                                  \
69141cc406Sopenharmony_ci    IF_DBG(                                                             \
70141cc406Sopenharmony_ci    if (!(dev))                                                         \
71141cc406Sopenharmony_ci      {                                                                 \
72141cc406Sopenharmony_ci        DBG (0, "BUG: NULL device\n");                                  \
73141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;                                       \
74141cc406Sopenharmony_ci      }                                                                 \
75141cc406Sopenharmony_ci     )                                                                  \
76141cc406Sopenharmony_ci  } while (SANE_FALSE)
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci/** Check that the device is open.
79141cc406Sopenharmony_ci *
80141cc406Sopenharmony_ci * @param dev       Pointer to the device object (GT68xx_Device).
81141cc406Sopenharmony_ci * @param func_name Function name (for use in debug messages).
82141cc406Sopenharmony_ci */
83141cc406Sopenharmony_ci#define CHECK_DEV_OPEN(dev, func_name)                                  \
84141cc406Sopenharmony_ci  do {                                                                  \
85141cc406Sopenharmony_ci    IF_DBG(                                                             \
86141cc406Sopenharmony_ci    CHECK_DEV_NOT_NULL ((dev), (func_name));                            \
87141cc406Sopenharmony_ci    if ((dev)->fd == -1)                                                \
88141cc406Sopenharmony_ci      {                                                                 \
89141cc406Sopenharmony_ci        DBG (0, "%s: BUG: device %p not open\n", (func_name),           \
90141cc406Sopenharmony_ci             ((void *) dev));                                           \
91141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;                                       \
92141cc406Sopenharmony_ci      }                                                                 \
93141cc406Sopenharmony_ci    )                                                                   \
94141cc406Sopenharmony_ci  } while (SANE_FALSE)
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci/** Check that the device is open and active.
97141cc406Sopenharmony_ci *
98141cc406Sopenharmony_ci * @param dev       Pointer to the device (GT68xx_Device).
99141cc406Sopenharmony_ci * @param func_name Function name (for use in debug messages).
100141cc406Sopenharmony_ci */
101141cc406Sopenharmony_ci#define CHECK_DEV_ACTIVE(dev, func_name)                                \
102141cc406Sopenharmony_ci  do {                                                                  \
103141cc406Sopenharmony_ci    IF_DBG(                                                             \
104141cc406Sopenharmony_ci    CHECK_DEV_OPEN ((dev), (func_name));                                \
105141cc406Sopenharmony_ci    if (!(dev)->active)                                                 \
106141cc406Sopenharmony_ci      {                                                                 \
107141cc406Sopenharmony_ci        DBG (0, "%s: BUG: device %p not active\n", (func_name),         \
108141cc406Sopenharmony_ci               ((void *) dev));                                         \
109141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;                                       \
110141cc406Sopenharmony_ci      }                                                                 \
111141cc406Sopenharmony_ci   )                                                                    \
112141cc406Sopenharmony_ci  } while (SANE_FALSE)
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_ci#ifndef NDEBUG
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci/** Dump a request packet for debugging purposes.
118141cc406Sopenharmony_ci *
119141cc406Sopenharmony_ci * @param prefix String printed before the packet contents.
120141cc406Sopenharmony_ci * @param req    The request packet to be dumped.
121141cc406Sopenharmony_ci */
122141cc406Sopenharmony_cistatic void
123141cc406Sopenharmony_cidump_req (SANE_String_Const prefix, GT68xx_Packet req)
124141cc406Sopenharmony_ci{
125141cc406Sopenharmony_ci  int i;
126141cc406Sopenharmony_ci  char buf[GT68XX_PACKET_SIZE * 3 + 1];
127141cc406Sopenharmony_ci
128141cc406Sopenharmony_ci  for (i = 0; i < GT68XX_PACKET_SIZE; ++i)
129141cc406Sopenharmony_ci    sprintf (buf + i * 3, " %02x", req[i]);
130141cc406Sopenharmony_ci  DBG (8, "%s%s\n", prefix, buf);
131141cc406Sopenharmony_ci}
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci#endif /* not NDEBUG */
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_ci/** Dump a request packet if the debug level is at 8 or above.
136141cc406Sopenharmony_ci *
137141cc406Sopenharmony_ci * @param prefix String printed before the packet contents.
138141cc406Sopenharmony_ci * @param req    The request packet to be dumped.
139141cc406Sopenharmony_ci */
140141cc406Sopenharmony_ci#define DUMP_REQ(prefix, req) \
141141cc406Sopenharmony_ci  do { IF_DBG( if (DBG_LEVEL >= 8) dump_req ((prefix), (req)); ) } while (0)
142141cc406Sopenharmony_ci
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ciSANE_Status
145141cc406Sopenharmony_cigt68xx_device_new (GT68xx_Device ** dev_return)
146141cc406Sopenharmony_ci{
147141cc406Sopenharmony_ci  GT68xx_Device *dev;
148141cc406Sopenharmony_ci
149141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_new: enter\n");
150141cc406Sopenharmony_ci  if (!dev_return)
151141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci  dev = (GT68xx_Device *) malloc (sizeof (GT68xx_Device));
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_ci  if (!dev)
156141cc406Sopenharmony_ci    {
157141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_new: couldn't malloc %lu bytes for device\n",
158141cc406Sopenharmony_ci	   (u_long) sizeof (GT68xx_Device));
159141cc406Sopenharmony_ci      *dev_return = 0;
160141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
161141cc406Sopenharmony_ci    }
162141cc406Sopenharmony_ci  *dev_return = dev;
163141cc406Sopenharmony_ci
164141cc406Sopenharmony_ci  memset (dev, 0, sizeof (GT68xx_Device));
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci  dev->fd = -1;
167141cc406Sopenharmony_ci  dev->active = SANE_FALSE;
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci  dev->model = NULL;
170141cc406Sopenharmony_ci  dev->command_set_private = NULL;
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ci  dev->read_buffer = NULL;
173141cc406Sopenharmony_ci  dev->read_buffer_size = 32768;
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci  dev->manual_selection = SANE_FALSE;
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci  dev->scan_started = SANE_FALSE;
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci#ifdef USE_FORK
180141cc406Sopenharmony_ci  dev->shm_channel = NULL;
181141cc406Sopenharmony_ci#endif /* USE_FORK */
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_new:: leave: ok\n");
184141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
185141cc406Sopenharmony_ci}
186141cc406Sopenharmony_ci
187141cc406Sopenharmony_ciSANE_Status
188141cc406Sopenharmony_cigt68xx_device_free (GT68xx_Device * dev)
189141cc406Sopenharmony_ci{
190141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_free: enter: dev=%p\n", (void *) dev);
191141cc406Sopenharmony_ci  if (dev)
192141cc406Sopenharmony_ci    {
193141cc406Sopenharmony_ci      if (dev->active)
194141cc406Sopenharmony_ci	gt68xx_device_deactivate (dev);
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci      if (dev->fd != -1)
197141cc406Sopenharmony_ci	gt68xx_device_close (dev);
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_ci      if (dev->model && dev->model->allocated)
200141cc406Sopenharmony_ci	{
201141cc406Sopenharmony_ci	  DBG (7, "gt68xx_device_free: freeing model data %p\n",
202141cc406Sopenharmony_ci	       (void *) dev->model);
203141cc406Sopenharmony_ci	  free (dev->model);
204141cc406Sopenharmony_ci	}
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci      DBG (7, "gt68xx_device_free: freeing dev\n");
207141cc406Sopenharmony_ci      free (dev);
208141cc406Sopenharmony_ci    }
209141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_free: leave: ok\n");
210141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
211141cc406Sopenharmony_ci}
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_cistatic GT68xx_USB_Device_Entry *
214141cc406Sopenharmony_cigt68xx_find_usb_device_entry (SANE_Word vendor, SANE_Word product)
215141cc406Sopenharmony_ci{
216141cc406Sopenharmony_ci  GT68xx_USB_Device_Entry *entry;
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_ci  for (entry = gt68xx_usb_device_list; entry->model; ++entry)
219141cc406Sopenharmony_ci    {
220141cc406Sopenharmony_ci      if (vendor == entry->vendor && product == entry->product)
221141cc406Sopenharmony_ci	return entry;
222141cc406Sopenharmony_ci    }
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci  return NULL;
225141cc406Sopenharmony_ci}
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_cistatic SANE_Status
228141cc406Sopenharmony_cigt68xx_device_identify (GT68xx_Device * dev)
229141cc406Sopenharmony_ci{
230141cc406Sopenharmony_ci  SANE_Status status;
231141cc406Sopenharmony_ci  SANE_Word vendor, product;
232141cc406Sopenharmony_ci  GT68xx_USB_Device_Entry *entry;
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci  CHECK_DEV_OPEN (dev, "gt68xx_device_identify");
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_ci  status = sanei_usb_get_vendor_product (dev->fd, &vendor, &product);
237141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
238141cc406Sopenharmony_ci    {
239141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_identify: error getting USB id: %s\n",
240141cc406Sopenharmony_ci	   sane_strstatus (status));
241141cc406Sopenharmony_ci      return status;
242141cc406Sopenharmony_ci    }
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_ci  entry = gt68xx_find_usb_device_entry (vendor, product);
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci  if (entry)
247141cc406Sopenharmony_ci    {
248141cc406Sopenharmony_ci      dev->model = entry->model;
249141cc406Sopenharmony_ci    }
250141cc406Sopenharmony_ci  else
251141cc406Sopenharmony_ci    {
252141cc406Sopenharmony_ci      dev->model = NULL;
253141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_identify: unknown USB device (vendor 0x%04x, "
254141cc406Sopenharmony_ci	   "product 0x%04x)\n", vendor, product);
255141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
256141cc406Sopenharmony_ci    }
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
259141cc406Sopenharmony_ci}
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ciSANE_Status
262141cc406Sopenharmony_cigt68xx_device_open (GT68xx_Device * dev, const char *dev_name)
263141cc406Sopenharmony_ci{
264141cc406Sopenharmony_ci  SANE_Status status;
265141cc406Sopenharmony_ci  SANE_Int fd;
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_open: enter: dev=%p\n", (void *) dev);
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci  CHECK_DEV_NOT_NULL (dev, "gt68xx_device_open");
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci  if (dev->fd != -1)
272141cc406Sopenharmony_ci    {
273141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_open: device already open\n");
274141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
275141cc406Sopenharmony_ci    }
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci  status = sanei_usb_open (dev_name, &fd);
278141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
279141cc406Sopenharmony_ci    {
280141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_open: sanei_usb_open failed: %s\n",
281141cc406Sopenharmony_ci	   sane_strstatus (status));
282141cc406Sopenharmony_ci      return status;
283141cc406Sopenharmony_ci    }
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci  dev->fd = fd;
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci  if (!dev->model)
288141cc406Sopenharmony_ci    gt68xx_device_identify (dev);
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_open: leave: ok\n");
291141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
292141cc406Sopenharmony_ci}
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ciSANE_Status
295141cc406Sopenharmony_cigt68xx_device_close (GT68xx_Device * dev)
296141cc406Sopenharmony_ci{
297141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_close: enter: dev=%p\n", (void *) dev);
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci  CHECK_DEV_OPEN (dev, "gt68xx_device_close");
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci  if (dev->active)
302141cc406Sopenharmony_ci    gt68xx_device_deactivate (dev);
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci  sanei_usb_close (dev->fd);
305141cc406Sopenharmony_ci  dev->fd = -1;
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_close: leave: ok\n");
308141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
309141cc406Sopenharmony_ci}
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ciSANE_Bool
312141cc406Sopenharmony_cigt68xx_device_is_configured (GT68xx_Device * dev)
313141cc406Sopenharmony_ci{
314141cc406Sopenharmony_ci  if (dev && dev->model && dev->model->command_set)
315141cc406Sopenharmony_ci    return SANE_TRUE;
316141cc406Sopenharmony_ci  else
317141cc406Sopenharmony_ci    return SANE_FALSE;
318141cc406Sopenharmony_ci}
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ciSANE_Status
321141cc406Sopenharmony_cigt68xx_device_set_model (GT68xx_Device * dev, GT68xx_Model * model)
322141cc406Sopenharmony_ci{
323141cc406Sopenharmony_ci  if (dev->active)
324141cc406Sopenharmony_ci    {
325141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_set_model: device already active\n");
326141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
327141cc406Sopenharmony_ci    }
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci  if (dev->model && dev->model->allocated)
330141cc406Sopenharmony_ci    free (dev->model);
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci  dev->model = model;
333141cc406Sopenharmony_ci
334141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
335141cc406Sopenharmony_ci}
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_cistatic SANE_Bool
338141cc406Sopenharmony_cigt68xx_device_get_model (SANE_String name, GT68xx_Model ** model)
339141cc406Sopenharmony_ci{
340141cc406Sopenharmony_ci  GT68xx_USB_Device_Entry *entry;
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci  for (entry = gt68xx_usb_device_list; entry->model; ++entry)
343141cc406Sopenharmony_ci    {
344141cc406Sopenharmony_ci      if (strcmp (name, entry->model->name) == 0)
345141cc406Sopenharmony_ci	{
346141cc406Sopenharmony_ci	  *model = entry->model;
347141cc406Sopenharmony_ci	  return SANE_TRUE;
348141cc406Sopenharmony_ci	}
349141cc406Sopenharmony_ci    }
350141cc406Sopenharmony_ci  return SANE_FALSE;
351141cc406Sopenharmony_ci}
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ciSANE_Status
355141cc406Sopenharmony_cigt68xx_device_activate (GT68xx_Device * dev)
356141cc406Sopenharmony_ci{
357141cc406Sopenharmony_ci  SANE_Status status;
358141cc406Sopenharmony_ci  CHECK_DEV_OPEN (dev, "gt68xx_device_activate");
359141cc406Sopenharmony_ci  if (dev->active)
360141cc406Sopenharmony_ci    {
361141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_activate: device already active\n");
362141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
363141cc406Sopenharmony_ci    }
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci  if (!gt68xx_device_is_configured (dev))
366141cc406Sopenharmony_ci    {
367141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_activate: device is not configured\n");
368141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci
371141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_activate: model \"%s\"\n", dev->model->name);
372141cc406Sopenharmony_ci  if (dev->model->command_set->activate)
373141cc406Sopenharmony_ci    {
374141cc406Sopenharmony_ci      status = (*dev->model->command_set->activate) (dev);
375141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
376141cc406Sopenharmony_ci	{
377141cc406Sopenharmony_ci	  DBG (3, "gt68xx_device_activate: command-set-specific "
378141cc406Sopenharmony_ci	       "activate failed: %s\n", sane_strstatus (status));
379141cc406Sopenharmony_ci	  return status;
380141cc406Sopenharmony_ci	}
381141cc406Sopenharmony_ci    }
382141cc406Sopenharmony_ci  dev->afe = malloc (sizeof (*dev->afe));
383141cc406Sopenharmony_ci  dev->exposure = malloc (sizeof (*dev->exposure));
384141cc406Sopenharmony_ci  if (!dev->afe || !dev->exposure)
385141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
386141cc406Sopenharmony_ci  memcpy (dev->afe, &dev->model->afe_params, sizeof (*dev->afe));
387141cc406Sopenharmony_ci  memcpy (dev->exposure, &dev->model->exposure, sizeof (*dev->exposure));
388141cc406Sopenharmony_ci  dev->gamma_value = dev->model->default_gamma_value;
389141cc406Sopenharmony_ci  dev->active = SANE_TRUE;
390141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
391141cc406Sopenharmony_ci}
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ciSANE_Status
394141cc406Sopenharmony_cigt68xx_device_deactivate (GT68xx_Device * dev)
395141cc406Sopenharmony_ci{
396141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
397141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_deactivate");
398141cc406Sopenharmony_ci  if (dev->read_active)
399141cc406Sopenharmony_ci    gt68xx_device_read_finish (dev);
400141cc406Sopenharmony_ci  if (dev->model->command_set->deactivate)
401141cc406Sopenharmony_ci    {
402141cc406Sopenharmony_ci      status = (*dev->model->command_set->deactivate) (dev);
403141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
404141cc406Sopenharmony_ci	{
405141cc406Sopenharmony_ci	  DBG (3,
406141cc406Sopenharmony_ci	       "gt68xx_device_deactivate: command set-specific deactivate failed: %s\n",
407141cc406Sopenharmony_ci	       sane_strstatus (status));
408141cc406Sopenharmony_ci	  /* proceed with deactivate anyway */
409141cc406Sopenharmony_ci	}
410141cc406Sopenharmony_ci    }
411141cc406Sopenharmony_ci  if (dev->afe)
412141cc406Sopenharmony_ci    free (dev->afe);
413141cc406Sopenharmony_ci  dev->afe = 0;
414141cc406Sopenharmony_ci  if (dev->exposure)
415141cc406Sopenharmony_ci    free (dev->exposure);
416141cc406Sopenharmony_ci  dev->exposure = 0;
417141cc406Sopenharmony_ci  dev->active = SANE_FALSE;
418141cc406Sopenharmony_ci  return status;
419141cc406Sopenharmony_ci}
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ciSANE_Status
422141cc406Sopenharmony_cigt68xx_device_memory_write (GT68xx_Device * dev,
423141cc406Sopenharmony_ci			    SANE_Word addr, SANE_Word size, SANE_Byte * data)
424141cc406Sopenharmony_ci{
425141cc406Sopenharmony_ci  SANE_Status status;
426141cc406Sopenharmony_ci  DBG (8,
427141cc406Sopenharmony_ci       "gt68xx_device_memory_write: dev=%p, addr=0x%x, size=0x%x, data=%p\n",
428141cc406Sopenharmony_ci       (void *) dev, addr, size, (void *) data);
429141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_memory_write");
430141cc406Sopenharmony_ci  status =
431141cc406Sopenharmony_ci    sanei_usb_control_msg (dev->fd, 0x40,
432141cc406Sopenharmony_ci			   dev->model->command_set->request,
433141cc406Sopenharmony_ci			   dev->model->command_set->memory_write_value,
434141cc406Sopenharmony_ci			   addr, size, data);
435141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
436141cc406Sopenharmony_ci    {
437141cc406Sopenharmony_ci      DBG (3,
438141cc406Sopenharmony_ci	   "gt68xx_device_memory_write: sanei_usb_control_msg failed: %s\n",
439141cc406Sopenharmony_ci	   sane_strstatus (status));
440141cc406Sopenharmony_ci    }
441141cc406Sopenharmony_ci  return status;
442141cc406Sopenharmony_ci}
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ciSANE_Status
445141cc406Sopenharmony_cigt68xx_device_memory_read (GT68xx_Device * dev,
446141cc406Sopenharmony_ci			   SANE_Word addr, SANE_Word size, SANE_Byte * data)
447141cc406Sopenharmony_ci{
448141cc406Sopenharmony_ci  SANE_Status status;
449141cc406Sopenharmony_ci  DBG (8,
450141cc406Sopenharmony_ci       "gt68xx_device_memory_read: dev=%p, addr=0x%x, size=0x%x, data=%p\n",
451141cc406Sopenharmony_ci       (void *) dev, addr, size, (void *) data);
452141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_memory_read");
453141cc406Sopenharmony_ci  status =
454141cc406Sopenharmony_ci    sanei_usb_control_msg (dev->fd, 0xc0,
455141cc406Sopenharmony_ci			   dev->model->command_set->request,
456141cc406Sopenharmony_ci			   dev->model->command_set->memory_read_value,
457141cc406Sopenharmony_ci			   addr, size, data);
458141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
459141cc406Sopenharmony_ci    {
460141cc406Sopenharmony_ci      DBG (3,
461141cc406Sopenharmony_ci	   "gt68xx_device_memory_read: sanei_usb_control_msg failed: %s\n",
462141cc406Sopenharmony_ci	   sane_strstatus (status));
463141cc406Sopenharmony_ci    }
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci  return status;
466141cc406Sopenharmony_ci}
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_cistatic SANE_Status
469141cc406Sopenharmony_cigt68xx_device_generic_req (GT68xx_Device * dev,
470141cc406Sopenharmony_ci			   SANE_Byte request_type, SANE_Word request,
471141cc406Sopenharmony_ci			   SANE_Word cmd_value, SANE_Word cmd_index,
472141cc406Sopenharmony_ci			   SANE_Word res_value, SANE_Word res_index,
473141cc406Sopenharmony_ci			   GT68xx_Packet cmd, GT68xx_Packet res,
474141cc406Sopenharmony_ci			   size_t res_size)
475141cc406Sopenharmony_ci{
476141cc406Sopenharmony_ci  SANE_Status status;
477141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_generic_req: command=0x%02x\n", cmd[0]);
478141cc406Sopenharmony_ci  DUMP_REQ (">>", cmd);
479141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_generic_req");
480141cc406Sopenharmony_ci  status = sanei_usb_control_msg (dev->fd,
481141cc406Sopenharmony_ci				  request_type, request, cmd_value,
482141cc406Sopenharmony_ci				  cmd_index, GT68XX_PACKET_SIZE, cmd);
483141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
484141cc406Sopenharmony_ci    {
485141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_generic_req: writing command failed: %s\n",
486141cc406Sopenharmony_ci	   sane_strstatus (status));
487141cc406Sopenharmony_ci      return status;
488141cc406Sopenharmony_ci    }
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci  memset (res, 0, sizeof (GT68xx_Packet));
491141cc406Sopenharmony_ci  status = sanei_usb_control_msg (dev->fd,
492141cc406Sopenharmony_ci				  request_type | 0x80, request,
493141cc406Sopenharmony_ci				  res_value, res_index, res_size, res);
494141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
495141cc406Sopenharmony_ci    {
496141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_generic_req: reading response failed: %s\n",
497141cc406Sopenharmony_ci	   sane_strstatus (status));
498141cc406Sopenharmony_ci      return status;
499141cc406Sopenharmony_ci    }
500141cc406Sopenharmony_ci
501141cc406Sopenharmony_ci  DUMP_REQ ("<<", res);
502141cc406Sopenharmony_ci  return status;
503141cc406Sopenharmony_ci}
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ciSANE_Status
506141cc406Sopenharmony_cigt68xx_device_req (GT68xx_Device * dev, GT68xx_Packet cmd, GT68xx_Packet res)
507141cc406Sopenharmony_ci{
508141cc406Sopenharmony_ci  GT68xx_Command_Set *command_set = dev->model->command_set;
509141cc406Sopenharmony_ci  return gt68xx_device_generic_req (dev,
510141cc406Sopenharmony_ci				    command_set->request_type,
511141cc406Sopenharmony_ci				    command_set->request,
512141cc406Sopenharmony_ci				    command_set->send_cmd_value,
513141cc406Sopenharmony_ci				    command_set->send_cmd_index,
514141cc406Sopenharmony_ci				    command_set->recv_res_value,
515141cc406Sopenharmony_ci				    command_set->recv_res_index, cmd,
516141cc406Sopenharmony_ci				    res, GT68XX_PACKET_SIZE);
517141cc406Sopenharmony_ci}
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ciSANE_Status
520141cc406Sopenharmony_cigt68xx_device_small_req (GT68xx_Device * dev, GT68xx_Packet cmd,
521141cc406Sopenharmony_ci			 GT68xx_Packet res)
522141cc406Sopenharmony_ci{
523141cc406Sopenharmony_ci  GT68xx_Command_Set *command_set = dev->model->command_set;
524141cc406Sopenharmony_ci  GT68xx_Packet fixed_cmd;
525141cc406Sopenharmony_ci  int i;
526141cc406Sopenharmony_ci  for (i = 0; i < 8; ++i)
527141cc406Sopenharmony_ci    memcpy (fixed_cmd + i * 8, cmd, 8);
528141cc406Sopenharmony_ci  return gt68xx_device_generic_req (dev,
529141cc406Sopenharmony_ci				    command_set->request_type,
530141cc406Sopenharmony_ci				    command_set->request,
531141cc406Sopenharmony_ci				    command_set->send_small_cmd_value,
532141cc406Sopenharmony_ci				    command_set->send_small_cmd_index,
533141cc406Sopenharmony_ci				    command_set->recv_small_res_value,
534141cc406Sopenharmony_ci				    command_set->recv_small_res_index,
535141cc406Sopenharmony_ci				    fixed_cmd, res, 0x08);
536141cc406Sopenharmony_ci}
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_ciSANE_Status
540141cc406Sopenharmony_cigt68xx_device_download_firmware (GT68xx_Device * dev,
541141cc406Sopenharmony_ci				 SANE_Byte * data, SANE_Word size)
542141cc406Sopenharmony_ci{
543141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_download_firmware");
544141cc406Sopenharmony_ci  if (dev->model->command_set->download_firmware)
545141cc406Sopenharmony_ci    return (*dev->model->command_set->download_firmware) (dev, data, size);
546141cc406Sopenharmony_ci  else
547141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
548141cc406Sopenharmony_ci}
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ciSANE_Status
551141cc406Sopenharmony_cigt68xx_device_get_power_status (GT68xx_Device * dev, SANE_Bool * power_ok)
552141cc406Sopenharmony_ci{
553141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_get_power_status");
554141cc406Sopenharmony_ci  if (dev->model->command_set->get_power_status)
555141cc406Sopenharmony_ci    return (*dev->model->command_set->get_power_status) (dev, power_ok);
556141cc406Sopenharmony_ci  else
557141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
558141cc406Sopenharmony_ci}
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ciSANE_Status
561141cc406Sopenharmony_cigt68xx_device_get_ta_status (GT68xx_Device * dev, SANE_Bool * ta_attached)
562141cc406Sopenharmony_ci{
563141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_get_ta_status");
564141cc406Sopenharmony_ci  if (dev->model->command_set->get_ta_status)
565141cc406Sopenharmony_ci    return (*dev->model->command_set->get_ta_status) (dev, ta_attached);
566141cc406Sopenharmony_ci  else
567141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
568141cc406Sopenharmony_ci}
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ciSANE_Status
571141cc406Sopenharmony_cigt68xx_device_lamp_control (GT68xx_Device * dev, SANE_Bool fb_lamp,
572141cc406Sopenharmony_ci			    SANE_Bool ta_lamp)
573141cc406Sopenharmony_ci{
574141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_lamp_control");
575141cc406Sopenharmony_ci  if (dev->model->command_set->lamp_control)
576141cc406Sopenharmony_ci    return (*dev->model->command_set->lamp_control) (dev, fb_lamp, ta_lamp);
577141cc406Sopenharmony_ci  else
578141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
579141cc406Sopenharmony_ci}
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ciSANE_Status
582141cc406Sopenharmony_cigt68xx_device_is_moving (GT68xx_Device * dev, SANE_Bool * moving)
583141cc406Sopenharmony_ci{
584141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_is_moving");
585141cc406Sopenharmony_ci  if (dev->model->command_set->is_moving)
586141cc406Sopenharmony_ci    return (*dev->model->command_set->is_moving) (dev, moving);
587141cc406Sopenharmony_ci  else
588141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
589141cc406Sopenharmony_ci}
590141cc406Sopenharmony_ci
591141cc406Sopenharmony_ci/* currently not used */
592141cc406Sopenharmony_ci#if 0
593141cc406Sopenharmony_cistatic SANE_Status
594141cc406Sopenharmony_cigt68xx_device_move_relative (GT68xx_Device * dev, SANE_Int distance)
595141cc406Sopenharmony_ci{
596141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_move_relative");
597141cc406Sopenharmony_ci  if (dev->model->command_set->move_relative)
598141cc406Sopenharmony_ci    return (*dev->model->command_set->move_relative) (dev, distance);
599141cc406Sopenharmony_ci  else
600141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
601141cc406Sopenharmony_ci}
602141cc406Sopenharmony_ci#endif
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ciSANE_Status
605141cc406Sopenharmony_cigt68xx_device_carriage_home (GT68xx_Device * dev)
606141cc406Sopenharmony_ci{
607141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_carriage_home");
608141cc406Sopenharmony_ci  if (dev->model->command_set->carriage_home)
609141cc406Sopenharmony_ci    return (*dev->model->command_set->carriage_home) (dev);
610141cc406Sopenharmony_ci  else
611141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
612141cc406Sopenharmony_ci}
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ciSANE_Status
615141cc406Sopenharmony_cigt68xx_device_paperfeed (GT68xx_Device * dev)
616141cc406Sopenharmony_ci{
617141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_paperfeed");
618141cc406Sopenharmony_ci  if (dev->model->command_set->paperfeed)
619141cc406Sopenharmony_ci    return (*dev->model->command_set->paperfeed) (dev);
620141cc406Sopenharmony_ci  else
621141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
622141cc406Sopenharmony_ci}
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ciSANE_Status
625141cc406Sopenharmony_cigt68xx_device_start_scan (GT68xx_Device * dev)
626141cc406Sopenharmony_ci{
627141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_start_scan");
628141cc406Sopenharmony_ci  if (dev->model->command_set->start_scan)
629141cc406Sopenharmony_ci    {
630141cc406Sopenharmony_ci      if (!dev->scan_started)
631141cc406Sopenharmony_ci        {
632141cc406Sopenharmony_ci          dev->scan_started = SANE_TRUE;
633141cc406Sopenharmony_ci          return (*dev->model->command_set->start_scan) (dev);
634141cc406Sopenharmony_ci        }
635141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
636141cc406Sopenharmony_ci    }
637141cc406Sopenharmony_ci  else
638141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
639141cc406Sopenharmony_ci}
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_ciSANE_Status
642141cc406Sopenharmony_cigt68xx_device_read_scanned_data (GT68xx_Device * dev, SANE_Bool * ready)
643141cc406Sopenharmony_ci{
644141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_scanned_data");
645141cc406Sopenharmony_ci  if (dev->model->command_set->read_scanned_data)
646141cc406Sopenharmony_ci    return (*dev->model->command_set->read_scanned_data) (dev, ready);
647141cc406Sopenharmony_ci  else
648141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
649141cc406Sopenharmony_ci}
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ciSANE_Status
652141cc406Sopenharmony_cigt68xx_device_setup_scan (GT68xx_Device * dev,
653141cc406Sopenharmony_ci			  GT68xx_Scan_Request * request,
654141cc406Sopenharmony_ci			  GT68xx_Scan_Action action,
655141cc406Sopenharmony_ci			  GT68xx_Scan_Parameters * params)
656141cc406Sopenharmony_ci{
657141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_setup_scan");
658141cc406Sopenharmony_ci  if (dev->model->command_set->setup_scan)
659141cc406Sopenharmony_ci    return (*dev->model->command_set->setup_scan) (dev, request, action,
660141cc406Sopenharmony_ci						   params);
661141cc406Sopenharmony_ci  else
662141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
663141cc406Sopenharmony_ci}
664141cc406Sopenharmony_ci
665141cc406Sopenharmony_ciSANE_Status
666141cc406Sopenharmony_cigt68xx_device_set_afe (GT68xx_Device * dev, GT68xx_AFE_Parameters * params)
667141cc406Sopenharmony_ci{
668141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_set_afe");
669141cc406Sopenharmony_ci  if (dev->model->command_set->set_afe)
670141cc406Sopenharmony_ci    return (*dev->model->command_set->set_afe) (dev, params);
671141cc406Sopenharmony_ci  else
672141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
673141cc406Sopenharmony_ci}
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ciSANE_Status
676141cc406Sopenharmony_cigt68xx_device_set_exposure_time (GT68xx_Device * dev,
677141cc406Sopenharmony_ci				 GT68xx_Exposure_Parameters * params)
678141cc406Sopenharmony_ci{
679141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_set_exposure_time");
680141cc406Sopenharmony_ci  if (dev->model->command_set->set_exposure_time)
681141cc406Sopenharmony_ci    return (*dev->model->command_set->set_exposure_time) (dev, params);
682141cc406Sopenharmony_ci  else
683141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
684141cc406Sopenharmony_ci}
685141cc406Sopenharmony_ci
686141cc406Sopenharmony_ciSANE_Status
687141cc406Sopenharmony_cigt68xx_device_stop_scan (GT68xx_Device * dev)
688141cc406Sopenharmony_ci{
689141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_stop_scan");
690141cc406Sopenharmony_ci  if (dev->model->command_set->stop_scan)
691141cc406Sopenharmony_ci    {
692141cc406Sopenharmony_ci      if (dev->scan_started)
693141cc406Sopenharmony_ci        {
694141cc406Sopenharmony_ci          dev->scan_started = SANE_FALSE;
695141cc406Sopenharmony_ci          return (*dev->model->command_set->stop_scan) (dev);
696141cc406Sopenharmony_ci        }
697141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;  // Essentially a NOP.
698141cc406Sopenharmony_ci    }
699141cc406Sopenharmony_ci  else
700141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
701141cc406Sopenharmony_ci}
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ciSANE_Status
704141cc406Sopenharmony_cigt68xx_device_read_raw (GT68xx_Device * dev, SANE_Byte * buffer,
705141cc406Sopenharmony_ci			size_t * size)
706141cc406Sopenharmony_ci{
707141cc406Sopenharmony_ci  SANE_Status status;
708141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_raw");
709141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_read_raw: enter: size=%lu\n", (unsigned long) *size);
710141cc406Sopenharmony_ci  status = sanei_usb_read_bulk (dev->fd, buffer, size);
711141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
712141cc406Sopenharmony_ci    {
713141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_read_raw: bulk read failed: %s\n",
714141cc406Sopenharmony_ci	   sane_strstatus (status));
715141cc406Sopenharmony_ci      return status;
716141cc406Sopenharmony_ci    }
717141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_read_raw: leave: size=%lu\n", (unsigned long) *size);
718141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
719141cc406Sopenharmony_ci}
720141cc406Sopenharmony_ci
721141cc406Sopenharmony_ciSANE_Status
722141cc406Sopenharmony_cigt68xx_device_set_read_buffer_size (GT68xx_Device * dev, size_t buffer_size)
723141cc406Sopenharmony_ci{
724141cc406Sopenharmony_ci  CHECK_DEV_NOT_NULL (dev, "gt68xx_device_set_read_buffer_size");
725141cc406Sopenharmony_ci  if (dev->read_active)
726141cc406Sopenharmony_ci    {
727141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_set_read_buffer_size: BUG: read already "
728141cc406Sopenharmony_ci	   "active\n");
729141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
730141cc406Sopenharmony_ci    }
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci  buffer_size = (buffer_size + 63UL) & ~63UL;
733141cc406Sopenharmony_ci  if (buffer_size > 0)
734141cc406Sopenharmony_ci    {
735141cc406Sopenharmony_ci      dev->requested_buffer_size = buffer_size;
736141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
737141cc406Sopenharmony_ci    }
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci  DBG (3, "gt68xx_device_set_read_buffer_size: bad buffer size\n");
740141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
741141cc406Sopenharmony_ci}
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ciSANE_Status
744141cc406Sopenharmony_cigt68xx_device_read_prepare (GT68xx_Device * dev,
745141cc406Sopenharmony_ci			    size_t expected_count, SANE_Bool final_scan)
746141cc406Sopenharmony_ci{
747141cc406Sopenharmony_ci  size_t buffer_size;
748141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_prepare");
749141cc406Sopenharmony_ci  if (dev->read_active)
750141cc406Sopenharmony_ci    {
751141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_read_prepare: read already active\n");
752141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
753141cc406Sopenharmony_ci    }
754141cc406Sopenharmony_ci  DBG (5, "gt68xx_device_read_prepare: total size: %lu bytes\n",
755141cc406Sopenharmony_ci       (unsigned long) expected_count);
756141cc406Sopenharmony_ci  buffer_size = dev->requested_buffer_size;
757141cc406Sopenharmony_ci  DBG (5, "gt68xx_device_read_prepare: requested buffer size: %lu\n",
758141cc406Sopenharmony_ci       (unsigned long) buffer_size);
759141cc406Sopenharmony_ci  if (buffer_size > expected_count)
760141cc406Sopenharmony_ci    {
761141cc406Sopenharmony_ci      buffer_size = (expected_count + 63UL) & ~63UL;
762141cc406Sopenharmony_ci    }
763141cc406Sopenharmony_ci  DBG (5, "gt68xx_device_read_prepare: real size: %lu\n",
764141cc406Sopenharmony_ci       (unsigned long) buffer_size);
765141cc406Sopenharmony_ci  dev->read_buffer_size = buffer_size;
766141cc406Sopenharmony_ci  dev->read_buffer = (SANE_Byte *) malloc (buffer_size);
767141cc406Sopenharmony_ci  if (!dev->read_buffer)
768141cc406Sopenharmony_ci    {
769141cc406Sopenharmony_ci      DBG (3,
770141cc406Sopenharmony_ci	   "gt68xx_device_read_prepare: not enough memory for the read buffer (%lu bytes)\n",
771141cc406Sopenharmony_ci	   (unsigned long) buffer_size);
772141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
773141cc406Sopenharmony_ci    }
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci  dev->read_active = SANE_TRUE;
776141cc406Sopenharmony_ci  dev->final_scan = final_scan;
777141cc406Sopenharmony_ci  dev->read_pos = dev->read_bytes_in_buffer = 0;
778141cc406Sopenharmony_ci  dev->read_bytes_left = expected_count;
779141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
780141cc406Sopenharmony_ci}
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci#ifdef USE_FORK
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_cistatic SANE_Status
785141cc406Sopenharmony_cigt68xx_reader_process (GT68xx_Device * dev)
786141cc406Sopenharmony_ci{
787141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
788141cc406Sopenharmony_ci  SANE_Int buffer_id;
789141cc406Sopenharmony_ci  SANE_Byte *buffer_addr;
790141cc406Sopenharmony_ci  size_t size;
791141cc406Sopenharmony_ci  SANE_Int line = 0;
792141cc406Sopenharmony_ci  size_t read_bytes_left = dev->read_bytes_left;
793141cc406Sopenharmony_ci  shm_channel_writer_init (dev->shm_channel);
794141cc406Sopenharmony_ci  while (read_bytes_left > 0)
795141cc406Sopenharmony_ci    {
796141cc406Sopenharmony_ci      status = shm_channel_writer_get_buffer (dev->shm_channel,
797141cc406Sopenharmony_ci					      &buffer_id, &buffer_addr);
798141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
799141cc406Sopenharmony_ci	break;
800141cc406Sopenharmony_ci      DBG (9, "gt68xx_reader_process: buffer %d: get\n", buffer_id);
801141cc406Sopenharmony_ci      size = dev->read_buffer_size;
802141cc406Sopenharmony_ci      DBG (9, "gt68xx_reader_process: buffer %d: trying to read %lu bytes "
803141cc406Sopenharmony_ci	   "(%lu bytes left, line %d)\n", buffer_id, (unsigned long) size,
804141cc406Sopenharmony_ci	   (unsigned long) read_bytes_left, line);
805141cc406Sopenharmony_ci      status = gt68xx_device_read_raw (dev, buffer_addr, &size);
806141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
807141cc406Sopenharmony_ci	break;
808141cc406Sopenharmony_ci      DBG (9,
809141cc406Sopenharmony_ci	   "gt68xx_reader_process: buffer %d: read %lu bytes (line %d)\n",
810141cc406Sopenharmony_ci	   buffer_id, (unsigned long) size, line);
811141cc406Sopenharmony_ci      status =
812141cc406Sopenharmony_ci	shm_channel_writer_put_buffer (dev->shm_channel, buffer_id, size);
813141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
814141cc406Sopenharmony_ci	break;
815141cc406Sopenharmony_ci      DBG (9, "gt68xx_reader_process: buffer %d: put\n", buffer_id);
816141cc406Sopenharmony_ci      read_bytes_left -= size;
817141cc406Sopenharmony_ci      line++;
818141cc406Sopenharmony_ci    }
819141cc406Sopenharmony_ci  DBG (9, "gt68xx_reader_process: finished, now sleeping\n");
820141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
821141cc406Sopenharmony_ci    return status;
822141cc406Sopenharmony_ci  sleep (5 * 60);		/* wait until we are killed (or timeout) */
823141cc406Sopenharmony_ci  shm_channel_writer_close (dev->shm_channel);
824141cc406Sopenharmony_ci  return status;
825141cc406Sopenharmony_ci}
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_cistatic SANE_Status
828141cc406Sopenharmony_cigt68xx_device_read_start_fork (GT68xx_Device * dev)
829141cc406Sopenharmony_ci{
830141cc406Sopenharmony_ci  SANE_Status status;
831141cc406Sopenharmony_ci  int pid;
832141cc406Sopenharmony_ci  if (dev->shm_channel)
833141cc406Sopenharmony_ci    {
834141cc406Sopenharmony_ci      DBG (3,
835141cc406Sopenharmony_ci	   "gt68xx_device_read_start_fork: BUG: shm_channel already created\n");
836141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
837141cc406Sopenharmony_ci    }
838141cc406Sopenharmony_ci
839141cc406Sopenharmony_ci  status =
840141cc406Sopenharmony_ci    shm_channel_new (dev->read_buffer_size, SHM_BUFFERS, &dev->shm_channel);
841141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
842141cc406Sopenharmony_ci    {
843141cc406Sopenharmony_ci      DBG (3,
844141cc406Sopenharmony_ci	   "gt68xx_device_read_start_fork: cannot create shared memory channel: "
845141cc406Sopenharmony_ci	   "%s\n", sane_strstatus (status));
846141cc406Sopenharmony_ci      dev->shm_channel = NULL;
847141cc406Sopenharmony_ci      return status;
848141cc406Sopenharmony_ci    }
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci  pid = fork ();
851141cc406Sopenharmony_ci  if (pid == -1)
852141cc406Sopenharmony_ci    {
853141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_read_start_fork: cannot fork: %s\n",
854141cc406Sopenharmony_ci	   strerror (errno));
855141cc406Sopenharmony_ci      shm_channel_free (dev->shm_channel);
856141cc406Sopenharmony_ci      dev->shm_channel = NULL;
857141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
858141cc406Sopenharmony_ci    }
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci  if (pid == 0)
861141cc406Sopenharmony_ci    {
862141cc406Sopenharmony_ci      /* Child process */
863141cc406Sopenharmony_ci      status = gt68xx_reader_process (dev);
864141cc406Sopenharmony_ci      _exit (status);
865141cc406Sopenharmony_ci    }
866141cc406Sopenharmony_ci  else
867141cc406Sopenharmony_ci    {
868141cc406Sopenharmony_ci      /* Parent process */
869141cc406Sopenharmony_ci      dev->reader_pid = pid;
870141cc406Sopenharmony_ci      shm_channel_reader_init (dev->shm_channel);
871141cc406Sopenharmony_ci      shm_channel_reader_start (dev->shm_channel);
872141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
873141cc406Sopenharmony_ci    }
874141cc406Sopenharmony_ci}
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_ci#endif /* USE_FORK */
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_cistatic SANE_Status
880141cc406Sopenharmony_cigt68xx_device_read_start (GT68xx_Device * dev)
881141cc406Sopenharmony_ci{
882141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_start");
883141cc406Sopenharmony_ci#ifdef USE_FORK
884141cc406Sopenharmony_ci  /* Don't fork a separate process for every calibration scan. */
885141cc406Sopenharmony_ci  if (dev->final_scan)
886141cc406Sopenharmony_ci    return gt68xx_device_read_start_fork (dev);
887141cc406Sopenharmony_ci#endif /* USE_FORK */
888141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
889141cc406Sopenharmony_ci}
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ciSANE_Status
892141cc406Sopenharmony_cigt68xx_device_read (GT68xx_Device * dev, SANE_Byte * buffer, size_t * size)
893141cc406Sopenharmony_ci{
894141cc406Sopenharmony_ci  SANE_Status status;
895141cc406Sopenharmony_ci  size_t byte_count = 0;
896141cc406Sopenharmony_ci  size_t left_to_read = *size;
897141cc406Sopenharmony_ci  size_t transfer_size, block_size, raw_block_size;
898141cc406Sopenharmony_ci#ifdef USE_FORK
899141cc406Sopenharmony_ci  SANE_Int buffer_id;
900141cc406Sopenharmony_ci  SANE_Byte *buffer_addr;
901141cc406Sopenharmony_ci  SANE_Int buffer_bytes;
902141cc406Sopenharmony_ci#endif /* USE_FORK */
903141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_read");
904141cc406Sopenharmony_ci  if (!dev->read_active)
905141cc406Sopenharmony_ci    {
906141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_read: read not active\n");
907141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
908141cc406Sopenharmony_ci    }
909141cc406Sopenharmony_ci
910141cc406Sopenharmony_ci  while (left_to_read > 0)
911141cc406Sopenharmony_ci    {
912141cc406Sopenharmony_ci      if (dev->read_bytes_in_buffer == 0)
913141cc406Sopenharmony_ci	{
914141cc406Sopenharmony_ci	  block_size = dev->read_buffer_size;
915141cc406Sopenharmony_ci	  if (block_size > dev->read_bytes_left)
916141cc406Sopenharmony_ci	    block_size = dev->read_bytes_left;
917141cc406Sopenharmony_ci	  if (block_size == 0)
918141cc406Sopenharmony_ci	    break;
919141cc406Sopenharmony_ci	  raw_block_size = (block_size + 63UL) & ~63UL;
920141cc406Sopenharmony_ci	  DBG (7, "gt68xx_device_read: trying to read %ld bytes\n",
921141cc406Sopenharmony_ci	       (long) raw_block_size);
922141cc406Sopenharmony_ci#ifdef USE_FORK
923141cc406Sopenharmony_ci	  if (dev->shm_channel)
924141cc406Sopenharmony_ci	    {
925141cc406Sopenharmony_ci	      status = shm_channel_reader_get_buffer (dev->shm_channel,
926141cc406Sopenharmony_ci						      &buffer_id,
927141cc406Sopenharmony_ci						      &buffer_addr,
928141cc406Sopenharmony_ci						      &buffer_bytes);
929141cc406Sopenharmony_ci	      if (status == SANE_STATUS_GOOD && buffer_addr != NULL)
930141cc406Sopenharmony_ci		{
931141cc406Sopenharmony_ci		  DBG (9, "gt68xx_device_read: buffer %d: get\n", buffer_id);
932141cc406Sopenharmony_ci		  memcpy (dev->read_buffer, buffer_addr, buffer_bytes);
933141cc406Sopenharmony_ci		  shm_channel_reader_put_buffer (dev->shm_channel, buffer_id);
934141cc406Sopenharmony_ci		  DBG (9, "gt68xx_device_read: buffer %d: put\n", buffer_id);
935141cc406Sopenharmony_ci		}
936141cc406Sopenharmony_ci	    }
937141cc406Sopenharmony_ci	  else
938141cc406Sopenharmony_ci#endif /* USE_FORK */
939141cc406Sopenharmony_ci	    status = gt68xx_device_read_raw (dev, dev->read_buffer,
940141cc406Sopenharmony_ci					     &raw_block_size);
941141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
942141cc406Sopenharmony_ci	    {
943141cc406Sopenharmony_ci	      DBG (3, "gt68xx_device_read: read failed\n");
944141cc406Sopenharmony_ci	      return status;
945141cc406Sopenharmony_ci	    }
946141cc406Sopenharmony_ci	  dev->read_pos = 0;
947141cc406Sopenharmony_ci	  dev->read_bytes_in_buffer = block_size;
948141cc406Sopenharmony_ci	  dev->read_bytes_left -= block_size;
949141cc406Sopenharmony_ci	}
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci      transfer_size = left_to_read;
952141cc406Sopenharmony_ci      if (transfer_size > dev->read_bytes_in_buffer)
953141cc406Sopenharmony_ci	transfer_size = dev->read_bytes_in_buffer;
954141cc406Sopenharmony_ci      if (transfer_size > 0)
955141cc406Sopenharmony_ci	{
956141cc406Sopenharmony_ci	  memcpy (buffer, dev->read_buffer + dev->read_pos, transfer_size);
957141cc406Sopenharmony_ci	  dev->read_pos += transfer_size;
958141cc406Sopenharmony_ci	  dev->read_bytes_in_buffer -= transfer_size;
959141cc406Sopenharmony_ci	  byte_count += transfer_size;
960141cc406Sopenharmony_ci	  left_to_read -= transfer_size;
961141cc406Sopenharmony_ci	  buffer += transfer_size;
962141cc406Sopenharmony_ci	}
963141cc406Sopenharmony_ci    }
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci  *size = byte_count;
966141cc406Sopenharmony_ci  if (byte_count == 0)
967141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
968141cc406Sopenharmony_ci  else
969141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
970141cc406Sopenharmony_ci}
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ciSANE_Status
973141cc406Sopenharmony_cigt68xx_device_read_finish (GT68xx_Device * dev)
974141cc406Sopenharmony_ci{
975141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
976141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_finish");
977141cc406Sopenharmony_ci  if (!dev->read_active)
978141cc406Sopenharmony_ci    {
979141cc406Sopenharmony_ci      DBG (3, "gt68xx_device_read_finish: read not active\n");
980141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
981141cc406Sopenharmony_ci    }
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_read_finish: read_bytes_left = %ld\n",
984141cc406Sopenharmony_ci       (long) dev->read_bytes_left);
985141cc406Sopenharmony_ci#ifdef USE_FORK
986141cc406Sopenharmony_ci  if (dev->reader_pid != 0)
987141cc406Sopenharmony_ci    {
988141cc406Sopenharmony_ci      int pid_status;
989141cc406Sopenharmony_ci      /* usleep (100000); */
990141cc406Sopenharmony_ci      DBG (7, "gt68xx_device_read_finish: trying to kill reader process\n");
991141cc406Sopenharmony_ci      kill (dev->reader_pid, SIGKILL);
992141cc406Sopenharmony_ci      waitpid (dev->reader_pid, &pid_status, 0);
993141cc406Sopenharmony_ci      if (WIFEXITED (pid_status))
994141cc406Sopenharmony_ci	status = WEXITSTATUS (pid_status);
995141cc406Sopenharmony_ci      DBG (7, "gt68xx_device_read_finish: reader process killed\n");
996141cc406Sopenharmony_ci      dev->reader_pid = 0;
997141cc406Sopenharmony_ci    }
998141cc406Sopenharmony_ci  if (dev->shm_channel)
999141cc406Sopenharmony_ci    {
1000141cc406Sopenharmony_ci      shm_channel_free (dev->shm_channel);
1001141cc406Sopenharmony_ci      dev->shm_channel = NULL;
1002141cc406Sopenharmony_ci    }
1003141cc406Sopenharmony_ci
1004141cc406Sopenharmony_ci#endif /* USE_FORK */
1005141cc406Sopenharmony_ci
1006141cc406Sopenharmony_ci  free (dev->read_buffer);
1007141cc406Sopenharmony_ci  dev->read_buffer = NULL;
1008141cc406Sopenharmony_ci  dev->read_active = SANE_FALSE;
1009141cc406Sopenharmony_ci  DBG (7, "gt68xx_device_read_finish: exit (%s)\n", sane_strstatus (status));
1010141cc406Sopenharmony_ci  return status;
1011141cc406Sopenharmony_ci}
1012141cc406Sopenharmony_ci
1013141cc406Sopenharmony_cistatic SANE_Status
1014141cc406Sopenharmony_cigt68xx_device_check_result (GT68xx_Packet res, SANE_Byte command)
1015141cc406Sopenharmony_ci{
1016141cc406Sopenharmony_ci  if (res[0] != 0)
1017141cc406Sopenharmony_ci    {
1018141cc406Sopenharmony_ci      DBG (1, "gt68xx_device_check_result: result was %2X %2X "
1019141cc406Sopenharmony_ci	   "(expected: %2X %2X)\n", res[0], res[1], 0, command);
1020141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1021141cc406Sopenharmony_ci    }
1022141cc406Sopenharmony_ci  /* The Gt681xfw.usb firmware doesn't return the command byte
1023141cc406Sopenharmony_ci     in the second byte, so we can't rely on that test */
1024141cc406Sopenharmony_ci  if (res[1] != command)
1025141cc406Sopenharmony_ci    DBG (5, "gt68xx_device_check_result: warning: result was %2X %2X "
1026141cc406Sopenharmony_ci	 "(expected: %2X %2X)\n", res[0], res[1], 0, command);
1027141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1028141cc406Sopenharmony_ci}
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ciSANE_Status
1031141cc406Sopenharmony_cigt68xx_device_get_id (GT68xx_Device * dev)
1032141cc406Sopenharmony_ci{
1033141cc406Sopenharmony_ci  CHECK_DEV_ACTIVE (dev, "gt68xx_device_get_id");
1034141cc406Sopenharmony_ci  if (dev->model->command_set->get_id)
1035141cc406Sopenharmony_ci    return (*dev->model->command_set->get_id) (dev);
1036141cc406Sopenharmony_ci  else
1037141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1038141cc406Sopenharmony_ci}
1039141cc406Sopenharmony_ci
1040141cc406Sopenharmony_cistatic void
1041141cc406Sopenharmony_cigt68xx_device_fix_descriptor (GT68xx_Device * dev)
1042141cc406Sopenharmony_ci{
1043141cc406Sopenharmony_ci  SANE_Byte data[8];
1044141cc406Sopenharmony_ci  sanei_usb_control_msg (dev->fd, 0x80, 0x06, 0x01 << 8, 0, 8, data);
1045141cc406Sopenharmony_ci}
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci
1048141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */
1049