1 /* $OpenBSD: gpr.c,v 1.11 2005/01/27 17:04:55 millert 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
gpr_match(struct device * parent,void * match,void * aux)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
gpr_attach(struct device * parent,struct device * self,void * aux)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(psc->sc_pf, sc->sc_ih);
208 printf("%s%s\n", *intrstr ? ", " : "", intrstr);
209 if (sc->sc_ih != NULL)
210 return;
211
212 fail_intr:
213 pcmcia_mem_unmap(pa->pf, sc->sc_memwin);
214 fail_mem_map:
215 pcmcia_mem_free(pa->pf, &sc->sc_pmemh);
216 fail_mem_alloc:
217 pcmcia_io_unmap(pa->pf, sc->sc_iowin);
218 fail_io_map:
219 pcmcia_function_disable(pa->pf);
220 fail_enable:
221 pcmcia_io_free(pa->pf, &sc->sc_pioh);
222 fail_io_alloc:
223 return;
224 }
225
226 int
gpr_detach(struct device * dev,int flags)227 gpr_detach(struct device *dev, int flags)
228 {
229 struct gpr_softc *sc = (struct gpr_softc *)dev;
230
231 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
232 pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
233 pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
234 pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh);
235
236 return (0);
237 }
238
239 int
gpr_activate(struct device * dev,enum devact act)240 gpr_activate(struct device *dev, enum devact act)
241 {
242 struct gpr_softc *sc = (struct gpr_softc *)dev;
243
244 switch (act) {
245 case DVACT_ACTIVATE:
246 pcmcia_function_enable(sc->sc_pf);
247 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY,
248 gpr_intr, sc, sc->sc_dev.dv_xname);
249 break;
250
251 case DVACT_DEACTIVATE:
252 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
253 pcmcia_function_disable(sc->sc_pf);
254 break;
255 }
256
257 return (0);
258 }
259
260 int
gpropen(dev_t dev,int flags,int mode,struct proc * p)261 gpropen(dev_t dev, int flags, int mode, struct proc *p)
262 {
263 int unit = GPRUNIT(dev);
264 struct gpr_softc *sc;
265
266 DPRINTF(("%s: flags %d, mode %d\n", __func__, flags, mode));
267
268 if (unit >= gpr_cd.cd_ndevs ||
269 (sc = gpr_cd.cd_devs[unit]) == NULL)
270 return (ENXIO);
271
272 return (tlvput(sc, GPR400_SELECT, "\x02", 1));
273 }
274
275 int
gprclose(dev_t dev,int flags,int mode,struct proc * p)276 gprclose(dev_t dev, int flags, int mode, struct proc *p)
277 {
278 int unit = GPRUNIT(dev);
279 struct gpr_softc *sc = gpr_cd.cd_devs[unit];
280
281 DPRINTF(("%s: flags %d, mode %d\n", __func__, flags, mode));
282
283 (void)tlvput(sc, GPR400_CLOSE, (u_int8_t *)0, 0);
284
285 return (0);
286 }
287
288 int
gprioctl(dev_t dev,u_long cmd,caddr_t addr,int flags,struct proc * p)289 gprioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
290 {
291 int unit = GPRUNIT(dev);
292 struct gpr_softc *sc = gpr_cd.cd_devs[unit];
293 int error;
294
295 DPRINTF(("%s: cmd %d, flags 0x%x\n", __func__, cmd, flags));
296
297 switch (cmd) {
298 case GPR_RESET:
299 /*
300 * To reset and power up the reader, set bit 0 in the
301 * HAP register for at least 5us and wait for 20ms.
302 */
303 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL,
304 GPR400_RESET);
305 delay(10);
306 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL, 0);
307 tsleep(sc, PWAIT, "gpreset", hz / 40);
308 /* FALLTHROUGH */
309
310 case GPR_SELECT:
311 error = tlvput(sc, GPR400_SELECT, "\x02", 1);
312 break;
313
314 case GPR_POWER:
315 {
316 u_int8_t *mode;
317
318 if (*(int *)addr)
319 mode = "\x01"; /* Standby */
320 else
321 mode = "\x00"; /* Power down */
322
323 error = tlvput(sc, GPR400_POWER, mode, 1);
324 }
325 break;
326
327 case GPR_CLOSE:
328 error = tlvput(sc, GPR400_CLOSE, (u_int8_t *)0, 0);
329 break;
330
331 case GPR_RAM:
332 {
333 struct gpr400_ram r;
334
335 bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
336 sc->sc_offset, &r, sizeof(struct gpr400_ram));
337 error = copyout(&r, addr, sizeof(struct gpr400_ram));
338 }
339 break;
340
341 case GPR_CMD:
342 case GPR_OPEN:
343 case GPR_STATUS:
344 case GPR_TLV:
345 default:
346 error = EINVAL;
347 break;
348 };
349
350 return (error);
351 }
352
353 int
gpr_intr(void * arg)354 gpr_intr(void *arg)
355 {
356 struct gpr_softc *sc = arg;
357 u_int8_t val;
358
359 DPRINTF(("%s: got interrupt\n", __func__));
360
361 /* Ack interrupt */
362 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL);
363 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL,
364 val & ~GPR400_INTR);
365
366 wakeup(sc);
367
368 return (1);
369 }
370
371 int
tlvput(struct gpr_softc * sc,int cmd,u_int8_t * data,int len)372 tlvput(struct gpr_softc *sc, int cmd, u_int8_t *data, int len)
373 {
374 int resid, ret;
375
376 DPRINTF(("%s: cmd 0x%x, data %p, len %d\n", __func__,
377 cmd, data, len));
378
379 resid = len;
380 do {
381 int n, s;
382
383 n = min(resid, 28);
384 resid -= n;
385
386 if (resid)
387 cmd |= GPR400_CONT;
388 else
389 cmd &= ~GPR400_CONT;
390
391 DPRINTF(("%s: sending cmd 0x%x, len %d, left %d\n",
392 __func__, cmd, n, resid));
393
394 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0x02, cmd);
395 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0x03, n);
396
397 if (n) {
398 bus_space_write_region_1(sc->sc_iot, sc->sc_ioh,
399 0x04, data, n);
400 data += n;
401 }
402
403 s = spltty();
404
405 /* Tell the reader to process this command. */
406 bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL,
407 GPR400_IREQ);
408
409 tsleep(sc, PCATCH, "tlvput", 0);
410
411 splx(s);
412
413 /* Read the status. */
414 ret = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0x04);
415
416 DPRINTF(("%s: ret %d\n", __func__, ret));
417
418 if (ret != 0x00 || (!resid && ret != 0xe7))
419 return (EIO);
420
421 } while (resid > 0);
422
423 return (0);
424 }
425