/[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 1077 - (show annotations) (download)
Fri Jul 16 06:53:25 2004 UTC (8 years, 10 months ago) by rousseau
File MIME type: text/plain
File size: 14942 byte(s)
rename PCSCLITE_MAX_READERS in CCID_DRIVER_MAX_READERS

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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5