[BACK]Return to gpr.c CVS log [TXT][DIR] Up to [local] / sys / dev / pcmcia

Annotation of sys/dev/pcmcia/gpr.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb