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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5