[BACK]Return to ss_scanjet.c CVS log [TXT][DIR] Up to [local] / sys / scsi

Annotation of sys/scsi/ss_scanjet.c, Revision 1.1.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