/[pcsclite]/trunk/Drivers/ccid/src/ccid_serial.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/src/ccid_serial.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1479 - (show annotations) (download)
Wed Apr 27 14:10:38 2005 UTC (8 years ago) by rousseau
File MIME type: text/plain
File size: 16966 byte(s)
Open*ByName: do not initialise the now disappeared .dwMaxDataRate field
1 /*
2 * ccid_serial.c: communicate with a GemPC Twin smart card reader
3 * Copyright (C) 2001-2004 Ludovic Rousseau <ludovic.rousseau@free.fr>
4 *
5 * Thanks to Niki W. Waibel <niki.waibel@gmx.net> for a prototype version
6 *
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /*
23 * $Id$
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <termios.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <PCSC/ifdhandler.h>
37
38 #include "defs.h"
39 #include "ccid_ifdhandler.h"
40 #include "config.h"
41 #include "debug.h"
42 #include "ccid.h"
43 #include "utils.h"
44 #include "commands.h"
45
46 #define SYNC 0x03
47 #define CTRL_ACK 0x06
48 #define CTRL_NAK 0x15
49 #define RDR_to_PC_NotifySlotChange 0x50
50 #define CARD_ABSENT 0x02
51 #define CARD_PRESENT 0x03
52
53 /*
54 * normal command:
55 * 1 : SYNC
56 * 1 : CTRL
57 * 10 +data length : CCID command
58 * 1 : LRC
59 *
60 * SYNC : 0x03
61 * CTRL : ACK (0x06) or NAK (0x15)
62 * CCID command : see USB CCID specs
63 * LRC : xor of all the previous byes
64 *
65 * Error message:
66 * 1 : SYNC (0x03)
67 * 1 : CTRL (NAK: 0x15)
68 * 1 : LRC (0x16)
69 *
70 * Card insertion/withdrawal
71 * 1 : RDR_to_PC_NotifySlotChange (0x50)
72 * 1 : bmSlotIccState
73 * 0x02 if card absent
74 * 0x03 is card present
75 *
76 * Time request
77 * T=1 : normal CCID command
78 * T=0 : 1 byte (value between 0x80 and 0xFF)
79 *
80 */
81
82 /*
83 * You may get read timeout after a card movement.
84 * This is because you will get the echo of the CCID command
85 * but not the result of the command.
86 *
87 * This is not an applicative issue since the card is either removed (and
88 * powered off) or just inserted (and not yet powered on).
89 */
90
91 /* 271 = max size for short APDU
92 * 2 bytes for header
93 * 1 byte checksum
94 * doubled for echo
95 */
96 #define GEMPCTWIN_MAXBUF (271 +2 +1) * 2
97
98 typedef struct
99 {
100 /*
101 * File handle on the serial port
102 */
103 int fd;
104
105 /*
106 * device used ("/dev/ttyS?" under Linux)
107 */
108 /*@null@*/ char *device;
109
110 /*
111 * serial communication buffer
112 */
113 unsigned char buffer[GEMPCTWIN_MAXBUF];
114
115 /*
116 * next available byte
117 */
118 int buffer_offset;
119
120 /*
121 * number of available bytes
122 */
123 int buffer_offset_last;
124
125 /*
126 * CCID infos common to USB and serial
127 */
128 _ccid_descriptor ccid;
129
130 } _serialDevice;
131
132 /* The _serialDevice structure must be defined before including ccid_serial.h */
133 #include "ccid_serial.h"
134
135 unsigned int SerialDataRates[] = {
136 10753,
137 14337,
138 15625,
139 17204,
140 20833,
141 21505,
142 23438,
143 25806,
144 28674,
145 31250,
146 32258,
147 34409,
148 39063,
149 41667,
150 43011,
151 46875,
152 52083,
153 53763,
154 57348,
155 62500,
156 64516,
157 68817,
158 71685,
159 78125,
160 83333,
161 86022,
162 93750,
163 104667,
164 107527,
165 114695,
166 125000,
167 129032,
168 143369,
169 156250,
170 166667,
171 172043,
172 215054,
173 229391,
174 250000,
175 344086,
176 0
177 };
178
179 /* no need to initialize to 0 since it is static */
180 static _serialDevice serialDevice[CCID_DRIVER_MAX_READERS];
181
182 /* unexported functions */
183 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
184 int buffer_length, int min_length);
185
186 static int get_bytes(unsigned int reader_index, unsigned char *buffer,
187 int length);
188
189
190 /*****************************************************************************
191 *
192 * WriteSerial: Send bytes to the card reader
193 *
194 *****************************************************************************/
195 status_t WriteSerial(unsigned int reader_index, unsigned int length,
196 unsigned char *buffer)
197 {
198 int i;
199 unsigned char lrc;
200 unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
201
202 #ifdef DEBUG_LEVEL_COMM
203 char debug_header[] = "-> 123456 ";
204
205 sprintf(debug_header, "-> %06X ", reader_index);
206 #endif
207
208 if (length > GEMPCTWIN_MAXBUF-3)
209 {
210 DEBUG_CRITICAL3("command too long: %d for max %d",
211 length, GEMPCTWIN_MAXBUF-3);
212 return STATUS_UNSUCCESSFUL;
213 }
214
215 /* header */
216 low_level_buffer[0] = 0x03; /* SYNC */
217 low_level_buffer[1] = 0x06; /* ACK */
218
219 /* CCID command */
220 memcpy(low_level_buffer+2, buffer, length);
221
222 /* checksum */
223 lrc = 0;
224 for(i=0; i<length+2; i++)
225 lrc ^= low_level_buffer[i];
226 low_level_buffer[length+2] = lrc;
227
228 #ifdef DEBUG_LEVEL_COMM
229 DEBUG_XXD(debug_header, low_level_buffer, length+3);
230 #endif
231
232 if (write(serialDevice[reader_index].fd, low_level_buffer,
233 length+3) != length+3)
234 {
235 DEBUG_CRITICAL2("write error: %s", strerror(errno));
236 return STATUS_UNSUCCESSFUL;
237 }
238
239 return STATUS_SUCCESS;
240 } /* WriteSerial */
241
242
243 /*****************************************************************************
244 *
245 * ReadSerial: Receive bytes from the card reader
246 *
247 *****************************************************************************/
248 status_t ReadSerial(unsigned int reader_index,
249 /*@unused@*/ unsigned int *length, unsigned char *buffer)
250 {
251 unsigned char c;
252 int rv;
253 int echo;
254 int to_read;
255 int i;
256
257 /* we get the echo first */
258 echo = TRUE;
259
260 start:
261 DEBUG_COMM("start");
262 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
263 return rv;
264
265 if (c == RDR_to_PC_NotifySlotChange)
266 goto slot_change;
267
268 if (c == SYNC)
269 goto sync;
270
271 if (c >= 0x80)
272 {
273 DEBUG_COMM2("time request: 0x%02X", c);
274 goto start;
275 }
276
277 DEBUG_CRITICAL2("Got 0x%02X", c);
278 return STATUS_COMM_ERROR;
279
280 slot_change:
281 DEBUG_COMM("slot change");
282 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
283 return rv;
284
285 if (c == CARD_ABSENT)
286 {
287 DEBUG_COMM("Card removed");
288 }
289 else
290 if (c == CARD_PRESENT)
291 {
292 DEBUG_COMM("Card inserted");
293 }
294 else
295 {
296 DEBUG_COMM2("Unknown card movement: %d", c);
297 }
298 goto start;
299
300 sync:
301 DEBUG_COMM("sync");
302 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
303 return rv;
304
305 if (c == CTRL_ACK)
306 goto ack;
307
308 if (c == CTRL_NAK)
309 goto nak;
310
311 DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
312 return STATUS_COMM_ERROR;
313
314 nak:
315 DEBUG_COMM("nak");
316 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
317 return rv;
318
319 if (c != (SYNC ^ CTRL_NAK))
320 {
321 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
322 return STATUS_COMM_ERROR;
323 }
324 else
325 goto start;
326
327 ack:
328 DEBUG_COMM("ack");
329 /* normal CCID frame */
330 if ((rv = get_bytes(reader_index, buffer, 5)) != STATUS_SUCCESS)
331 return rv;
332
333 /* total frame size */
334 to_read = 10+dw2i(buffer, 1);
335
336 DEBUG_COMM2("frame size: %d", to_read);
337 if ((rv = get_bytes(reader_index, buffer+5, to_read-5)) != STATUS_SUCCESS)
338 return rv;
339
340 #ifdef DEBUG_LEVEL_COMM
341 DEBUG_XXD("frame: ", buffer, to_read);
342 #endif
343
344 /* lrc */
345 DEBUG_COMM("lrc");
346 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
347 return rv;
348
349 DEBUG_COMM2("lrc: 0x%02X", c);
350 for (i=0; i<to_read; i++)
351 c ^= buffer[i];
352
353 if (c != (SYNC ^ CTRL_ACK))
354 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
355
356 if (echo)
357 {
358 echo = FALSE;
359 goto start;
360 }
361
362 return STATUS_SUCCESS;
363 } /* ReadSerial */
364
365
366 /*****************************************************************************
367 *
368 * get_bytes: get n bytes
369 *
370 *****************************************************************************/
371 int get_bytes(unsigned int reader_index, unsigned char *buffer, int length)
372 {
373 int offset = serialDevice[reader_index].buffer_offset;
374 int offset_last = serialDevice[reader_index].buffer_offset_last;
375
376 DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
377 length);
378 /* enough data are available */
379 if (offset + length <= offset_last)
380 {
381 DEBUG_COMM("data available");
382 memcpy(buffer, serialDevice[reader_index].buffer + offset, length);
383 serialDevice[reader_index].buffer_offset += length;
384 }
385 else
386 {
387 int present, rv;
388
389 /* copy available data */
390 present = offset_last - offset;
391
392 if (present > 0)
393 {
394 DEBUG_COMM2("some data available: %d", present);
395 memcpy(buffer, serialDevice[reader_index].buffer + offset,
396 present);
397 }
398
399 /* get fresh data */
400 DEBUG_COMM2("get more data: %d", length - present);
401 rv = ReadChunk(reader_index, serialDevice[reader_index].buffer,
402 sizeof(serialDevice[reader_index].buffer), length - present);
403 if (rv < 0)
404 return STATUS_COMM_ERROR;
405
406 /* fill the buffer */
407 memcpy(buffer + present, serialDevice[reader_index].buffer,
408 length - present);
409 serialDevice[reader_index].buffer_offset = length - present;
410 serialDevice[reader_index].buffer_offset_last = rv;
411 DEBUG_COMM3("offset: %d, last_offset: %d",
412 serialDevice[reader_index].buffer_offset,
413 serialDevice[reader_index].buffer_offset_last);
414 }
415
416 return STATUS_SUCCESS;
417 } /* get_bytes */
418
419
420 /*****************************************************************************
421 *
422 * ReadChunk: read a minimum number of bytes
423 *
424 *****************************************************************************/
425 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
426 int buffer_length, int min_length)
427 {
428 int fd = serialDevice[reader_index].fd;
429 # ifndef S_SPLINT_S
430 fd_set fdset;
431 # endif
432 struct timeval t;
433 int i, rv = 0;
434 int already_read;
435 #ifdef DEBUG_LEVEL_COMM
436 char debug_header[] = "<- 123456 ";
437
438 sprintf(debug_header, "<- %06X ", reader_index);
439 #endif
440
441 already_read = 0;
442 while (already_read < min_length)
443 {
444 /* use select() to, eventually, timeout */
445 FD_ZERO(&fdset);
446 FD_SET(fd, &fdset);
447 t.tv_sec = serialDevice[reader_index].ccid.readTimeout;
448 t.tv_usec = 0;
449
450 i = select(fd+1, &fdset, NULL, NULL, &t);
451 if (i == -1)
452 {
453 DEBUG_CRITICAL2("select: %s", strerror(errno));
454 return -1;
455 }
456 else
457 if (i == 0)
458 {
459 DEBUG_COMM2("Timeout! (%d sec)", serialDevice[reader_index].ccid.readTimeout);
460 return -1;
461 }
462
463 rv = read(fd, buffer + already_read, buffer_length - already_read);
464 if (rv < 0)
465 {
466 DEBUG_COMM2("read error: %s", strerror(errno));
467 return -1;
468 }
469
470 #ifdef DEBUG_LEVEL_COMM
471 DEBUG_XXD(debug_header, buffer + already_read, rv);
472 #endif
473
474 already_read += rv;
475 DEBUG_COMM3("read: %d, to read: %d", already_read,
476 min_length);
477 }
478
479 return already_read;
480 } /* ReadChunk */
481
482
483 /*****************************************************************************
484 *
485 * OpenSerial: open the port
486 *
487 *****************************************************************************/
488 status_t OpenSerial(unsigned int reader_index, int channel)
489 {
490 char dev_name[FILENAME_MAX];
491
492 DEBUG_COMM3("Reader index: %X, Channel: %d", reader_index, channel);
493
494 /*
495 * Conversion of old-style ifd-hanler 1.0 CHANNELID
496 */
497 if (channel == 0x0103F8)
498 channel = 1;
499 else
500 if (channel == 0x0102F8)
501 channel = 2;
502 else
503 if (channel == 0x0103E8)
504 channel = 3;
505 else
506 if (channel == 0x0102E8)
507 channel = 4;
508
509 if (channel < 0)
510 {
511 DEBUG_CRITICAL2("wrong port number: %d", (int) channel);
512 return STATUS_UNSUCCESSFUL;
513 }
514
515 sprintf(dev_name, "/dev/pcsc/%d", (int) channel);
516
517 return OpenSerialByName(reader_index, dev_name);
518 } /* OpenSerial */
519
520 /*****************************************************************************
521 *
522 * OpenSerialByName: open the port
523 *
524 *****************************************************************************/
525 status_t OpenSerialByName(unsigned int reader_index, char *dev_name)
526 {
527 struct termios current_termios;
528 int i;
529 unsigned int reader = reader_index;
530
531 DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name);
532
533 /* check if the same channel is not already used */
534 for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
535 {
536 if (serialDevice[i].device &&
537 strcmp(serialDevice[i].device, dev_name) == 0)
538 {
539 DEBUG_CRITICAL2("Device %s already in use", dev_name);
540 return STATUS_UNSUCCESSFUL;
541 }
542 }
543
544 serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
545
546 if (-1 == serialDevice[reader].fd)
547 {
548 DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
549 return STATUS_UNSUCCESSFUL;
550 }
551
552 /* Set RTS signal to low to prevent the smart card reader
553 * from sending its plug and play string. */
554 {
555 int flags;
556
557 if (ioctl(serialDevice[reader].fd, TIOCMGET, &flags) < 0)
558 {
559 DEBUG_CRITICAL2("Get RS232 signals state failed: %s",
560 strerror(errno));
561 }
562 else
563 {
564 flags &= ~TIOCM_RTS;
565 if (ioctl(serialDevice[reader].fd, TIOCMSET, &flags) < 0)
566 {
567 DEBUG_CRITICAL2("Set RTS to low failed: %s", strerror(errno));
568 }
569 else
570 {
571 DEBUG_COMM("Plug-n-Play inhibition successful");
572 }
573 }
574 }
575
576 /* set channel used */
577 serialDevice[reader].device = strdup(dev_name);
578
579 /* empty in and out serial buffers */
580 if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
581 DEBUG_INFO2("tcflush() function error: %s", strerror(errno));
582
583 /* get config attributes */
584 if (tcgetattr(serialDevice[reader].fd, &current_termios) == -1)
585 {
586 DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
587 close(serialDevice[reader].fd);
588 serialDevice[reader].fd = -1;
589
590 return STATUS_UNSUCCESSFUL;
591 }
592
593 /* IGNBRK: ignore BREAK condition on input
594 * IGNPAR: ignore framing errors and parity errors. */
595 current_termios.c_iflag = IGNBRK | IGNPAR;
596 current_termios.c_oflag = 0; /* Raw output modes */
597 /* CS8: 8-bits character size
598 * CSTOPB: set two stop bits
599 * CREAD: enable receiver
600 * CLOCAL: ignore modem control lines */
601 current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;
602
603 /* Do not echo characters because if you connect to a host it or your modem
604 * will echo characters for you. Don't generate signals. */
605 current_termios.c_lflag = 0;
606
607 /* set serial port speed to 115200 bauds */
608 cfsetspeed(&current_termios, B115200);
609
610 DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration");
611 if (tcsetattr(serialDevice[reader].fd, TCSANOW, &current_termios) == -1)
612 {
613 close(serialDevice[reader].fd);
614 serialDevice[reader].fd = -1;
615 DEBUG_INFO2("tcsetattr error: %s", strerror(errno));
616
617 return STATUS_UNSUCCESSFUL;
618 }
619
620 serialDevice[reader].ccid.real_bSeq = 0;
621 serialDevice[reader].ccid.pbSeq = &serialDevice[reader].ccid.real_bSeq;
622 serialDevice[reader].ccid.readerID = GEMPCTWIN;
623 serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;
624 serialDevice[reader].ccid.dwMaxIFSD = 254;
625 serialDevice[reader].ccid.dwFeatures = 0x00010230;
626 serialDevice[reader].ccid.bPINSupport = 0x0;
627 serialDevice[reader].ccid.dwDefaultClock = 4000;
628 serialDevice[reader].ccid.bMaxSlotIndex = 0;
629 serialDevice[reader].ccid.bCurrentSlotIndex = 0;
630 serialDevice[reader].ccid.arrayOfSupportedDataRates = SerialDataRates;
631
632 serialDevice[reader].buffer_offset = 0;
633 serialDevice[reader].buffer_offset_last = 0;
634
635 /* perform a command to be sure a GemPC Twin reader is connected
636 * get the reader firmware */
637 {
638 unsigned char tx_buffer[] = { 0x02 };
639 unsigned char rx_buffer[50];
640 unsigned int rx_length = sizeof(rx_buffer);
641
642 /* 2 seconds timeout to not wait too long if no reader is connected */
643 serialDevice[reader].ccid.readTimeout = 2;
644
645 if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
646 rx_buffer, &rx_length))
647 {
648 DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected");
649 return STATUS_UNSUCCESSFUL;
650 }
651
652 /* normal timeout: 2 seconds */
653 serialDevice[reader].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT ;
654
655 rx_buffer[rx_length] = '\0';
656 DEBUG_INFO2("Firmware: %s", rx_buffer);
657 }
658
659 /* perform a command to configure GemPC Twin reader card movement
660 * notification to synchronous mode: the card movement is notified _after_
661 * the host command and _before_ the reader anwser */
662 {
663 unsigned char tx_buffer[] = { 0x01, 0x01, 0x01};
664 unsigned char rx_buffer[50];
665 unsigned int rx_length = sizeof(rx_buffer);
666
667 if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
668 rx_buffer, &rx_length))
669 {
670 DEBUG_CRITICAL("Change card movement notification failed.");
671 return STATUS_UNSUCCESSFUL;
672 }
673 }
674
675 return STATUS_SUCCESS;
676 } /* OpenSerialByName */
677
678
679 /*****************************************************************************
680 *
681 * CloseSerial: close the port
682 *
683 *****************************************************************************/
684 status_t CloseSerial(unsigned int reader_index)
685 {
686 unsigned int reader = reader_index;
687
688 close(serialDevice[reader].fd);
689 serialDevice[reader].fd = -1;
690
691 free(serialDevice[reader].device);
692 serialDevice[reader].device = NULL;
693
694 return STATUS_SUCCESS;
695 } /* CloseSerial */
696
697
698 /*****************************************************************************
699 *
700 * get_ccid_descriptor
701 *
702 ****************************************************************************/
703 _ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
704 {
705 return &serialDevice[reader_index].ccid;
706 } /* get_ccid_descriptor */
707
708

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5