root/dev/pcmcia/gpr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gpr_match
  2. gpr_attach
  3. gpr_detach
  4. gpr_activate
  5. gpropen
  6. gprclose
  7. gprioctl
  8. gpr_intr
  9. tlvput

    1 /*      $OpenBSD: gpr.c,v 1.12 2006/04/21 17:52:54 uwe Exp $    */
    2 
    3 /*
    4  * Copyright (c) 2002, Federico G. Schwindt
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions are
    9  * met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in
   14  *    the documentation and/or other materials provided with the
   15  *    distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 /*
   31  * A driver for the Gemplus GPR400 SmartCard reader.
   32  *
   33  * The gpr400 driver written by Wolf Geldmacher <wgeldmacher@paus.ch> for
   34  * Linux was used as documentation.
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/kernel.h>
   39 #include <sys/device.h>
   40 #include <sys/systm.h>
   41 #include <sys/proc.h>
   42 #include <sys/ioctl.h>
   43 #include <sys/conf.h>
   44 
   45 #include <dev/pcmcia/pcmciavar.h>
   46 #include <dev/pcmcia/pcmciareg.h>
   47 #include <dev/pcmcia/pcmciadevs.h>
   48 
   49 #include <dev/pcmcia/gprio.h>
   50 
   51 /* Registers in I/O space (32 bytes) */
   52 #define GPR400_HAP_CTRL         0x00    /* Handshake and PRG Control    */
   53 #define  GPR400_RESET             0x01  /* Master reset                 */
   54 #define  GPR400_IREQ              0x02  /* Interrupt request            */
   55 #define  GPR400_INTR              0x04  /* Interrupt                    */
   56                                         /* bits 3..8 PRG control        */
   57 #define GPR400_PD_CTRL          0x01    /* PRG data                     */
   58 /* bytes 3..32 used for data exchange */
   59 
   60 /* Registers in attribute memory (read only) */ 
   61 #define GPR400_SETUP            0x018   /* General Setup                */
   62 #define  GPR400_LOCK_MASK        0x08   /* 0: locked, 1: unlocked       */
   63 #define GPR400_REG1             0x01a   /* SmartCard Reg. 1             */
   64 #define  GPR400_DET_MASK         0x08   /* 0: in the reader, 1: removed */
   65 #define  GPR400_INS_MASK         0x80   /* 0: not inserted, 1: inserted */
   66 #define GPR400_REG2             0x01c   /* SmartCard Reg. 2             */
   67 #define GPR400_CAC              0x01e   /* Clock and Control            */
   68 
   69 /* TLV */
   70 #define GPR400_CLOSE            0x10    /* Close session                */
   71 #define GPR400_OPEN             0x20    /* Open session                 */
   72 #define GPR400_APDU             0x30    /* APDU exchange                */
   73 #define GPR400_POWER            0x40    /* Power down/Standby           */
   74                                         /* 0: Power down, 1: Standby    */
   75 #define GPR400_SELECT           0x50    /* Select card                  */
   76 #define  GPR400_DRV0             0x00   /* Downloaded driver 0          */
   77 #define  GPR400_ISODRV           0x02   /* ISO7816-3 driver             */
   78 #define  GPR400_CLK_MASK         0x08   /* 0: 3.68MHz, 1: 7.36MHz       */
   79 #define GPR400_STATUS           0xA0    /* Reader status                */
   80 
   81 #define GPR400_CONT             0x04    /* Chain block                  */
   82 
   83 #define GPR400_MEM_LEN          0x1000
   84 
   85 #define GPRUNIT(x)              (minor(x) & 0x0f)
   86 
   87 #ifdef GPRDEBUG
   88 int gprdebug;
   89 #define DPRINTF(x)              if (gprdebug) printf x
   90 #else
   91 #define DPRINTF(x)
   92 #endif
   93 
   94 struct gpr_softc {
   95         struct device                   sc_dev;
   96 
   97         struct pcmcia_function         *sc_pf;
   98 
   99         bus_space_handle_t              sc_ioh;
  100         bus_space_tag_t                 sc_iot;
  101 
  102         struct pcmcia_io_handle         sc_pioh;
  103         int                             sc_iowin;
  104 
  105         bus_space_handle_t              sc_memh;
  106         bus_space_tag_t                 sc_memt;
  107 
  108         struct pcmcia_mem_handle        sc_pmemh;
  109         int                             sc_memwin;
  110         bus_addr_t                      sc_offset;
  111 
  112         void *                          sc_ih;
  113 };
  114 
  115 int     gpr_match(struct device *, void *, void *);
  116 void    gpr_attach(struct device *, struct device *, void *);
  117 int     gpr_detach(struct device *, int);
  118 int     gpr_activate(struct device *, enum devact);
  119 
  120 int     gpropen(dev_t, int, int, struct proc *);
  121 int     gprclose(dev_t, int, int, struct proc *);
  122 int     gprioctl(dev_t, u_long, caddr_t, int, struct proc *);
  123 
  124 int     gpr_intr(void *);
  125 
  126 int     tlvput(struct gpr_softc *, int, u_int8_t *, int);
  127 
  128 struct cfattach gpr_ca = {
  129         sizeof(struct gpr_softc), gpr_match, gpr_attach, gpr_detach,
  130             gpr_activate
  131 };
  132 
  133 struct cfdriver gpr_cd = {
  134         NULL, "gpr", DV_DULL
  135 };
  136 
  137 int
  138 gpr_match(struct device *parent, void *match, void *aux)
  139 {
  140         struct pcmcia_attach_args *pa = aux;
  141 
  142         if (pa->manufacturer == PCMCIA_VENDOR_GEMPLUS &&
  143             pa->product == PCMCIA_PRODUCT_GEMPLUS_GPR400)
  144                 return (1);
  145 
  146         return (0);
  147 }
  148 
  149 void
  150 gpr_attach(struct device *parent, struct device *self, void *aux)
  151 {
  152         struct gpr_softc *sc = (void *)self;
  153         struct pcmcia_attach_args *pa = aux;
  154         struct pcmcia_config_entry *cfe;
  155         const char *intrstr;
  156 
  157         for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe;
  158              cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
  159 
  160                 if (!pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
  161                     cfe->iospace[0].length, cfe->iospace[0].length,
  162                     &sc->sc_pioh))
  163                         break;
  164         }
  165 
  166         if (cfe == NULL) {
  167                 printf(": can't alloc i/o space\n");
  168                 goto fail_io_alloc;
  169         }
  170 
  171         pcmcia_function_init(pa->pf, cfe);
  172         if (pcmcia_function_enable(pa->pf)) {
  173                 printf(": function enable failed\n");
  174                 goto fail_enable;
  175         }
  176 
  177         if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0,
  178             sc->sc_pioh.size, &sc->sc_pioh, &sc->sc_iowin)) {
  179                 printf(": can't map i/o space\n");
  180                 goto fail_io_map;
  181         }
  182 
  183         /*
  184          * GPR400 has some registers in attribute memory as well.
  185          */
  186         if (pcmcia_mem_alloc(pa->pf, GPR400_MEM_LEN, &sc->sc_pmemh)) {
  187                 printf(": can't map mem space\n");
  188                 goto fail_mem_alloc;
  189         }
  190 
  191         if (pcmcia_mem_map(pa->pf, PCMCIA_MEM_ATTR, pa->pf->ccr_base,
  192             GPR400_MEM_LEN, &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin)) {
  193                 printf(": can't map memory\n");
  194                 goto fail_mem_map;
  195         }
  196 
  197         sc->sc_pf = pa->pf;
  198         sc->sc_iot = sc->sc_pioh.iot;
  199         sc->sc_ioh = sc->sc_pioh.ioh;
  200         sc->sc_memt = sc->sc_pmemh.memt;
  201         sc->sc_memh = sc->sc_pmemh.memh;
  202 
  203         printf(" port 0x%lx/%d", sc->sc_pioh.addr, sc->sc_pioh.size);
  204 
  205         sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_TTY, gpr_intr, sc,
  206             sc->sc_dev.dv_xname);
  207         intrstr = pcmcia_intr_string(sc->sc_pf, sc->sc_ih);
  208         printf("%s%s\n", *intrstr ? ", " : "", intrstr);
  209         if (sc->sc_ih != NULL)
  210                 return;
  211 
  212         pcmcia_mem_unmap(pa->pf, sc->sc_memwin);
  213 fail_mem_map:
  214         pcmcia_mem_free(pa->pf, &sc->sc_pmemh);
  215 fail_mem_alloc:
  216         pcmcia_io_unmap(pa->pf, sc->sc_iowin);
  217 fail_io_map:
  218         pcmcia_function_disable(pa->pf);
  219 fail_enable:
  220         pcmcia_io_free(pa->pf, &sc->sc_pioh);
  221 fail_io_alloc:
  222         return;
  223 }
  224 
  225 int
  226 gpr_detach(struct device *dev, int flags)
  227 {
  228         struct gpr_softc *sc = (struct gpr_softc *)dev;
  229 
  230         pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
  231         pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
  232         pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
  233         pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh);
  234 
  235         return (0);
  236 }
  237 
  238 int
  239 gpr_activate(struct device *dev, enum devact act)
  240 {
  241         struct gpr_softc *sc = (struct gpr_softc *)dev;
  242 
  243         switch (act) {
  244         case DVACT_ACTIVATE:
  245                 pcmcia_function_enable(sc->sc_pf);
  246                 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY,
  247                     gpr_intr, sc, sc->sc_dev.dv_xname);
  248                 break;
  249 
  250         case DVACT_DEACTIVATE:
  251                 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  252                 pcmcia_function_disable(sc->sc_pf);
  253                 break;
  254         }
  255 
  256         return (0);
  257 }
  258 
  259 int
  260 gpropen(dev_t dev, int flags, int mode, struct proc *p)
  261 {
  262         int unit = GPRUNIT(dev);
  263         struct gpr_softc *sc;
  264 
  265         DPRINTF(("%s: flags %d, mode %d\n", __func__, flags, mode));
  266 
  267         if (unit >= gpr_cd.cd_ndevs ||
  268             (sc = gpr_cd.cd_devs[unit]) == NULL)
  269                 return (ENXIO);
  270 
  271         return (tlvput(sc, GPR400_SELECT, "\x02", 1));
  272 }
  273 
  274 int
  275 gprclose(dev_t dev, int flags, int mode, struct proc *p)
  276 {
  277         int unit = GPRUNIT(dev);
  278         struct gpr_softc *sc = gpr_cd.cd_devs[unit];
  279 
  280         DPRINTF(("%s: flags %d, mode %d\n", __func__, flags, mode));
  281 
  282         (void)tlvput(sc, GPR400_CLOSE, (u_int8_t *)0, 0);
  283 
  284         return (0);
  285 }
  286 
  287 int
  288 gprioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
  289 {
  290         int unit = GPRUNIT(dev);
  291         struct gpr_softc *sc = gpr_cd.cd_devs[unit];
  292         int error;
  293 
  294         DPRINTF(("%s: cmd %d, flags 0x%x\n", __func__, cmd, flags));
  295 
  296         switch (cmd) {
  297         case GPR_RESET:
  298                 /*
  299                  * To reset and power up the reader, set bit 0 in the
  300                  * HAP register for at least 5us and wait for 20ms.
  301                  */
  302                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL,
  303                     GPR400_RESET);
  304                 delay(10);
  305                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL, 0);
  306                 tsleep(sc, PWAIT, "gpreset", hz / 40);
  307                 /* FALLTHROUGH */
  308 
  309         case GPR_SELECT:
  310                 error = tlvput(sc, GPR400_SELECT, "\x02", 1);
  311                 break;
  312 
  313         case GPR_POWER:
  314                 {
  315                         u_int8_t *mode;
  316 
  317                         if (*(int *)addr)
  318                                 mode = "\x01";  /* Standby      */
  319                         else
  320                                 mode = "\x00";  /* Power down   */
  321 
  322                         error = tlvput(sc, GPR400_POWER, mode, 1);
  323                 }
  324                 break;
  325 
  326         case GPR_CLOSE:
  327                 error = tlvput(sc, GPR400_CLOSE, (u_int8_t *)0, 0);
  328                 break;
  329 
  330         case GPR_RAM:
  331                 {
  332                         struct gpr400_ram r;
  333 
  334                         bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
  335                             sc->sc_offset, &r, sizeof(struct gpr400_ram));
  336                         error = copyout(&r, addr, sizeof(struct gpr400_ram));
  337                 }
  338                 break;
  339 
  340         case GPR_CMD:
  341         case GPR_OPEN:
  342         case GPR_STATUS:
  343         case GPR_TLV:
  344         default:
  345                 error = EINVAL;
  346                 break;
  347         };
  348 
  349         return (error);
  350 }
  351 
  352 int
  353 gpr_intr(void *arg)
  354 {
  355         struct gpr_softc *sc = arg;
  356         u_int8_t val;
  357 
  358         DPRINTF(("%s: got interrupt\n", __func__));
  359 
  360         /* Ack interrupt */
  361         val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL);
  362         bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL,
  363             val & ~GPR400_INTR);
  364 
  365         wakeup(sc);
  366 
  367         return (1);
  368 }
  369 
  370 int
  371 tlvput(struct gpr_softc *sc, int cmd, u_int8_t *data, int len)
  372 {
  373         int resid, ret;
  374 
  375         DPRINTF(("%s: cmd 0x%x, data %p, len %d\n", __func__,
  376             cmd, data, len));
  377 
  378         resid = len;
  379         do {
  380                 int n, s;
  381 
  382                 n = min(resid, 28);
  383                 resid -= n;
  384 
  385                 if (resid)
  386                         cmd |= GPR400_CONT;
  387                 else
  388                         cmd &= ~GPR400_CONT;
  389 
  390                 DPRINTF(("%s: sending cmd 0x%x, len %d, left %d\n",
  391                     __func__, cmd, n, resid));
  392 
  393                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0x02, cmd);
  394                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0x03, n);
  395 
  396                 if (n) {
  397                         bus_space_write_region_1(sc->sc_iot, sc->sc_ioh,
  398                             0x04, data, n);
  399                         data += n;
  400                 }
  401 
  402                 s = spltty();
  403 
  404                 /* Tell the reader to process this command. */
  405                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL,
  406                     GPR400_IREQ);
  407 
  408                 tsleep(sc, PCATCH, "tlvput", 0);
  409 
  410                 splx(s);
  411 
  412                 /* Read the status.     */
  413                 ret = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0x04);
  414 
  415                 DPRINTF(("%s: ret %d\n", __func__, ret));
  416 
  417                 if (ret != 0x00 || (!resid && ret != 0xe7))
  418                         return (EIO);
  419 
  420         } while (resid > 0);
  421 
  422         return (0);
  423 }

/* [<][>][^][v][top][bottom][index][help] */