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