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