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

Cache object: bc3b8625ec45be57a2622a699d3fe760


[ 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.