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

Revision 964, 14.9 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 * Driver for Towitoko readers
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7#include "internal.h"
8#include <unistd.h>
9#include <stdio.h>
10#include <string.h>
11
12static int twt_led(ifd_reader_t *, int);
13static int twt_try_reset(ifd_reader_t *, const void *, size_t, void *, size_t);
14static int twt_command(ifd_reader_t *, const void *, size_t, void *, size_t);
15static int twt_recv_checksum(const unsigned char *, size_t);
16static size_t twt_send_checksum(unsigned char *, size_t);
17
18enum {
19        TWT_LED_OFF = 0,
20        TWT_LED_RED,
21        TWT_LED_GREEN,
22        TWT_LED_YELLOW
23};
24
25#define TWT_PAGESIZE    15
26
27/*
28 * Initialize the reader
29 */
30static int twt_open(ifd_reader_t * reader, const char *device_name)
31{
32        ifd_device_params_t params;
33        ifd_device_t *dev;
34        unsigned char buffer[256];
35
36        ifd_debug(1, "called, device=%s", device_name);
37
38        reader->name = "Towitoko Reader";
39        reader->nslots = 1;
40
41        if (!(dev = ifd_device_open(device_name)))
42                return -1;
43        reader->device = dev;
44
45        if (dev->type == IFD_DEVICE_TYPE_SERIAL) {
46                if (ifd_device_get_parameters(dev, &params) < 0)
47                        return -1;
48
49                params.serial.speed = 9600;
50                params.serial.bits = 8;
51                params.serial.stopbits = 2;
52                params.serial.parity = IFD_SERIAL_PARITY_EVEN;
53                params.serial.dtr = 1;
54                params.serial.rts = 1;
55
56                if (ifd_device_set_parameters(dev, &params) < 0)
57                        return -1;
58        }
59
60        sleep(1);
61        ifd_device_flush(dev);
62
63        if (twt_command(reader, "\x00", 1, buffer, 2) < 0)
64                goto failed;
65
66        ifd_debug(1, "towitoko reader type 0x%02x", buffer[0]);
67
68        /* Special handling for some towitoko readers
69         * (according to SCEZ) */
70        switch (buffer[0]) {
71        case 0x61:
72                reader->name = "Towitoko Chipdrive Micro";
73                break;
74        case 0x80:              /* Kartenzwerg */
75                reader->name = "Towitoko Kartenzwerg";
76                params.serial.stopbits = 1;
77                params.serial.parity = IFD_SERIAL_PARITY_NONE;
78                /* XXX - Kartenzwerg is for synchronous cards
79                 * only. Should we have a flag for this? */
80                break;
81        case 0x64:
82                reader->name = "Towitoko Kartenzwerg II";
83                params.serial.stopbits = 1;
84                params.serial.parity = IFD_SERIAL_PARITY_NONE;
85                break;
86        case 0x84:
87                reader->name = "Towitoko Chipdrive External";
88                break;
89        case 0x88:              /* Twin */
90                reader->name = "Towitoko Chipdrive Twin";
91                reader->nslots = 2;
92                params.serial.rts = 0;
93                break;
94        case 0x90:
95                reader->name = "Towitoko Chipdrive Internal";
96                break;
97        default:
98                reader->name = "Towitoko";
99        }
100
101        if (ifd_device_set_parameters(dev, &params) < 0)
102                return -1;
103
104        return 0;
105
106      failed:
107        ct_error("towitoko: failed to initialize device");
108        return -1;
109}
110
111/*
112 * Activate the reader
113 */
114static int twt_activate(ifd_reader_t * reader)
115{
116        unsigned char cmd[2] = { 0x60, 0x0F };
117
118        ifd_debug(1, "called.");
119        if (twt_command(reader, cmd, sizeof(cmd), NULL, 0) < 0)
120                return -1;
121
122        return 0;
123}
124
125static int twt_deactivate(ifd_reader_t * reader)
126{
127        unsigned char cmd[2] = { 0x61, 0x0F };
128
129        ifd_debug(1, "called.");
130        if (twt_command(reader, cmd, sizeof(cmd), NULL, 0) < 0)
131                return -1;
132        return 0;
133}
134
135static int twt_close(ifd_reader_t * reader)
136{
137        twt_led(reader, TWT_LED_OFF);
138        return 0;
139}
140
141/*
142 * Check card status
143 */
144static int twt_card_status(ifd_reader_t * reader, int slot, int *status)
145{
146        unsigned char byte;
147        int r;
148
149        if (slot != 0) {
150                ct_error("towitoko: bad slot index %u", slot);
151                return IFD_ERROR_INVALID_SLOT;
152        }
153
154        if ((r = twt_command(reader, "\x03", 1, &byte, 1)) < 0)
155                return r;
156
157        *status = 0;
158        if (byte & 0x40)
159                *status |= IFD_CARD_PRESENT;
160        if (byte & 0x80)
161                *status |= IFD_CARD_STATUS_CHANGED;
162
163        twt_led(reader, (byte & 0x40) ? TWT_LED_RED : TWT_LED_OFF);
164
165        return 0;
166}
167
168/*
169 * Reset the card and get the ATR
170 */
171static int twt_card_reset(ifd_reader_t * reader, int slot, void *atr,
172                          size_t size)
173{
174        static unsigned char reset1[] = { 0x80, 0x6F, 0x00, 0x05, 0x76 };
175        static unsigned char reset2[] = { 0xA0, 0x6F, 0x00, 0x05, 0x74 };
176        int r, i, n = 0, status;
177
178        ifd_debug(1, "called.");
179
180        if (slot != 0) {
181                ct_error("towitoko: bad slot index %u", slot);
182                return IFD_ERROR_INVALID_SLOT;
183        }
184
185        /* Activate the reader */
186        if ((r = twt_activate(reader)) < 0)
187                return r;
188
189        /* Get the card status */
190        if ((r = twt_card_status(reader, slot, &status)) < 0)
191                return r;
192
193        if (!(status & IFD_CARD_PRESENT))
194                return IFD_ERROR_NO_CARD;
195
196        /* SCEZ does this three times - I have no clue why */
197        for (i = 0; i < 1; i++) {
198                n = twt_try_reset(reader, reset1, sizeof(reset1), atr, size);
199                if (n != 0)
200                        return n;
201                n = twt_try_reset(reader, reset2, sizeof(reset2), atr, size);
202                if (n != 0)
203                        return n;
204        }
205
206        /* See if this is a synchronous card */
207        return ifd_sync_detect_icc(reader, slot, atr, size);
208}
209
210static int twt_try_reset(ifd_reader_t * reader, const void *cmd, size_t cmd_len,
211                         void *atr, size_t atr_len)
212{
213        ifd_device_t *dev = reader->device;
214        int rc;
215
216        ifd_debug(2, "sending %s", ct_hexdump(cmd, cmd_len));
217
218        ct_config.suppress_errors++;
219        if (ifd_device_type(dev) != IFD_DEVICE_TYPE_SERIAL) {
220                rc = ifd_device_transceive(dev, cmd, cmd_len,
221                                           atr, atr_len, 1000);
222        } else {
223                if (ifd_device_send(dev, (const unsigned char *)cmd, cmd_len) <
224                    0)
225                        return -1;
226                rc = ifd_device_recv(dev, (unsigned char *)atr, 1, 1000);
227        }
228        ct_config.suppress_errors--;
229
230        if (rc == IFD_ERROR_TIMEOUT)
231                return 0;
232
233        if (rc == 1) {
234                unsigned char c = *(unsigned char *)atr;
235
236                ifd_debug(1, "received first ATR byte: 0x%02x", c);
237                if (c != 0x3f && c != 0x3b && c != 0x03)
238                        return 0;
239        }
240
241        return rc;
242}
243
244/*
245 * Change the parity
246 */
247static int twt_change_parity(ifd_reader_t * reader, int parity)
248{
249        unsigned char cmd[] = { 0x6F, 0x00, 0x6A, 0x0F };
250        ifd_device_t *dev = reader->device;
251        ifd_device_params_t params;
252        int r;
253
254        if (dev->type != IFD_DEVICE_TYPE_SERIAL)
255                return IFD_ERROR_NOT_SUPPORTED;
256
257        if (ifd_device_get_parameters(dev, &params) < 0)
258                return -1;
259
260        switch (parity) {
261        case IFD_SERIAL_PARITY_EVEN:
262                cmd[1] = 0x40;
263                break;
264        case IFD_SERIAL_PARITY_ODD:
265                cmd[1] = 0x80;
266                break;
267        default:
268                ct_error("towitoko: parity NONE not supported");
269                return IFD_ERROR_NOT_SUPPORTED;
270        }
271
272        if ((r = twt_command(reader, cmd, 4, NULL, 0)) < 0) {
273                ct_error("towitoko: failed to change parity");
274                return r;
275        }
276
277        params.serial.parity = parity;
278        return ifd_device_set_parameters(dev, &params);
279}
280
281/*
282 * Change the serial speed
283 */
284static struct twt_speed {
285        unsigned int value;
286        unsigned char c1, c2;
287} twt_speed[] = {
288        {
289        1200, 0x60, 0x07}, {
290        2400, 0x2E, 0x03}, {
291        4800, 0x17, 0x05}, {
292        9600, 0x0B, 0x02}, {
293        14400, 0x07, 0x01}, {
294        19200, 0x05, 0x02}, {
295        28800, 0x03, 0x00}, {
296        38400, 0x02, 0x00}, {
297        57600, 0x01, 0x00}, {
298        115200, 0x80, 0x00}, {
299        0}
300};
301
302static int twt_change_speed(ifd_reader_t * reader, unsigned int speed)
303{
304        unsigned char cmd[] = { 0x6E, 0x00, 0x00, 0x00, 0x08 };
305        ifd_device_t *dev = reader->device;
306        struct twt_speed *spd;
307        ifd_device_params_t params;
308        int r;
309
310        if (dev->type != IFD_DEVICE_TYPE_SERIAL)
311                return IFD_ERROR_NOT_SUPPORTED;
312
313        if ((r = ifd_device_get_parameters(dev, &params)) < 0)
314                return r;
315
316        for (spd = twt_speed; spd->value; spd++) {
317                if (speed <= spd->value)
318                        break;
319        }
320        if (spd->value == 0)
321                return IFD_ERROR_NOT_SUPPORTED;
322
323        params.serial.speed = spd->value;
324        cmd[1] = spd->c1;
325        cmd[3] = spd->c2;
326
327        if ((r = twt_command(reader, cmd, sizeof(cmd), NULL, 0)) < 0) {
328                ct_error("towitoko: failed to change speed");
329                return r;
330        }
331
332        return ifd_device_set_parameters(dev, &params);
333}
334
335/*
336 * Send command to IFD
337 */
338static int twt_send(ifd_reader_t * reader, unsigned int dad,
339                    const unsigned char *buffer, size_t len)
340{
341        unsigned char cmd[] = { 0x6F, 0x00, 0x05, 0x00 };
342        unsigned int count;
343        ifd_device_t *dev;
344
345        if (!(dev = reader->device))
346                return -1;
347
348        ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
349        while (len) {
350                if ((count = len) > 255)
351                        count = 255;
352
353                cmd[1] = count;
354                twt_send_checksum(cmd, 3);
355
356                if (ifd_device_send(dev, cmd, 4) < 0
357                    || ifd_device_send(dev, buffer, count) < 0)
358                        return -1;
359
360                buffer += count;
361                len -= count;
362        }
363
364        return 0;
365}
366
367/*
368 * Receive data from IFD
369 */
370static int twt_recv(ifd_reader_t * reader, unsigned int dad,
371                    unsigned char *buffer, size_t len, long timeout)
372{
373        int n;
374
375        n = ifd_device_recv(reader->device, buffer, len, timeout);
376        if (n < 0)
377                return -1;
378        ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
379        return n;
380}
381
382/*
383 * Read synchronous card
384 */
385static int twt_sync_read_buffer(ifd_reader_t * reader, int slot, int proto,
386                                unsigned char *buffer, size_t len)
387{
388        size_t total = 0;
389        int r;
390
391        while (total < len) {
392                unsigned char cmd;
393                size_t cnt;
394
395                if ((cnt = len - total) > TWT_PAGESIZE)
396                        cnt = TWT_PAGESIZE;
397                cmd = (cnt - 1) | 0x10;
398
399                r = twt_command(reader, &cmd, 1, buffer + total, cnt);
400                if (r < 0) {
401                        if (total)
402                                return total;
403                        return r;
404                }
405
406                total += cnt;
407        }
408
409        return total;
410}
411
412static int twt_sync_set_read_address(ifd_reader_t * reader, int slot, int proto,
413                                     unsigned short addr)
414{
415        unsigned char cmd_i2c_short[] =
416            { 0x7C, 0x64, 0x41, 0x00, 0x00, 0x64, 0x40, 0x00, 0x0F };
417        unsigned char cmd_i2c_long[] =
418            { 0x7C, 0x64, 0x42, 0xA0, 0x00, 0x00, 0x64, 0x40, 0xA1, 0x0F };
419        unsigned char cmd_2wire[] =
420            { 0x70, 0x64, 0x42, 0x30, 0x00, 0x00, 0x65, 0x0F };
421        unsigned char cmd_3wire[] =
422            { 0x70, 0xA0, 0x42, 0x00, 0x00, 0x00, 0x80, 0x50, 0x0F };
423        unsigned char hi, lo, *cmd;
424        size_t len;
425
426        hi = addr >> 8;
427        lo = addr & 0xFF;
428
429        switch (proto) {
430        case IFD_PROTOCOL_I2C_SHORT:
431                cmd = cmd_i2c_short;
432                len = sizeof(cmd_i2c_short);
433                cmd[3] = (hi << 1) | 0xA0;
434                cmd[4] = lo;
435                cmd[7] = (hi << 1) | 0xA1;
436                break;
437
438        case IFD_PROTOCOL_I2C_LONG:
439                cmd = cmd_i2c_long;
440                len = sizeof(cmd_i2c_long);
441                cmd[4] = hi;
442                cmd[5] = lo;
443                break;
444
445        case IFD_PROTOCOL_2WIRE:
446                cmd = cmd_2wire;
447                len = sizeof(cmd_2wire);
448                cmd[4] = lo;
449                break;
450
451        case IFD_PROTOCOL_3WIRE:
452                cmd = cmd_3wire;
453                len = sizeof(cmd_3wire);
454                cmd[3] = (hi << 6) | 0x0e;
455                cmd[4] = lo;
456                break;
457
458        default:
459                return IFD_ERROR_NOT_SUPPORTED;
460        }
461
462        return twt_command(reader, cmd, len, NULL, 0);
463}
464
465static int twt_sync_read(ifd_reader_t * reader, int slot, int proto,
466                         unsigned short addr, unsigned char *buffer, size_t len)
467{
468        int r;
469
470        if ((r = twt_sync_set_read_address(reader, slot, proto, addr)) < 0)
471                return r;
472
473        return twt_sync_read_buffer(reader, slot, proto, buffer, len);
474}
475
476/*
477 * Write synchronous card
478 */
479static int twt_sync_write_buffer(ifd_reader_t * reader, int slot, int proto,
480                                 const unsigned char *buffer, size_t len)
481{
482        size_t total = 0;
483        int r;
484
485        while (total < len) {
486                unsigned char cmd[TWT_PAGESIZE + 2];
487                size_t cnt;
488
489                if ((cnt = len - total) > TWT_PAGESIZE)
490                        cnt = TWT_PAGESIZE;
491                cmd[0] = (cnt - 1) | 0x40;
492                memcpy(cmd + 1, buffer + total, cnt);
493                cmd[cnt + 1] = 0x0F;
494
495                r = twt_command(reader, cmd, cnt + 2, NULL, 0);
496                if (r < 0) {
497                        if (total)
498                                return total;
499                        return r;
500                }
501
502                total += cnt;
503        }
504
505        return total;
506}
507
508static int twt_sync_set_write_address(ifd_reader_t * reader, int slot,
509                                      int proto, unsigned short addr)
510{
511        unsigned char cmd_i2c_short1[] =
512            { 0x7C, 0x64, 0x41, 0xA0, 0x00, 0x64, 0x40, 0xA1, 0x0F };
513        unsigned char cmd_i2c_short2[] = { 0x7E, 0x10 };
514        unsigned char cmd_i2c_short3[] =
515            { 0x7E, 0x66, 0x6E, 0x00, 0x00, 0x10, 0x0F };
516        unsigned char cmd_i2c_long1[] =
517            { 0x7C, 0x64, 0x42, 0xA0, 0x00, 0x00, 0x64, 0x40, 0xA1, 0x0F };
518        unsigned char cmd_i2c_long2[] = { 0x7E, 0x10 };
519        unsigned char cmd_i2c_long3[] =
520            { 0x7F, 0x66, 0x6E, 0x00, 0x00, 0xA0, 0x0F };
521        unsigned char cmd_2wire[] = { 0x72, 0x6E, 0x00, 0x38, 0x03, 0x0F };
522        unsigned char cmd_3wire[] =
523            { 0x73, 0x67, 0x6E, 0x00, 0x00, 0x02, 0x0F };
524        unsigned char hi, lo, *cmd, status;
525        size_t len;
526        int r;
527
528        hi = addr >> 8;
529        lo = addr & 0xFF;
530
531        switch (proto) {
532        case IFD_PROTOCOL_I2C_SHORT:
533                if ((r =
534                     twt_command(reader, cmd_i2c_short1, sizeof(cmd_i2c_short1),
535                                 NULL, 0)) < 0)
536                        return r;
537                if ((r =
538                     twt_command(reader, cmd_i2c_short2, sizeof(cmd_i2c_short2),
539                                 &status, 1)) < 0)
540                        return r;
541
542                cmd = cmd_i2c_short3;
543                len = sizeof(cmd_i2c_short3);
544                cmd[3] = lo;
545                cmd[4] = (hi << 1) | 0xA0;
546                cmd[5] = 0x00 /* pagemode */ ;
547                break;
548
549        case IFD_PROTOCOL_I2C_LONG:
550                if ((r =
551                     twt_command(reader, cmd_i2c_long1, sizeof(cmd_i2c_long1),
552                                 NULL, 0)) < 0)
553                        return r;
554                if ((r =
555                     twt_command(reader, cmd_i2c_long2, sizeof(cmd_i2c_long2),
556                                 &status, 1)) < 0)
557                        return r;
558
559                cmd = cmd_i2c_long3;
560                len = sizeof(cmd_i2c_long3);
561                cmd[3] = lo;
562                cmd[4] = hi;
563                break;
564
565        case IFD_PROTOCOL_2WIRE:
566                cmd = cmd_2wire;
567                len = sizeof(cmd_2wire);
568                cmd[2] = lo;
569                break;
570
571        case IFD_PROTOCOL_3WIRE:
572                cmd = cmd_3wire;
573                len = sizeof(cmd_3wire);
574                cmd[3] = lo;
575                cmd[4] = (hi << 6) | 0x33;
576                break;
577
578        default:
579                return IFD_ERROR_NOT_SUPPORTED;
580        }
581
582        return twt_command(reader, cmd, len, NULL, 0);
583}
584
585static int twt_sync_write(ifd_reader_t * reader, int slot, int proto,
586                          unsigned short addr, const unsigned char *buffer,
587                          size_t len)
588{
589        int r;
590
591        if ((r = twt_sync_set_write_address(reader, slot, proto, addr)) < 0)
592                return r;
593
594        return twt_sync_write_buffer(reader, slot, proto, buffer, len);
595}
596
597/*
598 * Turn LED on/off
599 */
600static int twt_led(ifd_reader_t * reader, int what)
601{
602        unsigned char cmd[] = { 0x6F, 0x00, 0x6A, 0x0F };
603
604        cmd[1] = what;
605        return twt_command(reader, cmd, sizeof(cmd), NULL, 0);
606}
607
608/*
609 * Helper functions
610 */
611static int twt_command(ifd_reader_t * reader, const void *cmd, size_t cmd_len,
612                       void *res, size_t res_len)
613{
614        unsigned char buffer[254];
615        int rc;
616
617        if (res_len > sizeof(buffer) - 1 || cmd_len > sizeof(buffer) - 1)
618                return IFD_ERROR_BUFFER_TOO_SMALL;
619
620        memcpy(buffer, cmd, cmd_len);
621        cmd_len = twt_send_checksum(buffer, cmd_len);
622
623        if (ct_config.debug > 1)
624                ifd_debug(3, "sending:%s", ct_hexdump(buffer, cmd_len));
625
626        rc = ifd_device_transceive(reader->device,
627                                   buffer, cmd_len, buffer, res_len + 1, -1);
628        if (rc < 0) {
629                ct_error("towitoko: transceive error: %s", ct_strerror(rc));
630                return rc;
631        }
632
633        if (ct_config.debug > 1)
634                ifd_debug(3, "received:%s", ct_hexdump(buffer, res_len + 1));
635
636        if (!twt_recv_checksum(buffer, res_len + 1)) {
637                ct_error("towitoko: command failed (bad checksum)");
638                return -1;
639        }
640
641        if (res && res_len)
642                memcpy(res, buffer, res_len);
643
644        return 0;
645}
646
647static unsigned char twt_checksum(unsigned char cs, const unsigned char *data,
648                                  size_t len)
649{
650        unsigned char b;
651
652        while (len--) {
653                b = cs ^ *data++;
654                /* rotate left one bit and toggle LSB */
655                cs = ((b << 1) | (b >> 7)) ^ 0x01;
656        }
657        return cs;
658}
659
660static int twt_recv_checksum(const unsigned char *data, size_t len)
661{
662        if (len == 0)
663                return 0;
664
665        return data[len - 1] == twt_checksum(0x01, data, len - 1);
666}
667
668static size_t twt_send_checksum(unsigned char *data, size_t len)
669{
670        data[len] = twt_checksum(0x00, data, len);
671        return len + 1;
672}
673
674/*
675 * Driver operations
676 */
677static struct ifd_driver_ops towitoko_driver;
678
679void ifd_towitoko_register(void)
680{
681        towitoko_driver.open = twt_open;
682        towitoko_driver.close = twt_close;
683        towitoko_driver.change_parity = twt_change_parity;
684        towitoko_driver.change_speed = twt_change_speed;
685        towitoko_driver.activate = twt_activate;
686        towitoko_driver.deactivate = twt_deactivate;
687        towitoko_driver.card_status = twt_card_status;
688        towitoko_driver.card_reset = twt_card_reset;
689        towitoko_driver.send = twt_send;
690        towitoko_driver.recv = twt_recv;
691        towitoko_driver.sync_read = twt_sync_read;
692        towitoko_driver.sync_write = twt_sync_write;
693
694        ifd_driver_register("towitoko", &towitoko_driver);
695}
Note: See TracBrowser for help on using the repository browser.