/[pcsclite]/trunk/Drivers/ccid/src/ccid_serial.c
ViewVC logotype

Diff of /trunk/Drivers/ccid/src/ccid_serial.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 452 by rousseau, Wed Sep 10 09:17:43 2003 UTC revision 453 by rousseau, Fri Sep 19 12:08:09 2003 UTC
# Line 40  Line 40 
40  #include "utils.h"  #include "utils.h"
41    
42  /* communication timeout in seconds */  /* communication timeout in seconds */
43  #define SERIAL_TIMEOUT 10  #define SERIAL_TIMEOUT 2
44    
45  #define SYNC 0x03  #define SYNC 0x03
46  #define CTRL_ACK 0x06  #define CTRL_ACK 0x06
# Line 67  Line 67 
67   * 1 : LRC (0x16)   * 1 : LRC (0x16)
68   *   *
69   * Card insertion/withdrawal   * Card insertion/withdrawal
  * 1 : SYNC  
  * 1 : CTRL  
70   * 1 : RDR_to_PC_NotifySlotChange (0x50)   * 1 : RDR_to_PC_NotifySlotChange (0x50)
71   * 1 : bmSlotIccState   * 1 : bmSlotIccState
72   *     0x02 if card absent   *     0x02 if card absent
73   *     0x03 is card present   *     0x03 is card present
  * 1 : LRC  
74   *   *
75   * Time request   * Time request
76   * T=1 : normal CCID command   * T=1 : normal CCID command
# Line 81  Line 78 
78   *   *
79   */   */
80    
81    /*
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  typedef struct  typedef struct
98  {  {
99          /*          /*
# Line 94  typedef struct Line 107  typedef struct
107          int channel;          int channel;
108    
109          /*          /*
110             * 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           * CCID infos common to USB and serial           * CCID infos common to USB and serial
126           */           */
127          _ccid_descriptor ccid;          _ccid_descriptor ccid;
# Line 107  static _serialDevice serialDevice[PCSCLI Line 135  static _serialDevice serialDevice[PCSCLI
135          [ 0 ... (PCSCLITE_MAX_READERS-1) ] = { -1, -1 }          [ 0 ... (PCSCLITE_MAX_READERS-1) ] = { -1, -1 }
136  };  };
137    
 /* 271 = max size for short APDU  
  * 2 bytes for header  
  * 1 byte checksum  
  * doubled for echo */  
 #define GEMPCTWIN_MAXBUF (271 +2 +1) *2  
   
