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

Cache object: 8ea520df3d24cbc14d738ae0ba6cdebf


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