The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/scsipi/ss_scanjet.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d0b8e71563520825e6a800f93939228e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.