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/i386/isa/qcamio.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 /*
    2  * Connectix QuickCam parallel-port camera video capture driver.
    3  * Copyright (c) 1996, Paul Traina.
    4  *
    5  * This driver is based in part on work
    6  * Copyright (c) 1996, Thomas Davis.
    7  *
    8  * Additional ideas from code written by Michael Chinn and Nelson Minar.
    9  *
   10  * QuickCam(TM) is a registered trademark of Connectix Inc.
   11  * Use this driver at your own risk, it is not warranted by
   12  * Connectix or the authors.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer
   19  *    in this position and unchanged.
   20  * 2. Redistributions in binary form must reproduce the above copyright
   21  *    notice, this list of conditions and the following disclaimer in the
   22  *    documentation and/or other materials provided with the distribution.
   23  * 3. The name of the author may not be used to endorse or promote products
   24  *    derived from this software withough specific prior written permission
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 #ifndef NQCAM
   39 #include        "qcam.h"                /* this file defines NQCAM _only_ */
   40 #endif
   41 
   42 #if NQCAM > 0
   43 
   44 #if defined(__FreeBSD__) || defined(__NetBSD__)
   45 #include        <sys/param.h>
   46 #include        <machine/cpufunc.h>
   47 #ifdef  KERNEL
   48 #include        <sys/systm.h>
   49 #include        <machine/clock.h>
   50 #include        <machine/qcam.h>
   51 #else   /* user mode version of driver */
   52 #include        <unistd.h>
   53 #include        <stdio.h>
   54 #include        "qcam.h"
   55 #endif  /* KERNEL */
   56 #endif  /* FreeBSD or NetBSD */
   57 
   58 #ifdef  bsdi
   59 #include        <sys/param.h>
   60 #include        <sys/conf.h>
   61 #include        <sys/device.h>
   62 #include        "qcam.h"
   63 #endif  /* bsdi */
   64 
   65 #ifdef  __linux__
   66 #include        <linux/kernel.h>
   67 #include        <linux/sched.h>
   68 #include        <linux/string.h>
   69 #include        <linux/delay.h>
   70 #include        <asm/io.h>
   71 #include        "qcam-linux.h"
   72 #include        "qcam.h"
   73 #endif  /* __linux__ */
   74 
   75 #ifdef  _SCO_DS
   76 #include        <limits.h>
   77 #include        <errno.h>
   78 #include        <sys/types.h>
   79 #include        "qcam-sco.h"
   80 #include        "qcam.h"
   81 #endif
   82 
   83 #ifdef __FreeBSD__
   84 #include        <i386/isa/qcamreg.h>
   85 #include        <i386/isa/qcamdefs.h>
   86 #else
   87 #include        "qcamreg.h"
   88 #include        "qcamdefs.h"
   89 #endif
   90 
   91 /*
   92  * There should be _NO_ operating system dependant code or definitions
   93  * past this point.
   94  */
   95 
   96 static const u_char qcam_zoommode[3][3] = {
   97         { QC_XFER_WIDE,   QC_XFER_WIDE,   QC_XFER_WIDE },
   98         { QC_XFER_NARROW, QC_XFER_WIDE,   QC_XFER_WIDE },
   99         { QC_XFER_TIGHT,  QC_XFER_NARROW, QC_XFER_WIDE }
  100 };
  101 
  102 static int qcam_timeouts;
  103 
  104 #ifdef  QCAM_GRAB_STATS
  105 
  106 #define STATBUFSIZE (QC_MAXFRAMEBUFSIZE*2+50)
  107 static u_short qcam_rsbhigh[STATBUFSIZE];
  108 static u_short qcam_rsblow[STATBUFSIZE];
  109 static u_short *qcam_rsbhigh_p   = qcam_rsbhigh;
  110 static u_short *qcam_rsblow_p    = qcam_rsblow;
  111 static u_short *qcam_rsbhigh_end = &qcam_rsbhigh[STATBUFSIZE];
  112 static u_short *qcam_rsblow_end  = &qcam_rsblow[STATBUFSIZE];
  113 
  114 #define STATHIGH(T) \
  115         if (qcam_rsbhigh_p < qcam_rsbhigh_end) \
  116                 *qcam_rsbhigh_p++ = ((T) - timeout); \
  117         if (!timeout) qcam_timeouts++;
  118 
  119 #define STATLOW(T) \
  120         if (qcam_rsblow_p < qcam_rsblow_end) \
  121                 *qcam_rsblow_p++ = ((T) - timeout); \
  122         if (!timeout) qcam_timeouts++;
  123 
  124 #else
  125 
  126 #define STATHIGH(T)     if (!timeout) qcam_timeouts++;
  127 #define STATLOW(T)      if (!timeout) qcam_timeouts++;
  128 
  129 #endif  /* QCAM_GRAB_STATS */
  130 
  131 #define READ_STATUS_BYTE_HIGH(P, V, T) { \
  132         u_short timeout = (T); \
  133         do { (V) = read_status((P)); \
  134         } while (!(((V) & 0x08)) && --timeout); STATHIGH(T) \
  135 }
  136 
  137 #define READ_STATUS_BYTE_LOW(P, V, T) { \
  138         u_short timeout = (T); \
  139         do { (V) = read_status((P)); \
  140         } while (((V) & 0x08) && --timeout); STATLOW(T) \
  141 }
  142                 
  143 #define READ_DATA_WORD_HIGH(P, V, T) { \
  144         u_int timeout = (T); \
  145         do { (V) = read_data_word((P)); \
  146         } while (!((V) & 0x01) && --timeout); STATHIGH(T) \
  147 }
  148 
  149 #define READ_DATA_WORD_LOW(P, V, T) { \
  150         u_int timeout = (T); \
  151         do { (V) = read_data_word((P)); \
  152         } while (((V) & 0x01) && --timeout); STATLOW(T) \
  153 }
  154 
  155 inline static int
  156 sendbyte (u_int port, int value, int sdelay)
  157 {
  158         u_char s1, s2;
  159 
  160         write_data(port, value);
  161         if (sdelay) {
  162             DELAY(sdelay);
  163             write_data(port, value);
  164         }
  165 
  166         write_control(port, QC_CTL_HIGHNIB);
  167         READ_STATUS_BYTE_HIGH(port, s1, QC_TIMEOUT_CMD);
  168 
  169         write_control(port, QC_CTL_LOWNIB);
  170         READ_STATUS_BYTE_LOW(port, s2, QC_TIMEOUT_CMD);
  171 
  172         return (s1 & 0xf0) | (s2 >> 4);
  173 }
  174 
  175 static int
  176 send_command (struct qcam_softc *qs, int cmd, int value)
  177 {
  178         if (sendbyte(qs->iobase, cmd, qs->exposure) != cmd)
  179                 return 1;
  180 
  181         if (sendbyte(qs->iobase, value, qs->exposure) != value)
  182                 return 1;
  183 
  184         return 0;                       /* success */
  185 }
  186 
  187 static int
  188 send_xfermode (struct qcam_softc *qs, int value)
  189 {
  190         if (sendbyte(qs->iobase, QC_XFERMODE, qs->exposure) != QC_XFERMODE)
  191                 return 1;
  192 
  193         if (sendbyte(qs->iobase, value, qs->exposure) != value)
  194                 return 1;
  195 
  196         return 0;
  197 }
  198 
  199 void
  200 qcam_reset (struct qcam_softc *qs)
  201 {
  202         register u_int  iobase = qs->iobase;
  203         register u_char result;
  204 
  205         write_control(iobase, 0x20);
  206         write_data   (iobase, 0x75);
  207 
  208         result = read_data(iobase);
  209 
  210         if ((result != 0x75) && !(qs->flags & QC_FORCEUNI))
  211             qs->flags |= QC_BIDIR_HW;   /* bidirectional parallel port */
  212         else
  213             qs->flags &= ~QC_BIDIR_HW;
  214 
  215         write_control(iobase, 0x0b);
  216         DELAY(250);
  217         write_control(iobase, QC_CTL_LOWNIB);
  218         DELAY(250);
  219 }
  220 
  221 static int
  222 qcam_waitfor_bi (u_int port)
  223 {
  224         u_char s1, s2;
  225 
  226         write_control(port, QC_CTL_HIGHWORD);
  227         READ_STATUS_BYTE_HIGH(port, s1, QC_TIMEOUT_INIT);
  228 
  229         write_control(port, QC_CTL_LOWWORD);
  230         READ_STATUS_BYTE_LOW(port, s2, QC_TIMEOUT);
  231 
  232         return (s1 & 0xf0) | (s2 >> 4);
  233 }
  234 
  235 /*
  236  * The pixels are read in 16 bits at a time, and we get 3 valid pixels per
  237  * 16-bit read.  The encoding format looks like this:
  238  *
  239  * |---- status reg -----| |----- data reg ------|
  240  * 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
  241  *  3  3  3  3  2  x  x  x  2  2  2  1  1  1  1  R
  242  *
  243  *  1 = left pixel      R = camera ready
  244  *  2 = middle pixel    x = unknown/unused?
  245  *  3 = right pixel
  246  *
  247  * XXX do not use this routine yet!  It does not work.
  248  *     Nelson believes that even though 6 pixels are read in per 2 words,
  249  *     only the 1 & 2 pixels from the first word are correct.  This seems
  250  *     bizzare, more study is needed here.
  251  */
  252 
  253 #define DECODE_WORD_BI4BPP(P, W) \
  254         *(P)++ = 15 - (((W) >> 12) & 0x0f); \
  255         *(P)++ = 15 - ((((W) >> 8) & 0x08) | (((W) >> 5) & 0x07)); \
  256         *(P)++ = 15 - (((W) >>  1) & 0x0f);
  257 
  258 static void
  259 qcam_bi_4bit (struct qcam_softc *qs)
  260 {
  261         u_char *p;
  262         u_int   port;
  263         u_short word;
  264 
  265         port = qs->iobase;                      /* for speed */
  266 
  267         qcam_waitfor_bi(port);
  268 
  269         /*
  270          * Unlike the other routines, this routine has NOT be interleaved
  271          * yet because we don't have the algorythm for 4bbp down tight yet,
  272          * so why add to the confusion?
  273          */
  274         for (p = qs->buffer; p < qs->buffer_end; ) {
  275                 write_control(port, QC_CTL_HIGHWORD);
  276                 READ_DATA_WORD_HIGH(port, word, QC_TIMEOUT);
  277                 DECODE_WORD_BI4BPP(p, word);
  278 
  279                 write_control(port, QC_CTL_LOWWORD);
  280                 READ_DATA_WORD_HIGH(port, word, QC_TIMEOUT);
  281                 DECODE_WORD_BI4BPP(p, word);
  282         }
  283 }
  284 
  285 /*
  286  * The pixels are read in 16 bits at a time, 12 of those bits contain
  287  * pixel information, the format looks like this:
  288  *
  289  * |---- status reg -----| |----- data reg ------|
  290  * 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
  291  *  2  2  2  2  2  x  x  x  2  1  1  1  1  1  1  R
  292  *
  293  * 1 = left pixel               R = camera ready
  294  * 2 = right pixel              x = unknown/unused?
  295  */
  296 
  297 #define DECODE_WORD_BI6BPP(P, W) \
  298         *(P)++ = 63 -  (((W) >>  1) & 0x3f); \
  299         *(P)++ = 63 - ((((W) >> 10) & 0x3e) | (((W) >> 7) & 0x01));
  300 
  301 static void
  302 qcam_bi_6bit (struct qcam_softc *qs)
  303 {
  304         u_char *p;
  305         u_short hi, low;
  306         u_int   port;
  307 
  308         port = qs->iobase;                      /* for speed */
  309 
  310         qcam_waitfor_bi(port);
  311 
  312         /*
  313          * This was interleaved before, but I cut it back to the simple
  314          * mode so that it's easier for people to play with it.  A quick
  315          * unrolling of the loop coupled with interleaved decoding and I/O
  316          * should get us a slight CPU bonus later.
  317          */
  318         for (p = qs->buffer; p < qs->buffer_end; ) {
  319                 write_control(port, QC_CTL_HIGHWORD);
  320                 READ_DATA_WORD_HIGH(port, hi, QC_TIMEOUT);
  321                 DECODE_WORD_BI6BPP(p, hi);
  322 
  323                 write_control(port, QC_CTL_LOWWORD);
  324                 READ_DATA_WORD_LOW(port, low, QC_TIMEOUT);
  325                 DECODE_WORD_BI6BPP(p, low);
  326         }
  327 }
  328 
  329 /*
  330  * We're doing something tricky here that makes this routine a little
  331  * more complex than you would expect.  We're interleaving the high
  332  * and low nibble reads with the math required for nibble munging.
  333  * This should allow us to use the "free" time while we're waiting for
  334  * the next nibble to come ready to do any data conversion operations.
  335  */
  336 #define DECODE_WORD_UNI4BPP(P, W) \
  337         *(P)++ = 15 - ((W) >> 4);
  338 
  339 static void
  340 qcam_uni_4bit (struct qcam_softc *qs)
  341 {
  342         u_char  *p, *end, hi, low;
  343         u_int   port;
  344 
  345         port = qs->iobase;
  346         p    = qs->buffer;
  347         end  = qs->buffer_end - 1;
  348 
  349         /* request and wait for first nibble */
  350 
  351         write_control(port, QC_CTL_HIGHNIB);
  352         READ_STATUS_BYTE_HIGH(port, hi, QC_TIMEOUT_INIT);
  353 
  354         /* request second nibble, munge first nibble while waiting, read 2nd */
  355 
  356         write_control(port, QC_CTL_LOWNIB);
  357         DECODE_WORD_UNI4BPP(p, hi);
  358         READ_STATUS_BYTE_LOW(port, low, QC_TIMEOUT);
  359 
  360         while (p < end) {
  361                 write_control(port, QC_CTL_HIGHNIB);
  362                 DECODE_WORD_UNI4BPP(p, low);
  363                 READ_STATUS_BYTE_HIGH(port, hi, QC_TIMEOUT);
  364 
  365                 write_control(port, QC_CTL_LOWNIB);
  366                 DECODE_WORD_UNI4BPP(p, hi);
  367                 READ_STATUS_BYTE_LOW(port, low, QC_TIMEOUT);
  368         }
  369         DECODE_WORD_UNI4BPP(p, low);
  370 }
  371 
  372 /*
  373  * If you treat each pair of nibble operations as pulling in a byte, you
  374  * end up with a byte stream that looks like this:
  375  *
  376  *    msb             lsb
  377  *      2 2 1 1 1 1 1 1
  378  *      2 2 2 2 3 3 3 3
  379  *      3 3 4 4 4 4 4 4
  380  */
  381 
  382 static void
  383 qcam_uni_6bit (struct qcam_softc *qs)
  384 {
  385         u_char  *p;
  386         u_int   port;
  387         u_char  word1, word2, word3, hi, low;
  388 
  389         port = qs->iobase;
  390 
  391         /*
  392          * This routine has been partially interleaved... we can do a better
  393          * job, but for right now, I've deliberately kept it less efficient
  394          * so we can play with decoding without hurting peoples brains.
  395          */
  396         for (p = qs->buffer; p < qs->buffer_end; ) {
  397                 write_control(port, QC_CTL_HIGHNIB);
  398                 READ_STATUS_BYTE_HIGH(port, hi, QC_TIMEOUT_INIT);
  399                 write_control(port, QC_CTL_LOWNIB);
  400                 READ_STATUS_BYTE_LOW(port, low, QC_TIMEOUT);
  401                 write_control(port, QC_CTL_HIGHNIB);
  402                 word1 = (hi & 0xf0) | (low >>4);
  403                 READ_STATUS_BYTE_HIGH(port, hi, QC_TIMEOUT);
  404                 write_control(port, QC_CTL_LOWNIB);
  405                 *p++ = 63 - (word1 >> 2);
  406                 READ_STATUS_BYTE_LOW(port, low, QC_TIMEOUT);
  407                 write_control(port, QC_CTL_HIGHNIB);
  408                 word2 = (hi & 0xf0) | (low >> 4);
  409                 READ_STATUS_BYTE_HIGH(port, hi, QC_TIMEOUT);
  410                 write_control(port, QC_CTL_LOWNIB);
  411                 *p++ = 63 - (((word1 & 0x03) << 4) | (word2 >> 4));
  412                 READ_STATUS_BYTE_LOW(port, low, QC_TIMEOUT);
  413                 word3 = (hi & 0xf0) | (low >> 4);
  414                 *p++ = 63 - (((word2 & 0x0f) << 2) | (word3 >> 6));
  415                 *p++ = 63 - (word3 & 0x3f);
  416         }
  417 
  418         /* XXX this is something xfqcam does, doesn't make sense to me,
  419            but we don't see timeoutes here... ? */
  420         write_control(port, QC_CTL_LOWNIB);
  421         READ_STATUS_BYTE_LOW(port, word1, QC_TIMEOUT);
  422         write_control(port, QC_CTL_HIGHNIB);
  423         READ_STATUS_BYTE_LOW(port, word1, QC_TIMEOUT);
  424 }
  425 
  426 static void
  427 qcam_xferparms (struct qcam_softc *qs)
  428 {
  429         int bidir;
  430 
  431         qs->xferparms = 0;
  432 
  433         bidir = (qs->flags & QC_BIDIR_HW);
  434         if (bidir)
  435                 qs->xferparms |= QC_XFER_BIDIR;
  436 
  437         if (qcam_debug)
  438                 printf("qcam%d: %dbpp %sdirectional scan mode selected\n",
  439                         qs->unit, qs->bpp, bidir ? "bi" : "uni");
  440 
  441         if (qs->bpp == 6) {
  442                 qs->xferparms |= QC_XFER_6BPP;
  443                 qs->scanner    = bidir ? qcam_bi_6bit : qcam_uni_6bit;
  444         } else {
  445                 qs->scanner    = bidir ? qcam_bi_4bit : qcam_uni_4bit;
  446         }
  447 
  448         if (qs->x_size > 160 || qs->y_size > 120) {
  449                 qs->xferparms |= qcam_zoommode[0][qs->zoom];
  450         } else if (qs->x_size > 80 || qs->y_size > 60) {
  451                 qs->xferparms |= qcam_zoommode[1][qs->zoom];
  452         } else
  453                 qs->xferparms |= qcam_zoommode[2][qs->zoom];
  454 }
  455 
  456 static void
  457 qcam_init (struct qcam_softc *qs)
  458 {
  459         int x_size = (qs->bpp == 4) ? qs->x_size / 2 : qs->x_size / 4;
  460 
  461         qcam_xferparms(qs);
  462 
  463         send_command(qs, QC_BRIGHTNESS,   qs->brightness);
  464         send_command(qs, QC_BRIGHTNESS,   1);
  465         send_command(qs, QC_BRIGHTNESS,   1);
  466         send_command(qs, QC_BRIGHTNESS,   qs->brightness);
  467         send_command(qs, QC_BRIGHTNESS,   qs->brightness);
  468         send_command(qs, QC_BRIGHTNESS,   qs->brightness);
  469         send_command(qs, QC_YSIZE,        qs->y_size);
  470         send_command(qs, QC_XSIZE,        x_size);
  471         send_command(qs, QC_YORG,         qs->y_origin);
  472         send_command(qs, QC_XORG,         qs->x_origin);
  473         send_command(qs, QC_CONTRAST,     qs->contrast);
  474         send_command(qs, QC_WHITEBALANCE, qs->whitebalance);
  475 
  476         if (qs->buffer)
  477             qs->buffer_end = qs->buffer +
  478                              min((qs->x_size*qs->y_size), QC_MAXFRAMEBUFSIZE);
  479 
  480         qs->init_req = 0;
  481 }
  482 
  483 int
  484 qcam_scan (struct qcam_softc *qs)
  485 {
  486         int timeouts;
  487 
  488 #ifdef  QCAM_GRAB_STATS
  489         bzero(qcam_rsbhigh, sizeof(qcam_rsbhigh));
  490         bzero(qcam_rsblow,  sizeof(qcam_rsblow));
  491         qcam_rsbhigh_p = qcam_rsbhigh;
  492         qcam_rsblow_p  = qcam_rsblow;
  493 #endif
  494 
  495         timeouts = qcam_timeouts;
  496 
  497         if (qs->init_req)
  498                 qcam_init(qs);
  499 
  500         if (send_xfermode(qs, qs->xferparms))
  501                 return 1;
  502 
  503         if (qcam_debug && (timeouts != qcam_timeouts))
  504                 printf("qcam%d: %d timeouts during init\n", qs->unit,
  505                         qcam_timeouts - timeouts);
  506 
  507         timeouts = qcam_timeouts;
  508 
  509         if (qs->scanner)
  510                 (*qs->scanner)(qs);
  511         else
  512                 return 1;
  513 
  514         if (qcam_debug && (timeouts != qcam_timeouts))
  515                 printf("qcam%d: %d timeouts during scan\n", qs->unit,
  516                         qcam_timeouts - timeouts);
  517 
  518         write_control(qs->iobase, 0x0f);
  519 
  520         return 0;                       /* success */
  521 }
  522 
  523 void
  524 qcam_default (struct qcam_softc *qs)
  525 {
  526         qs->contrast     = QC_DEF_CONTRAST;
  527         qs->brightness   = QC_DEF_BRIGHTNESS;
  528         qs->whitebalance = QC_DEF_WHITEBALANCE;
  529         qs->x_size       = QC_DEF_XSIZE;
  530         qs->y_size       = QC_DEF_YSIZE;
  531         qs->x_origin     = QC_DEF_XORG;
  532         qs->y_origin     = QC_DEF_YORG;
  533         qs->bpp          = QC_DEF_BPP;
  534         qs->zoom         = QC_DEF_ZOOM;
  535         qs->exposure     = QC_DEF_EXPOSURE;
  536 }
  537 
  538 int
  539 qcam_ioctl_get (struct qcam_softc *qs, struct qcam *info)
  540 {
  541         info->qc_version        = QC_IOCTL_VERSION;
  542         info->qc_xsize          = qs->x_size;
  543         info->qc_ysize          = qs->y_size;
  544         info->qc_xorigin        = qs->x_origin;
  545         info->qc_yorigin        = qs->y_origin;
  546         info->qc_bpp            = qs->bpp;
  547         info->qc_zoom           = qs->zoom;
  548         info->qc_exposure       = qs->exposure;
  549         info->qc_brightness     = qs->brightness;
  550         info->qc_whitebalance   = qs->whitebalance;
  551         info->qc_contrast       = qs->contrast;
  552 
  553         return 0;               /* success */
  554 }
  555 
  556 int
  557 qcam_ioctl_set (struct qcam_softc *qs, struct qcam *info)
  558 {
  559         /*
  560          * sanity check parameters passed in by user
  561          * we're extra paranoid right now because the API
  562          * is in flux
  563          */
  564         if (info->qc_xsize        > QC_MAX_XSIZE        ||
  565             info->qc_ysize        > QC_MAX_YSIZE        ||
  566             info->qc_xorigin      > QC_MAX_XSIZE        ||
  567             info->qc_yorigin      > QC_MAX_YSIZE        ||
  568             (info->qc_bpp != 4 && info->qc_bpp != 6)    ||
  569             info->qc_zoom         > QC_ZOOM_200         ||
  570             info->qc_brightness   > UCHAR_MAX           ||
  571             info->qc_whitebalance > UCHAR_MAX           ||
  572             info->qc_contrast     > UCHAR_MAX)
  573         return 1;               /* failure */
  574 
  575         /* version check */
  576         if (info->qc_version != QC_IOCTL_VERSION)
  577                 return 1;       /* failure */
  578 
  579         qs->x_size        = info->qc_xsize;
  580         qs->y_size        = info->qc_ysize;
  581         qs->x_origin      = info->qc_xorigin;
  582         qs->y_origin      = info->qc_yorigin;
  583         qs->bpp           = info->qc_bpp;
  584         qs->zoom          = info->qc_zoom;
  585         qs->exposure      = info->qc_exposure;
  586         qs->brightness    = info->qc_brightness;
  587         qs->whitebalance  = info->qc_whitebalance;
  588         qs->contrast      = info->qc_contrast;
  589 
  590         /* request initialization before next scan pass */
  591         qs->init_req = 1;
  592 
  593         return 0;               /* success */
  594 }
  595 
  596 #ifndef QCAM_INVASIVE_SCAN
  597 /*
  598  * Attempt a non-destructive probe for the QuickCam.
  599  * Current models appear to toggle the upper 4 bits of
  600  * the status register at approximately 5-10 Hz.
  601  *
  602  * Be aware that this isn't the way that Connectix detects the
  603  * camera (they send a reset and try to handshake),  but this
  604  * way is safe.
  605  */
  606 int
  607 qcam_detect (u_int port)
  608 {
  609         int i, transitions = 0;
  610         u_char reg, last;
  611 
  612         write_control(port, 0x20);
  613         write_control(port, 0x0b);
  614         write_control(port, 0x0e);
  615 
  616         last = reg = read_status(port);
  617 
  618         for (i = 0; i < QC_PROBELIMIT; i++) {
  619             reg = read_status(port) & 0xf0;
  620 
  621             if (reg != last)    /* if we got a toggle, count it */
  622                 transitions++;
  623 
  624             last = reg;
  625             LONGDELAY(100000);  /* 100ms */
  626         }
  627 
  628         return transitions >= QC_PROBECNTLOW &&
  629                transitions <= QC_PROBECNTHI;
  630 }
  631 #else
  632 /*
  633  * This form of probing for the camera can cause garbage to show
  634  * up on your printers if they're plugged in instead.  However,
  635  * some folks have a problem with the nondestructive scan when
  636  * using EPP/ECP parallel ports.
  637  *
  638  * Try to send down a brightness command, if we succeed, we've
  639  * got a camera on the remote side.
  640  */
  641 int
  642 qcam_detect (u_int port)
  643 {
  644         write_control(port, 0x20);
  645         write_data(port, 0x75);
  646         read_data(port);
  647         write_control(port, 0x0b);
  648         DELAY(250);
  649         write_control(port, 0x0e);
  650         DELAY(250);
  651 
  652         if (sendbyte(port, QC_BRIGHTNESS, QC_DEF_EXPOSURE) != QC_BRIGHTNESS)
  653                 return 0;       /* failure */
  654         return (sendbyte(port, 1, QC_DEF_EXPOSURE) == 1);
  655 }
  656 #endif
  657 
  658 #endif /* NQCAM */

Cache object: 13a7deeb0e839b49774acf6612622ea2


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