root/scsi/ss_scanjet.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scanjet_attach
  2. scanjet_set_params
  3. scanjet_trigger_scanner
  4. scanjet_read
  5. scanjet_ctl_write
  6. scanjet_ctl_read
  7. show_es
  8. scanjet_set_window
  9. atoi
  10. scanjet_compute_sizes

    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 }

/* [<][>][^][v][top][bottom][index][help] */