Annotation of sys/scsi/ss.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ss.c,v 1.58 2006/12/21 02:05:46 krw Exp $ */
! 2: /* $NetBSD: ss.c,v 1.10 1996/05/05 19:52:55 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995, 1997 Kenneth Stailey. All rights reserved.
! 6: * modified for configurable scanner support by Joachim Koenig
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by Kenneth Stailey.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/fcntl.h>
! 37: #include <sys/errno.h>
! 38: #include <sys/ioctl.h>
! 39: #include <sys/malloc.h>
! 40: #include <sys/buf.h>
! 41: #include <sys/proc.h>
! 42: #include <sys/user.h>
! 43: #include <sys/device.h>
! 44: #include <sys/conf.h>
! 45: #include <sys/scanio.h>
! 46:
! 47: #include <scsi/scsi_all.h>
! 48: #include <scsi/scsi_scanner.h>
! 49: #include <scsi/scsiconf.h>
! 50: #include <scsi/ssvar.h>
! 51:
! 52: #include <scsi/ss_mustek.h>
! 53:
! 54: #define SSMODE(z) ( minor(z) & 0x03)
! 55: #define SSUNIT(z) ((minor(z) >> 4) )
! 56:
! 57: /*
! 58: * If the mode is 3 (e.g. minor = 3,7,11,15)
! 59: * then the device has been openned to set defaults
! 60: * This mode does NOT ALLOW I/O, only ioctls
! 61: */
! 62: #define MODE_REWIND 0
! 63: #define MODE_NONREWIND 1
! 64: #define MODE_CONTROL 3
! 65:
! 66: struct quirkdata {
! 67: char *name;
! 68: u_int quirks;
! 69: #define SS_Q_WINDOW_DESC_LEN 0x0001 /* needs special WDL */
! 70: #define SS_Q_BRIGHTNESS 0x0002 /* needs special value for brightness */
! 71: #define SS_Q_REV_BRIGHTNESS 0x0004 /* reverse brightness control in s/w */
! 72: #define SS_Q_THRESHOLD 0x0008 /* needs special value for threshold */
! 73: #define SS_Q_MONO_THRESHOLD 0x0010 /* same as SS_Q_THRESHOLD but only
! 74: * for monochrome image data */
! 75: #define SS_Q_CONTRAST 0x0020 /* needs special value for contrast */
! 76: #define SS_Q_REV_CONTRAST 0x0040 /* reverse contrast control in s/w */
! 77: #define SS_Q_HALFTONE 0x0080 /* uses non-zero halftone */
! 78: #define SS_Q_SET_RIF 0x0100 /* set RIF bit */
! 79: #define SS_Q_PADDING_TYPE 0x0200 /* does not truncate to byte boundary */
! 80: #define SS_Q_BIT_ORDERING 0x0400 /* needs non-zero bit ordering */
! 81: long window_descriptor_length;
! 82: u_int8_t brightness;
! 83: u_int8_t threshold;
! 84: u_int8_t contrast;
! 85: u_int8_t halftone_pattern[2];
! 86: int pad_type;
! 87: long bit_ordering;
! 88: u_int8_t scanner_type;
! 89: /*
! 90: * To enable additional scanner options, point vendor_unique_sw
! 91: * at a function that adds more stuff to the SET_WINDOW parameters.
! 92: */
! 93: int (*vendor_unique_sw)(struct ss_softc *, struct scan_io *,
! 94: struct scsi_set_window *, void *);
! 95: /*
! 96: * If the scanner requires use of GET_BUFFER_STATUS before READ
! 97: * it can be called from ss_minphys().
! 98: */
! 99: void (*special_minphys)(struct ss_softc *, struct buf *);
! 100:
! 101: /*
! 102: *
! 103: */
! 104: int (*compute_sizes)(void);
! 105: };
! 106:
! 107: struct ss_quirk_inquiry_pattern {
! 108: struct scsi_inquiry_pattern pattern;
! 109: struct quirkdata quirkdata;
! 110: };
! 111:
! 112: struct quirkdata ss_gen_quirks = {
! 113: "generic", 0, 0, 0, 0, 0,
! 114: {0, 0}, 0, 0, GENERIC_SCSI2,
! 115: NULL, NULL, NULL
! 116: };
! 117:
! 118: void ssstrategy(struct buf *);
! 119: void ssstart(void *);
! 120: void ssminphys(struct buf *);
! 121:
! 122: void ss_identify_scanner(struct ss_softc *, struct scsi_inquiry_data*);
! 123: int ss_set_window(struct ss_softc *, struct scan_io *);
! 124:
! 125: int ricoh_is410_sw(struct ss_softc *, struct scan_io *,
! 126: struct scsi_set_window *, void *);
! 127: int umax_uc630_sw(struct ss_softc *, struct scan_io *,
! 128: struct scsi_set_window *, void *);
! 129: #ifdef NOTYET /* for ADF support */
! 130: int fujitsu_m3096g_sw(struct ss_softc *, struct scan_io *,
! 131: struct scsi_set_window *, void *);
! 132: #endif
! 133:
! 134: void get_buffer_status(struct ss_softc *, struct buf *);
! 135:
! 136: /*
! 137: * WDL:
! 138: *
! 139: * Ricoh IS-50 & IS-410 insist on 320 (even it transfer len is less.)
! 140: * Ricoh FS-1 accepts 256 (I haven't tested other values.)
! 141: * UMAX UC-630 accepts 46 (I haven't tested other values.)
! 142: * Fujitsu M3096G wants 40 <= x <= 248 (tested OK at 40 & 64.)
! 143: */
! 144:
! 145: const struct ss_quirk_inquiry_pattern ss_quirk_patterns[] = {
! 146: {{T_SCANNER, T_FIXED,
! 147: "ULTIMA ", "AT3 1.60 ", " "}, {
! 148: "Ultima AT3",
! 149: SS_Q_HALFTONE |
! 150: SS_Q_PADDING_TYPE,
! 151: 0, 0, 0, 0, { 3, 0 }, 0, 0,
! 152: ULTIMA_AT3,
! 153: NULL, NULL, NULL
! 154: }},
! 155: {{T_SCANNER, T_FIXED,
! 156: "ULTIMA ", "A6000C PLUS ", " "}, {
! 157: "Ultima A6000C",
! 158: SS_Q_HALFTONE |
! 159: SS_Q_PADDING_TYPE,
! 160: 0, 0, 0, 0, { 3, 0 }, 0, 0,
! 161: ULTIMA_AC6000C,
! 162: NULL, NULL, NULL
! 163: }},
! 164: {{T_SCANNER, T_FIXED,
! 165: "RICOH ", "IS50 ", " "}, {
! 166: "Ricoh IS-50",
! 167: SS_Q_WINDOW_DESC_LEN |
! 168: SS_Q_REV_BRIGHTNESS |
! 169: SS_Q_THRESHOLD |
! 170: SS_Q_REV_CONTRAST |
! 171: SS_Q_HALFTONE |
! 172: SS_Q_BIT_ORDERING,
! 173: 320, 0, 0, 0, { 2, 0x0a }, 0, 7,
! 174: RICOH_IS50,
! 175: ricoh_is410_sw, get_buffer_status, NULL
! 176: }},
! 177: {{T_SCANNER, T_FIXED,
! 178: "RICOH ", "IS410 ", " "}, {
! 179: "Ricoh IS-410",
! 180: SS_Q_WINDOW_DESC_LEN |
! 181: SS_Q_THRESHOLD |
! 182: SS_Q_HALFTONE |
! 183: SS_Q_BIT_ORDERING,
! 184: 320, 0, 0, 0, { 2, 0x0a }, 0, 7,
! 185: RICOH_IS410,
! 186: ricoh_is410_sw, get_buffer_status, NULL
! 187: }},
! 188: {{T_SCANNER, T_FIXED, /* Ricoh IS-410 OEMed by IBM */
! 189: "IBM ", "2456-001 ", " "}, {
! 190: "IBM 2456",
! 191: SS_Q_WINDOW_DESC_LEN |
! 192: SS_Q_THRESHOLD |
! 193: SS_Q_HALFTONE |
! 194: SS_Q_BIT_ORDERING,
! 195: 320, 0, 0, 0, { 2, 0x0a }, 0, 7,
! 196: RICOH_IS410,
! 197: ricoh_is410_sw, get_buffer_status, NULL
! 198: }},
! 199: {{T_SCANNER, T_FIXED,
! 200: "UMAX ", "UC630 ", " "}, {
! 201: "UMAX UC-630",
! 202: SS_Q_WINDOW_DESC_LEN |
! 203: SS_Q_HALFTONE,
! 204: 0x2e, 0, 0, 0, { 0, 1 }, 0, 0,
! 205: UMAX_UC630,
! 206: umax_uc630_sw, NULL, NULL
! 207: }},
! 208: {{T_SCANNER, T_FIXED,
! 209: "UMAX ", "UG630 ", " "}, {
! 210: "UMAX UG-630",
! 211: SS_Q_WINDOW_DESC_LEN |
! 212: SS_Q_HALFTONE,
! 213: 0x2e, 0, 0, 0, { 0, 1 }, 0, 0,
! 214: UMAX_UG630,
! 215: umax_uc630_sw, NULL, NULL
! 216: }},
! 217: #ifdef NOTYET /* ADF version */
! 218: {{T_SCANNER, T_FIXED,
! 219: "FUJITSU ", "M3096Gm ", " "}, {
! 220: "Fujitsu M3096G",
! 221: SS_Q_WINDOW_DESC_LEN |
! 222: SS_Q_BRIGHTNESS |
! 223: SS_Q_MONO_THRESHOLD |
! 224: SS_Q_HALFTONE |
! 225: SS_Q_SET_RIF |
! 226: SS_Q_PADDING_TYPE,
! 227: 64, 0, 0, 0, { 0, 1 }, 0, 0,
! 228: FUJITSU_M3096G,
! 229: fujistsu_m3096g_sw, NULL, NULL
! 230: }},
! 231: #else /* flatbed-only version */
! 232: {{T_SCANNER, T_FIXED,
! 233: "FUJITSU ", "M3096Gm ", " "}, {
! 234: "Fujitsu M3096G",
! 235: SS_Q_BRIGHTNESS |
! 236: SS_Q_MONO_THRESHOLD |
! 237: SS_Q_CONTRAST |
! 238: SS_Q_HALFTONE |
! 239: SS_Q_PADDING_TYPE,
! 240: 0, 0, 0, 0, { 0, 1 }, 0, 0,
! 241: FUJITSU_M3096G,
! 242: NULL, NULL, NULL
! 243: }},
! 244: #endif
! 245: };
! 246:
! 247:
! 248: int ssmatch(struct device *, void *, void *);
! 249: void ssattach(struct device *, struct device *, void *);
! 250:
! 251: struct cfattach ss_ca = {
! 252: sizeof(struct ss_softc), ssmatch, ssattach
! 253: };
! 254:
! 255: struct cfdriver ss_cd = {
! 256: NULL, "ss", DV_DULL
! 257: };
! 258:
! 259: struct scsi_device ss_switch = {
! 260: NULL,
! 261: ssstart,
! 262: NULL,
! 263: NULL,
! 264: };
! 265:
! 266: const struct scsi_inquiry_pattern ss_patterns[] = {
! 267: {T_SCANNER, T_FIXED,
! 268: "", "", ""},
! 269: {T_SCANNER, T_REMOV,
! 270: "", "", ""},
! 271: {T_PROCESSOR, T_FIXED,
! 272: "HP ", "C1750A ", ""},
! 273: {T_PROCESSOR, T_FIXED,
! 274: "HP ", "C1790A ", ""},
! 275: {T_PROCESSOR, T_FIXED,
! 276: "HP ", "C2500A ", ""},
! 277: {T_PROCESSOR, T_FIXED,
! 278: "HP ", "C2570A ", ""},
! 279: {T_PROCESSOR, T_FIXED,
! 280: "HP ", "C2520A ", ""},
! 281: {T_PROCESSOR, T_FIXED,
! 282: "HP ", "C1130A ", ""},
! 283: {T_PROCESSOR, T_FIXED,
! 284: "HP ", "C5110A ", ""},
! 285: {T_PROCESSOR, T_FIXED,
! 286: "HP ", "C6290A ", ""},
! 287: {T_PROCESSOR, T_FIXED,
! 288: "HP ", "C5190A ", ""},
! 289: {T_PROCESSOR, T_FIXED,
! 290: "HP ", "C7190A ", ""},
! 291: {T_PROCESSOR, T_FIXED,
! 292: "HP ", "C6270A ", ""},
! 293: {T_PROCESSOR, T_FIXED,
! 294: "HP ", "C7670A ", ""},
! 295: };
! 296:
! 297: int
! 298: ssmatch(parent, match, aux)
! 299: struct device *parent;
! 300: void *match, *aux;
! 301: {
! 302: struct scsi_attach_args *sa = aux;
! 303: int priority;
! 304:
! 305: (void)scsi_inqmatch(sa->sa_inqbuf,
! 306: ss_patterns, sizeof(ss_patterns)/sizeof(ss_patterns[0]),
! 307: sizeof(ss_patterns[0]), &priority);
! 308: return (priority);
! 309: }
! 310:
! 311: /*
! 312: * The routine called by the low level scsi routine when it discovers
! 313: * A device suitable for this driver
! 314: * If it is a know special, call special attach routine to install
! 315: * special handlers into the ss_softc structure
! 316: */
! 317: void
! 318: ssattach(parent, self, aux)
! 319: struct device *parent, *self;
! 320: void *aux;
! 321: {
! 322: struct ss_softc *ss = (void *)self;
! 323: struct scsi_attach_args *sa = aux;
! 324: struct scsi_link *sc_link = sa->sa_sc_link;
! 325:
! 326: SC_DEBUG(sc_link, SDEV_DB2, ("ssattach:\n"));
! 327:
! 328: /*
! 329: * Store information needed to contact our base driver
! 330: */
! 331: ss->sc_link = sc_link;
! 332: sc_link->device = &ss_switch;
! 333: sc_link->device_softc = ss;
! 334: sc_link->openings = 1;
! 335:
! 336: if (!bcmp(sa->sa_inqbuf->vendor, "MUSTEK", 6))
! 337: mustek_attach(ss, sa);
! 338: else if (!bcmp(sa->sa_inqbuf->vendor, "HP ", 8))
! 339: scanjet_attach(ss, sa);
! 340: else
! 341: ss_identify_scanner(ss, sa->sa_inqbuf);
! 342:
! 343: /*
! 344: * populate the scanio struct with legal values
! 345: */
! 346: ss->sio.scan_width = 1200;
! 347: ss->sio.scan_height = 1200;
! 348: ss->sio.scan_x_resolution = 100;
! 349: ss->sio.scan_y_resolution = 100;
! 350: ss->sio.scan_x_origin = 0;
! 351: ss->sio.scan_y_origin = 0;
! 352: ss->sio.scan_brightness = 128;
! 353: ss->sio.scan_contrast = 128;
! 354: ss->sio.scan_quality = 100;
! 355: ss->sio.scan_image_mode = SIM_GRAYSCALE;
! 356:
! 357: /* XXX fill in the rest of the scan_io struct by calling the
! 358: compute_sizes routine */
! 359:
! 360: /*
! 361: * Set up the buf queue for this device
! 362: */
! 363: ss->buf_queue.b_active = 0;
! 364: ss->buf_queue.b_actf = 0;
! 365: ss->buf_queue.b_actb = &ss->buf_queue.b_actf;
! 366: }
! 367:
! 368: void
! 369: ss_identify_scanner(ss, inqbuf)
! 370: struct ss_softc *ss;
! 371: struct scsi_inquiry_data *inqbuf;
! 372: {
! 373: const struct ss_quirk_inquiry_pattern *finger;
! 374: int priority;
! 375: /*
! 376: * look for non-standard scanners with help of the quirk table
! 377: * and install functions for special handling
! 378: */
! 379: finger = (const struct ss_quirk_inquiry_pattern *)scsi_inqmatch(inqbuf,
! 380: ss_quirk_patterns,
! 381: sizeof(ss_quirk_patterns)/sizeof(ss_quirk_patterns[0]),
! 382: sizeof(ss_quirk_patterns[0]), &priority);
! 383: if (priority != 0) {
! 384: ss->quirkdata = &finger->quirkdata;
! 385: if (ss->quirkdata->special_minphys != NULL) {
! 386: ss->special.minphys = ss->quirkdata->special_minphys;
! 387: }
! 388: ss->sio.scan_scanner_type = ss->quirkdata->scanner_type;
! 389: printf("\n%s: %s\n", ss->sc_dev.dv_xname, ss->quirkdata->name);
! 390: } else {
! 391: printf("\n%s: generic scanner\n", ss->sc_dev.dv_xname);
! 392: bzero(&ss_gen_quirks, sizeof(ss_gen_quirks));
! 393: ss->quirkdata = &ss_gen_quirks;
! 394: ss->sio.scan_scanner_type = GENERIC_SCSI2;
! 395: }
! 396: }
! 397:
! 398: /*
! 399: * open the device.
! 400: */
! 401: int
! 402: ssopen(dev, flag, mode, p)
! 403: dev_t dev;
! 404: int flag;
! 405: int mode;
! 406: struct proc *p;
! 407: {
! 408: int unit;
! 409: u_int ssmode;
! 410: int error = 0;
! 411: struct ss_softc *ss;
! 412: struct scsi_link *sc_link;
! 413:
! 414: unit = SSUNIT(dev);
! 415: if (unit >= ss_cd.cd_ndevs)
! 416: return (ENXIO);
! 417: ss = ss_cd.cd_devs[unit];
! 418: if (!ss)
! 419: return (ENXIO);
! 420:
! 421: ssmode = SSMODE(dev);
! 422: sc_link = ss->sc_link;
! 423:
! 424: SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n", dev,
! 425: unit, ss_cd.cd_ndevs));
! 426:
! 427: if (sc_link->flags & SDEV_OPEN) {
! 428: printf("%s: already open\n", ss->sc_dev.dv_xname);
! 429: return (EBUSY);
! 430: }
! 431:
! 432: /*
! 433: * Catch any unit attention errors.
! 434: *
! 435: * SCSI_IGNORE_MEDIA_CHANGE: when you have an ADF, some scanners
! 436: * consider paper to be a changeable media
! 437: *
! 438: */
! 439: error = scsi_test_unit_ready(sc_link, TEST_READY_RETRIES,
! 440: SCSI_IGNORE_MEDIA_CHANGE | SCSI_IGNORE_ILLEGAL_REQUEST |
! 441: (ssmode == MODE_CONTROL ? SCSI_IGNORE_NOT_READY : 0));
! 442: if (error)
! 443: goto bad;
! 444:
! 445: sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */
! 446:
! 447: /*
! 448: * If the mode is 3 (e.g. minor = 3,7,11,15)
! 449: * then the device has been opened to set defaults
! 450: * This mode does NOT ALLOW I/O, only ioctls
! 451: */
! 452: if (ssmode == MODE_CONTROL)
! 453: return (0);
! 454:
! 455: SC_DEBUG(sc_link, SDEV_DB2, ("open complete\n"));
! 456: return (0);
! 457:
! 458: bad:
! 459: sc_link->flags &= ~SDEV_OPEN;
! 460: return (error);
! 461: }
! 462:
! 463: /*
! 464: * close the device.. only called if we are the LAST
! 465: * occurence of an open device
! 466: */
! 467: int
! 468: ssclose(dev, flag, mode, p)
! 469: dev_t dev;
! 470: int flag;
! 471: int mode;
! 472: struct proc *p;
! 473: {
! 474: struct ss_softc *ss = ss_cd.cd_devs[SSUNIT(dev)];
! 475: int error;
! 476:
! 477: SC_DEBUG(ss->sc_link, SDEV_DB1, ("closing\n"));
! 478:
! 479: if (SSMODE(dev) == MODE_REWIND) {
! 480: if (ss->special.rewind_scanner) {
! 481: /* call special handler to rewind/abort scan */
! 482: error = (ss->special.rewind_scanner)(ss);
! 483: if (error)
! 484: return (error);
! 485: } else {
! 486: /* XXX add code to restart a SCSI2 scanner, if any */
! 487: }
! 488: ss->sio.scan_window_size = 0;
! 489: ss->flags &= ~SSF_TRIGGERED;
! 490: }
! 491: ss->sc_link->flags &= ~SDEV_OPEN;
! 492:
! 493: return (0);
! 494: }
! 495:
! 496: /*
! 497: * trim the size of the transfer if needed,
! 498: * called by physio
! 499: * basically the smaller of our min and the scsi driver's
! 500: * minphys
! 501: */
! 502: void
! 503: ssminphys(bp)
! 504: struct buf *bp;
! 505: {
! 506: struct ss_softc *ss = ss_cd.cd_devs[SSUNIT(bp->b_dev)];
! 507:
! 508: (ss->sc_link->adapter->scsi_minphys)(bp);
! 509:
! 510: /*
! 511: * trim the transfer further for special devices this is
! 512: * because some scanners only read multiples of a line at a
! 513: * time, also some cannot disconnect, so the read must be
! 514: * short enough to happen quickly
! 515: */
! 516: if (ss->special.minphys)
! 517: (ss->special.minphys)(ss, bp);
! 518: }
! 519:
! 520: /*
! 521: * Do a read on a device for a user process.
! 522: * Prime scanner at start of read, check uio values, call ssstrategy
! 523: * via physio for the actual transfer.
! 524: */
! 525: int
! 526: ssread(dev, uio, flag)
! 527: dev_t dev;
! 528: struct uio *uio;
! 529: int flag;
! 530: {
! 531: struct ss_softc *ss = ss_cd.cd_devs[SSUNIT(dev)];
! 532: int error;
! 533:
! 534: /* if the scanner has not yet been started, do it now */
! 535: if (!(ss->flags & SSF_TRIGGERED)) {
! 536: if (ss->special.trigger_scanner) {
! 537: error = (ss->special.trigger_scanner)(ss);
! 538: if (error)
! 539: return (error);
! 540: } else {
! 541: struct scsi_start_stop trigger_cmd;
! 542: bzero(&trigger_cmd, sizeof(trigger_cmd));
! 543: trigger_cmd.opcode = START_STOP;
! 544: trigger_cmd.how = SSS_START;
! 545: scsi_scsi_cmd(ss->sc_link,
! 546: (struct scsi_generic *)&trigger_cmd,
! 547: sizeof(trigger_cmd), 0, 0, 4, 5000, NULL, 0);
! 548: }
! 549: ss->flags |= SSF_TRIGGERED;
! 550: }
! 551:
! 552: return (physio(ssstrategy, NULL, dev, B_READ, ssminphys, uio));
! 553: }
! 554:
! 555: /*
! 556: * Actually translate the requested transfer into one the physical
! 557: * driver can understand The transfer is described by a buf and will
! 558: * include only one physical transfer.
! 559: */
! 560: void
! 561: ssstrategy(bp)
! 562: struct buf *bp;
! 563: {
! 564: struct ss_softc *ss = ss_cd.cd_devs[SSUNIT(bp->b_dev)];
! 565: struct buf *dp;
! 566: int s;
! 567:
! 568: SC_DEBUG(ss->sc_link, SDEV_DB2, ("ssstrategy: %ld bytes @ blk %d\n",
! 569: bp->b_bcount, bp->b_blkno));
! 570:
! 571: if (bp->b_bcount > ss->sio.scan_window_size)
! 572: bp->b_bcount = ss->sio.scan_window_size;
! 573:
! 574: /*
! 575: * If it's a null transfer, return immediately
! 576: */
! 577: if (bp->b_bcount == 0)
! 578: goto done;
! 579:
! 580: s = splbio();
! 581:
! 582: /*
! 583: * Place it in the queue of activities for this scanner
! 584: * at the end (a bit silly because we only have on user..)
! 585: * (but it could fork() or dup())
! 586: */
! 587: dp = &ss->buf_queue;
! 588: bp->b_actf = NULL;
! 589: bp->b_actb = dp->b_actb;
! 590: *dp->b_actb = bp;
! 591: dp->b_actb = &bp->b_actf;
! 592:
! 593: /*
! 594: * Tell the device to get going on the transfer if it's
! 595: * not doing anything, otherwise just wait for completion
! 596: * (All a bit silly if we're only allowing 1 open but..)
! 597: */
! 598: ssstart(ss);
! 599:
! 600: splx(s);
! 601: return;
! 602:
! 603: done:
! 604: /*
! 605: * Correctly set the buf to indicate a completed xfer
! 606: */
! 607: bp->b_resid = bp->b_bcount;
! 608: s = splbio();
! 609: biodone(bp);
! 610: splx(s);
! 611: }
! 612:
! 613: /*
! 614: * ssstart looks to see if there is a buf waiting for the device
! 615: * and that the device is not already busy. If both are true,
! 616: * It dequeues the buf and creates a scsi command to perform the
! 617: * transfer required. The transfer request will call scsi_done
! 618: * on completion, which will in turn call this routine again
! 619: * so that the next queued transfer is performed.
! 620: * The bufs are queued by the strategy routine (ssstrategy)
! 621: *
! 622: * This routine is also called after other non-queued requests
! 623: * have been made of the scsi driver, to ensure that the queue
! 624: * continues to be drained.
! 625: * ssstart() is called at splbio
! 626: */
! 627: void
! 628: ssstart(v)
! 629: void *v;
! 630: {
! 631: struct ss_softc *ss = v;
! 632: struct scsi_link *sc_link = ss->sc_link;
! 633: struct buf *bp, *dp;
! 634: struct scsi_r_scanner read_cmd;
! 635: int flags;
! 636:
! 637: SC_DEBUG(sc_link, SDEV_DB2, ("ssstart\n"));
! 638: /*
! 639: * See if there is a buf to do and we are not already
! 640: * doing one
! 641: */
! 642: while (sc_link->openings > 0) {
! 643: /* if a special awaits, let it proceed first */
! 644: if (sc_link->flags & SDEV_WAITING) {
! 645: sc_link->flags &= ~SDEV_WAITING;
! 646: wakeup((caddr_t)sc_link);
! 647: return;
! 648: }
! 649:
! 650: /*
! 651: * See if there is a buf with work for us to do..
! 652: */
! 653: dp = &ss->buf_queue;
! 654: if ((bp = dp->b_actf) == NULL)
! 655: return;
! 656: if ((dp = bp->b_actf) != NULL)
! 657: dp->b_actb = bp->b_actb;
! 658: else
! 659: ss->buf_queue.b_actb = bp->b_actb;
! 660: *bp->b_actb = dp;
! 661:
! 662: if (ss->special.read) {
! 663: (ss->special.read)(ss, bp);
! 664: } else {
! 665: /* generic scsi2 scanner read */
! 666: bzero(&read_cmd, sizeof(read_cmd));
! 667: read_cmd.opcode = READ_BIG;
! 668: _lto3b(bp->b_bcount, read_cmd.len);
! 669: flags = SCSI_DATA_IN;
! 670: /*
! 671: * go ask the adapter to do all this for us
! 672: */
! 673: if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)
! 674: &read_cmd, sizeof(read_cmd), (u_char *) bp->b_data,
! 675: bp->b_bcount, 0, 100000, bp, flags | SCSI_NOSLEEP))
! 676: printf("%s: not queued\n", ss->sc_dev.dv_xname);
! 677: }
! 678: }
! 679: }
! 680:
! 681: /*
! 682: * Perform special action on behalf of the user;
! 683: * knows about the internals of this device
! 684: */
! 685: int
! 686: ssioctl(dev, cmd, addr, flag, p)
! 687: dev_t dev;
! 688: u_long cmd;
! 689: caddr_t addr;
! 690: int flag;
! 691: struct proc *p;
! 692: {
! 693: struct ss_softc *ss = ss_cd.cd_devs[SSUNIT(dev)];
! 694: int error = 0;
! 695: struct scan_io *sio;
! 696:
! 697: switch (cmd) {
! 698: case SCIOCGET:
! 699: /* call special handler, if any */
! 700: if (ss->special.get_params) {
! 701: error = (ss->special.get_params)(ss);
! 702: if (error)
! 703: return (error);
! 704: }
! 705: bcopy(&ss->sio, addr, sizeof(struct scan_io));
! 706: break;
! 707: case SCIOCSET:
! 708: sio = (struct scan_io *)addr;
! 709:
! 710: /* call special handler, if any */
! 711: if (ss->special.set_params) {
! 712: error = (ss->special.set_params)(ss, sio);
! 713: if (error)
! 714: return (error);
! 715: } else {
! 716: /* XXX add routine to validate parameters */
! 717: ss_set_window(ss, sio);
! 718: }
! 719: break;
! 720: case SCIOCRESTART:
! 721: /* call special handler, if any */
! 722: if (ss->special.rewind_scanner ) {
! 723: error = (ss->special.rewind_scanner)(ss);
! 724: if (error)
! 725: return (error);
! 726: } else
! 727: /* XXX add code for SCSI2 scanner, if any */
! 728: return (EOPNOTSUPP);
! 729: ss->flags &= ~SSF_TRIGGERED;
! 730: break;
! 731: case SCIOC_USE_ADF:
! 732: /* XXX add Automatic Document Feeder Support */
! 733: return (EOPNOTSUPP);
! 734: default:
! 735: if (SSMODE(dev) != MODE_CONTROL)
! 736: return (ENOTTY);
! 737: return (scsi_do_ioctl(ss->sc_link, dev, cmd, addr,
! 738: flag, p));
! 739: }
! 740: return (error);
! 741: }
! 742:
! 743: int
! 744: ss_set_window(ss, sio)
! 745: struct ss_softc *ss;
! 746: struct scan_io *sio;
! 747: {
! 748: struct scsi_set_window window_cmd;
! 749: struct {
! 750: struct scsi_window_data window_data;
! 751: /* vendor_unique must provide enough space for worst case
! 752: * (currently Ricoh IS-410.) 40 + 280 = 320 which is the size
! 753: * of its window descriptor length
! 754: */
! 755: u_int8_t vendor_unique[280];
! 756: } wd;
! 757: #define window_data wd.window_data
! 758: #define vendor_unique wd.vendor_unique
! 759: struct scsi_link *sc_link = ss->sc_link;
! 760:
! 761: /*
! 762: * The CDB for SET WINDOW goes in here.
! 763: * The two structures that follow are sent via data out.
! 764: */
! 765: bzero(&window_cmd, sizeof(window_cmd));
! 766: window_cmd.opcode = SET_WINDOW;
! 767: _lto3l(sizeof(window_data), window_cmd.len);
! 768:
! 769: bzero(&window_data, sizeof(window_data));
! 770: if (ss->quirkdata->quirks & SS_Q_WINDOW_DESC_LEN)
! 771: _lto2l(ss->quirkdata->window_descriptor_length,
! 772: window_data.window_desc_len);
! 773: else
! 774: _lto2l(40L, window_data.window_desc_len);
! 775:
! 776: /* start of SET_WINDOW parameter block */
! 777:
! 778: /* leave window id at zero */
! 779: /* leave auto bit at zero */
! 780: _lto2l(sio->scan_x_resolution, window_data.x_res);
! 781: _lto2l(sio->scan_y_resolution, window_data.y_res);
! 782: _lto4l(sio->scan_x_origin, window_data.x_org);
! 783: _lto4l(sio->scan_y_origin, window_data.y_org);
! 784: _lto4l(sio->scan_width, window_data.width);
! 785: _lto4l(sio->scan_height, window_data.length);
! 786:
! 787: if (ss->quirkdata->quirks & SS_Q_REV_BRIGHTNESS)
! 788: window_data.brightness = 256 - sio->scan_brightness;
! 789: else if (ss->quirkdata->quirks & SS_Q_BRIGHTNESS)
! 790: window_data.brightness = ss->quirkdata->brightness;
! 791: else
! 792: window_data.brightness = sio->scan_brightness;
! 793:
! 794: /*
! 795: * threshold: Default is to follow brightness.
! 796: * If SS_Q_MONO_THRESHOLD is set then the quirkdata contains a special
! 797: * value to be used instead of default when image data is monochrome.
! 798: * Otherwise if SS_Q_THRESHOLD is set then the quirkdata contains
! 799: * the threshold to always use.
! 800: * Both SS_Q_MONO_THRESHOLD and SS_Q_THRESHOLD should not be set at
! 801: * the same time.
! 802: */
! 803: if (ss->quirkdata->quirks & SS_Q_MONO_THRESHOLD) {
! 804: if (sio->scan_image_mode == SIM_BINARY_MONOCHROME ||
! 805: sio->scan_image_mode == SIM_DITHERED_MONOCHROME)
! 806: window_data.threshold = ss->quirkdata->threshold;
! 807: else
! 808: window_data.threshold = sio->scan_brightness;
! 809: } else if (ss->quirkdata->quirks & SS_Q_THRESHOLD)
! 810: window_data.threshold = ss->quirkdata->threshold;
! 811: else
! 812: window_data.threshold = sio->scan_brightness;
! 813:
! 814: if (ss->quirkdata->quirks & SS_Q_REV_CONTRAST)
! 815: window_data.contrast = 256 - sio->scan_contrast;
! 816: else if (ss->quirkdata->quirks & SS_Q_CONTRAST)
! 817: window_data.contrast = ss->quirkdata->contrast;
! 818: else
! 819: window_data.contrast = sio->scan_contrast;
! 820:
! 821: switch (sio->scan_image_mode) {
! 822: case SIM_RED:
! 823: case SIM_GREEN:
! 824: case SIM_BLUE:
! 825: window_data.image_comp = SIM_GRAYSCALE;
! 826: break;
! 827: default:
! 828: window_data.image_comp = sio->scan_image_mode;
! 829: }
! 830:
! 831: window_data.bits_per_pixel = sio->scan_bits_per_pixel;
! 832:
! 833: if (ss->quirkdata->quirks & SS_Q_HALFTONE) {
! 834: window_data.halftone_pattern[0] =
! 835: ss->quirkdata->halftone_pattern[0];
! 836: window_data.halftone_pattern[1] =
! 837: ss->quirkdata->halftone_pattern[1];
! 838: } /* else leave halftone set to zero. */
! 839:
! 840: if (ss->quirkdata->quirks & SS_Q_SET_RIF)
! 841: window_data.rif = 1;
! 842:
! 843: if (ss->quirkdata->quirks & SS_Q_PADDING_TYPE)
! 844: window_data.pad_type = ss->quirkdata->pad_type;
! 845: else
! 846: window_data.pad_type = 3; /* 3 = truncate to byte boundary */
! 847:
! 848: if (ss->quirkdata->quirks & SS_Q_BIT_ORDERING)
! 849: _lto2l(ss->quirkdata->bit_ordering, window_data.bit_ordering);
! 850: /* else leave bit_ordering set to zero. */
! 851:
! 852: /* leave compression type & argument set to zero. */
! 853:
! 854: #undef window_data
! 855:
! 856: if (ss->quirkdata->vendor_unique_sw != NULL)
! 857: return ((*ss->quirkdata->vendor_unique_sw)(ss, sio,
! 858: &window_cmd, (void *)&wd));
! 859: else
! 860: /* send the command to the scanner */
! 861: return (scsi_scsi_cmd(sc_link,
! 862: (struct scsi_generic *)&window_cmd,
! 863: sizeof(window_cmd), (u_char *) &wd.window_data,
! 864: (ss->quirkdata->quirks & SS_Q_WINDOW_DESC_LEN) ?
! 865: ss->quirkdata->window_descriptor_length : 40,
! 866: 4, 5000, NULL, SCSI_DATA_OUT));
! 867: }
! 868:
! 869: int
! 870: ricoh_is410_sw(ss, sio, wcmd, vwd)
! 871: struct ss_softc *ss;
! 872: struct scan_io *sio;
! 873: struct scsi_set_window *wcmd;
! 874: void *vwd;
! 875: {
! 876: struct ricoh_is410_window_data {
! 877: struct scsi_window_data window_data;
! 878: u_int8_t res1;
! 879: u_int8_t res2;
! 880: u_int mrif:1; /* reverse image format (grayscale negative) */
! 881: u_int filtering:3;
! 882: u_int gamma_id:4;
! 883: } *rwd = (struct ricoh_is410_window_data*)vwd;
! 884: struct scsi_link *sc_link = ss->sc_link;
! 885:
! 886: rwd->mrif = 1; /* force grayscale to match PGM */
! 887:
! 888: /* send the command to the scanner */
! 889: return (scsi_scsi_cmd(sc_link, (struct scsi_generic *)wcmd,
! 890: sizeof(struct scsi_set_window), (u_char *)rwd,
! 891: sizeof(struct ricoh_is410_window_data), 4, 5000, NULL,
! 892: SCSI_DATA_OUT));
! 893: }
! 894:
! 895: int
! 896: umax_uc630_sw(ss, sio, wcmd, vwd)
! 897: struct ss_softc *ss;
! 898: struct scan_io *sio;
! 899: struct scsi_set_window *wcmd;
! 900: void *vwd;
! 901: {
! 902: struct umax_uc630_window_data {
! 903: struct scsi_window_data window_data;
! 904: u_int8_t speed;
! 905: u_int8_t select_color;
! 906: u_int8_t highlight;
! 907: u_int8_t shadow;
! 908: u_int8_t paper_length[2];
! 909: } *uwd = (struct umax_uc630_window_data*)vwd;
! 910: struct scsi_link *sc_link = ss->sc_link;
! 911:
! 912: uwd->speed = 1; /* speed: fastest speed that doesn't smear */
! 913: switch (sio->scan_image_mode) { /* UMAX has three-pass color. */
! 914: case SIM_RED: /* This selects which filter to use. */
! 915: uwd->select_color = 0x80;
! 916: break;
! 917: case SIM_GREEN:
! 918: uwd->select_color = 0x40;
! 919: break;
! 920: case SIM_BLUE:
! 921: uwd->select_color = 0x20;
! 922: break;
! 923: }
! 924: uwd->highlight = 50; /* 50 = highest; 0 = lowest */
! 925: /* leave shadow set to zero. */
! 926: /* XXX paper length is for ADF */
! 927:
! 928: /* send the command to the scanner */
! 929: return (scsi_scsi_cmd(sc_link, (struct scsi_generic *)wcmd,
! 930: sizeof(struct scsi_set_window), (u_char *)uwd,
! 931: sizeof(struct umax_uc630_window_data), 4, 5000, NULL,
! 932: SCSI_DATA_OUT));
! 933: }
! 934:
! 935: #ifdef NOTYET /* for ADF support */
! 936: int
! 937: fujitsu_m3096g_sw(ss, sio, wcmd, vwd)
! 938: struct ss_softc *ss;
! 939: struct scan_io *sio;
! 940: struct scsi_set_window *wcmd;
! 941: void *vwd;
! 942: {
! 943: struct fujitsu_m3096g_window_data {
! 944: struct scsi_window_data window_data;
! 945: u_int8_t id;
! 946: u_int8_t res1;
! 947: u_int8_t outline;
! 948: u_int8_t emphasis;
! 949: u_int8_t mixed;
! 950: u_int8_t mirroring;
! 951: u_int8_t res2[5];
! 952: u_int8_t subwindow_list[2];
! 953: u_int paper_size_std:2;
! 954: u_int res3:1;
! 955: u_int paper_orientaton:1;
! 956: u_int paper_size_type:4;
! 957: /* defines for Paper Size Type: */
! 958: #define FUJITSU_PST_A3 0x03
! 959: #define FUJITSU_PST_A4 0x04
! 960: #define FUJITSU_PST_A5 0x05
! 961: #define FUJITSU_PST_DOUBLE_LETTER 0x06
! 962: #define FUJITSU_PST_LETTER 0x07
! 963: #define FUJITSU_PST_B4 0x0C
! 964: #define FUJITSU_PST_B5 0x0D
! 965: #define FUJITSU_PST_LEGAL 0x0F
! 966: u_int8_t paper_width_x[4];
! 967: u_int8_t paper_width_y[4];
! 968: u_int8_t res4[2];
! 969: } *fwd = (struct fujitsu_m3096g_window_data*)vwd;
! 970: struct scsi_link *sc_link = ss->sc_link;
! 971:
! 972: /* send the command to the scanner */
! 973: return (scsi_scsi_cmd(sc_link, (struct scsi_generic *)wcmd,
! 974: sizeof(struct scsi_set_window), (u_char *)fwd,
! 975: sizeof(struct fujitsu_m3096g_window_data), 4, 5000, NULL,
! 976: SCSI_DATA_OUT));
! 977: }
! 978: #endif
! 979:
! 980: void
! 981: get_buffer_status(ss, bp)
! 982: struct ss_softc *ss;
! 983: struct buf *bp;
! 984: {
! 985: struct scsi_get_buffer_status gbs_cmd;
! 986: struct scsi_link *sc_link = ss->sc_link;
! 987: struct {
! 988: u_int8_t stat_len[3];
! 989: u_int8_t res1;
! 990: u_int8_t window_id;
! 991: u_int8_t res2;
! 992: u_int8_t tgt_accept_buf_len[3];
! 993: u_int8_t tgt_send_buf_len[3];
! 994: } buf_sz_retn;
! 995: int flags;
! 996:
! 997: bzero(&gbs_cmd, sizeof(gbs_cmd));
! 998: gbs_cmd.opcode = GET_BUFFER_STATUS;
! 999: _lto2b(12, gbs_cmd.len);
! 1000: flags = SCSI_DATA_IN;
! 1001:
! 1002: if (scsi_scsi_cmd(sc_link, (struct scsi_generic *) &gbs_cmd,
! 1003: sizeof(gbs_cmd), (u_char *) &buf_sz_retn, sizeof(buf_sz_retn),
! 1004: 0, 100000, bp, flags | SCSI_NOSLEEP)) {
! 1005: printf("%s: not queued\n", ss->sc_dev.dv_xname);
! 1006: }
! 1007: bp->b_bcount = MIN(_3btol(buf_sz_retn.tgt_send_buf_len), bp->b_bcount);
! 1008: }
! 1009:
! 1010: #ifdef NOTYET
! 1011: int
! 1012: umax_compute_sizes(ss)
! 1013: struct ss_softc *ss;
! 1014: {
! 1015: ss->sio.scan_lines = ;
! 1016: ss->sio.scan_window_size = ;
! 1017: }
! 1018:
! 1019: int
! 1020: calc_umax_row_len(dpi, ww)
! 1021: int dpi;
! 1022: int ww;
! 1023: {
! 1024: int st[301];
! 1025: int i;
! 1026: int rowB = 0;
! 1027:
! 1028: for (i = 1; i <= 300; i++)
! 1029: st[i] = 1;
! 1030:
! 1031: for (i = 1; i <= 300 - dpi; i++)
! 1032: st[i * 300 / (300 - dpi)] = 0;
! 1033:
! 1034: for (i = 1; i <= (ww % 1200) / 4; i++) {
! 1035: if (st[i])
! 1036: rowB++;
! 1037: }
! 1038:
! 1039: return ((ww / 1200) * dpi + rowB);
! 1040: }
! 1041: #endif
CVSweb