Annotation of sys/scsi/ss_scanjet.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ss_scanjet.c,v 1.31 2007/06/01 20:59:04 moritz Exp $ */
! 2: /* $NetBSD: ss_scanjet.c,v 1.6 1996/05/18 22:58:01 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995 Kenneth Stailey. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Kenneth Stailey.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * special functions for the HP ScanJet IIc and IIcx
! 35: */
! 36:
! 37: #include <sys/types.h>
! 38: #include <sys/param.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/fcntl.h>
! 41: #include <sys/errno.h>
! 42: #include <sys/ioctl.h>
! 43: #include <sys/malloc.h>
! 44: #include <sys/buf.h>
! 45: #include <sys/proc.h>
! 46: #include <sys/user.h>
! 47: #include <sys/device.h>
! 48: #include <sys/conf.h> /* for cdevsw */
! 49: #include <sys/scanio.h>
! 50:
! 51: #include <scsi/scsi_all.h>
! 52: #include <scsi/scsi_scanner.h>
! 53: #include <scsi/scsiconf.h>
! 54: #include <scsi/ssvar.h>
! 55:
! 56: #define SCANJET_RETRIES 4
! 57:
! 58: int scanjet_set_params(struct ss_softc *, struct scan_io *);
! 59: int scanjet_trigger_scanner(struct ss_softc *);
! 60: int scanjet_read(struct ss_softc *, struct buf *);
! 61:
! 62: /* only used internally */
! 63: int scanjet_ctl_write(struct ss_softc *, char *, u_int, int);
! 64: int scanjet_ctl_read(struct ss_softc *, char *, u_int, int);
! 65: int scanjet_set_window(struct ss_softc *, int);
! 66: int scanjet_compute_sizes(struct ss_softc *, int);
! 67: /* Maybe move to libkern? */
! 68: #define atoi local_atoi
! 69: __inline static int atoi(const char *);
! 70:
! 71:
! 72: /*
! 73: * structure for the special handlers
! 74: */
! 75: struct ss_special scanjet_special = {
! 76: scanjet_set_params,
! 77: scanjet_trigger_scanner,
! 78: NULL,
! 79: NULL, /* no special minphys */
! 80: scanjet_read, /* scsi 6-byte read */
! 81: NULL, /* no "rewind" code (yet?) */
! 82: NULL, /* no adf support right now */
! 83: NULL /* no adf support right now */
! 84: };
! 85:
! 86: /*
! 87: * scanjet_attach: attach special functions to ss
! 88: */
! 89: void
! 90: scanjet_attach(ss, sa)
! 91: struct ss_softc *ss;
! 92: struct scsi_attach_args *sa;
! 93: {
! 94: #ifdef SCSIDEBUG
! 95: struct scsi_link *sc_link = sa->sa_sc_link;
! 96: #endif
! 97: int error;
! 98:
! 99: SC_DEBUG(sc_link, SDEV_DB1, ("scanjet_attach: start\n"));
! 100: ss->sio.scan_scanner_type = 0;
! 101:
! 102: printf("\n%s: ", ss->sc_dev.dv_xname);
! 103:
! 104: /* first, check the model (which determines nothing yet) */
! 105:
! 106: if (!bcmp(sa->sa_inqbuf->product, "C1750A", 6)) {
! 107: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 108: printf("HP ScanJet IIc");
! 109: }
! 110: /* The IIp is a grayscale-only HP SCL scanner */
! 111: if (!bcmp(sa->sa_inqbuf->product, "C1790A", 6)) {
! 112: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 113: printf("HP ScanJet IIp");
! 114: }
! 115: if (!bcmp(sa->sa_inqbuf->product, "C2500A", 6)) {
! 116: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 117: printf("HP ScanJet IIcx");
! 118: }
! 119: /* The 3p is a grayscale-only HP SCL scanner */
! 120: if (!bcmp(sa->sa_inqbuf->product, "C2570A", 6)) {
! 121: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 122: printf("HP ScanJet 3p");
! 123: }
! 124: /* The 3c/4c/6100C report as the same? */
! 125: if (!bcmp(sa->sa_inqbuf->product, "C2520A", 6)) {
! 126: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 127: printf("HP ScanJet 3c/4c/6100C");
! 128: }
! 129: if (!bcmp(sa->sa_inqbuf->product, "C1130A", 6)) {
! 130: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 131: printf("HP ScanJet 4p");
! 132: }
! 133: if (!bcmp(sa->sa_inqbuf->product, "C5110A", 6)) {
! 134: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 135: printf("HP ScanJet 5p");
! 136: }
! 137: if (!bcmp(sa->sa_inqbuf->product, "C6290A", 6)) {
! 138: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 139: printf("HP ScanJet 4100C");
! 140: }
! 141: if (!bcmp(sa->sa_inqbuf->product, "C5190A", 6)) {
! 142: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 143: printf("HP ScanJet 5100C");
! 144: }
! 145: if (!bcmp(sa->sa_inqbuf->product, "C7190A", 6)) {
! 146: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 147: printf("HP ScanJet 5200C");
! 148: }
! 149: if (!bcmp(sa->sa_inqbuf->product, "C6270A", 6)) {
! 150: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 151: printf("HP ScanJet 6200C");
! 152: }
! 153: if (!bcmp(sa->sa_inqbuf->product, "C7670A", 6)) {
! 154: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
! 155: printf("HP ScanJet 6300C");
! 156: }
! 157:
! 158: SC_DEBUG(sc_link, SDEV_DB1, ("scanjet_attach: scanner_type = %d\n",
! 159: ss->sio.scan_scanner_type));
! 160:
! 161: /* now install special handlers */
! 162: ss->special = scanjet_special;
! 163:
! 164: /*
! 165: * fill in the rest of the scan_io struct by calling
! 166: * set_window and compute_sizes routines
! 167: */
! 168: error = scanjet_set_window(ss, SCSI_POLL);
! 169: if (error) {
! 170: printf(" set_window failed\n");
! 171: return;
! 172: }
! 173:
! 174: error = scanjet_compute_sizes(ss, SCSI_POLL);
! 175: if (error) {
! 176: printf(" compute_sizes failed\n");
! 177: return;
! 178: }
! 179:
! 180: printf("\n");
! 181: }
! 182:
! 183: /*
! 184: * check the parameters if the scanjet is capable of fulfilling it
! 185: * but don't send the command to the scanner in case the user wants
! 186: * to change parameters by more than one call
! 187: */
! 188: int
! 189: scanjet_set_params(ss, sio)
! 190: struct ss_softc *ss;
! 191: struct scan_io *sio;
! 192: {
! 193: int error;
! 194:
! 195: #if 0
! 196: /*
! 197: * if the scanner is triggered, then rewind it
! 198: */
! 199: if (ss->flags & SSF_TRIGGERED) {
! 200: error = scanjet_rewind_scanner(ss);
! 201: if (error)
! 202: return (error);
! 203: }
! 204: #endif
! 205:
! 206: /* size constraints... */
! 207: if (sio->scan_width == 0 ||
! 208: sio->scan_x_origin + sio->scan_width > 10200 || /* 8.5" */
! 209: sio->scan_height == 0 ||
! 210: sio->scan_y_origin + sio->scan_height > 16800) /* 14" */
! 211: return (EINVAL);
! 212:
! 213: /* resolution (dpi)... */
! 214: if (sio->scan_x_resolution < 100 ||
! 215: sio->scan_x_resolution > 400 ||
! 216: sio->scan_y_resolution < 100 ||
! 217: sio->scan_y_resolution > 400)
! 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_COLOR:
! 225: break;
! 226: default:
! 227: return (EINVAL);
! 228: }
! 229:
! 230: /* change ss_softc to the new values, but save ro-variables */
! 231: sio->scan_scanner_type = ss->sio.scan_scanner_type;
! 232: bcopy(sio, &ss->sio, sizeof(struct scan_io));
! 233:
! 234: error = scanjet_set_window(ss, 0);
! 235: if (error) {
! 236: uprintf("%s: set_window failed\n", ss->sc_dev.dv_xname);
! 237: return (error);
! 238: }
! 239: error = scanjet_compute_sizes(ss, 0);
! 240: if (error) {
! 241: uprintf("%s: compute_sizes failed\n", ss->sc_dev.dv_xname);
! 242: return (error);
! 243: }
! 244:
! 245: return (0);
! 246: }
! 247:
! 248: /*
! 249: * trigger the scanner to start a scan operation
! 250: * this includes sending the mode- and window-data,
! 251: * and starting the scanner
! 252: */
! 253: int
! 254: scanjet_trigger_scanner(ss)
! 255: struct ss_softc *ss;
! 256: {
! 257: static char *escape_codes = "\033*f0S";
! 258: int error;
! 259:
! 260: error = scanjet_set_window(ss, 0);
! 261: if (error) {
! 262: uprintf("%s: set_window failed\n", ss->sc_dev.dv_xname);
! 263: return (error);
! 264: }
! 265: error = scanjet_compute_sizes(ss, 0);
! 266: if (error) {
! 267: uprintf("%s: compute_sizes failed\n", ss->sc_dev.dv_xname);
! 268: return (error);
! 269: }
! 270:
! 271: /* send "trigger" operation */
! 272: error = scanjet_ctl_write(ss, escape_codes, strlen(escape_codes), 0);
! 273: if (error) {
! 274: uprintf("%s: trigger_scanner failed\n", ss->sc_dev.dv_xname);
! 275: return (error);
! 276: }
! 277:
! 278: return (0);
! 279: }
! 280:
! 281: int
! 282: scanjet_read(ss, bp)
! 283: struct ss_softc *ss;
! 284: struct buf *bp;
! 285: {
! 286: struct scsi_rw_scanner cmd;
! 287: struct scsi_link *sc_link = ss->sc_link;
! 288:
! 289: /*
! 290: * Fill out the scsi command
! 291: */
! 292: bzero(&cmd, sizeof(cmd));
! 293: cmd.opcode = READ;
! 294:
! 295: /*
! 296: * Handle "fixed-block-mode" tape drives by using the
! 297: * block count instead of the length.
! 298: */
! 299: _lto3b(bp->b_bcount, cmd.len);
! 300:
! 301: /*
! 302: * go ask the adapter to do all this for us
! 303: */
! 304: if (scsi_scsi_cmd(sc_link, (struct scsi_generic *) &cmd, sizeof(cmd),
! 305: (u_char *) bp->b_data, bp->b_bcount, SCANJET_RETRIES, 100000, bp,
! 306: SCSI_NOSLEEP | SCSI_DATA_IN) != SUCCESSFULLY_QUEUED)
! 307: printf("%s: not queued\n", ss->sc_dev.dv_xname);
! 308: else {
! 309: if (bp->b_bcount >= ss->sio.scan_window_size)
! 310: ss->sio.scan_window_size = 0;
! 311: else
! 312: ss->sio.scan_window_size -= bp->b_bcount;
! 313: }
! 314:
! 315: return (0);
! 316: }
! 317:
! 318:
! 319: /*
! 320: * Do a synchronous write. Used to send control messages.
! 321: */
! 322: int
! 323: scanjet_ctl_write(ss, buf, size, flags)
! 324: struct ss_softc *ss;
! 325: char *buf;
! 326: u_int size;
! 327: int flags;
! 328: {
! 329: struct scsi_rw_scanner cmd;
! 330:
! 331: bzero(&cmd, sizeof(cmd));
! 332: cmd.opcode = WRITE;
! 333: _lto3b(size, cmd.len);
! 334: return (scsi_scsi_cmd(ss->sc_link, (struct scsi_generic *) &cmd,
! 335: sizeof(cmd), (u_char *) buf, size, 0, 100000, NULL,
! 336: flags | SCSI_DATA_OUT));
! 337: }
! 338:
! 339:
! 340: /*
! 341: * Do a synchronous read. Used to read responses to control messages.
! 342: */
! 343: int
! 344: scanjet_ctl_read(ss, buf, size, flags)
! 345: struct ss_softc *ss;
! 346: char *buf;
! 347: u_int size;
! 348: int flags;
! 349: {
! 350: struct scsi_rw_scanner cmd;
! 351:
! 352: bzero(&cmd, sizeof(cmd));
! 353: cmd.opcode = READ;
! 354: _lto3b(size, cmd.len);
! 355: return (scsi_scsi_cmd(ss->sc_link, (struct scsi_generic *) &cmd,
! 356: sizeof(cmd), (u_char *) buf, size, 0, 100000, NULL,
! 357: flags | SCSI_DATA_IN));
! 358: }
! 359:
! 360:
! 361: #ifdef SCANJETDEBUG
! 362: static void show_es(char *es)
! 363: {
! 364: char *p = es;
! 365:
! 366: while (*p) {
! 367: if (*p == '\033')
! 368: printf("[Esc]");
! 369: else
! 370: printf("%c", *p);
! 371: ++p;
! 372: }
! 373: printf("\n");
! 374: }
! 375: #endif
! 376:
! 377: /*
! 378: * simulate SCSI_SET_WINDOW for ScanJets
! 379: */
! 380: int
! 381: scanjet_set_window(ss, flags)
! 382: struct ss_softc *ss;
! 383: int flags;
! 384: {
! 385: char escape_codes[128];
! 386: size_t len;
! 387: int n;
! 388:
! 389: snprintf(escape_codes, sizeof escape_codes,
! 390: "\033*f%ldP\033*f%ldQ\033*f%ldX\033*f%ldY\033*a%dR\033*a%dS",
! 391: ss->sio.scan_width / 4,
! 392: ss->sio.scan_height / 4,
! 393: ss->sio.scan_x_origin / 4,
! 394: ss->sio.scan_y_origin / 4,
! 395: ss->sio.scan_x_resolution,
! 396: ss->sio.scan_y_resolution);
! 397:
! 398: switch (ss->sio.scan_image_mode) {
! 399: case SIM_BINARY_MONOCHROME:
! 400: ss->sio.scan_bits_per_pixel = 1;
! 401: /*
! 402: * Use line art mode (\033*aoT) and make image data be
! 403: * min-is-white ala PBM (\033*a0I).
! 404: */
! 405: strlcat(escape_codes, "\033*a0T\033*a0I", sizeof escape_codes);
! 406: break;
! 407: case SIM_DITHERED_MONOCHROME:
! 408: ss->sio.scan_bits_per_pixel = 1;
! 409: /*
! 410: * Use dithered mode (\033*a3T) and make image data be
! 411: * min-is-white ala PBM (\033*a0I).
! 412: */
! 413: strlcat(escape_codes, "\033*a3T\033*a0I", sizeof escape_codes);
! 414: break;
! 415: case SIM_GRAYSCALE:
! 416: ss->sio.scan_bits_per_pixel = 8;
! 417: /*
! 418: * Use grayscale mode (\033*a4T) and make image data be
! 419: * min-is-black ala PGM (\033*a1I)
! 420: */
! 421: strlcat(escape_codes, "\033*a4T\033*a1I", sizeof escape_codes);
! 422: break;
! 423: case SIM_COLOR:
! 424: ss->sio.scan_bits_per_pixel = 24;
! 425: /*
! 426: * Use RGB color mode (\033*a5T), make image data be
! 427: * min-is-black ala PPM (\033*a1I) and use pass-through matrix,
! 428: * i.e. disable NTSC (\033*u2T).
! 429: */
! 430: strlcat(escape_codes, "\033*a5T\033*a1I\033*u2T",
! 431: sizeof escape_codes);
! 432: break;
! 433: }
! 434:
! 435: /*
! 436: * If the escape sequence has been truncated at this point, appending
! 437: * the next sequence will also cause truncation, and this time we pay
! 438: * attention.
! 439: */
! 440: len = strlen(escape_codes);
! 441: n = snprintf(escape_codes + len, sizeof escape_codes - len,
! 442: "\033*a%dG\033*a%dL\033*a%dK",
! 443: ss->sio.scan_bits_per_pixel,
! 444: (int)(ss->sio.scan_brightness) - 128,
! 445: (int)(ss->sio.scan_contrast) - 128);
! 446:
! 447: if (n >= sizeof escape_codes - len)
! 448: return (ENOMEM);
! 449: len += n;
! 450:
! 451: return (scanjet_ctl_write(ss, escape_codes, len, flags));
! 452: }
! 453:
! 454: /* atoi() is from /sys/arch/amiga/dev/ite.c
! 455: and is only used in scanjet_compute_sizes */
! 456:
! 457: __inline static int
! 458: atoi(cp)
! 459: const char *cp;
! 460: {
! 461: int n;
! 462:
! 463: for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++)
! 464: n = n * 10 + *cp - '0';
! 465:
! 466: return (n);
! 467: }
! 468:
! 469: int
! 470: scanjet_compute_sizes(ss, flags)
! 471: struct ss_softc *ss;
! 472: int flags;
! 473: {
! 474: int error;
! 475: static char *wfail = "%s: interrogate write failed\n";
! 476: static char *rfail = "%s: interrogate read failed\n";
! 477: static char *dfail = "%s: bad data returned\n";
! 478: static char *mono = "\033*s1025E"; /* bytes wide */
! 479: static char *color = "\033*s1024E"; /* pixels wide */
! 480: static char *high = "\033*s1026E"; /* pixels high */
! 481: char response[20];
! 482: char *p;
! 483:
! 484: /*
! 485: * Deal with the fact that the HP ScanJet IIc uses 1/300" not 1/1200"
! 486: * as its base unit of measurement. PINT uses 1/1200" (yes I know
! 487: * ScanJet II's use decipoints as well but 1200 % 720 != 0)
! 488: */
! 489: ss->sio.scan_width = (ss->sio.scan_width + 3) & 0xfffffffc;
! 490: ss->sio.scan_height = (ss->sio.scan_height + 3) & 0xfffffffc;
! 491:
! 492: switch (ss->sio.scan_image_mode) {
! 493: case SIM_BINARY_MONOCHROME:
! 494: case SIM_DITHERED_MONOCHROME:
! 495: error = scanjet_ctl_write(ss, mono, strlen(mono), flags);
! 496: break;
! 497: case SIM_GRAYSCALE:
! 498: case SIM_COLOR:
! 499: error = scanjet_ctl_write(ss, color, strlen(color), flags);
! 500: break;
! 501: default:
! 502: error = EIO;
! 503: break;
! 504: }
! 505: if (error) {
! 506: uprintf(wfail, ss->sc_dev.dv_xname);
! 507: return (error);
! 508: }
! 509: error = scanjet_ctl_read(ss, response, 20, flags);
! 510: if (error) {
! 511: uprintf(rfail, ss->sc_dev.dv_xname);
! 512: return (error);
! 513: }
! 514: p = strchr(response, 'd');
! 515: if (p == NULL) {
! 516: uprintf(dfail, ss->sc_dev.dv_xname);
! 517: return (EIO);
! 518: }
! 519: ss->sio.scan_pixels_per_line = atoi(p + 1);
! 520: if (ss->sio.scan_image_mode < SIM_GRAYSCALE)
! 521: ss->sio.scan_pixels_per_line *= 8;
! 522:
! 523: error = scanjet_ctl_write(ss, high, strlen(high), flags);
! 524: if (error) {
! 525: uprintf(wfail, ss->sc_dev.dv_xname);
! 526: return (error);
! 527: }
! 528: error = scanjet_ctl_read(ss, response, 20, flags);
! 529: if (error) {
! 530: uprintf(rfail, ss->sc_dev.dv_xname);
! 531: return (error);
! 532: }
! 533: p = strchr(response, 'd');
! 534: if (p == NULL) {
! 535: uprintf(dfail, ss->sc_dev.dv_xname);
! 536: return (EIO);
! 537: }
! 538: ss->sio.scan_lines = atoi(p + 1);
! 539:
! 540: ss->sio.scan_window_size = ss->sio.scan_lines *
! 541: ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8);
! 542:
! 543: return (0);
! 544: }
CVSweb