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