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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5