1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci   Copyright (C) 2008, Panasonic Russia Ltd.
3141cc406Sopenharmony_ci   Copyright (C) 2010, m. allan noah
4141cc406Sopenharmony_ci*/
5141cc406Sopenharmony_ci/*
6141cc406Sopenharmony_ci   Panasonic KV-S20xx USB-SCSI scanners.
7141cc406Sopenharmony_ci*/
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci#include "../include/sane/config.h"
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci#include <string.h>
12141cc406Sopenharmony_ci/*#include <unistd.h>*/
13141cc406Sopenharmony_ci
14141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
15141cc406Sopenharmony_ci#define BACKEND_NAME kvs20xx
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
18141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
19141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci#include "kvs20xx.h"
22141cc406Sopenharmony_ci#include "kvs20xx_cmd.h"
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_cistatic SANE_Status
25141cc406Sopenharmony_ciusb_send_command (struct scanner *s, struct cmd *c, struct response *r,
26141cc406Sopenharmony_ci		  void *buf)
27141cc406Sopenharmony_ci{
28141cc406Sopenharmony_ci  SANE_Status st;
29141cc406Sopenharmony_ci  struct bulk_header *h = (struct bulk_header *) buf;
30141cc406Sopenharmony_ci  u8 resp[sizeof (*h) + STATUS_SIZE];
31141cc406Sopenharmony_ci  size_t sz = sizeof (*h) + MAX_CMD_SIZE;
32141cc406Sopenharmony_ci  memset (h, 0, sz);
33141cc406Sopenharmony_ci  h->length = cpu2be32 (sz);
34141cc406Sopenharmony_ci  h->type = cpu2be16 (COMMAND_BLOCK);
35141cc406Sopenharmony_ci  h->code = cpu2be16 (COMMAND_CODE);
36141cc406Sopenharmony_ci  memcpy (h + 1, c->cmd, c->cmd_size);
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci  st = sanei_usb_write_bulk (s->file, (const SANE_Byte *) h, &sz);
39141cc406Sopenharmony_ci  if (st)
40141cc406Sopenharmony_ci    return st;
41141cc406Sopenharmony_ci  if (sz != sizeof (*h) + MAX_CMD_SIZE)
42141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
43141cc406Sopenharmony_ci  if (c->dir == CMD_IN)
44141cc406Sopenharmony_ci    {
45141cc406Sopenharmony_ci      sz = sizeof (*h) + c->data_size;
46141cc406Sopenharmony_ci      st = sanei_usb_read_bulk (s->file, (SANE_Byte *) h, &sz);
47141cc406Sopenharmony_ci      c->data = h + 1;
48141cc406Sopenharmony_ci      c->data_size = sz - sizeof (*h);
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci      if (st || sz < sizeof (*h))
51141cc406Sopenharmony_ci	{
52141cc406Sopenharmony_ci	  st = sanei_usb_release_interface (s->file, 0);
53141cc406Sopenharmony_ci	  if (st)
54141cc406Sopenharmony_ci	    return st;
55141cc406Sopenharmony_ci	  st = sanei_usb_claim_interface (s->file, 0);
56141cc406Sopenharmony_ci	  if (st)
57141cc406Sopenharmony_ci	    return st;
58141cc406Sopenharmony_ci	  r->status = CHECK_CONDITION;
59141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
60141cc406Sopenharmony_ci	}
61141cc406Sopenharmony_ci
62141cc406Sopenharmony_ci    }
63141cc406Sopenharmony_ci  else if (c->dir == CMD_OUT)
64141cc406Sopenharmony_ci    {
65141cc406Sopenharmony_ci      sz = sizeof (*h) + c->data_size;
66141cc406Sopenharmony_ci      memset (h, 0, sizeof (*h));
67141cc406Sopenharmony_ci      h->length = cpu2be32 (sizeof (*h) + c->data_size);
68141cc406Sopenharmony_ci      h->type = cpu2be16 (DATA_BLOCK);
69141cc406Sopenharmony_ci      h->code = cpu2be16 (DATA_CODE);
70141cc406Sopenharmony_ci      memcpy (h + 1, c->data, c->data_size);
71141cc406Sopenharmony_ci      st = sanei_usb_write_bulk (s->file, (const SANE_Byte *) h, &sz);
72141cc406Sopenharmony_ci      if (st)
73141cc406Sopenharmony_ci	return st;
74141cc406Sopenharmony_ci    }
75141cc406Sopenharmony_ci  sz = sizeof (resp);
76141cc406Sopenharmony_ci  st = sanei_usb_read_bulk (s->file, resp, &sz);
77141cc406Sopenharmony_ci  if (st || sz != sizeof (resp))
78141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
79141cc406Sopenharmony_ci  r->status = be2cpu32 (*((u32 *) (resp + sizeof (*h))));
80141cc406Sopenharmony_ci  return st;
81141cc406Sopenharmony_ci}
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ciSANE_Status
84141cc406Sopenharmony_cikvs20xx_sense_handler (int __sane_unused__ fd,
85141cc406Sopenharmony_ci		       u_char * sense_buffer, void __sane_unused__ * arg)
86141cc406Sopenharmony_ci{
87141cc406Sopenharmony_ci  unsigned i;
88141cc406Sopenharmony_ci  SANE_Status st = SANE_STATUS_GOOD;
89141cc406Sopenharmony_ci  for (i = 0; i < sizeof (s_errors) / sizeof (s_errors[0]); i++)
90141cc406Sopenharmony_ci    if ((sense_buffer[2] & 0xf) == s_errors[i].sense
91141cc406Sopenharmony_ci	&& sense_buffer[12] == s_errors[i].asc
92141cc406Sopenharmony_ci	&& sense_buffer[13] == s_errors[i].ascq)
93141cc406Sopenharmony_ci      {
94141cc406Sopenharmony_ci	st = s_errors[i].st;
95141cc406Sopenharmony_ci	break;
96141cc406Sopenharmony_ci      }
97141cc406Sopenharmony_ci  if (st == SANE_STATUS_GOOD && sense_buffer[2] & END_OF_MEDIUM)
98141cc406Sopenharmony_ci    st = SANE_STATUS_EOF;
99141cc406Sopenharmony_ci  if (i == sizeof (s_errors) / sizeof (s_errors[0]))
100141cc406Sopenharmony_ci    st = SANE_STATUS_IO_ERROR;
101141cc406Sopenharmony_ci  DBG (DBG_ERR,
102141cc406Sopenharmony_ci       "send_command: CHECK_CONDITION: sense:0x%x ASC:0x%x ASCQ:0x%x\n",
103141cc406Sopenharmony_ci       sense_buffer[2], sense_buffer[12], sense_buffer[13]);
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci  return st;
106141cc406Sopenharmony_ci}
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_cistatic SANE_Status
109141cc406Sopenharmony_cisend_command (struct scanner * s, struct cmd * c)
110141cc406Sopenharmony_ci{
111141cc406Sopenharmony_ci  SANE_Status st = SANE_STATUS_GOOD;
112141cc406Sopenharmony_ci  if (s->bus == USB)
113141cc406Sopenharmony_ci    {
114141cc406Sopenharmony_ci      struct response r;
115141cc406Sopenharmony_ci      memset (&r, 0, sizeof (r));
116141cc406Sopenharmony_ci      st = usb_send_command (s, c, &r, s->buffer);
117141cc406Sopenharmony_ci      if (st)
118141cc406Sopenharmony_ci	return st;
119141cc406Sopenharmony_ci      if (r.status)
120141cc406Sopenharmony_ci	{
121141cc406Sopenharmony_ci	  u8 b[sizeof (struct bulk_header) + RESPONSE_SIZE];
122141cc406Sopenharmony_ci	  struct cmd c2 = {
123141cc406Sopenharmony_ci            {0},
124141cc406Sopenharmony_ci	    6,
125141cc406Sopenharmony_ci            0,
126141cc406Sopenharmony_ci	    RESPONSE_SIZE,
127141cc406Sopenharmony_ci	    CMD_IN
128141cc406Sopenharmony_ci	  };
129141cc406Sopenharmony_ci	  c2.cmd[0] = REQUEST_SENSE;
130141cc406Sopenharmony_ci	  c2.cmd[4] = RESPONSE_SIZE;
131141cc406Sopenharmony_ci	  st = usb_send_command (s, &c2, &r, b);
132141cc406Sopenharmony_ci	  if (st)
133141cc406Sopenharmony_ci	    return st;
134141cc406Sopenharmony_ci	  st = kvs20xx_sense_handler (0, b + sizeof (struct bulk_header), NULL);
135141cc406Sopenharmony_ci	}
136141cc406Sopenharmony_ci    }
137141cc406Sopenharmony_ci  else
138141cc406Sopenharmony_ci    {
139141cc406Sopenharmony_ci      if (c->dir == CMD_OUT)
140141cc406Sopenharmony_ci	{
141141cc406Sopenharmony_ci	  memcpy (s->buffer, c->cmd, c->cmd_size);
142141cc406Sopenharmony_ci	  memcpy (s->buffer + c->cmd_size, c->data, c->data_size);
143141cc406Sopenharmony_ci	  st = sanei_scsi_cmd (s->file, s->buffer, c->cmd_size + c->data_size,
144141cc406Sopenharmony_ci			       NULL, NULL);
145141cc406Sopenharmony_ci	}
146141cc406Sopenharmony_ci      else if (c->dir == CMD_IN)
147141cc406Sopenharmony_ci	{
148141cc406Sopenharmony_ci	  c->data = s->buffer;
149141cc406Sopenharmony_ci	  st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size,
150141cc406Sopenharmony_ci			       c->data, (size_t *) & c->data_size);
151141cc406Sopenharmony_ci	}
152141cc406Sopenharmony_ci      else
153141cc406Sopenharmony_ci	{
154141cc406Sopenharmony_ci	  st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, NULL, NULL);
155141cc406Sopenharmony_ci	}
156141cc406Sopenharmony_ci    }
157141cc406Sopenharmony_ci  return st;
158141cc406Sopenharmony_ci}
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ciSANE_Status
161141cc406Sopenharmony_cikvs20xx_test_unit_ready (struct scanner * s)
162141cc406Sopenharmony_ci{
163141cc406Sopenharmony_ci  struct cmd c = {
164141cc406Sopenharmony_ci    {0},
165141cc406Sopenharmony_ci    6,
166141cc406Sopenharmony_ci    0,
167141cc406Sopenharmony_ci    0,
168141cc406Sopenharmony_ci    CMD_NONE
169141cc406Sopenharmony_ci  };
170141cc406Sopenharmony_ci  c.cmd[0] = TEST_UNIT_READY;
171141cc406Sopenharmony_ci  if (send_command (s, &c))
172141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
175141cc406Sopenharmony_ci}
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ciSANE_Status
178141cc406Sopenharmony_cikvs20xx_set_timeout (struct scanner * s, int timeout)
179141cc406Sopenharmony_ci{
180141cc406Sopenharmony_ci  u16 t = cpu2be16 ((u16) timeout);
181141cc406Sopenharmony_ci  struct cmd c = {
182141cc406Sopenharmony_ci    {0},
183141cc406Sopenharmony_ci    10,
184141cc406Sopenharmony_ci    0,
185141cc406Sopenharmony_ci    0,
186141cc406Sopenharmony_ci    CMD_OUT
187141cc406Sopenharmony_ci  };
188141cc406Sopenharmony_ci  c.cmd[0] = SET_TIMEOUT;
189141cc406Sopenharmony_ci  c.cmd[2] = 0x8d;
190141cc406Sopenharmony_ci  copy16 (c.cmd + 7, cpu2be16 (sizeof (t)));
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci  c.data = &t;
193141cc406Sopenharmony_ci  c.data_size = sizeof (t);
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci  if (s->bus == USB)
196141cc406Sopenharmony_ci    sanei_usb_set_timeout (timeout * 1000);
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci  return send_command (s, &c);
199141cc406Sopenharmony_ci}
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ciSANE_Status
202141cc406Sopenharmony_cikvs20xx_set_window (struct scanner * s, int wnd_id)
203141cc406Sopenharmony_ci{
204141cc406Sopenharmony_ci  struct window wnd;
205141cc406Sopenharmony_ci  struct cmd c = {
206141cc406Sopenharmony_ci    {0},
207141cc406Sopenharmony_ci    10,
208141cc406Sopenharmony_ci    0,
209141cc406Sopenharmony_ci    0,
210141cc406Sopenharmony_ci    CMD_OUT
211141cc406Sopenharmony_ci  };
212141cc406Sopenharmony_ci  c.cmd[0] = SET_WINDOW;
213141cc406Sopenharmony_ci  copy16 (c.cmd + 7, cpu2be16 (sizeof (wnd)));
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci  c.data = &wnd;
216141cc406Sopenharmony_ci  c.data_size = sizeof (wnd);
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_ci  kvs20xx_init_window (s, &wnd, wnd_id);
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci  return send_command (s, &c);
221141cc406Sopenharmony_ci}
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ciSANE_Status
224141cc406Sopenharmony_cikvs20xx_reset_window (struct scanner * s)
225141cc406Sopenharmony_ci{
226141cc406Sopenharmony_ci  struct cmd c = {
227141cc406Sopenharmony_ci    {0},
228141cc406Sopenharmony_ci    10,
229141cc406Sopenharmony_ci    0,
230141cc406Sopenharmony_ci    0,
231141cc406Sopenharmony_ci    CMD_NONE
232141cc406Sopenharmony_ci  };
233141cc406Sopenharmony_ci  c.cmd[0] = SET_WINDOW;
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci  return send_command (s, &c);
236141cc406Sopenharmony_ci}
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ciSANE_Status
239141cc406Sopenharmony_cikvs20xx_scan (struct scanner * s)
240141cc406Sopenharmony_ci{
241141cc406Sopenharmony_ci  struct cmd c = {
242141cc406Sopenharmony_ci    {0},
243141cc406Sopenharmony_ci    6,
244141cc406Sopenharmony_ci    0,
245141cc406Sopenharmony_ci    0,
246141cc406Sopenharmony_ci    CMD_NONE
247141cc406Sopenharmony_ci  };
248141cc406Sopenharmony_ci  c.cmd[0] = SCAN;
249141cc406Sopenharmony_ci  return send_command (s, &c);
250141cc406Sopenharmony_ci}
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ciSANE_Status
253141cc406Sopenharmony_cikvs20xx_document_exist (struct scanner * s)
254141cc406Sopenharmony_ci{
255141cc406Sopenharmony_ci  SANE_Status status;
256141cc406Sopenharmony_ci  struct cmd c = {
257141cc406Sopenharmony_ci    {0},
258141cc406Sopenharmony_ci    10,
259141cc406Sopenharmony_ci    0,
260141cc406Sopenharmony_ci    6,
261141cc406Sopenharmony_ci    CMD_IN,
262141cc406Sopenharmony_ci  };
263141cc406Sopenharmony_ci  u8 *d;
264141cc406Sopenharmony_ci  c.cmd[0] = READ_10;
265141cc406Sopenharmony_ci  c.cmd[2] = 0x81;
266141cc406Sopenharmony_ci  set24 (c.cmd + 6, c.data_size);
267141cc406Sopenharmony_ci  status = send_command (s, &c);
268141cc406Sopenharmony_ci  if (status)
269141cc406Sopenharmony_ci    return status;
270141cc406Sopenharmony_ci  d = c.data;
271141cc406Sopenharmony_ci  if (d[0] & 0x20)
272141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci  return SANE_STATUS_NO_DOCS;
275141cc406Sopenharmony_ci}
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ciSANE_Status
278141cc406Sopenharmony_cikvs20xx_read_picture_element (struct scanner * s, unsigned side,
279141cc406Sopenharmony_ci			      SANE_Parameters * p)
280141cc406Sopenharmony_ci{
281141cc406Sopenharmony_ci  SANE_Status status;
282141cc406Sopenharmony_ci  struct cmd c = {
283141cc406Sopenharmony_ci    {0},
284141cc406Sopenharmony_ci    10,
285141cc406Sopenharmony_ci    0,
286141cc406Sopenharmony_ci    16,
287141cc406Sopenharmony_ci    CMD_IN
288141cc406Sopenharmony_ci  };
289141cc406Sopenharmony_ci  u32 *data;
290141cc406Sopenharmony_ci  c.cmd[0] = READ_10;
291141cc406Sopenharmony_ci  c.cmd[2] = 0x80;
292141cc406Sopenharmony_ci  c.cmd[5] = side;
293141cc406Sopenharmony_ci  set24 (c.cmd + 6, c.data_size);
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_ci  status = send_command (s, &c);
296141cc406Sopenharmony_ci  if (status)
297141cc406Sopenharmony_ci    return status;
298141cc406Sopenharmony_ci  data = (u32 *) c.data;
299141cc406Sopenharmony_ci  p->pixels_per_line = be2cpu32 (data[0]);
300141cc406Sopenharmony_ci  p->lines = be2cpu32 (data[1]);
301141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
302141cc406Sopenharmony_ci}
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ciSANE_Status
305141cc406Sopenharmony_cikvs20xx_read_image_data (struct scanner * s, unsigned page, unsigned side,
306141cc406Sopenharmony_ci			 void *buf, unsigned max_size, unsigned *size)
307141cc406Sopenharmony_ci{
308141cc406Sopenharmony_ci  SANE_Status status;
309141cc406Sopenharmony_ci  struct cmd c = {
310141cc406Sopenharmony_ci    {0},
311141cc406Sopenharmony_ci    10,
312141cc406Sopenharmony_ci    0,
313141cc406Sopenharmony_ci    0,
314141cc406Sopenharmony_ci    CMD_IN
315141cc406Sopenharmony_ci  };
316141cc406Sopenharmony_ci  c.cmd[0] = READ_10;
317141cc406Sopenharmony_ci  c.cmd[4] = page;
318141cc406Sopenharmony_ci  c.cmd[5] = side;
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci  c.data_size = max_size < MAX_READ_DATA_SIZE ? max_size : MAX_READ_DATA_SIZE;
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci  set24 (c.cmd + 6, c.data_size);
323141cc406Sopenharmony_ci  status = send_command (s, &c);
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci  if (status && status != SANE_STATUS_EOF)
326141cc406Sopenharmony_ci    return status;
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci  *size = c.data_size;
329141cc406Sopenharmony_ci  DBG (DBG_INFO, "kvs20xx_read_image_data: read %d, status %d\n", *size, status);
330141cc406Sopenharmony_ci  memcpy (buf, c.data, *size);
331141cc406Sopenharmony_ci  return status;
332141cc406Sopenharmony_ci}
333141cc406Sopenharmony_ci
334141cc406Sopenharmony_ciSANE_Status
335141cc406Sopenharmony_ciget_adjust_data (struct scanner * s, unsigned *dummy_length)
336141cc406Sopenharmony_ci{
337141cc406Sopenharmony_ci  SANE_Status status;
338141cc406Sopenharmony_ci  struct cmd c = {
339141cc406Sopenharmony_ci    {0},
340141cc406Sopenharmony_ci    10,
341141cc406Sopenharmony_ci    0,
342141cc406Sopenharmony_ci    40,
343141cc406Sopenharmony_ci    CMD_IN
344141cc406Sopenharmony_ci  };
345141cc406Sopenharmony_ci  u16 *data;
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci  c.cmd[0] = GET_ADJUST_DATA;
348141cc406Sopenharmony_ci  c.cmd[2] = 0x9b;
349141cc406Sopenharmony_ci  c.cmd[8] = 40;
350141cc406Sopenharmony_ci  status = send_command (s, &c);
351141cc406Sopenharmony_ci  if (status)
352141cc406Sopenharmony_ci    return status;
353141cc406Sopenharmony_ci  data = (u16 *) c.data;
354141cc406Sopenharmony_ci  *dummy_length = be2cpu16 (data[0]);
355141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
356141cc406Sopenharmony_ci}
357