138  /*****************************************************************************  /*****************************************************************************
139   *   *
140   *                              WriteSerial: Send bytes to the card reader   *                              WriteSerial: Send bytes to the card reader
# Line 121  static _serialDevice serialDevice[PCSCLI Line 143  static _serialDevice serialDevice[PCSCLI
143  status_t WriteSerial(int lun, int length, unsigned char *buffer)  status_t WriteSerial(int lun, int length, unsigned char *buffer)
144  {  {
145          int i;          int i;
         int reader = LunToReaderIndex(lun);  
146          unsigned char lrc;          unsigned char lrc;
147          unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];          unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
148    
# Line 155  status_t WriteSerial(int lun, int length Line 176  status_t WriteSerial(int lun, int length
176          DEBUG_XXD(debug_header, low_level_buffer, length+3);          DEBUG_XXD(debug_header, low_level_buffer, length+3);
177  #endif  #endif
178    
179          if (write(serialDevice[reader].fd, low_level_buffer, length+3) != length+3)          if (write(serialDevice[LunToReaderIndex(lun)].fd, low_level_buffer,
180                    length+3) != length+3)
181          {          {
182                  DEBUG_CRITICAL2("WriteSerial: write error: %s", strerror(errno));                  DEBUG_CRITICAL2("WriteSerial: write error: %s", strerror(errno));
183                  return STATUS_UNSUCCESSFUL;                  return STATUS_UNSUCCESSFUL;
# Line 172  status_t WriteSerial(int lun, int length Line 194  status_t WriteSerial(int lun, int length
194   *****************************************************************************/   *****************************************************************************/
195  status_t ReadSerial(int lun, int *length, unsigned char *buffer)  status_t ReadSerial(int lun, int *length, unsigned char *buffer)
196  {  {
197          int fd = serialDevice[LunToReaderIndex(lun)].fd;          unsigned char c;
198          static unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];          int rv;
199          int buffer_size, len, rv, already_read, to_read;          int echo;
200          unsigned char *reader_to_pc;          int to_read;
201          unsigned char lrc;          int i;
         int skipped, i;  
 #ifdef DEBUG_LEVEL_COMM  
         char debug_header[] = "<- 121234 ";  
202    
203          sprintf(debug_header, "<- %06X ", (int)lun);          /* we get the echo first */
204  #endif          echo = TRUE;
205    
206          buffer_size = *length;  start:
207            if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
208                    return rv;
209    
210          /* error by default (zero length) */          if (c == RDR_to_PC_NotifySlotChange)
211          *length = 0;                  goto slot_change;
212    
213          rv = ReadChunk(fd, low_level_buffer, sizeof(low_level_buffer), 3, lun);          if (c == SYNC)
214          if (rv < 0)                  goto sync;
                 return STATUS_UNSUCCESSFUL;  
215    
216          /* Nb of bytes already read */          if (c >= 0x80)
217          already_read = rv;                  goto start;
218    
219  #ifdef DEBUG_LEVEL_COMM          DEBUG_CRITICAL2("Got 0x%02X", c);
220          DEBUG_XXD(debug_header, low_level_buffer, rv);          return STATUS_COMM_ERROR;
 #endif  
221    
222          /* skip the echo of the previous command */  slot_change:
223          skipped = skip_echo(low_level_buffer, sizeof(low_level_buffer));          if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
224          if (skipped == 0)                  return rv;
                 return STATUS_UNSUCCESSFUL;  
225    
226          /* Nb of bytes until the end of the buffer */          if (c == CARD_ABSENT)
227          len = sizeof(low_level_buffer) - skipped;                  DEBUG_COMM("Card removed");
228          already_read -= skipped;          else
229          reader_to_pc = low_level_buffer + skipped;                  if (c == CARD_PRESENT)
230                            DEBUG_COMM("Card inserted");
231                    else
232                            DEBUG_COMM2("Unknown card movement: %d", buffer[3]);
233            goto start;
234    
235          to_read = 2 +1; /* minimal frame size */  sync:
236            if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
237                    return rv;
238    
239          while (already_read < to_read)          if (c == CTRL_ACK)
240          {                  goto ack;
                 rv = ReadChunk(fd, reader_to_pc + already_read, len, 1, lun);  
                 if (rv < 0)  
                         return STATUS_UNSUCCESSFUL;  
241    
242                  already_read += rv;          if (c == CTRL_NAK)
243                  len -= rv;                  goto nak;
         }  
244    
245          if (reader_to_pc[0] != SYNC)          DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
246          {          return STATUS_COMM_ERROR;
                 DEBUG_CRITICAL2("No SYNC byte found: 0x%02X", buffer[0]);  
                 return STATUS_UNSUCCESSFUL;  
         }  
247    
248          if (reader_to_pc[1] != CTRL_ACK)  nak:
249          {          if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
250                  DEBUG_CRITICAL2("No ACK byte found: 0x%02X", buffer[0]);                  return rv;
                 return 0;  
         }  
251    
252          /* read up to CCID frame length */          if (c != (SYNC ^ CTRL_NAK))
         to_read = 5; /* bMessageType + dwLength */  
         while (already_read < to_read)  
253          {          {
254                  rv = ReadChunk(fd, reader_to_pc + already_read, len, 1, lun);                  DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
255                  if (rv < 0)                  return STATUS_COMM_ERROR;
                         return STATUS_UNSUCCESSFUL;  
   
                 already_read += rv;  
                 len -= rv;  
256          }          }
257            else
258                    goto start;
259    
260          /* normal CCID command */  ack:
261          to_read = 10+3+dw2i(reader_to_pc, 3);          /* normal CCID frame */
262            if ((rv = get_bytes(lun, buffer, 5)) != STATUS_SUCCESS)
263          while (already_read < to_read)                  return rv;
264          {  
265                  rv = ReadChunk(fd, reader_to_pc + already_read, len, 1, lun);          /* total frame size */
266                  if (rv < 0)          to_read = 10+dw2i(buffer, 1);
267                          return STATUS_UNSUCCESSFUL;  
268            if ((rv = get_bytes(lun, buffer+5, to_read-5)) != STATUS_SUCCESS)
269                  already_read += rv;                  return rv;
270                  len -= rv;  
271          }          /* lrc */
272            if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
273                    return rv;
274    
         lrc = 0;  
275          for (i=0; i<to_read; i++)          for (i=0; i<to_read; i++)
276                  lrc ^= reader_to_pc[i];                  c ^= buffer[i];
   
         if (lrc != 0)  
                 DEBUG_CRITICAL2("Wrong lrc: 0x%02X", lrc);  
277    
278  #ifdef DEBUG_LEVEL_COMM          if (c != (SYNC ^ CTRL_ACK))
279          DEBUG_XXD(debug_header, reader_to_pc, to_read);          {
280  #endif                  DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
281                    //return STATUS_COMM_ERROR;
282          /* copy up to buffer_size bytes */          }
         *length = to_read-3;  
283    
284          memcpy(buffer, reader_to_pc+2, *length);          if (echo)
285            {
286                    echo = FALSE;
287                    goto start;
288            }
289    
290          return STATUS_SUCCESS;          return STATUS_SUCCESS;
291  } /* ReadSerial */  } /* ReadSerial */
# Line 281  status_t ReadSerial(int lun, int *length Line 293  status_t ReadSerial(int lun, int *length
293    
294  /*****************************************************************************  /*****************************************************************************
295   *   *
296   *                              skip_echo: skip the echo of the previous command   *                              get_bytes: get n bytes
297   *   *
298   *****************************************************************************/   *****************************************************************************/
299  int skip_echo(unsigned char *buffer, int buffer_length)  int get_bytes(int lun, unsigned char *buffer, int length)
300  {  {
301          unsigned char lrc;          int offset = serialDevice[LunToReaderIndex(lun)].buffer_offset;
302          int i;          int offset_last = serialDevice[LunToReaderIndex(lun)].buffer_offset_last;
303    
304          if (buffer[0] != SYNC)          /* enough data are available */
305            if (offset + length <= offset_last)
306          {          {
307                  DEBUG_CRITICAL2("No SYNC byte found: 0x%02X", buffer[0]);                  memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset, length);
308                  return 0;                  serialDevice[LunToReaderIndex(lun)].buffer_offset += length;
309          }          }
310            else
         if (buffer[1] != CTRL_ACK)  
311          {          {
312                  DEBUG_CRITICAL2("No ACK byte found: 0x%02X", buffer[0]);                  int present, rv;
                 return 0;  
         }  
313    
314          if (buffer[2] == RDR_to_PC_NotifySlotChange)                  /* copy available data */
315          {                  present = offset_last - offset;
316                  switch (buffer[3])  
317                  {                  if (present > 0)
318                          case CARD_PRESENT:                          memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset, present);
                                 DEBUG_INFO("Card inserted");  
                                 break;  
   
                         case CARD_ABSENT:  
                                 DEBUG_INFO("Card removed");  
                                 break;  
   
                         default:  
                                 DEBUG_INFO2("Unknown card movement: %d", buffer[3]);  
                                 break;  
                 }  
   
                 lrc = 0;  
                 for (i=0; i<5; i++)  
                         lrc ^= buffer[i];  
319    
320                  if (lrc != 0)                  /* get fresh data */
321                          DEBUG_CRITICAL2("Wrong lrc: 0x%02", lrc);                  rv = ReadChunk(lun, serialDevice[LunToReaderIndex(lun)].buffer, sizeof(serialDevice[LunToReaderIndex(lun)].buffer), length - present);
322                    if (rv < 0)
323                            return STATUS_COMM_ERROR;
324    
325                  /* Card insertion/withdrawal */                  /* fill the buffer */
326                  return 5;                  memcpy(buffer + present, serialDevice[LunToReaderIndex(lun)].buffer,
327                            length - present);
328                    serialDevice[LunToReaderIndex(lun)].buffer_offset = length - present;
329                    serialDevice[LunToReaderIndex(lun)].buffer_offset_last = rv;
330          }          }
331    
332          /* normal CCID command, 2 for SYNC CTRL, 1 for length offset in CCID cmd */  DEBUG_XXD("pouet: ", buffer, length);
333          return 2 + 10 + dw2i(buffer, 2 +1) +1;  
334  } /* skip_echo */          return STATUS_SUCCESS;
335    } /* get_bytes */
336    
337    
338  /*****************************************************************************  /*****************************************************************************
# Line 339  int skip_echo(unsigned char *buffer, int Line 340  int skip_echo(unsigned char *buffer, int
340   *                              ReadChunk: read a minimum number of bytes   *                              ReadChunk: read a minimum number of bytes
341   *   *
342   *****************************************************************************/   *****************************************************************************/
343  int ReadChunk(int fd, unsigned char *buffer, int buffer_length, int min_length, int lun)  int ReadChunk(int lun, unsigned char *buffer, int buffer_length, int min_length)
344  {  {
345            int fd = serialDevice[LunToReaderIndex(lun)].fd;
346          fd_set fdset;          fd_set fdset;
347          struct timeval t;          struct timeval t;
348          int i, rv;          int i, rv;
# Line 350  int ReadChunk(int fd, unsigned char *buf Line 352  int ReadChunk(int fd, unsigned char *buf
352          sprintf(debug_header, "<- %06X ", (int)lun);          sprintf(debug_header, "<- %06X ", (int)lun);
353  #endif  #endif
354    
 time_request:  
355          /* use select() to, eventually, timeout */          /* use select() to, eventually, timeout */
356          FD_ZERO(&fdset);          FD_ZERO(&fdset);
357          FD_SET(fd, &fdset);          FD_SET(fd, &fdset);
# Line 377  time_request: Line 378  time_request:
378                  return -1;                  return -1;
379          }          }
380    
381          if ((rv == 1) && (buffer[0] >= 0x80))  #ifdef DEBUG_LEVEL_COMM
382          {          DEBUG_XXD(debug_header, buffer, rv);
383                  DEBUG_COMM2("Time request: 0x%02X", buffer[0]);  #endif
                 goto time_request;  
         }  
384    
385          /* too short */          /* too short */
386          if (rv < min_length)          if (rv < min_length)
387          {          {
 #ifdef DEBUG_LEVEL_COMM  
                 DEBUG_XXD(debug_header, buffer, rv);  
 #endif  
388                  DEBUG_COMM3("ReadSerial: only %d byte(s) read, needed %d", rv,                  DEBUG_COMM3("ReadSerial: only %d byte(s) read, needed %d", rv,
389                          min_length);                          min_length);
390    
# Line 503  status_t OpenSerial(int lun, int channel Line 499  status_t OpenSerial(int lun, int channel
499          serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;          serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;
500          serialDevice[reader].ccid.dwFeatures = 0x00010230;          serialDevice[reader].ccid.dwFeatures = 0x00010230;
501    
502            serialDevice[reader].buffer_offset = 0;
503            serialDevice[reader].buffer_offset_last = 0;
504    
505          ccid_open_hack(lun);          ccid_open_hack(lun);
506    
507          return STATUS_SUCCESS;          return STATUS_SUCCESS;

Legend:
Removed from v.452  
changed lines
  Added in v.453

  ViewVC Help
Powered by ViewVC 1.1.5