1 | /* $NetBSD: ss_mustek.c,v 1.43 2016/11/20 15:37:19 mlelstv Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1995 Joachim Koenig-Baltes. All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. All advertising materials mentioning features or use of this software |
15 | * must display the following acknowledgement: |
16 | * This product includes software developed by Joachim Koenig-Baltes. |
17 | * 4. The name of the author may not be used to endorse or promote products |
18 | * derived from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * special driver for MUSTEK flatbed scanners MFS 06000CX and MFS 12000CX |
34 | * these scanners come with their own scsi card, containing an NCR53C400 |
35 | * SCSI controller chip. I'm in the progress of writing a driver for this |
36 | * card to work under NetBSD-current. I've hooked it up to a Seagate ST01 |
37 | * hostadapter in the meantime, giving 350KB/sec for higher resolutions! |
38 | * |
39 | * I tried to connect it to my Adaptec 1542B, but with no success. It seems, |
40 | * it does not like synchronous negotiation between Hostadapter and other |
41 | * targets, but I could not turn this off for the 1542B. |
42 | * |
43 | * There is also an other reason why you would not like to connect it to your |
44 | * favourite SCSI host adapter: The Mustek DOES NOT DISCONNECT. It will block |
45 | * other traffic from the bus while a transfer is active. |
46 | */ |
47 | |
48 | #include <sys/cdefs.h> |
49 | __KERNEL_RCSID(0, "$NetBSD: ss_mustek.c,v 1.43 2016/11/20 15:37:19 mlelstv Exp $" ); |
50 | |
51 | #include <sys/param.h> |
52 | #include <sys/kernel.h> |
53 | #include <sys/systm.h> |
54 | #include <sys/fcntl.h> |
55 | #include <sys/errno.h> |
56 | #include <sys/ioctl.h> |
57 | #include <sys/malloc.h> |
58 | #include <sys/buf.h> |
59 | #include <sys/bufq.h> |
60 | #include <sys/proc.h> |
61 | #include <sys/device.h> |
62 | #include <sys/conf.h> /* for cdevsw */ |
63 | #include <sys/scanio.h> |
64 | |
65 | #include <dev/scsipi/scsipi_all.h> |
66 | #include <dev/scsipi/scsi_all.h> |
67 | #include <dev/scsipi/scsi_scanner.h> |
68 | #include <dev/scsipi/scsipiconf.h> |
69 | #include <dev/scsipi/scsipi_base.h> |
70 | #include <dev/scsipi/ssvar.h> |
71 | #include <dev/scsipi/ss_mustek.h> |
72 | |
73 | #define MUSTEK_RETRIES 4 |
74 | |
75 | static int mustek_get_params(struct ss_softc *); |
76 | static int mustek_set_params(struct ss_softc *, struct scan_io *); |
77 | static int mustek_trigger_scanner(struct ss_softc *); |
78 | static void mustek_minphys(struct ss_softc *, struct buf *); |
79 | static int mustek_read(struct ss_softc *, struct buf *); |
80 | static int mustek_rewind_scanner(struct ss_softc *); |
81 | |
82 | /* only used internally */ |
83 | static int mustek_get_status(struct ss_softc *, int, int); |
84 | static void mustek_compute_sizes(struct ss_softc *); |
85 | |
86 | /* structure for the special handlers */ |
87 | static struct ss_special mustek_special = { |
88 | mustek_set_params, |
89 | mustek_trigger_scanner, |
90 | mustek_get_params, |
91 | mustek_minphys, |
92 | mustek_read, |
93 | mustek_rewind_scanner, |
94 | NULL, /* no adf support right now */ |
95 | NULL /* no adf support right now */ |
96 | }; |
97 | |
98 | /* mustek_attach: attach special functions to ss */ |
99 | void |
100 | mustek_attach(struct ss_softc *ss, struct scsipibus_attach_args *sa) |
101 | { |
102 | #ifdef SCSIPI_DEBUG |
103 | struct scsipi_periph *periph = sa->sa_periph; |
104 | #endif |
105 | |
106 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_attach: start\n" )); |
107 | ss->sio.scan_scanner_type = 0; |
108 | |
109 | printf("\n%s: " , device_xname(ss->sc_dev)); |
110 | |
111 | /* first, check the model which determines resolutions */ |
112 | if (!memcmp(sa->sa_inqbuf.product, "MFS-06000CX" , 11)) { |
113 | ss->sio.scan_scanner_type = MUSTEK_06000CX; |
114 | printf("Mustek 6000CX Flatbed 3-pass color scanner, " |
115 | "3 - 600 dpi\n" ); |
116 | } |
117 | if (!memcmp(sa->sa_inqbuf.product, "MFS-12000CX" , 11)) { |
118 | ss->sio.scan_scanner_type = MUSTEK_12000CX; |
119 | printf("Mustek 12000CX Flatbed 3-pass color scanner, " |
120 | "6 - 1200 dpi\n" ); |
121 | } |
122 | |
123 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_attach: scanner_type = %d\n" , |
124 | ss->sio.scan_scanner_type)); |
125 | |
126 | /* install special handlers */ |
127 | ss->special = &mustek_special; |
128 | |
129 | /* |
130 | * populate the scanio struct with legal values |
131 | * the default should come from user space |
132 | */ |
133 | ss->sio.scan_width = 1200; |
134 | ss->sio.scan_height = 1200; |
135 | ss->sio.scan_x_resolution = 99; |
136 | ss->sio.scan_y_resolution = 99; |
137 | ss->sio.scan_x_origin = 0; |
138 | ss->sio.scan_y_origin = 0; |
139 | ss->sio.scan_brightness = 100; |
140 | ss->sio.scan_contrast = 100; |
141 | ss->sio.scan_quality = 100; |
142 | ss->sio.scan_image_mode = SIM_GRAYSCALE; |
143 | |
144 | mustek_compute_sizes(ss); |
145 | } |
146 | |
147 | static int |
148 | mustek_get_params (struct ss_softc *ss) |
149 | { |
150 | return 0; |
151 | } |
152 | |
153 | /* |
154 | * check the parameters if the mustek is capable of fulfilling it |
155 | * but don't send the command to the scanner in case the user wants |
156 | * to change parameters by more than one call |
157 | */ |
158 | static int |
159 | mustek_set_params(struct ss_softc *ss, struct scan_io *sio) |
160 | { |
161 | int error; |
162 | |
163 | /* if the scanner is triggered, then rewind it */ |
164 | if (ss->flags & SSF_TRIGGERED) { |
165 | error = mustek_rewind_scanner(ss); |
166 | if (error) |
167 | return error; |
168 | } |
169 | |
170 | /* size constraints: 8.5" horizontally and 14" vertically */ |
171 | #ifdef MUSTEK_INCH_SPEC |
172 | /* sizes must be a multiple of 1/8" */ |
173 | sio->scan_x_origin -= sio->scan_x_origin % 150; |
174 | sio->scan_y_origin -= sio->scan_y_origin % 150; |
175 | sio->scan_width -= sio->scan_width % 150; |
176 | sio->scan_height -= sio->scan_height % 150; |
177 | #endif |
178 | if (sio->scan_width == 0 || |
179 | sio->scan_x_origin + sio->scan_width > 10200 || |
180 | sio->scan_height == 0 || |
181 | sio->scan_y_origin + sio->scan_height > 16800) |
182 | return EINVAL; |
183 | |
184 | /* |
185 | * for now, only realize the values for the MUSTEK_06000CX |
186 | * in the future, values for the MUSTEK_12000CX will be implemented |
187 | */ |
188 | |
189 | /* |
190 | * resolution (dpi) must be <= 300 and a multiple of 3 or |
191 | * between 300 and 600 and a multiple of 30 |
192 | */ |
193 | sio->scan_x_resolution -= sio->scan_x_resolution <= 300 ? |
194 | sio->scan_x_resolution % 3 : sio->scan_x_resolution % 30; |
195 | sio->scan_y_resolution -= sio->scan_y_resolution <= 300 ? |
196 | sio->scan_y_resolution % 3 : sio->scan_y_resolution % 30; |
197 | if (sio->scan_x_resolution < 3 || sio->scan_x_resolution > 600 || |
198 | sio->scan_x_resolution != sio->scan_y_resolution) |
199 | return EINVAL; |
200 | |
201 | /* assume brightness values are between 64 and 136 in steps of 3 */ |
202 | sio->scan_brightness -= (sio->scan_brightness - 64) % 3; |
203 | if (sio->scan_brightness < 64 || sio->scan_brightness > 136) |
204 | return EINVAL; |
205 | |
206 | /* contrast values must be between 16 and 184 in steps of 7 */ |
207 | sio->scan_contrast -= (sio->scan_contrast - 16) % 7; |
208 | if (sio->scan_contrast < 16 || sio->scan_contrast > 184) |
209 | return EINVAL; |
210 | |
211 | /* |
212 | * velocity: between 0 (fast) and 4 (slow) which will be mapped |
213 | * to 100% = 4, 80% = 3, 60% = 2, 40% = 1, 20% = 0 |
214 | * must be a multiple of 20 |
215 | */ |
216 | sio->scan_quality -= sio->scan_quality % 20; |
217 | if (sio->scan_quality < 20 || sio->scan_quality > 100) |
218 | return EINVAL; |
219 | |
220 | switch (sio->scan_image_mode) { |
221 | case SIM_BINARY_MONOCHROME: |
222 | case SIM_DITHERED_MONOCHROME: |
223 | case SIM_GRAYSCALE: |
224 | case SIM_RED: |
225 | case SIM_GREEN: |
226 | case SIM_BLUE: |
227 | break; |
228 | default: |
229 | return EINVAL; |
230 | } |
231 | |
232 | /* change ss_softc to the new values, but save ro-variables */ |
233 | sio->scan_scanner_type = ss->sio.scan_scanner_type; |
234 | memcpy(&ss->sio, sio, sizeof(struct scan_io)); |
235 | |
236 | mustek_compute_sizes(ss); |
237 | |
238 | return 0; |
239 | } |
240 | |
241 | /* |
242 | * trim the requested transfer to a multiple of the line size |
243 | * this is called only from ssread() which guarantees, scanner is triggered |
244 | * In the future, it will trim the transfer to not read to much at a time |
245 | * because the mustek cannot disconnect. It will be calculated by the |
246 | * resolution, the velocity and the number of bytes per line. |
247 | */ |
248 | static void |
249 | mustek_minphys(struct ss_softc *ss, struct buf *bp) |
250 | { |
251 | #ifdef SCSIPI_DEBUG |
252 | struct scsipi_periph *periph = ss->sc_periph; |
253 | #endif |
254 | |
255 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_minphys: before: %d\n" , |
256 | bp->b_bcount)); |
257 | bp->b_bcount -= bp->b_bcount % |
258 | ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8); |
259 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_minphys: after: %d\n" , |
260 | bp->b_bcount)); |
261 | } |
262 | |
263 | /* |
264 | * trigger the scanner to start a scan operation |
265 | * this includes sending the mode- and window-data, starting the scanner |
266 | * and getting the image size info |
267 | */ |
268 | static int |
269 | mustek_trigger_scanner(struct ss_softc *ss) |
270 | { |
271 | struct mustek_mode_select_cmd mode_cmd; |
272 | struct mustek_mode_select_data mode_data; |
273 | struct mustek_set_window_cmd window_cmd; |
274 | struct mustek_set_window_data window_data; |
275 | struct mustek_start_scan_cmd start_scan_cmd; |
276 | struct scsipi_periph *periph = ss->sc_periph; |
277 | int pixel_tlx, pixel_tly, pixel_brx, pixel_bry, paperlength; |
278 | int error; |
279 | |
280 | mustek_compute_sizes(ss); |
281 | |
282 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner\n" )); |
283 | |
284 | /* set the window params and send the scsi command */ |
285 | memset(&window_cmd, 0, sizeof(window_cmd)); |
286 | window_cmd.opcode = MUSTEK_SET_WINDOW; |
287 | window_cmd.length = sizeof(window_data); |
288 | |
289 | memset(&window_data, 0, sizeof(window_data)); |
290 | window_data.frame.header = MUSTEK_LINEART_BACKGROUND | MUSTEK_UNIT_SPEC; |
291 | #ifdef MUSTEK_INCH_SPEC |
292 | /* the positional values are all 1 byte because 256 / 8 = 32" */ |
293 | pixel_tlx = ss->sio.scan_x_origin / 150; |
294 | pixel_tly = ss->sio.scan_y_origin / 150; |
295 | pixel_brx = pixel_tlx + ss->sio.scan_width / 150; |
296 | pixel_bry = pixel_tly + ss->sio.scan_height / 150; |
297 | #else |
298 | pixel_tlx = (ss->sio.scan_x_origin * ss->sio.scan_x_resolution) / 1200; |
299 | pixel_tly = (ss->sio.scan_y_origin * ss->sio.scan_y_resolution) / 1200; |
300 | pixel_brx = pixel_tlx + |
301 | (ss->sio.scan_width * ss->sio.scan_x_resolution) / 1200; |
302 | pixel_bry = pixel_tly + |
303 | (ss->sio.scan_height * ss->sio.scan_y_resolution) / 1200; |
304 | #endif |
305 | _lto2l(pixel_tlx, window_data.frame.tl_x); |
306 | _lto2l(pixel_tly, window_data.frame.tl_y); |
307 | _lto2l(pixel_brx, window_data.frame.br_x); |
308 | _lto2l(pixel_bry, window_data.frame.br_y); |
309 | |
310 | #if MUSTEK_WINDOWS >= 1 |
311 | window_data.window1 = window_data.frame; |
312 | window_data.window1.header = MUSTEK_WINDOW_MASK | MUSTEK_UNIT_SPEC; |
313 | #endif |
314 | |
315 | /* send the set window command to the scanner */ |
316 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_set_parms: set_window\n" )); |
317 | error = scsipi_command(periph, (void *)&window_cmd, sizeof(window_cmd), |
318 | (void *)&window_data, sizeof(window_data), |
319 | MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_OUT); |
320 | if (error) |
321 | return error; |
322 | |
323 | /* |
324 | * do what it takes to actualize the mode |
325 | */ |
326 | memset(&mode_cmd, 0, sizeof(mode_cmd)); |
327 | mode_cmd.opcode = MUSTEK_MODE_SELECT; |
328 | _lto2b(sizeof(mode_data), mode_cmd.length); |
329 | |
330 | memset(&mode_data, 0, sizeof(mode_data)); |
331 | mode_data.mode = |
332 | MUSTEK_MODE_MASK | MUSTEK_HT_PATTERN_BUILTIN | MUSTEK_UNIT_SPEC; |
333 | if (ss->sio.scan_x_resolution <= 300) |
334 | mode_data.resolution = ss->sio.scan_x_resolution / 3; |
335 | else |
336 | /* |
337 | * the resolution values is computed by modulo 100, but not |
338 | * for 600dpi, where the value is 100 (a bit tricky, but ...) |
339 | */ |
340 | mode_data.resolution = |
341 | ((ss->sio.scan_x_resolution - 1) % 100) + 1; |
342 | |
343 | mode_data.brightness = (ss->sio.scan_brightness - 64) / 3; |
344 | mode_data.contrast = (ss->sio.scan_contrast - 16) / 7; |
345 | mode_data.grain = 0; |
346 | mode_data.velocity = ss->sio.scan_quality / 20 - 1; |
347 | #ifdef MUSTEK_INCH_SPEC |
348 | paperlength = 14 * 8; /* 14" */ |
349 | #else |
350 | paperlength = 14 * ss->sio.scan_y_resolution; /* 14" */ |
351 | #endif |
352 | _lto2l(paperlength, mode_data.paperlength); |
353 | |
354 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: mode_select\n" )); |
355 | /* send the command to the scanner */ |
356 | error = scsipi_command(periph, (void *)&mode_cmd, sizeof(mode_cmd), |
357 | (void *)&mode_data, sizeof(mode_data), |
358 | MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_OUT); |
359 | if (error) |
360 | return error; |
361 | |
362 | /* |
363 | * now construct and send the start command |
364 | */ |
365 | memset(&start_scan_cmd, 0, sizeof(start_scan_cmd)); |
366 | start_scan_cmd.opcode = MUSTEK_START_STOP; |
367 | start_scan_cmd.mode = MUSTEK_SCAN_START; |
368 | if (ss->sio.scan_x_resolution <= 300) |
369 | start_scan_cmd.mode |= MUSTEK_RES_STEP_1; |
370 | else |
371 | start_scan_cmd.mode |= MUSTEK_RES_STEP_10; |
372 | switch (ss->sio.scan_image_mode) { |
373 | case SIM_BINARY_MONOCHROME: |
374 | case SIM_DITHERED_MONOCHROME: |
375 | start_scan_cmd.mode |= MUSTEK_BIT_MODE | MUSTEK_GRAY_FILTER; |
376 | break; |
377 | case SIM_GRAYSCALE: |
378 | start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_GRAY_FILTER; |
379 | break; |
380 | case SIM_RED: |
381 | start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_RED_FILTER; |
382 | break; |
383 | case SIM_GREEN: |
384 | start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_GREEN_FILTER; |
385 | break; |
386 | case SIM_BLUE: |
387 | start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_BLUE_FILTER; |
388 | break; |
389 | } |
390 | |
391 | /* send the command to the scanner */ |
392 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: start_scan\n" )); |
393 | error = scsipi_command(periph, |
394 | (void *)&start_scan_cmd, sizeof(start_scan_cmd), NULL, 0, |
395 | MUSTEK_RETRIES, 5000, NULL, 0); |
396 | if (error) |
397 | return error; |
398 | |
399 | /* |
400 | * now check if scanner ready this time with update of size info |
401 | * we wait here so that if the user issues a read directly afterwards, |
402 | * the scanner will respond directly (otherwise we had to sleep with |
403 | * a buffer locked in memory) |
404 | */ |
405 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: get_status\n" )); |
406 | error = mustek_get_status(ss, 60, 1); |
407 | if (error) |
408 | return error; |
409 | |
410 | return 0; |
411 | } |
412 | |
413 | /* stop a scan operation in progress */ |
414 | static int |
415 | mustek_rewind_scanner(struct ss_softc *ss) |
416 | { |
417 | struct mustek_start_scan_cmd cmd; |
418 | struct scsipi_periph *periph = ss->sc_periph; |
419 | int error; |
420 | |
421 | if (ss->sio.scan_window_size != 0) { |
422 | /* |
423 | * only if not all data has been read, the scanner has to be |
424 | * stopped |
425 | */ |
426 | memset(&cmd, 0, sizeof(cmd)); |
427 | cmd.opcode = MUSTEK_START_STOP; |
428 | cmd.mode = MUSTEK_SCAN_STOP; |
429 | |
430 | /* send the command to the scanner */ |
431 | SC_DEBUG(periph, SCSIPI_DB1, |
432 | ("mustek_rewind_scanner: stop_scan\n" )); |
433 | error = scsipi_command(periph, |
434 | (void *)&cmd, sizeof(cmd), |
435 | NULL, 0, |
436 | MUSTEK_RETRIES, 5000, NULL, 0); |
437 | if (error) |
438 | return error; |
439 | } |
440 | |
441 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_rewind_scanner: end\n" )); |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | /* read the requested number of bytes/lines from the scanner */ |
447 | static int |
448 | mustek_read(struct ss_softc *ss, struct buf *bp) |
449 | { |
450 | struct mustek_read_cmd cmd; |
451 | struct scsipi_xfer *xs; |
452 | struct scsipi_periph *periph = ss->sc_periph; |
453 | u_long lines_to_read; |
454 | int error __diagused; |
455 | |
456 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_read: start\n" )); |
457 | |
458 | memset(&cmd, 0, sizeof(cmd)); |
459 | cmd.opcode = MUSTEK_READ; |
460 | |
461 | /* instead of the bytes, the mustek wants the number of lines */ |
462 | lines_to_read = bp->b_bcount / |
463 | ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8); |
464 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_read: read %ld lines\n" , |
465 | lines_to_read)); |
466 | _lto3b(lines_to_read, cmd.length); |
467 | |
468 | /* go ask the adapter to do all this for us */ |
469 | xs = scsipi_make_xs_locked(periph, |
470 | (struct scsipi_generic *) &cmd, sizeof(cmd), |
471 | (u_char *) bp->b_data, bp->b_bcount, |
472 | MUSTEK_RETRIES, 10000, bp, |
473 | XS_CTL_NOSLEEP | XS_CTL_ASYNC | XS_CTL_DATA_IN); |
474 | if (xs == NULL) { |
475 | /* |
476 | * out of memory. Keep this buffer in the queue, and |
477 | * retry later. |
478 | */ |
479 | callout_reset(&ss->sc_callout, hz / 2, ssrestart, |
480 | periph); |
481 | return 0; |
482 | } |
483 | #ifdef DIAGNOSTIC |
484 | if (bufq_get(ss->buf_queue) != bp) |
485 | panic("ssstart(): dequeued wrong buf" ); |
486 | #else |
487 | bufq_get(ss->buf_queue); |
488 | #endif |
489 | error = scsipi_execute_xs(xs); |
490 | /* with a scsipi_xfer preallocated, scsipi_command can't fail */ |
491 | KASSERT(error == 0); |
492 | ss->sio.scan_lines -= lines_to_read; |
493 | #if 0 |
494 | if (ss->sio.scan_lines < 0) |
495 | ss->sio.scan_lines = 0; |
496 | #endif |
497 | ss->sio.scan_window_size -= bp->b_bcount; |
498 | #if 0 |
499 | if (ss->sio.scan_window_size < 0) |
500 | ss->sio.scan_window_size = 0; |
501 | #endif |
502 | return 0; |
503 | } |
504 | |
505 | /* |
506 | * check if the scanner is ready to take commands |
507 | * wait timeout seconds and try only every second |
508 | * if update, then update picture size info |
509 | * |
510 | * returns EBUSY if scanner not ready |
511 | */ |
512 | static int |
513 | mustek_get_status(struct ss_softc *ss, int timeout, int update) |
514 | { |
515 | struct mustek_get_status_cmd cmd; |
516 | struct mustek_get_status_data data; |
517 | struct scsipi_periph *periph = ss->sc_periph; |
518 | int error, lines, bytes_per_line; |
519 | |
520 | memset(&cmd, 0, sizeof(cmd)); |
521 | cmd.opcode = MUSTEK_GET_STATUS; |
522 | cmd.length = sizeof(data); |
523 | |
524 | while (1) { |
525 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_get_status: stat_cmd\n" )); |
526 | error = scsipi_command(periph, (void *)&cmd, sizeof(cmd), |
527 | (void *)&data, sizeof(data), |
528 | MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_IN); |
529 | if (error) |
530 | return error; |
531 | if ((data.ready_busy == MUSTEK_READY) || |
532 | (timeout-- <= 0)) |
533 | break; |
534 | /* please wait a second */ |
535 | kpause("mtkrdy" , false, hz, NULL); |
536 | } |
537 | |
538 | if (update) { |
539 | bytes_per_line = _2ltol(data.bytes_per_line); |
540 | lines = _3ltol(data.lines); |
541 | if (lines != ss->sio.scan_lines) { |
542 | printf("mustek: lines actual(%d) != computed(%ld)\n" , |
543 | lines, ss->sio.scan_lines); |
544 | return EIO; |
545 | } |
546 | if (bytes_per_line * lines != ss->sio.scan_window_size) { |
547 | printf("mustek: win-size actual(%d) != computed(%ld)\n" , |
548 | bytes_per_line * lines, ss->sio.scan_window_size); |
549 | return EIO; |
550 | } |
551 | |
552 | SC_DEBUG(periph, SCSIPI_DB1, |
553 | ("mustek_get_size: bpl=%ld, lines=%ld\n" , |
554 | (ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) |
555 | / 8, ss->sio.scan_lines)); |
556 | SC_DEBUG(periph, SCSIPI_DB1, ("window size = %ld\n" , |
557 | ss->sio.scan_window_size)); |
558 | } |
559 | |
560 | SC_DEBUG(periph, SCSIPI_DB1, ("mustek_get_status: end\n" )); |
561 | if (data.ready_busy == MUSTEK_READY) |
562 | return 0; |
563 | else |
564 | return EBUSY; |
565 | } |
566 | |
567 | /* |
568 | * mustek_compute_sizes: compute window_size and lines for the picture |
569 | * this function is called from different places in the code |
570 | */ |
571 | static void |
572 | mustek_compute_sizes(struct ss_softc *ss) |
573 | { |
574 | |
575 | switch (ss->sio.scan_image_mode) { |
576 | case SIM_BINARY_MONOCHROME: |
577 | case SIM_DITHERED_MONOCHROME: |
578 | ss->sio.scan_bits_per_pixel = 1; |
579 | break; |
580 | case SIM_GRAYSCALE: |
581 | case SIM_RED: |
582 | case SIM_GREEN: |
583 | case SIM_BLUE: |
584 | ss->sio.scan_bits_per_pixel = 8; |
585 | break; |
586 | } |
587 | |
588 | /* |
589 | * horizontal number of bytes is always a multiple of 2, |
590 | * in 8-bit mode at least |
591 | */ |
592 | ss->sio.scan_pixels_per_line = |
593 | (ss->sio.scan_width * ss->sio.scan_x_resolution) / 1200; |
594 | if (ss->sio.scan_bits_per_pixel == 1) |
595 | /* make it a multiple of 16, and thus of 2 bytes */ |
596 | ss->sio.scan_pixels_per_line = |
597 | (ss->sio.scan_pixels_per_line + 15) & 0xfffffff0; |
598 | else |
599 | ss->sio.scan_pixels_per_line = |
600 | (ss->sio.scan_pixels_per_line + 1) & 0xfffffffe; |
601 | |
602 | ss->sio.scan_lines = |
603 | (ss->sio.scan_height * ss->sio.scan_y_resolution) / 1200; |
604 | ss->sio.scan_window_size = ss->sio.scan_lines * |
605 | ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8); |
606 | } |
607 | |