* configure.ac: Required newer versions of some libraries.
[gnupg.git] / scd / ccid-driver.c
1 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
2  *      Copyright (C) 2003 Free Software Foundation, Inc.
3  *      Written by Werner Koch.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  *
21  * ALTERNATIVELY, this file may be distributed under the terms of the
22  * following license, in which case the provisions of this license are
23  * required INSTEAD OF the GNU General Public License. If you wish to
24  * allow use of your version of this file only under the terms of the
25  * GNU General Public License, and not to allow others to use your
26  * version of this file under the terms of the following license,
27  * indicate your decision by deleting this paragraph and the license
28  * below.
29  *
30  * Redistribution and use in source and binary forms, with or without
31  * modification, are permitted provided that the following conditions
32  * are met:
33  * 1. Redistributions of source code must retain the above copyright
34  *    notice, and the entire permission notice in its entirety,
35  *    including the disclaimer of warranties.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. The name of the author may not be used to endorse or promote
40  *    products derived from this software without specific prior
41  *    written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
44  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
47  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
48  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
49  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
51  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
53  * OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55
56
57 /* CCID (ChipCardInterfaceDevices) is a specification for accessing
58    smartcard via a reader connected to the USB.  
59
60    This is a limited driver allowing to use some CCID drivers directly
61    without any other specila drivers. This is a fallback driver to be
62    used when nothing else works or the system should be kept minimal
63    for security reasons.  It makes use of the libusb library to gain
64    portable access to USB.
65
66    This driver has been tested with the SCM SCR335 smartcard reader
67    and requires that reader implements the TPDU level exchange and
68    does fully automatic initialization.
69 */
70
71 #ifdef HAVE_CONFIG_H
72 # include <config.h>
73 #endif
74
75 #if defined(HAVE_LIBUSB) || defined(TEST)
76
77 #include <errno.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include <assert.h>
82
83 #include <usb.h>
84
85 #include "ccid-driver.h"
86
87 #define DRVNAME "ccid-driver: "
88
89
90 #ifdef GNUPG_DEFAULT_SCDAEMON /* This source is used within the
91                                  gnupg>=1.9 source tree. */
92 # include "scdaemon.h"
93
94 # define DEBUGOUT(t)         do { if (DBG_CARD_IO) \
95                                   log_debug (DRVNAME t); } while (0)
96 # define DEBUGOUT_1(t,a)     do { if (DBG_CARD_IO) \
97                                   log_debug (DRVNAME t,(a)); } while (0)
98 # define DEBUGOUT_2(t,a,b)   do { if (DBG_CARD_IO) \
99                                   log_debug (DRVNAME t,(a),(b)); } while (0)
100 # define DEBUGOUT_3(t,a,b,c) do { if (DBG_CARD_IO) \
101                                   log_debug (DRVNAME t,(a),(b),(c));} while (0)
102 # define DEBUGOUT_CONT_1(t,a)  do { if (DBG_CARD_IO) \
103                                   log_printf (t,(a)); } while (0)
104 # define DEBUGOUT_CONT_3(t,a,b,c) do { if (DBG_CARD_IO) \
105                                   log_printf (t,(a),(b),(c)); } while (0)
106 # define DEBUGOUT_LF()       do { if (DBG_CARD_IO) \
107                                   log_printf ("\n"); } while (0)
108
109 #else /* Other usage of this source - don't use gnupg specifics. */
110
111 # define DEBUGOUT(t)          fprintf (stderr, DRVNAME t)
112 # define DEBUGOUT_1(t,a)      fprintf (stderr, DRVNAME t, (a))
113 # define DEBUGOUT_2(t,a,b)    fprintf (stderr, DRVNAME t, (a), (b))
114 # define DEBUGOUT_3(t,a,b,c)  fprintf (stderr, DRVNAME t, (a), (b), (c))
115 # define DEBUGOUT_CONT_1(t,a)      fprintf (stderr, t, (a))
116 # define DEBUGOUT_CONT_3(t,a,b,c)  fprintf (stderr, t, (a), (b), (c))
117 # define DEBUGOUT_LF()        putc ('\n', stderr)
118
119 #endif /* This source not used by scdaemon. */
120
121
122 enum {
123   RDR_to_PC_NotifySlotChange= 0x50,
124   RDR_to_PC_HardwareError   = 0x51,
125
126   PC_to_RDR_SetParameters   = 0x61,
127   PC_to_RDR_IccPowerOn      = 0x62,
128   PC_to_RDR_IccPowerOff     = 0x63,
129   PC_to_RDR_GetSlotStatus   = 0x65,
130   PC_to_RDR_Secure          = 0x69,
131   PC_to_RDR_T0APDU          = 0x6a,
132   PC_to_RDR_Escape          = 0x6b,
133   PC_to_RDR_GetParameters   = 0x6c,
134   PC_to_RDR_ResetParameters = 0x6d,
135   PC_to_RDR_IccClock        = 0x6e,
136   PC_to_RDR_XfrBlock        = 0x6f,
137   PC_to_RDR_Mechanical      = 0x71,
138   PC_to_RDR_Abort           = 0x72,
139   PC_to_RDR_SetDataRate     = 0x73,
140
141   RDR_to_PC_DataBlock       = 0x80,
142   RDR_to_PC_SlotStatus      = 0x81,
143   RDR_to_PC_Parameters      = 0x82,
144   RDR_to_PC_Escape          = 0x83,
145   RDR_to_PC_DataRate        = 0x84
146 };
147
148
149 /* Store information on the driver's state.  A pointer to such a
150    structure is used as handle for most functions. */
151 struct ccid_driver_s {
152   usb_dev_handle *idev;
153   int seqno;
154   unsigned char t1_ns;
155   unsigned char t1_nr;
156 };
157
158
159
160
161 /* Open the reader with the internal number READERNO and return a a
162    pointer to be used as handle in HANDLE.  Returns 0 on success. */
163 int 
164 ccid_open_reader (ccid_driver_t *handle, int readerno)
165 {
166   static int initialized;
167
168   int rc;
169   usb_match_handle *match = NULL;
170   struct usb_device *dev = NULL;
171   usb_dev_handle *idev = NULL;
172
173   *handle = NULL;
174   if (!initialized)
175     {
176       usb_init ();
177       initialized = 1;
178     }
179   
180   rc = usb_create_match (&match, -1, -1, 11, -1, -1);
181   if (rc)
182     {
183       DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
184       return -1;
185     }
186
187   while (usb_find_device(match, dev, &dev) >= 0) 
188     {
189       DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
190                   dev->descriptor->idVendor, dev->descriptor->idProduct);
191       if (!readerno)
192         {
193           rc = usb_open (dev, &idev);
194           if (rc)
195             {
196               DEBUGOUT_1 ("usb_open failed: %d\n", rc);
197               goto leave;
198             }
199
200           rc = usb_claim_interface (idev, 0);
201           if (rc)
202             {
203               DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
204               goto leave;
205             }
206
207           *handle = calloc (1, sizeof **handle);
208           if (!*handle)
209             {
210               DEBUGOUT ("out of memory\n");
211               rc = -1;
212               goto leave;
213             }
214           (*handle)->idev = idev;
215           idev = NULL;
216           break;
217         }
218       readerno--;
219     }
220
221
222  leave:
223   if (idev)
224     usb_close (idev);
225   /* fixme: Do we need to release dev or is it supposed to be a
226      shallow copy of the list created internally by usb_init ? */
227   usb_free_match (match);
228
229   return rc;
230 }
231
232
233 /* Return False if a card is present and powered. */
234 int
235 ccid_check_card_presence (ccid_driver_t handle)
236 {
237
238   return -1;
239 }
240
241
242 static void
243 set_msg_len (unsigned char *msg, unsigned int length)
244 {
245   msg[1] = length;
246   msg[2] = length >> 8;
247   msg[3] = length >> 16;
248   msg[4] = length >> 24;
249 }
250
251
252 /* Write a MSG of length MSGLEN to the designated bulk out endpoint.
253    Returns 0 on success. */
254 static int
255 bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
256 {
257   int rc;
258
259   rc = usb_bulk_write (handle->idev, 
260                        1, /*endpoint */
261                        msg, msglen,
262                        1000 /* ms timeout */);
263   if (rc == msglen)
264     return 0;
265
266   if (rc == -1)
267     DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
268   else
269     DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
270   return -1;
271 }
272
273
274 /* Read a maximum of LENGTH bytes from the bulk in endpoint into
275    BUFFER and return the actual read number if bytes in NREAD. SEQNO
276    is the sequence number used to send the request and EXPECTED_TYPE
277    the type of message we expect. Does checks on the ccid
278    header. Returns 0 on success. */
279 static int
280 bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
281          size_t *nread, int expected_type, int seqno)
282 {
283   int i, rc;
284   size_t msglen;
285
286   rc = usb_bulk_read (handle->idev, 
287                       0x82,
288                       buffer, length,
289                       10000 /* ms timeout */ );
290   /* Fixme: instead of using a 10 second timeout we should better
291      handle the timeout here and retry if appropriate.  */
292   if (rc < 0)
293     {
294       DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
295       return -1;
296     }
297
298   *nread = msglen = rc;
299
300   if (msglen < 10)
301     {
302       DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
303       return -1;
304     }
305   if (buffer[0] != expected_type)
306     {
307       DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
308       return -1;
309     }
310   if (buffer[5] != 0)    
311     {
312       DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
313       return -1;
314     }
315   if (buffer[6] != seqno)    
316     {
317       DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
318                   seqno, buffer[6]);
319       return -1;
320     }
321
322   DEBUGOUT_3 ("status: %02X  error: %02X clock-status: %02X\n"
323               "               data:",  buffer[7], buffer[8], buffer[9] );
324   for (i=10; i < msglen; i++)
325     DEBUGOUT_CONT_1 (" %02X", buffer[i]);
326   DEBUGOUT_LF ();
327
328   return 0;
329 }
330
331
332 /* experimental */
333 int
334 ccid_poll (ccid_driver_t handle)
335 {
336   int rc;
337   unsigned char msg[10];
338   size_t msglen;
339   int i, j;
340
341   rc = usb_bulk_read (handle->idev, 
342                       0x83,
343                       msg, sizeof msg,
344                       0 /* ms timeout */ );
345   if (rc < 0 && errno == ETIMEDOUT)
346     return 0;
347
348   if (rc < 0)
349     {
350       DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
351       return -1;
352     }
353
354   msglen = rc;
355   rc = 0;
356
357   if (msglen < 1)
358     {
359       DEBUGOUT ("intr-in msg too short\n");
360       return -1;
361     }
362
363   if (msg[0] == RDR_to_PC_NotifySlotChange)
364     {
365       DEBUGOUT ("notify slot change:");
366       for (i=1; i < msglen; i++)
367         for (j=0; j < 4; j++)
368           DEBUGOUT_CONT_3 (" %d:%c%c",
369                            (i-1)*4+j, 
370                            (msg[i] & (1<<(j*2)))? 'p':'-',
371                            (msg[i] & (2<<(j*2)))? '*':' ');
372       DEBUGOUT_LF ();
373     }
374   else if (msg[0] == RDR_to_PC_HardwareError)    
375     {
376       DEBUGOUT ("hardware error occured\n");
377     }
378   else
379     {
380       DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
381     }
382
383   return 0;
384 }
385
386
387
388 int 
389 ccid_slot_status (ccid_driver_t handle)
390 {
391   int rc;
392   unsigned char msg[100];
393   size_t msglen;
394   unsigned char seqno;
395
396   msg[0] = PC_to_RDR_GetSlotStatus;
397   msg[5] = 0; /* slot */
398   msg[6] = seqno = handle->seqno++;
399   msg[7] = 0; /* RFU */
400   msg[8] = 0; /* RFU */
401   msg[9] = 0; /* RFU */
402   set_msg_len (msg, 0);
403
404   rc = bulk_out (handle, msg, 10);
405   if (rc)
406     return rc;
407   rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
408   if (rc)
409     return rc;
410
411   return 0;
412 }
413
414
415 int 
416 ccid_get_atr (ccid_driver_t handle,
417               unsigned char *atr, size_t maxatrlen, size_t *atrlen)
418 {
419   int rc;
420   unsigned char msg[100];
421   size_t msglen;
422   unsigned char seqno;
423
424   msg[0] = PC_to_RDR_IccPowerOn;
425   msg[5] = 0; /* slot */
426   msg[6] = seqno = handle->seqno++;
427   msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
428   msg[8] = 0; /* RFU */
429   msg[9] = 0; /* RFU */
430   set_msg_len (msg, 0);
431   msglen = 10;
432
433   rc = bulk_out (handle, msg, msglen);
434   if (rc)
435     return rc;
436   rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
437   if (rc)
438     return rc;
439   
440   if (atr)
441     {
442       size_t n = msglen - 10;
443
444       if (n > maxatrlen)
445         n = maxatrlen;
446       memcpy (atr, msg+10, n);
447       *atrlen = n;
448     }
449
450   return 0;
451 }
452
453
454 \f
455 /*
456   Protocol T=1 overview
457
458   Block Structure:
459            Prologue Field:
460    1 byte     Node Address (NAD) 
461    1 byte     Protocol Control Byte (PCB)
462    1 byte     Length (LEN) 
463            Information Field:
464    0-254 byte APDU or Control Information (INF)
465            Epilogue Field:
466    1 byte     Error Detection Code (EDC)
467
468   NAD:  
469    bit 7     unused
470    bit 4..6  Destination Node Address (DAD)
471    bit 3     unused
472    bit 2..0  Source Node Address (SAD)
473
474    If node adresses are not used, SAD and DAD should be set to 0 on
475    the first block sent to the card.  If they are used they should
476    have different values (0 for one is okay); that first block sets up
477    the addresses of the nodes.
478
479   PCB:
480    Information Block (I-Block):
481       bit 7    0
482       bit 6    Sequence number (yep, that is modulo 2)
483       bit 5    Chaining flag 
484       bit 4..0 reserved
485    Received-Ready Block (R-Block):
486       bit 7    1
487       bit 6    0
488       bit 5    0
489       bit 4    Sequence number
490       bit 3..0  0 = no error
491                 1 = EDC or parity error
492                 2 = other error
493                 other values are reserved
494    Supervisory Block (S-Block):
495       bit 7    1
496       bit 6    1
497       bit 5    clear=request,set=response
498       bit 4..0  0 = resyncronisation request
499                 1 = information field size request
500                 2 = abort request
501                 3 = extension of BWT request
502                 4 = VPP error
503                 other values are reserved
504
505 */
506
507 int
508 ccid_transceive (ccid_driver_t handle,
509                  const unsigned char *apdu, size_t apdulen,
510                  unsigned char *resp, size_t maxresplen, size_t *nresp)
511 {
512   int rc;
513   unsigned char send_buffer[10+258], recv_buffer[10+258];
514   unsigned char *msg, *tpdu, *p;
515   size_t msglen, tpdulen, n;
516   unsigned char seqno;
517   int i;
518   unsigned char crc;
519   size_t dummy_nresp;
520   int sending = 1;
521
522   if (!nresp)
523     nresp = &dummy_nresp;
524
525   *nresp = 0;
526   
527   /* Construct an I-Block. */
528   if (apdulen > 254)
529     return -1; /* Invalid length. */
530
531   msg = send_buffer;
532
533   tpdu = msg+10;
534   tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
535   tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
536   tpdu[2] = apdulen;
537   memcpy (tpdu+3, apdu, apdulen);
538   crc = 0;
539   for (i=0,p=tpdu; i < apdulen+3; i++)
540     crc ^= *p++;
541   tpdu[3+apdulen] = crc;
542
543   tpdulen = apdulen + 4;
544
545   for (;;)
546     {
547       msg[0] = PC_to_RDR_XfrBlock;
548       msg[5] = 0; /* slot */
549       msg[6] = seqno = handle->seqno++;
550       msg[7] = 4; /* bBWI */
551       msg[8] = 0; /* RFU */
552       msg[9] = 0; /* RFU */
553       set_msg_len (msg, tpdulen);
554       msglen = 10 + tpdulen;
555
556       DEBUGOUT ("sending");
557       for (i=0; i < msglen; i++)
558         DEBUGOUT_CONT_1 (" %02X", msg[i]);
559       DEBUGOUT_LF ();
560       
561 /*       fprintf (stderr, "T1: put %c-block seq=%d\n", */
562 /*                ((msg[11] & 0xc0) == 0x80)? 'R' : */
563 /*                (msg[11] & 0x80)? 'S' : 'I', */
564 /*         ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40))); */
565   
566       rc = bulk_out (handle, msg, msglen);
567       if (rc)
568         return rc;
569
570       msg = recv_buffer;
571       rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
572                     RDR_to_PC_DataBlock, seqno);
573       if (rc)
574         return rc;
575       
576       tpdu = msg + 10;
577       tpdulen = msglen - 10;
578       
579       if (tpdulen < 4) 
580         {
581           DEBUGOUT ("cannot yet handle short blocks!\n");
582           return -1; 
583         }
584
585 /*       fprintf (stderr, "T1: got %c-block seq=%d err=%d\n", */
586 /*                ((msg[11] & 0xc0) == 0x80)? 'R' : */
587 /*                (msg[11] & 0x80)? 'S' : 'I', */
588 /*         ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), */
589 /*                ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0 */
590 /*                ); */
591
592       if (!(tpdu[1] & 0x80))
593         { /* This is an I-block. */
594           
595           if (sending)
596             { /* last block sent was successful. */
597               handle->t1_ns ^= 1;
598               sending = 0;
599             }
600
601           if (!!(tpdu[1] & 0x40) != handle->t1_nr)
602             { /* Reponse does not match our sequence number. */
603               msg = send_buffer;
604               tpdu = msg+10;
605               tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
606               tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4 | 2); /* R-block */
607               tpdu[2] = 0;
608               tpdulen = 3;
609               for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
610                 crc ^= *p++;
611               tpdu[tpdulen++] = crc;
612
613               continue;
614             }
615
616           handle->t1_nr ^= 1;
617
618           p = tpdu + 3; /* Skip the prologue field. */
619           n = tpdulen - 3 - 1; /* Strip the epilogue field. */
620           /* fixme: verify the checksum. */
621           if (resp)
622             {
623               if (n > maxresplen)
624                 {
625                   DEBUGOUT ("provided buffer too short for received data\n");
626                   return -1;
627                 }
628               
629               memcpy (resp, p, n); 
630               resp += n;
631               *nresp += n;
632               maxresplen -= n;
633             }
634           
635           if (!(tpdu[1] & 0x20))
636             return 0; /* No chaining requested - ready. */
637           
638           msg = send_buffer;
639           tpdu = msg+10;
640           tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
641           tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4); /* R-block */
642           tpdu[2] = 0;
643           tpdulen = 3;
644           for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
645             crc ^= *p++;
646           tpdu[tpdulen++] = crc;
647           
648         }
649       else if ((tpdu[1] & 0xc0) == 0x80)
650         { /* This is a R-block. */
651           if ( (tpdu[1] & 0x0f)) 
652             { /* Error: repeat last block */
653               msg = send_buffer;
654             }
655           else
656             {
657               DEBUGOUT ("unxpectec ACK R-block received\n");
658               return -1;
659             }
660         }
661       else 
662         { /* This is a S-block. */
663           DEBUGOUT_2 ("T1 S-block %s received cmd=%d\n",
664                       (tpdu[1] & 0x20)? "response": "request",
665                       (tpdu[1] & 0x1f));
666           if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
667             { /* Wait time extension request. */
668               unsigned char bwi = tpdu[3];
669               msg = send_buffer;
670               tpdu = msg+10;
671               tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
672               tpdu[1] = (0xc0 | 0x20 | 3); /* S-block response */
673               tpdu[2] = 1;
674               tpdu[3] = bwi;
675               tpdulen = 4;
676               for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
677                 crc ^= *p++;
678               tpdu[tpdulen++] = crc;
679               DEBUGOUT_1 ("T1 waittime extension of bwi=%d\n", bwi);
680             }
681           else
682             return -1;
683         }
684     } /* end T=1 protocol loop. */
685
686   return 0;
687 }
688
689
690
691
692 #ifdef TEST
693 int
694 main (int argc, char **argv)
695 {
696   int rc;
697   ccid_driver_t ccid;
698
699   rc = ccid_open_reader (&ccid, 0);
700   if (rc)
701     return 1;
702
703   ccid_poll (ccid);
704   fputs ("getting ATR ...\n", stderr);
705   rc = ccid_get_atr (ccid, NULL, 0, NULL);
706   if (rc)
707     return 1;
708
709   ccid_poll (ccid);
710   fputs ("getting slot status ...\n", stderr);
711   rc = ccid_slot_status (ccid);
712   if (rc)
713     return 1;
714
715   ccid_poll (ccid);
716
717   {
718     static unsigned char apdu[] = {
719       0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01};
720   rc = ccid_transceive (ccid,
721                         apdu, sizeof apdu,
722                         NULL, 0, NULL);
723   }
724   ccid_poll (ccid);
725
726   {
727     static unsigned char apdu[] = {
728       0, 0xCA, 0, 0x65, 254 };
729   rc = ccid_transceive (ccid,
730                         apdu, sizeof apdu,
731                         NULL, 0, NULL);
732   }
733   ccid_poll (ccid);
734
735
736   return 0;
737 }
738
739 /*
740  * Local Variables:
741  *  compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
742  * End:
743  */
744 #endif /*TEST*/
745 #endif /*HAVE_LIBUSB*/