1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 2001-2002 Matthew C. Duggan and Simon Krix
3141cc406Sopenharmony_ci   This file is part of the SANE package.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
19141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
22141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
23141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
24141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
25141cc406Sopenharmony_ci   account of linking the SANE library code into it.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
28141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
32141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
33141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
36141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
37141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   -----
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   This file is part of the canon_pp backend, supporting Canon CanoScan
42141cc406Sopenharmony_ci   Parallel scanners and also distributed as part of the stand-alone driver.
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci   Low Level Function library for Canon CanoScan Parallel Scanners by
45141cc406Sopenharmony_ci   Simon Krix <kinsei@users.sourceforge.net>
46141cc406Sopenharmony_ci   */
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci#ifndef NOSANE
49141cc406Sopenharmony_ci#include "../include/sane/config.h"
50141cc406Sopenharmony_ci#endif
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci#include <sys/time.h>
53141cc406Sopenharmony_ci#include <unistd.h>
54141cc406Sopenharmony_ci#include <ieee1284.h>
55141cc406Sopenharmony_ci#include "canon_pp-io.h"
56141cc406Sopenharmony_ci#include "canon_pp-dev.h"
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#ifdef NOSANE
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci/* No SANE, Things that only apply to stand-alone */
61141cc406Sopenharmony_ci#include <stdio.h>
62141cc406Sopenharmony_ci#include <stdarg.h>
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_cistatic void DBG(int level, const char *format, ...)
65141cc406Sopenharmony_ci{
66141cc406Sopenharmony_ci	va_list args;
67141cc406Sopenharmony_ci	va_start(args, format);
68141cc406Sopenharmony_ci	if (level < 50) vfprintf(stderr, format, args);
69141cc406Sopenharmony_ci	va_end(args);
70141cc406Sopenharmony_ci}
71141cc406Sopenharmony_ci#else
72141cc406Sopenharmony_ci
73141cc406Sopenharmony_ci/* Fix problem with DBG macro definition having a - in the name */
74141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
75141cc406Sopenharmony_ci#include "canon_pp.h"
76141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
77141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci#endif
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci/* 0x00 = Nibble Mode (M1284_NIBBLE)
82141cc406Sopenharmony_ci   0x10 = ECP Mode (M1284_ECP)
83141cc406Sopenharmony_ci   The scanner driver seems not to support ECP RLE mode
84141cc406Sopenharmony_ci   (which is a huge bummer because compression would be
85141cc406Sopenharmony_ci   ace) nor EPP mode.
86141cc406Sopenharmony_ci   */
87141cc406Sopenharmony_cistatic int ieee_mode = M1284_NIBBLE;
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci/* For super-verbose debugging */
90141cc406Sopenharmony_ci/* #define DUMP_PACKETS 1 */
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_ci/* Some sort of initialisation command */
93141cc406Sopenharmony_cistatic unsigned char cmd_init[10] = { 0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0 };
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci/************* Local Prototypes ******************/
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci/* Used by wake_scanner */
98141cc406Sopenharmony_cistatic int scanner_reset(struct parport *port);
99141cc406Sopenharmony_cistatic void scanner_chessboard_control(struct parport *port);
100141cc406Sopenharmony_cistatic void scanner_chessboard_data(struct parport *port, int mode);
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_ci/* Used by read_data */
103141cc406Sopenharmony_cistatic int ieee_transfer(struct parport *port, int length,
104141cc406Sopenharmony_ci		unsigned char *data);
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci/* Low level functions */
107141cc406Sopenharmony_cistatic int readstatus(struct parport *port);
108141cc406Sopenharmony_cistatic int expect(struct parport *port, const char *step, int s,
109141cc406Sopenharmony_ci		int mask, unsigned int delay);
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci/* Port-level functions */
112141cc406Sopenharmony_cistatic void outdata(struct parport *port, int d);
113141cc406Sopenharmony_cistatic void outcont(struct parport *port, int d, int mask);
114141cc406Sopenharmony_cistatic void outboth(struct parport *port, int d, int c);
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci/************************************/
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci/*
119141cc406Sopenharmony_ci * IEEE 1284 defines many values for m,
120141cc406Sopenharmony_ci * but these scanners only support 2: nibble and ECP modes.
121141cc406Sopenharmony_ci * And no data compression either (argh!)
122141cc406Sopenharmony_ci * 0 = Nibble-mode reverse channel transfer
123141cc406Sopenharmony_ci * 16 = ECP-mode
124141cc406Sopenharmony_ci */
125141cc406Sopenharmony_civoid sanei_canon_pp_set_ieee1284_mode(int m)
126141cc406Sopenharmony_ci{
127141cc406Sopenharmony_ci	ieee_mode = m;
128141cc406Sopenharmony_ci}
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ciint sanei_canon_pp_wake_scanner(struct parport *port, int mode)
131141cc406Sopenharmony_ci{
132141cc406Sopenharmony_ci	/* The scanner tristates the printer's control lines
133141cc406Sopenharmony_ci	   (essentially disabling the passthrough port) and exits
134141cc406Sopenharmony_ci	   from Transparent Mode ready for communication. */
135141cc406Sopenharmony_ci	int i = 0;
136141cc406Sopenharmony_ci	int tmp;
137141cc406Sopenharmony_ci	int max_cycles = 3;
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci	tmp = readstatus(port);
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci	/* Reset only works on 30/40 models */
142141cc406Sopenharmony_ci	if (mode != INITMODE_20P)
143141cc406Sopenharmony_ci	{
144141cc406Sopenharmony_ci		if ((tmp != READY))
145141cc406Sopenharmony_ci		{
146141cc406Sopenharmony_ci			DBG(40, "Scanner not ready (0x%x). Attempting to "
147141cc406Sopenharmony_ci					"reset...\n", tmp);
148141cc406Sopenharmony_ci			scanner_reset(port);
149141cc406Sopenharmony_ci			/* give it more of a chance to reset in this case */
150141cc406Sopenharmony_ci			max_cycles = 5;
151141cc406Sopenharmony_ci		}
152141cc406Sopenharmony_ci	} else {
153141cc406Sopenharmony_ci		DBG(0, "WARNING: Don't know how to reset an FBx20P, you may "
154141cc406Sopenharmony_ci				"have to power cycle\n");
155141cc406Sopenharmony_ci	}
156141cc406Sopenharmony_ci
157141cc406Sopenharmony_ci	do
158141cc406Sopenharmony_ci	{
159141cc406Sopenharmony_ci		i++;
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci		/* Send the wakeup sequence */
162141cc406Sopenharmony_ci		scanner_chessboard_control(port);
163141cc406Sopenharmony_ci		scanner_chessboard_data(port, mode);
164141cc406Sopenharmony_ci
165141cc406Sopenharmony_ci		if (expect(port, NULL, 0x03, 0x1f, 800000) &&
166141cc406Sopenharmony_ci				(mode == INITMODE_AUTO))
167141cc406Sopenharmony_ci		{
168141cc406Sopenharmony_ci			/* 630 Style init failed, try 620 style */
169141cc406Sopenharmony_ci			scanner_chessboard_control(port);
170141cc406Sopenharmony_ci			scanner_chessboard_data(port, INITMODE_20P);
171141cc406Sopenharmony_ci		}
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci		if (expect(port, "Scanner wakeup reply 1", 0x03, 0x1f, 50000))
174141cc406Sopenharmony_ci		{
175141cc406Sopenharmony_ci			outboth(port, 0x04, 0x0d);
176141cc406Sopenharmony_ci			usleep(100000);
177141cc406Sopenharmony_ci			outcont(port, 0x07, 0x0f);
178141cc406Sopenharmony_ci			usleep(100000);
179141cc406Sopenharmony_ci		}
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci	} while ((i < max_cycles) && expect(port, "Scanner wakeup reply 2",
182141cc406Sopenharmony_ci					0x03, 0x1f, 100000));
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci	/* Block just after chessboarding
185141cc406Sopenharmony_ci	   Reply 1 (S3 and S4 on, S5 and S7 off) */
186141cc406Sopenharmony_ci	outcont(port, 0, HOSTBUSY); /* C1 off */
187141cc406Sopenharmony_ci	/* Reply 2 - If it ain't happening by now, it ain't gonna happen. */
188141cc406Sopenharmony_ci	if (expect(port, "Reply 2", 0xc, 0x1f, 800000))
189141cc406Sopenharmony_ci		return -1;
190141cc406Sopenharmony_ci	outcont(port, HOSTBUSY, HOSTBUSY); /* C1 on */
191141cc406Sopenharmony_ci	if (expect(port, "Reply 3", 0x0b, 0x1f, 800000))
192141cc406Sopenharmony_ci		return -1;
193141cc406Sopenharmony_ci	outboth(port, 0, NSELECTIN | NINIT | HOSTCLK); /* Clear D, C3+, C1- */
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci	/* If we had to try the wakeup cycle more than once, we should wait
196141cc406Sopenharmony_ci	 * here for 10 seconds to let the scanner pull itself together -
197141cc406Sopenharmony_ci	 * it can actually take longer, but I can't wait that long! */
198141cc406Sopenharmony_ci	if (i > 1)
199141cc406Sopenharmony_ci	{
200141cc406Sopenharmony_ci		DBG(10, "Had to reset scanner, waiting for the "
201141cc406Sopenharmony_ci				"head to get back.\n");
202141cc406Sopenharmony_ci		usleep(10000000);
203141cc406Sopenharmony_ci	}
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci	return 0;
206141cc406Sopenharmony_ci}
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci
209141cc406Sopenharmony_ciint sanei_canon_pp_write(struct parport *port, int length, unsigned char *data)
210141cc406Sopenharmony_ci{
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci#ifdef DUMP_PACKETS
213141cc406Sopenharmony_ci	ssize_t count;
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci	DBG(10,"Sending: ");
216141cc406Sopenharmony_ci	for (count = 0; count < length; count++)
217141cc406Sopenharmony_ci	{
218141cc406Sopenharmony_ci		DBG(10,"%02x ", data[count]);
219141cc406Sopenharmony_ci		if (count % 20 == 19)
220141cc406Sopenharmony_ci			DBG(10,"\n      ");
221141cc406Sopenharmony_ci	}
222141cc406Sopenharmony_ci	if (count % 20 != 19) DBG(10,"\n");
223141cc406Sopenharmony_ci#endif
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci	DBG(100, "NEW Send Command (length %i):\n", length);
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci	switch (ieee_mode)
228141cc406Sopenharmony_ci	{
229141cc406Sopenharmony_ci		case M1284_BECP:
230141cc406Sopenharmony_ci		case M1284_ECPRLE:
231141cc406Sopenharmony_ci		case M1284_ECPSWE:
232141cc406Sopenharmony_ci		case M1284_ECP:
233141cc406Sopenharmony_ci			ieee1284_negotiate(port, ieee_mode);
234141cc406Sopenharmony_ci			if (ieee1284_ecp_write_data(port, 0, (char *)data,
235141cc406Sopenharmony_ci						length) != length)
236141cc406Sopenharmony_ci				return -1;
237141cc406Sopenharmony_ci			break;
238141cc406Sopenharmony_ci		case M1284_NIBBLE:
239141cc406Sopenharmony_ci			if (ieee1284_compat_write(port, 0, (char *)data,
240141cc406Sopenharmony_ci						length) != length)
241141cc406Sopenharmony_ci				return -1;
242141cc406Sopenharmony_ci			break;
243141cc406Sopenharmony_ci		default:
244141cc406Sopenharmony_ci			DBG(0, "Invalid mode in write!\n");
245141cc406Sopenharmony_ci	}
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci	DBG(100, "<< write");
248141cc406Sopenharmony_ci
249141cc406Sopenharmony_ci	return 0;
250141cc406Sopenharmony_ci}
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ciint sanei_canon_pp_read(struct parport *port, int length, unsigned char *data)
253141cc406Sopenharmony_ci{
254141cc406Sopenharmony_ci	int count, offset;
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci	DBG(200, "NEW read_data (%i bytes):\n", length);
257141cc406Sopenharmony_ci	ieee1284_negotiate(port, ieee_mode);
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci	/* This is special; Nibble mode needs a little
260141cc406Sopenharmony_ci	   extra help from us. */
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci	if (ieee_mode == M1284_NIBBLE)
263141cc406Sopenharmony_ci	{
264141cc406Sopenharmony_ci		/* Interrupt phase */
265141cc406Sopenharmony_ci		outcont(port, NSELECTIN, HOSTBUSY | NSELECTIN);
266141cc406Sopenharmony_ci		if (expect(port, "Read Data 1", 0, NDATAAVAIL, 6000000))
267141cc406Sopenharmony_ci		{
268141cc406Sopenharmony_ci			DBG(10,"Error 1\n");
269141cc406Sopenharmony_ci			ieee1284_terminate(port);
270141cc406Sopenharmony_ci			return 1;
271141cc406Sopenharmony_ci		}
272141cc406Sopenharmony_ci		outcont(port, HOSTBUSY, HOSTBUSY);
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci		if (expect(port, "Read Data 2",  NACK, NACK, 1000000))
275141cc406Sopenharmony_ci		{
276141cc406Sopenharmony_ci			DBG(1,"Error 2\n");
277141cc406Sopenharmony_ci			ieee1284_terminate(port);
278141cc406Sopenharmony_ci			return 1;
279141cc406Sopenharmony_ci		}
280141cc406Sopenharmony_ci		if (expect(port, "Read Data 3 (Ready?)",  0, PERROR, 1000000))
281141cc406Sopenharmony_ci		{
282141cc406Sopenharmony_ci			DBG(1,"Error 3\n");
283141cc406Sopenharmony_ci			ieee1284_terminate(port);
284141cc406Sopenharmony_ci			return 1;
285141cc406Sopenharmony_ci		}
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci		/* Host-Busy Data Available phase */
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci		if ((readstatus(port) & NDATAAVAIL) == NDATAAVAIL)
290141cc406Sopenharmony_ci		{
291141cc406Sopenharmony_ci			DBG(1,"No data to read.\n");
292141cc406Sopenharmony_ci			ieee1284_terminate(port);
293141cc406Sopenharmony_ci			return 1;
294141cc406Sopenharmony_ci		}
295141cc406Sopenharmony_ci	}
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci	offset = 0;
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci	DBG(100, "-> ieee_transfer(%d) *\n", length);
300141cc406Sopenharmony_ci	count = ieee_transfer(port, length, data);
301141cc406Sopenharmony_ci	DBG(100, "<- (%d)\n", count);
302141cc406Sopenharmony_ci	/* Early-out if it was not implemented */
303141cc406Sopenharmony_ci	if (count == E1284_NOTIMPL)
304141cc406Sopenharmony_ci		return 2;
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci	length -= count;
307141cc406Sopenharmony_ci	offset+= count;
308141cc406Sopenharmony_ci	while (length > 0)
309141cc406Sopenharmony_ci	{
310141cc406Sopenharmony_ci		/* If 0 bytes were transferred, it's a legal
311141cc406Sopenharmony_ci		   "No data" condition (I think). Otherwise,
312141cc406Sopenharmony_ci		   it may have run out of buffer.. keep reading*/
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci		if (count < 0) {
315141cc406Sopenharmony_ci			DBG(10, "Couldn't read enough data (need %d more "
316141cc406Sopenharmony_ci					"of %d)\n", length+count,length+offset);
317141cc406Sopenharmony_ci			ieee1284_terminate(port);
318141cc406Sopenharmony_ci			return 1;
319141cc406Sopenharmony_ci		}
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci		DBG(100, "-> ieee_transfer(%d)\n", length);
322141cc406Sopenharmony_ci		count = ieee_transfer(port, length, data+offset);
323141cc406Sopenharmony_ci		DBG(100, "<- (%d)\n", count);
324141cc406Sopenharmony_ci		length-=count;
325141cc406Sopenharmony_ci		offset+= count;
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci	}
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci#ifdef DUMP_PACKETS
330141cc406Sopenharmony_ci	if (length <= 60)
331141cc406Sopenharmony_ci	{
332141cc406Sopenharmony_ci		DBG(10,"Read: ");
333141cc406Sopenharmony_ci		for (count = 0; count < length; count++)
334141cc406Sopenharmony_ci		{
335141cc406Sopenharmony_ci			DBG(10,"%02x ", data[count]);
336141cc406Sopenharmony_ci			if (count % 20 == 19)
337141cc406Sopenharmony_ci				DBG(10,"\n      ");
338141cc406Sopenharmony_ci		}
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_ci		if (count % 20 != 19) DBG(10,"\n");
341141cc406Sopenharmony_ci		}
342141cc406Sopenharmony_ci	else
343141cc406Sopenharmony_ci	{
344141cc406Sopenharmony_ci		DBG(10,"Read: %i bytes\n", length);
345141cc406Sopenharmony_ci	}
346141cc406Sopenharmony_ci#endif
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci	if (ieee_mode == M1284_NIBBLE)
349141cc406Sopenharmony_ci    ieee1284_terminate(port);
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci	return 0;
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci}
354141cc406Sopenharmony_ci
355141cc406Sopenharmony_cistatic int ieee_transfer(struct parport *port, int length, unsigned char *data)
356141cc406Sopenharmony_ci{
357141cc406Sopenharmony_ci	int result = 0;
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci	DBG(100, "IEEE transfer (%i bytes)\n", length);
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci	switch (ieee_mode)
362141cc406Sopenharmony_ci	{
363141cc406Sopenharmony_ci		case M1284_BECP:
364141cc406Sopenharmony_ci		case M1284_ECP:
365141cc406Sopenharmony_ci		case M1284_ECPRLE:
366141cc406Sopenharmony_ci		case M1284_ECPSWE:
367141cc406Sopenharmony_ci			result = ieee1284_ecp_read_data(port, 0, (char *)data,
368141cc406Sopenharmony_ci					length);
369141cc406Sopenharmony_ci			break;
370141cc406Sopenharmony_ci		case M1284_NIBBLE:
371141cc406Sopenharmony_ci			result = ieee1284_nibble_read(port, 0, (char *)data,
372141cc406Sopenharmony_ci					length);
373141cc406Sopenharmony_ci			break;
374141cc406Sopenharmony_ci		default:
375141cc406Sopenharmony_ci			DBG(1, "Internal error: Wrong mode for transfer.\n"
376141cc406Sopenharmony_ci				"Please email stauff1@users.sourceforge.net\n"
377141cc406Sopenharmony_ci				"or kinsei@users.sourceforge.net\n");
378141cc406Sopenharmony_ci	}
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci	return result;
381141cc406Sopenharmony_ci}
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ciint sanei_canon_pp_check_status(struct parport *port)
384141cc406Sopenharmony_ci{
385141cc406Sopenharmony_ci	int status;
386141cc406Sopenharmony_ci	unsigned char data[2];
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci	DBG(200, "* Check Status:\n");
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci	if (sanei_canon_pp_read(port, 2, data))
391141cc406Sopenharmony_ci		return -1;
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci	status = data[0] | (data[1] << 8);
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci	switch(status)
396141cc406Sopenharmony_ci	{
397141cc406Sopenharmony_ci		case 0x0606:
398141cc406Sopenharmony_ci			DBG(200, "Ready - 0x0606\n");
399141cc406Sopenharmony_ci			return 0;
400141cc406Sopenharmony_ci			break;
401141cc406Sopenharmony_ci		case 0x1414:
402141cc406Sopenharmony_ci			DBG(200, "Busy - 0x1414\n");
403141cc406Sopenharmony_ci			return 1;
404141cc406Sopenharmony_ci			break;
405141cc406Sopenharmony_ci		case 0x0805:
406141cc406Sopenharmony_ci			DBG(200, "Resetting - 0x0805\n");
407141cc406Sopenharmony_ci			return 3;
408141cc406Sopenharmony_ci			break;
409141cc406Sopenharmony_ci		case 0x1515:
410141cc406Sopenharmony_ci			DBG(1, "!! Invalid Command - 0x1515\n");
411141cc406Sopenharmony_ci			return 2;
412141cc406Sopenharmony_ci			break;
413141cc406Sopenharmony_ci		case 0x0000:
414141cc406Sopenharmony_ci			DBG(200, "Nothing - 0x0000");
415141cc406Sopenharmony_ci			return 4;
416141cc406Sopenharmony_ci			break;
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci		default:
419141cc406Sopenharmony_ci			DBG(1, "!! Unknown status - %04x\n", status);
420141cc406Sopenharmony_ci			return 100;
421141cc406Sopenharmony_ci	}
422141cc406Sopenharmony_ci}
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci/* Send a raw byte to the printer port */
426141cc406Sopenharmony_cistatic void outdata(struct parport *port, int d)
427141cc406Sopenharmony_ci{
428141cc406Sopenharmony_ci	ieee1284_write_data(port, d & 0xff);
429141cc406Sopenharmony_ci}
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci/* Send the low nibble of d to the control port.
432141cc406Sopenharmony_ci   The mask affects which bits are changed. */
433141cc406Sopenharmony_cistatic void outcont(struct parport *port, int d, int mask)
434141cc406Sopenharmony_ci{
435141cc406Sopenharmony_ci	static int control_port_status = 0;
436141cc406Sopenharmony_ci	control_port_status = (control_port_status & ~mask) | (d & mask);
437141cc406Sopenharmony_ci	ieee1284_write_control(port, (control_port_status & 0x0f));
438141cc406Sopenharmony_ci}
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci/* Send a byte to both ports */
441141cc406Sopenharmony_cistatic void outboth(struct parport *port, int d, int c)
442141cc406Sopenharmony_ci{
443141cc406Sopenharmony_ci	ieee1284_write_data(port, d & 0xff);
444141cc406Sopenharmony_ci	outcont(port, c, 0x0f);
445141cc406Sopenharmony_ci}
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci/* readstatus():
448141cc406Sopenharmony_ci   Returns the LOGIC value of the S register (ie: all input lines)
449141cc406Sopenharmony_ci   shifted right to to make it easier to read. Note: S5 is inverted
450141cc406Sopenharmony_ci   by ieee1284_read_status so we don't need to */
451141cc406Sopenharmony_cistatic int readstatus(struct parport *port)
452141cc406Sopenharmony_ci{
453141cc406Sopenharmony_ci	return (ieee1284_read_status(port) & 0xf8) >> 3;
454141cc406Sopenharmony_ci}
455141cc406Sopenharmony_ci
456141cc406Sopenharmony_cistatic void scanner_chessboard_control(struct parport *port)
457141cc406Sopenharmony_ci{
458141cc406Sopenharmony_ci	/* Wiggle C1 and C3 (twice) */
459141cc406Sopenharmony_ci	outboth(port, 0x0, 13);
460141cc406Sopenharmony_ci	usleep(10);
461141cc406Sopenharmony_ci	outcont(port, 7, 0xf);
462141cc406Sopenharmony_ci	usleep(10);
463141cc406Sopenharmony_ci	outcont(port, 13, 0xf);
464141cc406Sopenharmony_ci	usleep(10);
465141cc406Sopenharmony_ci	outcont(port, 7, 0xf);
466141cc406Sopenharmony_ci	usleep(10);
467141cc406Sopenharmony_ci}
468141cc406Sopenharmony_ci
469141cc406Sopenharmony_cistatic void scanner_chessboard_data(struct parport *port, int mode)
470141cc406Sopenharmony_ci{
471141cc406Sopenharmony_ci	int count;
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci	/* initial weirdness here for 620P - seems to go quite fast,
474141cc406Sopenharmony_ci	 * just ignore it! */
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci	for (count = 0; count < 2; count++)
477141cc406Sopenharmony_ci	{
478141cc406Sopenharmony_ci		/* Wiggle data lines (4 times) while strobing C1 */
479141cc406Sopenharmony_ci		/* 33 here for *30P, 55 for *20P */
480141cc406Sopenharmony_ci		if (mode == INITMODE_20P)
481141cc406Sopenharmony_ci			outdata(port, 0x55);
482141cc406Sopenharmony_ci		else
483141cc406Sopenharmony_ci			outdata(port, 0x33);
484141cc406Sopenharmony_ci		outcont(port, HOSTBUSY, HOSTBUSY);
485141cc406Sopenharmony_ci		usleep(10);
486141cc406Sopenharmony_ci		outcont(port, 0, HOSTBUSY);
487141cc406Sopenharmony_ci		usleep(10);
488141cc406Sopenharmony_ci		outcont(port, HOSTBUSY, HOSTBUSY);
489141cc406Sopenharmony_ci		usleep(10);
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_ci		if (mode == INITMODE_20P)
492141cc406Sopenharmony_ci			outdata(port, 0xaa);
493141cc406Sopenharmony_ci		else
494141cc406Sopenharmony_ci			outdata(port, 0xcc);
495141cc406Sopenharmony_ci		outcont(port, HOSTBUSY, HOSTBUSY);
496141cc406Sopenharmony_ci		usleep(10);
497141cc406Sopenharmony_ci		outcont(port, 0, HOSTBUSY);
498141cc406Sopenharmony_ci		usleep(10);
499141cc406Sopenharmony_ci		outcont(port, HOSTBUSY, HOSTBUSY);
500141cc406Sopenharmony_ci		usleep(10);
501141cc406Sopenharmony_ci	}
502141cc406Sopenharmony_ci}
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci/* Reset the scanner. At least, it works 50% of the time. */
505141cc406Sopenharmony_cistatic int scanner_reset(struct parport *port)
506141cc406Sopenharmony_ci{
507141cc406Sopenharmony_ci
508141cc406Sopenharmony_ci	/* Resetting only works for the *30Ps, sorry */
509141cc406Sopenharmony_ci	if (readstatus(port) == 0x0b)
510141cc406Sopenharmony_ci	{
511141cc406Sopenharmony_ci		/* Init Block 1 - composed of a 0-byte IEEE read */
512141cc406Sopenharmony_ci		ieee1284_negotiate(port, 0x0);
513141cc406Sopenharmony_ci		ieee1284_terminate(port);
514141cc406Sopenharmony_ci		ieee1284_negotiate(port, 0x0);
515141cc406Sopenharmony_ci		ieee1284_terminate(port);
516141cc406Sopenharmony_ci		scanner_chessboard_data(port, 1);
517141cc406Sopenharmony_ci		scanner_chessboard_data(port, 1);
518141cc406Sopenharmony_ci		scanner_chessboard_data(port, 1);
519141cc406Sopenharmony_ci		scanner_chessboard_data(port, 1);
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci		scanner_chessboard_data(port, 0);
522141cc406Sopenharmony_ci		scanner_chessboard_data(port, 0);
523141cc406Sopenharmony_ci		scanner_chessboard_data(port, 0);
524141cc406Sopenharmony_ci		scanner_chessboard_data(port, 0);
525141cc406Sopenharmony_ci	}
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci	/* Reset Block 2 =============== */
528141cc406Sopenharmony_ci	outboth(port, 0x04, 0x0d);
529141cc406Sopenharmony_ci
530141cc406Sopenharmony_ci	/* Specifically, we want this: 00111 on S */
531141cc406Sopenharmony_ci	if (expect(port, "Reset 2 response 1", 0x7, 0x1f, 500000))
532141cc406Sopenharmony_ci		return 1;
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci	outcont(port, 0, HOSTCLK);
535141cc406Sopenharmony_ci	usleep(5);
536141cc406Sopenharmony_ci	outcont(port, 0x0f, 0xf); /* All lines must be 1. */
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci	/* All lines 1 */
539141cc406Sopenharmony_ci	if (expect(port, "Reset 2 response 2 (READY)",
540141cc406Sopenharmony_ci				0x1f, 0x1f, 500000))
541141cc406Sopenharmony_ci		return 1;
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci	outcont(port, 0, HOSTBUSY);
544141cc406Sopenharmony_ci	usleep(100000); /* a short pause */
545141cc406Sopenharmony_ci	outcont(port, HOSTBUSY, HOSTBUSY | NSELECTIN);
546141cc406Sopenharmony_ci
547141cc406Sopenharmony_ci	return 0;
548141cc406Sopenharmony_ci}
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci/* A timed version of expect, which will wait for delay before erroring
551141cc406Sopenharmony_ci   This is the one and only one we should be using */
552141cc406Sopenharmony_cistatic int expect(struct parport *port, const char *msg, int s,
553141cc406Sopenharmony_ci		int mask, unsigned int delay)
554141cc406Sopenharmony_ci{
555141cc406Sopenharmony_ci	struct timeval tv;
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci	tv.tv_sec = delay / 1000000;
558141cc406Sopenharmony_ci	tv.tv_usec = delay % 1000000;
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ci	if (ieee1284_wait_status(port, mask << 3, s << 3, &tv))
561141cc406Sopenharmony_ci	{
562141cc406Sopenharmony_ci		if (msg) DBG(10, "Timeout: %s (0x%02x in 0x%02x) - Status "
563141cc406Sopenharmony_ci				"= 0x%02x\n", msg, s, mask, readstatus(port));
564141cc406Sopenharmony_ci		return 1;
565141cc406Sopenharmony_ci	}
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci	return 0;
568141cc406Sopenharmony_ci}
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ciint sanei_canon_pp_scanner_init(struct parport *port)
571141cc406Sopenharmony_ci{
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci	int tries = 0;
574141cc406Sopenharmony_ci	int tmp = 0;
575141cc406Sopenharmony_ci
576141cc406Sopenharmony_ci	/* Put the scanner in nibble mode */
577141cc406Sopenharmony_ci	ieee1284_negotiate(port, 0x0);
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci	/* No data to read yet - return to idle mode */
580141cc406Sopenharmony_ci	ieee1284_terminate(port);
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci	/* In Windows, this is always ECP (or an attempt at it) */
583141cc406Sopenharmony_ci	if (sanei_canon_pp_write(port, 10, cmd_init))
584141cc406Sopenharmony_ci		return -1;
585141cc406Sopenharmony_ci	/* Note that we don't really mind what the status was as long as it
586141cc406Sopenharmony_ci	 * wasn't a read error (returns -1) */
587141cc406Sopenharmony_ci	/* In fact, the 620P gives an error on that last command, but they
588141cc406Sopenharmony_ci	 * keep going anyway */
589141cc406Sopenharmony_ci	if (sanei_canon_pp_check_status(port) < 0)
590141cc406Sopenharmony_ci		return -1;
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci	/* Try until it's ready */
593141cc406Sopenharmony_ci	sanei_canon_pp_write(port, 10, cmd_init);
594141cc406Sopenharmony_ci	while ((tries < 3) && (tmp = sanei_canon_pp_check_status(port)))
595141cc406Sopenharmony_ci	{
596141cc406Sopenharmony_ci		if (tmp < 0)
597141cc406Sopenharmony_ci			return -1;
598141cc406Sopenharmony_ci		DBG(10, "scanner_init: Giving the scanner a snooze...\n");
599141cc406Sopenharmony_ci		usleep(500000);
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci		tries++;
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci		sanei_canon_pp_write(port, 10, cmd_init);
604141cc406Sopenharmony_ci	}
605141cc406Sopenharmony_ci
606141cc406Sopenharmony_ci	if (tries == 3) return 1;
607141cc406Sopenharmony_ci
608141cc406Sopenharmony_ci	return 0;
609141cc406Sopenharmony_ci}
610