• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ---------------------------------------------------------------------- */
2 
3 /* sane - Scanner Access Now Easy.
4 
5    umax-usb.c
6 
7    (C) 2001-2002 Frank Zago
8 
9    This file is part of the SANE package.
10 
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2 of the
14    License, or (at your option) any later version.
15 
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <https://www.gnu.org/licenses/>.
23 
24    As a special exception, the authors of SANE give permission for
25    additional uses of the libraries contained in this release of SANE.
26 
27    The exception is that, if you link a SANE library with other files
28    to produce an executable, this does not by itself cause the
29    resulting executable to be covered by the GNU General Public
30    License.  Your use of that executable is in no way restricted on
31    account of linking the SANE library code into it.
32 
33    This exception does not, however, invalidate any other reasons why
34    the executable file might be covered by the GNU General Public
35    License.
36 
37    If you submit changes to SANE to the maintainers to be included in
38    a subsequent release, you agree by submitting the changes that
39    those changes may be distributed with this exception intact.
40 
41    If you write modifications of your own for SANE, it is your choice
42    whether to permit this exception to apply to your modifications.
43    If you do not wish that, delete this exception notice.
44 
45    This file implements a SANE backend for UMAX USB flatbed scanners.  */
46 
47 
48 /* ---------------------------------------------------------------------- */
49 
50 #include "../include/sane/sanei_usb.h"
51 
52 #include "../include/sane/sanei_pv8630.h"
53 
54 /* USB specific parts */
55 
56 /* Apparently this will recover from some errors. */
pv8630_mini_init_scanner(int fd)57 static void pv8630_mini_init_scanner(int fd)
58 {
59 	DBG(DBG_info, "mini_init_scanner\n");
60 
61 	/* (re-)init the device (?) */
62 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04 );
63 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02 );
64 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02 );
65 
66 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xd0, 0xff, 1000);
67 }
68 
69 /* Length of the CDB given the SCSI command. The last two are not
70    correct (vendor reserved). */
71 static u_char cdb_sizes[8] = {
72     6, 10, 10, 6, 16, 12, 0, 0
73 };
74 #define CDB_SIZE(opcode)	cdb_sizes[(((opcode) >> 5) & 7)]
75 
76 /* Sends a CDB to the scanner. Also sends the parameters and receives
77  * the data, if necessary. When this function returns with a
78  * SANE_STATUS_GOOD, the SCSI command has been completed.
79  *
80  * Note: I don't know about deferred commands.
81  */
sanei_umaxusb_cmd(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size)82 static SANE_Status sanei_umaxusb_cmd(int fd, const void *src, size_t src_size, void *dst, size_t * dst_size)
83 {
84 	unsigned char result;
85 	size_t cmd_size = CDB_SIZE (*(const char *) src);
86 	size_t param_size = src_size - cmd_size;
87 	const char * param_ptr = ((const char *) src) + cmd_size;
88 	size_t tmp_len;
89 
90 	DBG(DBG_info, "Sending SCSI cmd 0x%02x cdb len %ld, param len %ld, result len %ld\n", ((const unsigned char *)src)[0], (long)cmd_size, (long)param_size, dst_size? (long)*dst_size:(long)0);
91 
92 	/* This looks like some kind of pre-initialization. */
93 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x0c);
94 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf0, 0xff, 1000);
95 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04);
96 
97 	/* Send the CDB and check it's been received OK. */
98 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x16);
99 	sanei_pv8630_flush_buffer(fd);
100 	sanei_pv8630_prep_bulkwrite(fd, cmd_size);
101 
102 	tmp_len = cmd_size;
103 	sanei_pv8630_bulkwrite(fd, src, &tmp_len);
104 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf8, 0xff, 1000);
105 
106 	sanei_pv8630_flush_buffer(fd);
107 	sanei_pv8630_prep_bulkread(fd, 1);
108 
109 	result = 0xA5;				/* to be sure */
110 	tmp_len = 1;
111 	sanei_pv8630_bulkread(fd, &result, &tmp_len);
112 	if (result != 0) {
113 		DBG(DBG_info, "error in sanei_pv8630_bulkread (got %02x)\n", result);
114 		if (result == 8) {
115 			pv8630_mini_init_scanner(fd);
116 		}
117 		return(SANE_STATUS_IO_ERROR);
118 	}
119 
120 	/* Send the parameters and check they've been received OK. */
121 	if (param_size) {
122 		sanei_pv8630_flush_buffer(fd);
123 		sanei_pv8630_prep_bulkwrite(fd, param_size);
124 
125 		tmp_len = param_size;
126 		sanei_pv8630_bulkwrite(fd, param_ptr, &tmp_len);
127 		sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf8, 0xff, 1000);
128 
129 		sanei_pv8630_flush_buffer(fd);
130 		sanei_pv8630_prep_bulkread(fd, 1);
131 
132 		result = 0xA5;				/* to be sure */
133 		tmp_len = 1;
134 		sanei_pv8630_bulkread(fd, &result, &tmp_len);
135 		if (result != 0) {
136 			DBG(DBG_info, "error in sanei_pv8630_bulkread (got %02x)\n", result);
137 			if (result == 8) {
138 				pv8630_mini_init_scanner(fd);
139 			}
140 			return(SANE_STATUS_IO_ERROR);
141 		}
142 	}
143 
144 	/* If the SCSI command expect a return, get it. */
145 	if (dst_size != NULL && *dst_size != 0 && dst != NULL) {
146 		sanei_pv8630_flush_buffer(fd);
147 		sanei_pv8630_prep_bulkread(fd, *dst_size);
148 		sanei_pv8630_bulkread(fd, dst, dst_size);
149 
150 		DBG(DBG_info, "  SCSI cmd returned %lu bytes\n", (u_long) *dst_size);
151 
152 		sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf8, 0xff, 1000);
153 
154 		sanei_pv8630_flush_buffer(fd);
155 		sanei_pv8630_prep_bulkread(fd, 1);
156 
157 		result = 0x5A;			/* just to be sure */
158 		tmp_len = 1;
159 		sanei_pv8630_bulkread(fd, &result, &tmp_len);
160 		if (result != 0) {
161 			DBG(DBG_info, "error in sanei_pv8630_bulkread (got %02x)\n", result);
162 			if (result == 8) {
163 				pv8630_mini_init_scanner(fd);
164 			}
165 			return(SANE_STATUS_IO_ERROR);
166 		}
167 	}
168 
169 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04);
170 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02);
171 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02);
172 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xd0, 0xff, 1000);
173 
174 	DBG(DBG_info, "  SCSI command successfully executed\n");
175 
176 	return(SANE_STATUS_GOOD);
177 }
178 
179 /* Initialize the PowerVision 8630. */
pv8630_init_umaxusb_scanner(int fd)180 static SANE_Status pv8630_init_umaxusb_scanner(int fd)
181 {
182 	DBG(DBG_info, "Initializing the PV8630\n");
183 
184 	/* Init the device */
185 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04);
186 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02);
187 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02);
188 
189 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xd0, 0xff, 1000);
190 
191 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x0c);
192 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf0, 0xff, 1000);
193 
194 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04);
195 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf0, 0xff, 1000);
196 
197 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x0c);
198 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf0, 0xff, 1000);
199 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf8, 0xff, 1000);
200 
201 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04);
202 
203 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02);
204 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x02);
205 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xd0, 0xff, 1000);
206 
207 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x0c);
208 	sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf0, 0xff, 1000);
209 
210 	sanei_pv8630_write_byte(fd, PV8630_UNKNOWN, 0x04);
211 
212 	sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x16);
213 
214 	DBG(DBG_info, "PV8630 initialized\n");
215 
216 	return(SANE_STATUS_GOOD);
217 }
218 
219 
220 /*
221  * SCSI functions for the emulation.
222  *
223  * The following functions emulate their sanei_scsi_* counterpart.
224  *
225  */
226 
227 
228 /*
229  * sanei_umaxusb_req_wait() and sanei_umaxusb_req_enter()
230  *
231  * I don't know if it is possible to queue the reads to the
232  * scanner. So The queueing is disabled. The performance does not seems
233  * to be bad anyway.
234  */
235 
236 static void *umaxusb_req_buffer; /* keep the buffer ptr as an ID */
237 
sanei_umaxusb_req_enter(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size,void ** idp)238 static SANE_Status sanei_umaxusb_req_enter (int fd,
239 											const void *src, size_t src_size,
240 											void *dst, size_t * dst_size, void **idp)
241 {
242 	umaxusb_req_buffer = *idp = dst;
243 	return(sanei_umaxusb_cmd(fd, src, src_size, dst, dst_size));
244 }
245 
246 static SANE_Status
sanei_umaxusb_req_wait(void * id)247 sanei_umaxusb_req_wait (void *id)
248 {
249 	if (id != umaxusb_req_buffer) {
250 		DBG(DBG_info, "sanei_umaxusb_req_wait: AIE, invalid id\n");
251 		return(SANE_STATUS_IO_ERROR);
252 	}
253 	return(SANE_STATUS_GOOD);
254 }
255 
256 /* Open the device.
257  */
258 static SANE_Status
sanei_umaxusb_open(const char * dev,int * fdp,SANEI_SCSI_Sense_Handler handler,void * handler_arg)259 sanei_umaxusb_open (const char *dev, int *fdp,
260 					SANEI_SCSI_Sense_Handler handler, void *handler_arg)
261 {
262 	SANE_Status status;
263 
264 	(void) handler;			/* silence gcc */
265 	(void) handler_arg;		/* silence gcc */
266 
267 	status = sanei_usb_open (dev, fdp);
268 	if (status != SANE_STATUS_GOOD) {
269 		DBG (1, "sanei_umaxusb_open: open of `%s' failed: %s\n",
270 			 dev, sane_strstatus(status));
271 		return status;
272     } else {
273 		SANE_Word vendor;
274 		SANE_Word product;
275 
276 		/* We have opened the device. Check that it is a USB scanner. */
277 		if (sanei_usb_get_vendor_product (*fdp, &vendor, &product) != SANE_STATUS_GOOD) {
278 			/* This is not a USB scanner, or SANE or the OS doesn't support it. */
279 			sanei_usb_close(*fdp);
280 			*fdp = -1;
281 			return SANE_STATUS_UNSUPPORTED;
282 		}
283 
284 		/* So it's a scanner. Does this backend support it?
285 		 * Only the UMAX 2200 USB is currently supported. */
286 		if ((vendor != 0x1606) || (product != 0x0230)) {
287 			sanei_usb_close(*fdp);
288 			*fdp = -1;
289 			return SANE_STATUS_UNSUPPORTED;
290 		}
291 
292 		/* It's a good scanner. Initialize it.
293 		 *
294 		 * Note: pv8630_init_umaxusb_scanner() is for the UMAX
295 		 * 2200. Other UMAX scanner might need a different
296 		 * initialization routine. */
297 
298 		pv8630_init_umaxusb_scanner(*fdp);
299 	}
300 
301 	return(SANE_STATUS_GOOD);
302 }
303 
304 /* sanei_umaxusb_open_extended() is just a passthrough for sanei_umaxusb_open(). */
305 static SANE_Status
sanei_umaxusb_open_extended(const char * dev,int * fdp,SANEI_SCSI_Sense_Handler handler,void * handler_arg,int * buffersize)306 sanei_umaxusb_open_extended (const char *dev, int *fdp,
307 					SANEI_SCSI_Sense_Handler handler, void *handler_arg, int *buffersize)
308 {
309 	(void) buffersize;
310 	return(sanei_umaxusb_open(dev, fdp, handler, handler_arg));
311 }
312 
313 /* Close the scanner. */
314 static void
sanei_umaxusb_close(int fd)315 sanei_umaxusb_close (int fd)
316 {
317 	sanei_usb_close(fd);
318 }
319