| 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 | |