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