source: trunk/src/ifd/ifd-cardman.c @ 964

Revision 964, 9.6 KB checked in by aj, 5 years ago (diff)

indent changes only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * OMNIKEY CardMan 2020/6020/6120 driver
3 * This driver is not yet complete, but at least it
4 * spits out the ATR already.
5 * Needs a recentish Linux Kernel (2.4.5 does NOT work)
6 *
7 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
8 *
9 * Based on information from the cm2020 driver by
10 * Omnikey AG.
11 */
12
13#include "internal.h"
14#include <stdlib.h>
15#include <string.h>
16
17typedef struct cm_priv {
18        int icc_proto;
19        unsigned char rbuf[64];
20        unsigned int head, tail;
21} cm_priv_t;
22
23typedef int complete_fn_t(const void *, size_t);
24static int cm_set_card_parameters(ifd_device_t *, unsigned int baudRate);
25static int cm_transceive_t0(ifd_reader_t * reader,
26                            const void *sbuf, size_t slen,
27                            void *rbuf, size_t rlen);
28static int cm_usb_int(ifd_device_t * dev, int requesttype, int request,
29                      int value, int idx,
30                      const void *sbuf, size_t slen,
31                      void *rbuf, size_t rlen,
32                      complete_fn_t check, long timeout);
33static int cm_anyreply(const void *, size_t);
34
35/*
36 * Initialize the device
37 */
38static int cm_open(ifd_reader_t * reader, const char *device_name)
39{
40        ifd_device_t *dev;
41        cm_priv_t *priv;
42        ifd_device_params_t params;
43
44        reader->name = "OMNIKEY CardMan 2020/6020/6120";
45        reader->nslots = 1;
46        if (!(dev = ifd_device_open(device_name)))
47                return -1;
48        if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
49                ct_error("cardman: device %s is not a USB device", device_name);
50                ifd_device_close(dev);
51                return -1;
52        }
53
54        params = dev->settings;
55        params.usb.interface = 0;
56        if (ifd_device_set_parameters(dev, &params) < 0) {
57                ifd_device_close(dev);
58                return -1;
59        }
60        priv = (cm_priv_t *) calloc(1, sizeof(cm_priv_t));
61        if (!priv) {
62                ct_error("out of memory");
63                return IFD_ERROR_NO_MEMORY;
64        }
65
66        reader->driver_data = priv;
67        reader->device = dev;
68        dev->timeout = 2000;
69
70        return 0;
71}
72
73/*
74 * Power up the card slot
75 */
76static int cm_activate(ifd_reader_t * reader)
77{
78        ifd_device_t *dev = reader->device;
79        int rc;
80
81        ifd_debug(1, "called.");
82        /* Set async card @9600 bps, 2 stop bits, even parity */
83        if ((rc = cm_set_card_parameters(dev, 0x01)) < 0) {
84                ct_error("cardman: failed to set card parameters 9600/8E2");
85                return rc;
86        }
87        return 0;
88}
89
90static int cm_deactivate(ifd_reader_t * reader)
91{
92        ifd_device_t *dev = reader->device;
93        int rc;
94
95        ifd_debug(1, "called.");
96        if ((rc = ifd_usb_control(dev, 0x42, 0x11, 0, 0, NULL, 0, -1)) < 0) {
97                ct_error("cardman: failed to deactivate card");
98                return rc;
99        }
100        return 0;
101}
102
103/*
104 * Card status - always present
105 */
106static int cm_card_status(ifd_reader_t * reader, int slot, int *status)
107{
108        ifd_device_t *dev = reader->device;
109        unsigned char cm_status = 0;
110        int rc;
111
112        *status = 0;
113
114        if ((rc =
115             cm_usb_int(dev, 0x42, 0x20, 0, 0, NULL, 0, &cm_status, 1, NULL,
116                        -1)) < 0) {
117                ct_error("cardman: failed to get card status");
118                return -1;
119        }
120        if (rc == 1 && (cm_status & 0x42))
121                *status = IFD_CARD_PRESENT;
122        ifd_debug(1, "card %spresent", *status ? "" : "not ");
123        return 0;
124}
125
126/*
127 * Reset
128 */
129static int cm_card_reset(ifd_reader_t * reader, int slot, void *atr,
130                         size_t size)
131{
132        ifd_device_t *dev = reader->device;
133        unsigned char buffer[IFD_MAX_ATR_LEN];
134        int n;
135
136        /* Request the ATR */
137        if ((n = cm_usb_int(dev, 0x42, 0x10, 1, 0, NULL, 0,
138                            buffer, sizeof(buffer),
139                            (complete_fn_t *) ifd_atr_complete, -1)) < 0) {
140                ct_error("cardman: failed to reset card");
141                return n;
142        }
143
144        /* XXX Handle inverse convention, odd parity, etc */
145
146        if ((size_t) n > size)
147                n = size;
148        memcpy(atr, buffer, n);
149        return n;
150}
151
152/*
153 * Select a protocol for communication with the ICC.
154 */
155static int cm_set_protocol(ifd_reader_t * reader, int nslot, int proto)
156{
157        ifd_device_t *dev = reader->device;
158        ifd_slot_t *slot;
159        cm_priv_t *priv;
160        unsigned char pts[4], reply[4];
161        unsigned int baudRate;
162        int n;
163
164        ifd_debug(1, "called, proto=%d", proto);
165
166        pts[0] = 0xFF;
167        switch (proto) {
168        case IFD_PROTOCOL_T0:
169                pts[1] = 0x10;
170                pts[2] = 0x11;
171                break;
172        case IFD_PROTOCOL_T1:
173                pts[1] = 0x11;
174                /* XXX select Fi/Di according to TA1 */
175                pts[2] = 0x11;
176                break;
177        default:
178                return IFD_ERROR_NOT_SUPPORTED;
179        }
180        pts[3] = pts[0] ^ pts[1] ^ pts[2];
181
182        /* Send the PTS bytes */
183        if ((n =
184             cm_usb_int(dev, 0x42, 1, 0, 0, pts, 4, reply, 2, NULL, -1)) < 0) {
185                ct_error("cardman: failed to send PTS");
186                return n;
187        }
188        if (reply[0] != 4) {
189                ct_error("cardman: card refused PTS");
190                return IFD_ERROR_COMM_ERROR;
191        }
192#ifdef notyet
193        /* Receive PTS response */
194        if ((n = ifd_usb_control(dev, 0xC2, 0, 0, 0, reply, 4, -1)) < 0) {
195                ct_error("cardman: failed to receive PTS response");
196                return n;
197        }
198        if (n != 4) {
199                ct_error("cardman: received short PTS response (%u bytes)", n);
200                return IFD_ERROR_COMM_ERROR;
201        }
202        if (memcmp(pts, reply, 4)) {
203                ct_error("cardman: PTS reply does not match request", n);
204                return IFD_ERROR_COMM_ERROR;
205        }
206#endif
207
208        baudRate = pts[2] & 0xf;
209        /* Select f=5.12 MHz */
210        if ((pts[2] & 0xF0) == 0x90)
211                baudRate |= 0x10;
212        if ((n = cm_set_card_parameters(dev, baudRate)) < 0) {
213                ct_error
214                    ("cardman: failed to set card communication parameters");
215                return n;
216        }
217
218        /* T=0 goes through send/receive functions, but
219         * T=1 needs special massaging */
220        slot = &reader->slot[nslot];
221        if (proto == IFD_PROTOCOL_T0) {
222                slot->proto = ifd_protocol_new(proto, reader, slot->dad);
223        } else {
224                slot->proto = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT,
225                                               reader, slot->dad);
226        }
227        if (slot->proto == NULL) {
228                ct_error("cardman: internal error");
229                return -1;
230        }
231
232        priv = (cm_priv_t *) reader->driver_data;
233        priv->icc_proto = proto;
234
235        return 0;
236}
237
238/*
239 * Send/receive using the underlying protocol.
240 */
241static int cm_transparent(ifd_reader_t * reader, int dad,
242                          const void *sbuf, size_t slen, void *rbuf,
243                          size_t rlen)
244{
245        cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
246
247        switch (priv->icc_proto) {
248        case IFD_PROTOCOL_T0:
249                return cm_transceive_t0(reader, sbuf, slen, rbuf, rlen);
250        case IFD_PROTOCOL_T1:
251                return IFD_ERROR_NOT_SUPPORTED; /* not yet */
252        }
253
254        return IFD_ERROR_NOT_SUPPORTED;
255}
256
257static int cm_transceive_t0(ifd_reader_t * reader,
258                            const void *sbuf, size_t slen, void *rbuf,
259                            size_t rlen)
260{
261#if 0
262        ifd_device_t *dev = reader->device;
263        int rc;
264
265        if (len > 5) {
266                rc = ifd_usb_control(dev, 0x42, 2, 0, 0, rbuf, rlen);
267        } else {
268                unsigned char temp[5];
269
270                if (len < 4)
271                        return IFD_ERROR_INVALID_ARG;
272                temp[4] = 0;
273                memcpy(temp, sbuf, slen);
274                rc = ifd_usb_control(dev, 0x42, 3, 8, (temp[1] << 8) | temp[4],
275                                     temp, 5);
276        }
277#endif
278        return IFD_ERROR_NOT_SUPPORTED;
279}
280
281/*
282 * Send/receive routines
283 */
284static int cm_send_t0(ifd_reader_t * reader, unsigned int dad,
285                      const unsigned char *sbuf, size_t slen)
286{
287        cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
288        ifd_device_t *dev = reader->device;
289        int rc;
290
291        /* XXX how can we know if this is a CASE 1 or CASE 2 APDU? */
292        priv->head = priv->tail = 0;
293        rc = cm_usb_int(dev, 0x42, 2, 0, 0, sbuf, slen,
294                        priv->rbuf, sizeof(priv->rbuf), cm_anyreply, -1);
295        if (rc >= 0) {
296                priv->tail = rc;
297                rc = slen;
298        }
299        return rc;
300}
301
302static int cm_send(ifd_reader_t * reader, unsigned int dad,
303                   const unsigned char *buffer, size_t len)
304{
305        cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
306
307        switch (priv->icc_proto) {
308        case IFD_PROTOCOL_T0:
309                return cm_send_t0(reader, dad, buffer, len);
310        }
311
312        return IFD_ERROR_NOT_SUPPORTED;
313}
314
315static int cm_recv(ifd_reader_t * reader, unsigned int dad,
316                   unsigned char *buffer, size_t len, long timeout)
317{
318        cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
319
320        switch (priv->icc_proto) {
321        case IFD_PROTOCOL_T0:
322                if (priv->tail - priv->head < len)
323                        len = priv->tail - priv->head;
324                memcpy(buffer, priv->rbuf + priv->head, len);
325                priv->head += len;
326                return len;
327        }
328        return IFD_ERROR_NOT_SUPPORTED; /* not yet */
329}
330
331/*
332 * Set the card's baud rate etc
333 */
334static int cm_set_card_parameters(ifd_device_t * dev, unsigned int baudrate)
335{
336        return ifd_usb_control(dev, 0x42, 0x30, baudrate << 8, 2, NULL, 0, -1);
337}
338
339/*
340 * Send USB control message, and receive data via
341 * Interrupt URBs.
342 */
343static int cm_usb_int(ifd_device_t * dev, int requesttype, int request,
344                      int value, int idx, const void *sbuf, size_t slen,
345                      void *rbuf, size_t rlen, complete_fn_t complete,
346                      long timeout)
347{
348        ifd_usb_capture_t *cap;
349        struct timeval begin;
350        unsigned int total = 0;
351        int rc;
352
353        if (timeout < 0)
354                timeout = dev->timeout;
355
356        rc = ifd_usb_begin_capture(dev,
357                                   IFD_USB_URB_TYPE_INTERRUPT, 0x81, 8, &cap);
358        if (rc < 0)
359                return rc;
360
361        gettimeofday(&begin, NULL);
362        rc = ifd_usb_control(dev, requesttype, request,
363                             value, idx, (void *)sbuf, slen, timeout);
364        if (rc < 0)
365                goto out;
366
367        /* Capture URBs until we have a complete answer */
368        while (rc >= 0 && total < rlen) {
369                unsigned char temp[8];
370                long wait;
371
372                wait = timeout - ifd_time_elapsed(&begin);
373                if (wait <= 0)
374                        return IFD_ERROR_TIMEOUT;
375                rc = ifd_usb_capture(dev, cap, temp, sizeof(temp), wait);
376                if (rc > 0) {
377                        if (rc > (int)(rlen - total))
378                                rc = rlen - total;
379                        memcpy((caddr_t) rbuf + total, temp, rc);
380                        total += rc;
381
382                        if (complete && complete(rbuf, total))
383                                break;
384                }
385        }
386
387        if (rc >= 0) {
388                ifd_debug(3, "received %u bytes:%s", total,
389                          ct_hexdump(rbuf, total));
390                rc = total;
391        }
392
393      out:
394        ifd_usb_end_capture(dev, cap);
395        return rc;
396}
397
398static int cm_anyreply(const void *ptr, size_t len)
399{
400        return 1;
401}
402
403/*
404 * Driver operations
405 */
406static struct ifd_driver_ops cardman_driver;
407
408/*
409 * Initialize this module
410 */
411void ifd_cardman_register(void)
412{
413        cardman_driver.open = cm_open;
414        cardman_driver.activate = cm_activate;
415        cardman_driver.deactivate = cm_deactivate;
416        cardman_driver.card_status = cm_card_status;
417        cardman_driver.card_reset = cm_card_reset;
418        cardman_driver.send = cm_send;
419        cardman_driver.recv = cm_recv;
420        cardman_driver.set_protocol = cm_set_protocol;
421        cardman_driver.transparent = cm_transparent;
422
423        ifd_driver_register("cardman", &cardman_driver);
424}
Note: See TracBrowser for help on using the repository browser.