/[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 1047 - (hide annotations) (download)
Fri Jul 9 08:22:24 2004 UTC (8 years, 11 months ago) by rousseau
File MIME type: text/plain
File size: 14654 byte(s)
replace "121234" by "123456" to make it more clear it is a memory reservation
for 6 characters
1 rousseau 414 /*
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 rousseau 1022 #include <PCSC/ifdhandler.h>
36 rousseau 414
37 rousseau 877 #include "defs.h"
38     #include "ccid_ifdhandler.h"
39 rousseau 414 #include "config.h"
40     #include "debug.h"
41     #include "ccid.h"
42     #include "utils.h"
43 rousseau 1022 #include "commands.h"
44 rousseau 414
45     /* communication timeout in seconds */
46 rousseau 453 #define SERIAL_TIMEOUT 2
47 rousseau 414
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 rousseau 453 /*
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 rousseau 414 typedef struct
101     {
102     /*
103     * File handle on the serial port
104     */
105     int fd;
106    
107     /*
108 rousseau 649 * device used ("/dev/ttyS?" under Linux)
109 rousseau 414 */
110 rousseau 649 char *device;
111 rousseau 414
112     /*
113 rousseau 453 * 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 rousseau 414 * 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 rousseau 892 /* no need to initialize to 0 since it is static */
138     static _serialDevice serialDevice[PCSCLITE_MAX_READERS];
139 rousseau 414
140     /*****************************************************************************
141     *
142     * WriteSerial: Send bytes to the card reader
143     *
144     *****************************************************************************/
145 rousseau 1043 status_t WriteSerial(unsigned int lun, unsigned int length, unsigned char *buffer)
146 rousseau 414 {
147     int i;
148     unsigned char lrc;
149     unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
150    
151     #ifdef DEBUG_LEVEL_COMM
152 rousseau 1047 char debug_header[] = "-> 123456 ";
153 rousseau 414
154 rousseau 1043 sprintf(debug_header, "-> %06X ", lun);
155 rousseau 414 #endif
156    
157     if (length > GEMPCTWIN_MAXBUF-3)
158     {
159 rousseau 608 DEBUG_CRITICAL3("command too long: %d for max %d",
160 rousseau 414 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 rousseau 453 if (write(serialDevice[LunToReaderIndex(lun)].fd, low_level_buffer,
182     length+3) != length+3)
183 rousseau 414 {
184 rousseau 608 DEBUG_CRITICAL2("write error: %s", strerror(errno));
185 rousseau 414 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 rousseau 1043 status_t ReadSerial(unsigned int lun, unsigned int *length, unsigned char *buffer)
198 rousseau 414 {
199 rousseau 453 unsigned char c;
200     int rv;
201     int echo;
202     int to_read;
203     int i;
204 rousseau 414
205 rousseau 453 /* we get the echo first */
206     echo = TRUE;
207 rousseau 414
208 rousseau 453 start:
209 rousseau 462 DEBUG_COMM("start");
210 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
211     return rv;
212 rousseau 414
213 rousseau 453 if (c == RDR_to_PC_NotifySlotChange)
214     goto slot_change;
215 rousseau 414
216 rousseau 453 if (c == SYNC)
217     goto sync;
218 rousseau 414
219 rousseau 453 if (c >= 0x80)
220 rousseau 462 {
221     DEBUG_COMM2("time request: 0x%02X", c);
222 rousseau 453 goto start;
223 rousseau 462 }
224 rousseau 414
225 rousseau 453 DEBUG_CRITICAL2("Got 0x%02X", c);
226     return STATUS_COMM_ERROR;
227 rousseau 414
228 rousseau 453 slot_change:
229 rousseau 462 DEBUG_COMM("slot change");
230 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
231     return rv;
232 rousseau 414
233 rousseau 453 if (c == CARD_ABSENT)
234 rousseau 774 {
235 rousseau 453 DEBUG_COMM("Card removed");
236 rousseau 774 }
237 rousseau 453 else
238     if (c == CARD_PRESENT)
239 rousseau 774 {
240 rousseau 453 DEBUG_COMM("Card inserted");
241 rousseau 774 }
242 rousseau 453 else
243 rousseau 774 {
244 rousseau 1044 DEBUG_COMM2("Unknown card movement: %d", c);
245 rousseau 774 }
246 rousseau 453 goto start;
247 rousseau 414
248 rousseau 453 sync:
249 rousseau 462 DEBUG_COMM("sync");
250 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
251     return rv;
252 rousseau 414
253 rousseau 453 if (c == CTRL_ACK)
254     goto ack;
255 rousseau 414
256 rousseau 453 if (c == CTRL_NAK)
257     goto nak;
258 rousseau 414
259 rousseau 453 DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
260     return STATUS_COMM_ERROR;
261 rousseau 414
262 rousseau 453 nak:
263 rousseau 462 DEBUG_COMM("nak");
264 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
265     return rv;
266 rousseau 414
267 rousseau 453 if (c != (SYNC ^ CTRL_NAK))
268 rousseau 414 {
269 rousseau 453 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
270     return STATUS_COMM_ERROR;
271 rousseau 414 }
272 rousseau 453 else
273     goto start;
274 rousseau 414
275 rousseau 453 ack:
276 rousseau 462 DEBUG_COMM("ack");
277 rousseau 453 /* normal CCID frame */
278     if ((rv = get_bytes(lun, buffer, 5)) != STATUS_SUCCESS)
279     return rv;
280 rousseau 414
281 rousseau 453 /* total frame size */
282     to_read = 10+dw2i(buffer, 1);
283 rousseau 414
284 rousseau 462 DEBUG_COMM2("frame size: %d", to_read);
285 rousseau 453 if ((rv = get_bytes(lun, buffer+5, to_read-5)) != STATUS_SUCCESS)
286     return rv;
287 rousseau 414
288 rousseau 462 #ifdef DEBUG_LEVEL_COMM
289     DEBUG_XXD("frame: ", buffer, to_read);
290     #endif
291    
292 rousseau 453 /* lrc */
293 rousseau 462 DEBUG_COMM("lrc");
294 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
295     return rv;
296    
297 rousseau 462 DEBUG_COMM2("lrc: 0x%02X", c);
298 rousseau 414 for (i=0; i<to_read; i++)
299 rousseau 453 c ^= buffer[i];
300 rousseau 414
301 rousseau 453 if (c != (SYNC ^ CTRL_ACK))
302     DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
303 rousseau 414
304 rousseau 453 if (echo)
305     {
306     echo = FALSE;
307     goto start;
308     }
309 rousseau 414
310     return STATUS_SUCCESS;
311     } /* ReadSerial */
312    
313    
314     /*****************************************************************************
315     *
316 rousseau 453 * get_bytes: get n bytes
317 rousseau 414 *
318     *****************************************************************************/
319 rousseau 1043 int get_bytes(unsigned int lun, unsigned char *buffer, int length)
320 rousseau 414 {
321 rousseau 453 int offset = serialDevice[LunToReaderIndex(lun)].buffer_offset;
322     int offset_last = serialDevice[LunToReaderIndex(lun)].buffer_offset_last;
323 rousseau 414
324 rousseau 608 DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
325 rousseau 462 length);
326 rousseau 453 /* enough data are available */
327     if (offset + length <= offset_last)
328 rousseau 414 {
329 rousseau 608 DEBUG_COMM("data available");
330 rousseau 453 memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset, length);
331     serialDevice[LunToReaderIndex(lun)].buffer_offset += length;
332 rousseau 414 }
333 rousseau 453 else
334 rousseau 414 {
335 rousseau 453 int present, rv;
336 rousseau 414
337 rousseau 453 /* copy available data */
338     present = offset_last - offset;
339 rousseau 414
340 rousseau 453 if (present > 0)
341 rousseau 462 {
342 rousseau 608 DEBUG_COMM2("some data available: %d", present);
343 rousseau 462 memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset,
344     present);
345     }
346 rousseau 414
347 rousseau 453 /* get fresh data */
348 rousseau 608 DEBUG_COMM2("get more data: %d", length - present);
349 rousseau 453 rv = ReadChunk(lun, serialDevice[LunToReaderIndex(lun)].buffer, sizeof(serialDevice[LunToReaderIndex(lun)].buffer), length - present);
350     if (rv < 0)
351     return STATUS_COMM_ERROR;
352 rousseau 414
353 rousseau 453 /* 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 rousseau 608 DEBUG_COMM3("offset: %d, last_offset: %d",
359 rousseau 462 serialDevice[LunToReaderIndex(lun)].buffer_offset,
360     serialDevice[LunToReaderIndex(lun)].buffer_offset_last);
361 rousseau 414 }
362    
363 rousseau 453 return STATUS_SUCCESS;
364     } /* get_bytes */
365 rousseau 414
366 rousseau 453
367 rousseau 414 /*****************************************************************************
368     *
369     * ReadChunk: read a minimum number of bytes
370     *
371     *****************************************************************************/
372 rousseau 1043 int ReadChunk(unsigned int lun, unsigned char *buffer, int buffer_length, int min_length)
373 rousseau 414 {
374 rousseau 453 int fd = serialDevice[LunToReaderIndex(lun)].fd;
375 rousseau 1045 # ifndef S_SPLINT_S
376 rousseau 414 fd_set fdset;
377 rousseau 1045 # endif
378 rousseau 414 struct timeval t;
379 rousseau 462 int i, rv = 0;
380     int already_read;
381 rousseau 414 #ifdef DEBUG_LEVEL_COMM
382 rousseau 1047 char debug_header[] = "<- 123456 ";
383 rousseau 414
384 rousseau 1046 sprintf(debug_header, "<- %06X ", lun);
385 rousseau 414 #endif
386    
387 rousseau 462 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 rousseau 414
396 rousseau 462 i = select(fd+1, &fdset, NULL, NULL, &t);
397     if (i == -1)
398 rousseau 414 {
399 rousseau 462 DEBUG_CRITICAL2("select: %s", strerror(errno));
400 rousseau 414 return -1;
401     }
402 rousseau 462 else
403     if (i == 0)
404     {
405     DEBUG_COMM2("Timeout! (%d sec)", SERIAL_TIMEOUT);
406     return -1;
407     }
408 rousseau 414
409 rousseau 462 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 rousseau 414
416 rousseau 453 #ifdef DEBUG_LEVEL_COMM
417 rousseau 462 DEBUG_XXD(debug_header, buffer + already_read, rv);
418 rousseau 453 #endif
419 rousseau 414
420 rousseau 462 already_read += rv;
421 rousseau 608 DEBUG_COMM3("read: %d, to read: %d", already_read,
422 rousseau 414 min_length);
423     }
424    
425 rousseau 462 return already_read;
426 rousseau 414 } /* ReadChunk */
427    
428    
429     /*****************************************************************************
430     *
431     * OpenSerial: open the port
432     *
433     *****************************************************************************/
434 rousseau 1043 status_t OpenSerial(unsigned int lun, int channel)
435 rousseau 414 {
436     char dev_name[FILENAME_MAX];
437    
438 rousseau 608 DEBUG_COMM3("Lun: %X, Channel: %d", lun, channel);
439 rousseau 414
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 rousseau 649 return OpenSerialByName(lun, dev_name);
464     } /* OpenSerial */
465    
466     /*****************************************************************************
467     *
468     * OpenSerialByName: open the port
469     *
470     *****************************************************************************/
471 rousseau 1043 status_t OpenSerialByName(unsigned int lun, char *dev_name)
472 rousseau 649 {
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 rousseau 414 /* check if the same channel is not already used */
480     for (i=0; i<PCSCLITE_MAX_READERS; i++)
481     {
482 rousseau 649 if (serialDevice[i].device &&
483     strcmp(serialDevice[i].device, dev_name) == 0)
484 rousseau 414 {
485 rousseau 649 DEBUG_CRITICAL2("Device %s already in use", dev_name);
486 rousseau 414 return STATUS_UNSUCCESSFUL;
487     }
488     }
489    
490     serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
491    
492 rousseau 892 if (-1 == serialDevice[reader].fd)
493 rousseau 414 {
494     DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
495     return STATUS_UNSUCCESSFUL;
496     }
497    
498     /* set channel used */
499 rousseau 649 serialDevice[reader].device = strdup(dev_name);
500 rousseau 414
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 rousseau 672 serialDevice[reader].ccid.dwMaxIFSD = 254;
546 rousseau 414 serialDevice[reader].ccid.dwFeatures = 0x00010230;
547 rousseau 900 serialDevice[reader].ccid.bPINSupport = 0x0;
548 rousseau 694 serialDevice[reader].ccid.dwDefaultClock = 4000;
549     serialDevice[reader].ccid.dwMaxDataRate = 344086;
550 rousseau 414
551 rousseau 453 serialDevice[reader].buffer_offset = 0;
552     serialDevice[reader].buffer_offset_last = 0;
553    
554 rousseau 1022 /* perform a command to be sure a GemPC Twin reader is connected
555     * get the reader firmware */
556     {
557     char tx_buffer[] = "\x02";
558     char rx_buffer[50];
559     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 rousseau 414 return STATUS_SUCCESS;
573 rousseau 649 } /* OpenSerialByName */
574 rousseau 414
575    
576     /*****************************************************************************
577     *
578     * CloseSerial: close the port
579     *
580     *****************************************************************************/
581 rousseau 1043 status_t CloseSerial(unsigned int lun)
582 rousseau 414 {
583     int reader = LunToReaderIndex(lun);
584    
585     close(serialDevice[reader].fd);
586     serialDevice[reader].fd = -1;
587    
588 rousseau 649 free(serialDevice[reader].device);
589     serialDevice[reader].device = NULL;
590    
591 rousseau 414 return STATUS_SUCCESS;
592     } /* CloseSerial */
593    
594    
595     /*****************************************************************************
596     *
597     * get_ccid_descriptor
598     *
599     ****************************************************************************/
600 rousseau 1043 _ccid_descriptor *get_ccid_descriptor(unsigned int lun)
601 rousseau 414 {
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