/[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 1106 - (show annotations) (download)
Wed Jul 28 08:33:18 2004 UTC (8 years, 10 months ago) by rousseau
File MIME type: text/plain
File size: 15207 byte(s)
use reader_index instead of lun as reader identification
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 reader_index, unsigned char *buffer,
142 int buffer_length, int min_length);
143
144 static int get_bytes(unsigned int reader_index, unsigned char *buffer,
145 int length);
146
147
148 /*****************************************************************************
149 *
150 * WriteSerial: Send bytes to the card reader
151 *
152 *****************************************************************************/
153 status_t WriteSerial(unsigned int reader_index, unsigned int length,
154 unsigned char *buffer)
155 {
156 int i;
157 unsigned char lrc;
158 unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
159
160 #ifdef DEBUG_LEVEL_COMM
161 char debug_header[] = "-> 123456 ";
162
163 sprintf(debug_header, "-> %06X ", reader_index);
164 #endif
165
166 if (length > GEMPCTWIN_MAXBUF-3)
167 {
168 DEBUG_CRITICAL3("command too long: %d for max %d",
169 length, GEMPCTWIN_MAXBUF-3);
170 return STATUS_UNSUCCESSFUL;
171 }
172
173 /* header */
174 low_level_buffer[0] = 0x03; /* SYNC */
175 low_level_buffer[1] = 0x06; /* ACK */
176
177 /* CCID command */
178 memcpy(low_level_buffer+2, buffer, length);
179
180 /* checksum */
181 lrc = 0;
182 for(i=0; i<length+2; i++)
183 lrc ^= low_level_buffer[i];
184 low_level_buffer[length+2] = lrc;
185
186 #ifdef DEBUG_LEVEL_COMM
187 DEBUG_XXD(debug_header, low_level_buffer, length+3);
188 #endif
189
190 if (write(serialDevice[reader_index].fd, low_level_buffer,
191 length+3) != length+3)
192 {
193 DEBUG_CRITICAL2("write error: %s", strerror(errno));
194 return STATUS_UNSUCCESSFUL;
195 }
196
197 return STATUS_SUCCESS;
198 } /* WriteSerial */
199
200
201 /*****************************************************************************
202 *
203 * ReadSerial: Receive bytes from the card reader
204 *
205 *****************************************************************************/
206 status_t ReadSerial(unsigned int reader_index,
207 /*@unused@*/ unsigned int *length, unsigned char *buffer)
208 {
209 unsigned char c;
210 int rv;
211 int echo;
212 int to_read;
213 int i;
214
215 /* we get the echo first */
216 echo = TRUE;
217
218 start:
219 DEBUG_COMM("start");
220 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
221 return rv;
222
223 if (c == RDR_to_PC_NotifySlotChange)
224 goto slot_change;
225
226 if (c == SYNC)
227 goto sync;
228
229 if (c >= 0x80)
230 {
231 DEBUG_COMM2("time request: 0x%02X", c);
232 goto start;
233 }
234
235 DEBUG_CRITICAL2("Got 0x%02X", c);
236 return STATUS_COMM_ERROR;
237
238 slot_change:
239 DEBUG_COMM("slot change");
240 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
241 return rv;
242
243 if (c == CARD_ABSENT)
244 {
245 DEBUG_COMM("Card removed");
246 }
247 else
248 if (c == CARD_PRESENT)
249 {
250 DEBUG_COMM("Card inserted");
251 }
252 else
253 {
254 DEBUG_COMM2("Unknown card movement: %d", c);
255 }
256 goto start;
257
258 sync:
259 DEBUG_COMM("sync");
260 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
261 return rv;
262
263 if (c == CTRL_ACK)
264 goto ack;
265
266 if (c == CTRL_NAK)
267 goto nak;
268
269 DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
270 return STATUS_COMM_ERROR;
271
272 nak:
273 DEBUG_COMM("nak");
274 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
275 return rv;
276
277 if (c != (SYNC ^ CTRL_NAK))
278 {
279 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
280 return STATUS_COMM_ERROR;
281 }
282 else
283 goto start;
284
285 ack:
286 DEBUG_COMM("ack");
287 /* normal CCID frame */
288 if ((rv = get_bytes(reader_index, buffer, 5)) != STATUS_SUCCESS)
289 return rv;
290
291 /* total frame size */
292 to_read = 10+dw2i(buffer, 1);
293
294 DEBUG_COMM2("frame size: %d", to_read);
295 if ((rv = get_bytes(reader_index, buffer+5, to_read-5)) != STATUS_SUCCESS)
296 return rv;
297
298 #ifdef DEBUG_LEVEL_COMM
299 DEBUG_XXD("frame: ", buffer, to_read);
300 #endif
301
302 /* lrc */
303 DEBUG_COMM("lrc");
304 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
305 return rv;
306
307 DEBUG_COMM2("lrc: 0x%02X", c);
308 for (i=0; i<to_read; i++)
309 c ^= buffer[i];
310
311 if (c != (SYNC ^ CTRL_ACK))
312 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
313
314 if (echo)
315 {
316 echo = FALSE;
317 goto start;
318 }
319
320 return STATUS_SUCCESS;
321 } /* ReadSerial */
322
323
324 /*****************************************************************************
325 *
326 * get_bytes: get n bytes
327 *
328 *****************************************************************************/
329 int get_bytes(unsigned int reader_index, unsigned char *buffer, int length)
330 {
331 int offset = serialDevice[reader_index].buffer_offset;
332 int offset_last = serialDevice[reader_index].buffer_offset_last;
333
334 DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
335 length);
336 /* enough data are available */
337 if (offset + length <= offset_last)
338 {
339 DEBUG_COMM("data available");
340 memcpy(buffer, serialDevice[reader_index].buffer + offset, length);
341 serialDevice[reader_index].buffer_offset += length;
342 }
343 else
344 {
345 int present, rv;
346
347 /* copy available data */
348 present = offset_last - offset;
349
350 if (present > 0)
351 {
352 DEBUG_COMM2("some data available: %d", present);
353 memcpy(buffer, serialDevice[reader_index].buffer + offset,
354 present);
355 }
356
357 /* get fresh data */
358 DEBUG_COMM2("get more data: %d", length - present);
359 rv = ReadChunk(reader_index, serialDevice[reader_index].buffer,
360 sizeof(serialDevice[reader_index].buffer), length - present);
361 if (rv < 0)
362 return STATUS_COMM_ERROR;
363
364 /* fill the buffer */
365 memcpy(buffer + present, serialDevice[reader_index].buffer,
366 length - present);
367 serialDevice[reader_index].buffer_offset = length - present;
368 serialDevice[reader_index].buffer_offset_last = rv;
369 DEBUG_COMM3("offset: %d, last_offset: %d",
370 serialDevice[reader_index].buffer_offset,
371 serialDevice[reader_index].buffer_offset_last);
372 }
373
374 return STATUS_SUCCESS;
375 } /* get_bytes */
376
377
378 /*****************************************************************************
379 *
380 * ReadChunk: read a minimum number of bytes
381 *
382 *****************************************************************************/
383 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
384 int buffer_length, int min_length)
385 {
386 int fd = serialDevice[reader_index].fd;
387 # ifndef S_SPLINT_S
388 fd_set fdset;
389 # endif
390 struct timeval t;
391 int i, rv = 0;
392 int already_read;
393 #ifdef DEBUG_LEVEL_COMM
394 char debug_header[] = "<- 123456 ";
395
396 sprintf(debug_header, "<- %06X ", reader_index);
397 #endif
398
399 already_read = 0;
400 while (already_read < min_length)
401 {
402 /* use select() to, eventually, timeout */
403 FD_ZERO(&fdset);
404 FD_SET(fd, &fdset);
405 t.tv_sec = SERIAL_TIMEOUT;
406 t.tv_usec = 0;
407
408 i = select(fd+1, &fdset, NULL, NULL, &t);
409 if (i == -1)
410 {
411 DEBUG_CRITICAL2("select: %s", strerror(errno));
412 return -1;
413 }
414 else
415 if (i == 0)
416 {
417 DEBUG_COMM2("Timeout! (%d sec)", SERIAL_TIMEOUT);
418 return -1;
419 }
420
421 rv = read(fd, buffer + already_read, buffer_length - already_read);
422 if (rv < 0)
423 {
424 DEBUG_COMM2("read error: %s", strerror(errno));
425 return -1;
426 }
427
428 #ifdef DEBUG_LEVEL_COMM
429 DEBUG_XXD(debug_header, buffer + already_read, rv);
430 #endif
431
432 already_read += rv;
433 DEBUG_COMM3("read: %d, to read: %d", already_read,
434 min_length);
435 }
436
437 return already_read;
438 } /* ReadChunk */
439
440
441 /*****************************************************************************
442 *
443 * OpenSerial: open the port
444 *
445 *****************************************************************************/
446 status_t OpenSerial(unsigned int reader_index, int channel)
447 {
448 char dev_name[FILENAME_MAX];
449
450 DEBUG_COMM3("Reader index: %X, Channel: %d", reader_index, channel);
451
452 /*
453 * Conversion of old-style ifd-hanler 1.0 CHANNELID
454 */
455 if (channel == 0x0103F8)
456 channel = 1;
457 else
458 if (channel == 0x0102F8)
459 channel = 2;
460 else
461 if (channel == 0x0103E8)
462 channel = 3;
463 else
464 if (channel == 0x0102E8)
465 channel = 4;
466
467 if (channel < 0)
468 {
469 DEBUG_CRITICAL2("wrong port number: %d", (int) channel);
470 return STATUS_UNSUCCESSFUL;
471 }
472
473 sprintf(dev_name, "/dev/pcsc/%d", (int) channel);
474
475 return OpenSerialByName(reader_index, dev_name);
476 } /* OpenSerial */
477
478 /*****************************************************************************
479 *
480 * OpenSerialByName: open the port
481 *
482 *****************************************************************************/
483 status_t OpenSerialByName(unsigned int reader_index, char *dev_name)
484 {
485 struct termios current_termios;
486 int i;
487 unsigned int reader = reader_index;
488
489 DEBUG_COMM3("Reader index: %X, Device: %d", reader_index, dev_name);
490
491 /* check if the same channel is not already used */
492 for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
493 {
494 if (serialDevice[i].device &&
495 strcmp(serialDevice[i].device, dev_name) == 0)
496 {
497 DEBUG_CRITICAL2("Device %s already in use", dev_name);
498 return STATUS_UNSUCCESSFUL;
499 }
500 }
501
502 serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
503
504 if (-1 == serialDevice[reader].fd)
505 {
506 DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
507 return STATUS_UNSUCCESSFUL;
508 }
509
510 /* set channel used */
511 serialDevice[reader].device = strdup(dev_name);
512
513 /* empty in and out serial buffers */
514 if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
515 DEBUG_INFO2("tcflush() function error: %s", strerror(errno));
516
517 /* get config attributes */
518 if (tcgetattr(serialDevice[reader].fd, &current_termios) == -1)
519 {
520 DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
521 close(serialDevice[reader].fd);
522 serialDevice[reader].fd = -1;
523
524 return STATUS_UNSUCCESSFUL;
525 }
526
527 /* IGNBRK: ignore BREAK condition on input
528 * IGNPAR: ignore framing errors and parity errors. */
529 current_termios.c_iflag = IGNBRK | IGNPAR;
530 current_termios.c_oflag = 0; /* Raw output modes */
531 /* CS8: 8-bits character size
532 * CSTOPB: set two stop bits
533 * CREAD: enable receiver
534 * CLOCAL: ignore modem control lines */
535 current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;
536
537 /* Do not echo characters because if you connect to a host it or your modem
538 * will echo characters for you. Don't generate signals. */
539 current_termios.c_lflag = 0;
540
541 /* set serial port speed to 115200 bauds */
542 cfsetspeed(&current_termios, B115200);
543
544 DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration");
545 if (tcsetattr(serialDevice[reader].fd, TCSANOW, &current_termios) == -1)
546 {
547 close(serialDevice[reader].fd);
548 serialDevice[reader].fd = -1;
549 DEBUG_INFO2("tcsetattr error: %s", strerror(errno));
550
551 return STATUS_UNSUCCESSFUL;
552 }
553
554 serialDevice[reader].ccid.bSeq = 0;
555 serialDevice[reader].ccid.readerID = GEMPCTWIN;
556 serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;
557 serialDevice[reader].ccid.dwMaxIFSD = 254;
558 serialDevice[reader].ccid.dwFeatures = 0x00010230;
559 serialDevice[reader].ccid.bPINSupport = 0x0;
560 serialDevice[reader].ccid.dwDefaultClock = 4000;
561 serialDevice[reader].ccid.dwMaxDataRate = 344086;
562 serialDevice[reader].ccid.bMaxSlotIndex = 0;
563 serialDevice[reader].ccid.bCurrentSlotIndex = 0;
564 serialDevice[reader].ccid.defaultFeatures = serialDevice[reader].ccid.dwFeatures;
565
566 serialDevice[reader].buffer_offset = 0;
567 serialDevice[reader].buffer_offset_last = 0;
568
569 /* perform a command to be sure a GemPC Twin reader is connected
570 * get the reader firmware */
571 {
572 unsigned char tx_buffer[] = "\x02";
573 unsigned char rx_buffer[50];
574 unsigned int rx_length = sizeof(rx_buffer);
575
576 if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
577 rx_buffer, &rx_length))
578 {
579 DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not co,,ected");
580 return STATUS_UNSUCCESSFUL;
581 }
582
583 rx_buffer[rx_length] = '\0';
584 DEBUG_INFO2("Firmware: %s", rx_buffer);
585 }
586
587 return STATUS_SUCCESS;
588 } /* OpenSerialByName */
589
590
591 /*****************************************************************************
592 *
593 * CloseSerial: close the port
594 *
595 *****************************************************************************/
596 status_t CloseSerial(unsigned int reader_index)
597 {
598 unsigned int reader = reader_index;
599
600 close(serialDevice[reader].fd);
601 serialDevice[reader].fd = -1;
602
603 free(serialDevice[reader].device);
604 serialDevice[reader].device = NULL;
605
606 return STATUS_SUCCESS;
607 } /* CloseSerial */
608
609
610 /*****************************************************************************
611 *
612 * get_ccid_descriptor
613 *
614 ****************************************************************************/
615 _ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
616 {
617 return &serialDevice[reader_index].ccid;
618 } /* get_ccid_descriptor */
619
620

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5