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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5