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/cmx/cmx.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  * Copyright (c) 2006-2007 Daniel Roethlisberger <daniel@roe.ch>
    3  * Copyright (c) 2000-2004 OMNIKEY GmbH (www.omnikey.com)
    4  * 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 unmodified, this list of conditions, and the following
   11  *    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  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.3/sys/dev/cmx/cmx.c 176868 2008-03-06 08:09:45Z rink $");
   31 
   32 /*
   33  * OMNIKEY CardMan 4040 a.k.a. CardMan eXtended (cmx) driver.
   34  * This is a PCMCIA based smartcard reader which seems to work
   35  * like an I/O port mapped USB CCID smartcard device.
   36  *
   37  * I/O originally based on Linux driver version 1.1.0 by OMNIKEY.
   38  * Dual GPL/BSD.  Almost all of the code has been rewritten.
   39  * $Omnikey: cm4040_cs.c,v 1.7 2004/10/04 09:08:50 jp Exp $
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/sockio.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/poll.h>
   48 #include <sys/conf.h>
   49 #include <sys/fcntl.h>
   50 #include <sys/uio.h>
   51 #include <sys/selinfo.h>
   52 
   53 #include <sys/module.h>
   54 #include <sys/bus.h>
   55 
   56 #include <machine/bus.h>
   57 #include <machine/resource.h>
   58 #include <sys/rman.h>
   59 
   60 #include <dev/cmx/cmxvar.h>
   61 #include <dev/cmx/cmxreg.h>
   62 
   63 #ifdef CMX_DEBUG
   64 #define DEBUG_printf(dev, fmt, args...) \
   65         device_printf(dev, "%s: " fmt, __FUNCTION__, ##args)
   66 #else
   67 #define DEBUG_printf(dev, fmt, args...)
   68 #endif
   69 
   70 #define SPIN_COUNT                              1000
   71 #define WAIT_TICKS                              (hz/100)
   72 #define POLL_TICKS                              (hz/10)
   73 
   74 /* possibly bogus */
   75 #define CCID_DRIVER_BULK_DEFAULT_TIMEOUT        (150*hz)
   76 #define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT       (35*hz)
   77 #define CCID_DRIVER_MINIMUM_TIMEOUT             (3*hz)
   78 
   79 #ifdef CMX_DEBUG
   80 static char     BSRBITS[] = "\020"
   81         "\01BULK_OUT_FULL"              /* 0x01 */
   82         "\02BULK_IN_FULL"               /* 0x02 */
   83         "\03(0x04)";                    /* 0x04 */
   84 #ifdef CMX_INTR
   85 static char     SCRBITS[] = "\020"
   86         "\01POWER_DOWN"                 /* 0x01 */
   87         "\02PULSE_INTERRUPT"            /* 0x02 */
   88         "\03HOST_TO_READER_DONE"        /* 0x04 */
   89         "\04READER_TO_HOST_DONE"        /* 0x08 */
   90         "\05ACK_NOTIFY"                 /* 0x10 */
   91         "\06EN_NOTIFY"                  /* 0x20 */
   92         "\07ABORT"                      /* 0x40 */
   93         "\10HOST_TO_READER_START";      /* 0x80 */
   94 #endif /* CMX_INTR */
   95 static char     POLLBITS[] = "\020"
   96         "\01POLLIN"                     /* 0x0001 */
   97         "\02POLLPRI"                    /* 0x0002 */
   98         "\03POLLOUT"                    /* 0x0004 */
   99         "\04POLLERR"                    /* 0x0008 */
  100         "\05POLLHUP"                    /* 0x0010 */
  101         "\06POLLINVAL"                  /* 0x0020 */
  102         "\07POLLRDNORM"                 /* 0x0040 */
  103         "\10POLLRDBAND"                 /* 0x0080 */
  104         "\11POLLWRBAND";                /* 0x0100 */
  105 static char     MODEBITS[] = "\020"
  106         "\01READ"                       /* 0x0001 */
  107         "\02WRITE"                      /* 0x0002 */
  108         "\03NONBLOCK"                   /* 0x0004 */
  109         "\04APPEND"                     /* 0x0008 */
  110         "\05SHLOCK"                     /* 0x0010 */
  111         "\06EXLOCK"                     /* 0x0020 */
  112         "\07ASYNC"                      /* 0x0040 */
  113         "\10FSYNC"                      /* 0x0080 */
  114         "\11NOFOLLOW"                   /* 0x0100 */
  115         "\12CREAT"                      /* 0x0200 */
  116         "\13TRUNK"                      /* 0x0400 */
  117         "\14EXCL"                       /* 0x0800 */
  118         "\15(0x1000)"                   /* 0x1000 */
  119         "\16(0x2000)"                   /* 0x2000 */
  120         "\17HASLOCK"                    /* 0x4000 */
  121         "\20NOCTTY"                     /* 0x8000 */
  122         "\21DIRECT";                    /* 0x00010000 */
  123 #endif /* CMX_DEBUG */
  124 
  125 devclass_t cmx_devclass;
  126 
  127 static d_open_t         cmx_open;
  128 static d_close_t        cmx_close;
  129 static d_read_t         cmx_read;
  130 static d_write_t        cmx_write;
  131 static d_poll_t         cmx_poll;
  132 #ifdef CMX_INTR
  133 static void             cmx_intr(void *arg);
  134 #endif
  135 
  136 static struct cdevsw cmx_cdevsw = {
  137         .d_version =    D_VERSION,
  138         .d_open =       cmx_open,
  139         .d_close =      cmx_close,
  140         .d_read =       cmx_read,
  141         .d_write =      cmx_write,
  142         .d_poll =       cmx_poll,
  143         .d_name =       "cmx",
  144 };
  145 
  146 /*
  147  * Initialize the softc structure.  Must be called from
  148  * the bus specific device allocation routine.
  149  */
  150 void
  151 cmx_init_softc(device_t dev)
  152 {
  153         struct cmx_softc *sc = device_get_softc(dev);
  154         sc->dev = dev;
  155         sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
  156 }
  157 
  158 /*
  159  * Allocate driver resources.  Must be called from the
  160  * bus specific device allocation routine.  Caller must
  161  * ensure to call cmx_release_resources to free the
  162  * resources when detaching.
  163  * Return zero if successful, and ENOMEM if the resources
  164  * could not be allocated.
  165  */
  166 int
  167 cmx_alloc_resources(device_t dev)
  168 {
  169         struct cmx_softc *sc = device_get_softc(dev);
  170 #ifdef CMX_INTR
  171         int rv;
  172 #endif
  173 
  174         sc->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  175                         &sc->ioport_rid, RF_ACTIVE);
  176         if (!sc->ioport) {
  177                 device_printf(dev, "failed to allocate io port\n");
  178                 return ENOMEM;
  179         }
  180         sc->bst = rman_get_bustag(sc->ioport);
  181         sc->bsh = rman_get_bushandle(sc->ioport);
  182 
  183 #ifdef CMX_INTR
  184         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  185                         &sc->irq_rid, RF_ACTIVE);
  186         if (!sc->irq) {
  187                 device_printf(dev, "failed to allocate irq\n");
  188                 return ENOMEM;
  189         }
  190         if ((rv = bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY,
  191                         cmx_intr, sc, &sc->ih)) != 0) {
  192                 device_printf(dev, "failed to set up irq\n");
  193                 return ENOMEM;
  194         }
  195 #endif
  196 
  197         mtx_init(&sc->mtx, device_get_nameunit(dev),
  198                         "cmx softc lock",
  199                         MTX_DEF | MTX_RECURSE);
  200         callout_init_mtx(&sc->ch, &sc->mtx, 0);
  201 
  202         return 0;
  203 }
  204 
  205 /*
  206  * Release the resources allocated by cmx_allocate_resources.
  207  */
  208 void
  209 cmx_release_resources(device_t dev)
  210 {
  211         struct cmx_softc *sc = device_get_softc(dev);
  212 
  213         mtx_destroy(&sc->mtx);
  214 
  215 #ifdef CMX_INTR
  216         if (sc->ih) {
  217                 bus_teardown_intr(dev, sc->irq, sc->ih);
  218                 sc->ih = NULL;
  219         }
  220         if (sc->irq) {
  221                 bus_release_resource(dev, SYS_RES_IRQ,
  222                                 sc->irq_rid, sc->irq);
  223                 sc->irq = NULL;
  224         }
  225 #endif
  226 
  227         if (sc->ioport) {
  228                 bus_deactivate_resource(dev, SYS_RES_IOPORT,
  229                                 sc->ioport_rid, sc->ioport);
  230                 bus_release_resource(dev, SYS_RES_IOPORT,
  231                                 sc->ioport_rid, sc->ioport);
  232                 sc->ioport = NULL;
  233         }
  234         return;
  235 }
  236 
  237 /*
  238  * Bus independant device attachment routine.  Creates the
  239  * character device node.
  240  */
  241 int
  242 cmx_attach(device_t dev)
  243 {
  244         struct cmx_softc *sc = device_get_softc(dev);
  245 
  246         if (!sc || sc->dying)
  247                 return ENXIO;
  248 
  249         sc->cdev = make_dev(&cmx_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
  250                             "cmx%d", device_get_unit(dev));
  251         if (!sc->cdev) {
  252                 device_printf(dev, "failed to create character device\n");
  253                 return ENOMEM;
  254         }
  255         sc->cdev->si_drv1 = sc;
  256 
  257         return 0;
  258 }
  259 
  260 /*
  261  * Bus independant device detachment routine.  Makes sure all
  262  * allocated resources are freed, callouts disabled and waiting
  263  * processes unblocked.
  264  */
  265 int
  266 cmx_detach(device_t dev)
  267 {
  268         struct cmx_softc *sc = device_get_softc(dev);
  269 
  270         DEBUG_printf(dev, "called\n");
  271 
  272         sc->dying = 1;
  273 
  274         CMX_LOCK(sc);
  275         if (sc->polling) {
  276                 DEBUG_printf(sc->dev, "disabling polling\n");
  277                 callout_stop(&sc->ch);
  278                 sc->polling = 0;
  279                 CMX_UNLOCK(sc);
  280                 callout_drain(&sc->ch);
  281                 selwakeuppri(&sc->sel, PZERO);
  282         } else {
  283                 CMX_UNLOCK(sc);
  284         }
  285 
  286         wakeup(sc);
  287         destroy_dev(sc->cdev);
  288 
  289         DEBUG_printf(dev, "releasing resources\n");
  290         cmx_release_resources(dev);
  291         return 0;
  292 }
  293 
  294 /*
  295  * Wait for buffer status register events.  If test is non-zero,
  296  * wait until flags are set, otherwise wait until flags are unset.
  297  * Will spin SPIN_COUNT times, then sleep until timeout is reached.
  298  * Returns zero if event happened, EIO if the timeout was reached,
  299  * and ENXIO if the device was detached in the meantime.  When that
  300  * happens, the caller must quit immediately, since a detach is
  301  * in progress.
  302  */
  303 static inline int
  304 cmx_wait_BSR(struct cmx_softc *sc, uint8_t flags, int test)
  305 {
  306         int rv;
  307 
  308         for (int i = 0; i < SPIN_COUNT; i++) {
  309                 if (cmx_test_BSR(sc, flags, test))
  310                         return 0;
  311         }
  312 
  313         for (int i = 0; i * WAIT_TICKS < sc->timeout; i++) {
  314                 if (cmx_test_BSR(sc, flags, test))
  315                         return 0;
  316                 rv = tsleep(sc, PWAIT|PCATCH, "cmx", WAIT_TICKS);
  317                 /*
  318                  * Currently, the only reason for waking up with
  319                  * rv == 0 is when we are detaching, in which
  320                  * case sc->dying is always 1.
  321                  */
  322                 if (sc->dying)
  323                         return ENXIO;
  324                 if (rv != EAGAIN)
  325                         return rv;
  326         }
  327 
  328         /* timeout */
  329         return EIO;
  330 }
  331 
  332 /*
  333  * Set the sync control register to val.  Before and after writing
  334  * to the SCR, we wait for the BSR to not signal BULK_OUT_FULL.
  335  * Returns zero if successful, or whatever errors cmx_wait_BSR can
  336  * return.  ENXIO signals that the device has been detached in the
  337  * meantime, and that we should leave the kernel immediately.
  338  */
  339 static inline int
  340 cmx_sync_write_SCR(struct cmx_softc *sc, uint8_t val)
  341 {
  342         int rv = 0;
  343 
  344         if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) {
  345                 return rv;
  346         }
  347 
  348         cmx_write_SCR(sc, val);
  349 
  350         if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0)) != 0) {
  351                 return rv;
  352         }
  353 
  354         return 0;
  355 }
  356 
  357 /*
  358  * Returns a suitable timeout value based on the given command byte.
  359  * Some commands appear to need longer timeout values than others.
  360  */
  361 static inline unsigned long
  362 cmx_timeout_by_cmd(uint8_t cmd)
  363 {
  364         switch (cmd) {
  365         case CMD_PC_TO_RDR_XFRBLOCK:
  366         case CMD_PC_TO_RDR_SECURE:
  367         case CMD_PC_TO_RDR_TEST_SECURE:
  368         case CMD_PC_TO_RDR_OK_SECURE:
  369                 return CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
  370 
  371         case CMD_PC_TO_RDR_ICCPOWERON:
  372                 return CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
  373 
  374         case CMD_PC_TO_RDR_GETSLOTSTATUS:
  375         case CMD_PC_TO_RDR_ICCPOWEROFF:
  376         case CMD_PC_TO_RDR_GETPARAMETERS:
  377         case CMD_PC_TO_RDR_RESETPARAMETERS:
  378         case CMD_PC_TO_RDR_SETPARAMETERS:
  379         case CMD_PC_TO_RDR_ESCAPE:
  380         case CMD_PC_TO_RDR_ICCCLOCK:
  381         default:
  382                 return CCID_DRIVER_MINIMUM_TIMEOUT;
  383         }
  384 }
  385 
  386 /*
  387  * Periodical callout routine, polling the reader for data
  388  * availability.  If the reader signals data ready for reading,
  389  * wakes up the processes which are waiting in select()/poll().
  390  * Otherwise, reschedules itself with a delay of POLL_TICKS.
  391  */
  392 static void
  393 cmx_tick(void *xsc)
  394 {
  395         struct cmx_softc *sc = xsc;
  396         uint8_t bsr;
  397 
  398         CMX_LOCK(sc);
  399         if (sc->polling && !sc->dying) {
  400                 bsr = cmx_read_BSR(sc);
  401                 DEBUG_printf(sc->dev, "BSR=%b\n", bsr, BSRBITS);
  402                 if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
  403                         sc->polling = 0;
  404                         selwakeuppri(&sc->sel, PZERO);
  405                 } else {
  406                         callout_reset(&sc->ch, POLL_TICKS, cmx_tick, sc);
  407                 }
  408         }
  409         CMX_UNLOCK(sc);
  410 }
  411 
  412 /*
  413  * Open the character device.  Only a single process may open the
  414  * device at a time.
  415  */
  416 static int
  417 cmx_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
  418 {
  419         struct cmx_softc *sc = cdev->si_drv1;
  420 
  421         if (sc == NULL || sc->dying)
  422                 return ENXIO;
  423 
  424         CMX_LOCK(sc);
  425         if (sc->open) {
  426                 CMX_UNLOCK(sc);
  427                 return EBUSY;
  428         }
  429         sc->open = 1;
  430         CMX_UNLOCK(sc);
  431 
  432         DEBUG_printf(sc->dev, "open (flags=%b thread=%p)\n",
  433                         flags, MODEBITS, td);
  434         return 0;
  435 }
  436 
  437 /*
  438  * Close the character device.
  439  */
  440 static int
  441 cmx_close(struct cdev *cdev, int flags, int fmt, struct thread *td)
  442 {
  443         struct cmx_softc *sc = cdev->si_drv1;
  444 
  445         if (sc == NULL || sc->dying)
  446                 return ENXIO;
  447 
  448         CMX_LOCK(sc);
  449         if (!sc->open) {
  450                 CMX_UNLOCK(sc);
  451                 return EINVAL;
  452         }
  453         if (sc->polling) {
  454                 DEBUG_printf(sc->dev, "disabling polling\n");
  455                 callout_stop(&sc->ch);
  456                 sc->polling = 0;
  457                 CMX_UNLOCK(sc);
  458                 callout_drain(&sc->ch);
  459                 selwakeuppri(&sc->sel, PZERO);
  460                 CMX_LOCK(sc);
  461         }
  462         sc->open = 0;
  463         CMX_UNLOCK(sc);
  464 
  465         DEBUG_printf(sc->dev, "close (flags=%b thread=%p)\n",
  466                         flags, MODEBITS, td);
  467         return 0;
  468 }
  469 
  470 /*
  471  * Read from the character device.
  472  * Returns zero if successful, ENXIO if dying, EINVAL if an attempt
  473  * was made to read less than CMX_MIN_RDLEN bytes or less than the
  474  * device has available, or any of the errors that cmx_sync_write_SCR
  475  * can return.  Partial reads are not supported.
  476  */
  477 static int
  478 cmx_read(struct cdev *cdev, struct uio *uio, int flag)
  479 {
  480         struct cmx_softc *sc = cdev->si_drv1;
  481         unsigned long bytes_left;
  482         uint8_t uc;
  483         int rv, amnt, offset;
  484 
  485         if (sc == NULL || sc->dying)
  486                 return ENXIO;
  487 
  488         DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
  489                 uio->uio_resid, flag, MODEBITS);
  490 
  491         CMX_LOCK(sc);
  492         if (sc->polling) {
  493                 DEBUG_printf(sc->dev, "disabling polling\n");
  494                 callout_stop(&sc->ch);
  495                 sc->polling = 0;
  496                 CMX_UNLOCK(sc);
  497                 callout_drain(&sc->ch);
  498                 selwakeuppri(&sc->sel, PZERO);
  499         } else {
  500                 CMX_UNLOCK(sc);
  501         }
  502 
  503         if (uio->uio_resid == 0) {
  504                 return 0;
  505         }
  506 
  507         if (uio->uio_resid < CMX_MIN_RDLEN) {
  508                 return EINVAL;
  509         }
  510 
  511         if (flag & O_NONBLOCK) {
  512                 if (cmx_test_BSR(sc, BSR_BULK_IN_FULL, 0)) {
  513                         return EAGAIN;
  514                 }
  515         }
  516 
  517         for (int i = 0; i < 5; i++) {
  518                 if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
  519                         return rv;
  520                 }
  521                 sc->buf[i] = cmx_read_DTR(sc);
  522                 DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", i, sc->buf[i]);
  523         }
  524 
  525         bytes_left = CMX_MIN_RDLEN +
  526                         (0x000000FF&((char)sc->buf[1])) +
  527                         (0x0000FF00&((char)sc->buf[2] << 8)) +
  528                         (0x00FF0000&((char)sc->buf[3] << 16)) +
  529                         (0xFF000000&((char)sc->buf[4] << 24));
  530         DEBUG_printf(sc->dev, "msgsz=%lu\n", bytes_left);
  531 
  532         if (uio->uio_resid < bytes_left) {
  533                 return EINVAL;
  534         }
  535 
  536         offset = 5; /* prefetched header */
  537         while (bytes_left > 0) {
  538                 amnt = MIN(bytes_left, sizeof(sc->buf));
  539 
  540                 for (int i = offset; i < amnt; i++) {
  541                         if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1))!=0) {
  542                                 return rv;
  543                         }
  544                         sc->buf[i] = cmx_read_DTR(sc);
  545                         DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
  546                                         i, sc->buf[i]);
  547                 }
  548 
  549                 if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
  550                         DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
  551                         return rv;
  552                 }
  553 
  554                 if (offset)
  555                         offset = 0;
  556                 bytes_left -= amnt;
  557         }
  558 
  559         if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
  560                 return rv;
  561         }
  562 
  563         if ((rv = cmx_sync_write_SCR(sc, SCR_READER_TO_HOST_DONE)) != 0) {
  564                 return rv;
  565         }
  566 
  567         uc = cmx_read_DTR(sc);
  568         DEBUG_printf(sc->dev, "success (DTR=%02x)\n", uc);
  569         return 0;
  570 }
  571 
  572 /*
  573  * Write to the character device.
  574  * Returns zero if successful, NXIO if dying, EINVAL if less data
  575  * written than CMX_MIN_WRLEN, or any of the errors that cmx_sync_SCR
  576  * can return.
  577  */
  578 static int
  579 cmx_write(struct cdev *cdev, struct uio *uio, int flag)
  580 {
  581         struct cmx_softc *sc = cdev->si_drv1;
  582         int rv, amnt;
  583 
  584         if (sc == NULL || sc->dying)
  585                 return ENXIO;
  586 
  587         DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
  588                         uio->uio_resid, flag, MODEBITS);
  589 
  590         if (uio->uio_resid == 0) {
  591                 return 0;
  592         }
  593 
  594         if (uio->uio_resid < CMX_MIN_WRLEN) {
  595                 return EINVAL;
  596         }
  597 
  598         if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_START)) != 0) {
  599                 return rv;
  600         }
  601 
  602         sc->timeout = 0;
  603         while (uio->uio_resid > 0) {
  604                 amnt = MIN(uio->uio_resid, sizeof(sc->buf));
  605 
  606                 if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
  607                         DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
  608                         /* wildly guessed attempt to notify device */
  609                         sc->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
  610                         cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE);
  611                         return rv;
  612                 }
  613 
  614                 if (sc->timeout == 0) {
  615                         sc->timeout = cmx_timeout_by_cmd(sc->buf[0]);
  616                         DEBUG_printf(sc->dev, "cmd=%02x timeout=%lu\n",
  617                                         sc->buf[0], sc->timeout);
  618                 }
  619 
  620                 for (int i = 0; i < amnt; i++) {
  621                         if ((rv = cmx_wait_BSR(sc, BSR_BULK_OUT_FULL, 0))!=0) {
  622                                 return rv;
  623                         }
  624                         cmx_write_DTR(sc, sc->buf[i]);
  625                         DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
  626                                         i, sc->buf[i]);
  627                 }
  628         }
  629 
  630         if ((rv = cmx_sync_write_SCR(sc, SCR_HOST_TO_READER_DONE)) != 0) {
  631                 return rv;
  632         }
  633 
  634         DEBUG_printf(sc->dev, "success\n");
  635         return 0;
  636 }
  637 
  638 /*
  639  * Poll handler.  Writing is always possible, reading is only possible
  640  * if BSR_BULK_IN_FULL is set.  Will start the cmx_tick callout and
  641  * set sc->polling.
  642  */
  643 static int
  644 cmx_poll(struct cdev *cdev, int events, struct thread *td)
  645 {
  646         struct cmx_softc *sc = cdev->si_drv1;
  647         int revents = 0;
  648         uint8_t bsr = 0;
  649 
  650         if (sc == NULL || sc->dying)
  651                 return ENXIO;
  652 
  653         bsr = cmx_read_BSR(sc);
  654         DEBUG_printf(sc->dev, "called (events=%b BSR=%b)\n",
  655                         events, POLLBITS, bsr, BSRBITS);
  656 
  657         revents = events & (POLLOUT | POLLWRNORM);
  658         if (events & (POLLIN | POLLRDNORM)) {
  659                 if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
  660                         revents |= events & (POLLIN | POLLRDNORM);
  661                 } else {
  662                         selrecord(td, &sc->sel);
  663                         CMX_LOCK(sc);
  664                         if (!sc->polling) {
  665                                 DEBUG_printf(sc->dev, "enabling polling\n");
  666                                 sc->polling = 1;
  667                                 callout_reset(&sc->ch, POLL_TICKS,
  668                                                 cmx_tick, sc);
  669                         } else {
  670                                 DEBUG_printf(sc->dev, "already polling\n");
  671                         }
  672                         CMX_UNLOCK(sc);
  673                 }
  674         }
  675 
  676         DEBUG_printf(sc->dev, "success (revents=%b)\n", revents, POLLBITS);
  677 
  678         return revents;
  679 }
  680 
  681 #ifdef CMX_INTR
  682 /*
  683  * Interrupt handler.  Currently has no function except to
  684  * print register status (if debugging is also enabled).
  685  */
  686 static void
  687 cmx_intr(void *arg)
  688 {
  689         struct cmx_softc *sc = (struct cmx_softc *)arg;
  690 
  691         if (sc == NULL || sc->dying)
  692                 return;
  693 
  694         DEBUG_printf(sc->dev, "received interrupt (SCR=%b BSR=%b)\n",
  695                         cmx_read_SCR(sc), SCRBITS,
  696                         cmx_read_BSR(sc), BSRBITS);
  697 
  698         return;
  699 }
  700 #endif
  701 

Cache object: a4746a9f542df880f87be0c478d68b1d


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