* cardglue.c (open_card): Use shutdown code if possible.
authorWerner Koch <wk@gnupg.org>
Mon, 20 Sep 2004 13:15:37 +0000 (13:15 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 20 Sep 2004 13:15:37 +0000 (13:15 +0000)
(check_card_serialno): Ditto.

* ccid-driver.c (do_close_reader): Factored some code out from ...
(ccid_close_reader): ..here.
(ccid_shutdown_reader): New.

* apdu.c (apdu_shutdown_reader): New.
(shutdown_ccid_reader): New.

g10/ChangeLog
g10/apdu.c
g10/apdu.h
g10/cardglue.c
g10/ccid-driver.c
g10/ccid-driver.h

index 423e15a..b487124 100644 (file)
@@ -1,3 +1,15 @@
+2004-09-20  Werner Koch  <wk@g10code.com>
+
+       * cardglue.c (open_card): Use shutdown code if possible.
+       (check_card_serialno): Ditto.
+
+       * ccid-driver.c (do_close_reader): Factored some code out from ...
+       (ccid_close_reader): ..here.
+       (ccid_shutdown_reader): New.
+
+       * apdu.c (apdu_shutdown_reader): New.
+       (shutdown_ccid_reader): New.
+
 2004-09-17  Werner Koch  <wk@g10code.com>
 
        * g10.c (list_config): New config option ccid-reader-id.
index a3aa1ba..228fdec 100644 (file)
@@ -92,6 +92,7 @@ struct reader_table_s {
 
   /* Function pointers intialized to the various backends.  */
   int (*close_reader)(int);
+  int (*shutdown_reader)(int);
   int (*reset_reader)(int);
   int (*get_status_reader)(int, unsigned int *);
   int (*send_apdu_reader)(int,unsigned char *,size_t,
@@ -244,6 +245,7 @@ new_reader_slot (void)
     }
 #endif /*USE_GNU_PTH*/
   reader_table[reader].close_reader = NULL;
+  reader_table[reader].shutdown_reader = NULL;
   reader_table[reader].reset_reader = NULL;
   reader_table[reader].get_status_reader = NULL;
   reader_table[reader].send_apdu_reader = NULL;
@@ -1202,6 +1204,14 @@ close_ccid_reader (int slot)
   
 
 static int
+shutdown_ccid_reader (int slot)
+{
+  ccid_shutdown_reader (reader_table[slot].ccid.handle);
+  return 0;
+}                       
+  
+
+static int
 reset_ccid_reader (int slot)
 {
   int err;
@@ -1300,6 +1310,7 @@ open_ccid_reader (const char *portstr)
     }
 
   reader_table[slot].close_reader = close_ccid_reader;
+  reader_table[slot].shutdown_reader = shutdown_ccid_reader;
   reader_table[slot].reset_reader = reset_ccid_reader;
   reader_table[slot].get_status_reader = get_status_ccid;
   reader_table[slot].send_apdu_reader = send_apdu_ccid;
@@ -2051,6 +2062,19 @@ apdu_close_reader (int slot)
   return SW_HOST_NOT_SUPPORTED;
 }
 
+/* Shutdown a reader; that is basically the same as a close but keeps
+   the handle ready for later use. A apdu_reset_header should be used
+   to get it active again. */
+int
+apdu_shutdown_reader (int slot)
+{
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+  if (reader_table[slot].shutdown_reader)
+    return reader_table[slot].shutdown_reader (slot);
+  return SW_HOST_NOT_SUPPORTED;
+}
+
 /* Enumerate all readers and return information on whether this reader
    is in use.  The caller should start with SLOT set to 0 and
    increment it with each call until an error is returned. */
index a0654a2..f31e42e 100644 (file)
@@ -76,6 +76,7 @@ int apdu_open_remote_reader (const char *portstr,
                              void *writefnc_value,
                              void (*closefnc) (void *opaque),
                              void *closefnc_value);
+int apdu_shutdown_reader (int slot);
 int apdu_close_reader (int slot);
 int apdu_enum_reader (int slot, int *used);
 unsigned char *apdu_get_atr (int slot, size_t *atrlen);
index 7bb3c84..5faa41b 100644 (file)
@@ -54,7 +54,6 @@ static APP current_app;
 
 
 
-
 /* Create a serialno/fpr string from the serial number and the secret
    key.  caller must free the returned string.  There is no error
    return. [Taken from 1.9's keyid.c]*/
@@ -247,18 +246,25 @@ agent_release_card_info (struct agent_card_info_s *info)
 static APP
 open_card (void)
 {
-  int slot;
+  int slot = -1;
   int rc;
   APP app;
+  int did_shutdown = 0;
 
   card_close ();
 
+  
  retry:
-  slot = apdu_open_reader (default_reader_port);
-  if (slot == -1)
+  if (did_shutdown)
+    apdu_reset (slot);
+  else
     {
-      log_error ("card reader not available\n");
-      return NULL;
+      slot = apdu_open_reader (default_reader_port);
+      if (slot == -1)
+        {
+          log_error ("card reader not available\n");
+          return NULL;
+        }
     }
 
   app = xcalloc (1, sizeof *app);
@@ -268,11 +274,14 @@ open_card (void)
     {
       write_status_text (STATUS_CARDCTRL, "1");
       
+      did_shutdown = !!apdu_shutdown_reader (slot);
+
       if ( cpr_get_answer_okay_cancel ("cardctrl.insert_card.okay",
            _("Please insert the card and hit return or enter 'c' to cancel: "),
                                        1) )
         {
-          apdu_close_reader (slot);
+          if (!did_shutdown)
+            apdu_close_reader (slot);
           xfree (app);
           goto retry;
         }
@@ -323,7 +332,7 @@ card_close (void)
    function return 0 is the present card is okay, -1 if the user
    selected to insert a new card or an error value.  Note that the
    card context will be closed in all cases except for 0 as return
-   value. */
+   value and if it was possible to merely shutdown the reader. */
 static int
 check_card_serialno (APP app, const char *serialno)
 {
@@ -346,8 +355,12 @@ check_card_serialno (APP app, const char *serialno)
   if (ask)
     {
       char buf[5+32+1];
+      int did_shutdown = 0;
 
-      card_close ();
+      if (current_app && !apdu_shutdown_reader (current_app->slot))
+        did_shutdown = 1;
+      else
+        card_close ();
       tty_printf (_("Please remove the current card and "
                     "insert the one with the serial number:\n"
                     "   %.*s\n"), 32, serialno);
@@ -359,7 +372,14 @@ check_card_serialno (APP app, const char *serialno)
                           _("Hit return when ready "
                             "or enter 'c' to cancel: "),
                                        1) )
-        return -1;
+        {
+          card_close ();
+          return -1;
+        }
+      if (did_shutdown)
+        apdu_reset (current_app->slot);
+      else
+        card_close ();
       return gpg_error (GPG_ERR_INV_ID);
     }
   return 0;
index ccdcb46..77fea94 100644 (file)
@@ -196,6 +196,7 @@ struct ccid_driver_s
   int auto_ifsd;
   int max_ifsd;
   int ifsd;
+  int powered_off;
   int has_pinpad;
 };
 
@@ -863,6 +864,102 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
 }
 
 
+static void
+do_close_reader (ccid_driver_t handle)
+{
+  int rc;
+  unsigned char msg[100];
+  size_t msglen;
+  unsigned char seqno;
+  
+  if (!handle->powered_off)
+    {
+      msg[0] = PC_to_RDR_IccPowerOff;
+      msg[5] = 0; /* slot */
+      msg[6] = seqno = handle->seqno++;
+      msg[7] = 0; /* RFU */
+      msg[8] = 0; /* RFU */
+      msg[9] = 0; /* RFU */
+      set_msg_len (msg, 0);
+      msglen = 10;
+      
+      rc = bulk_out (handle, msg, msglen);
+      if (!rc)
+        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno);
+      handle->powered_off = 1;
+    }
+  if (handle->idev)
+    {
+      usb_release_interface (handle->idev, 0);
+      usb_close (handle->idev);
+      handle->idev = NULL;
+    }
+}
+
+
+/* Reset a reader on HANDLE.  This is useful in case a reader has been
+   plugged of and inserted at a different port.  By resetting the
+   handle, the same reader will be get used.  Note, that on error the
+   handle won't get released. 
+
+   This does not return an ATR, so ccid_get_atr should be called right
+   after this one.
+*/
+int 
+ccid_shutdown_reader (ccid_driver_t handle)
+{
+  int rc = 0;
+  struct usb_device *dev = NULL;
+  usb_dev_handle *idev = NULL;
+  unsigned char *ifcdesc_extra = NULL;
+  size_t ifcdesc_extra_len;
+
+  if (!handle || !handle->rid)
+    return CCID_DRIVER_ERR_INV_VALUE;
+
+  do_close_reader (handle);
+
+  idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
+                               &ifcdesc_extra, &ifcdesc_extra_len);
+  if (!idev)
+    {
+      DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
+      return CCID_DRIVER_ERR_NO_READER;
+    }
+
+
+  handle->idev = idev;
+
+  if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
+    {
+      DEBUGOUT ("device not supported\n");
+      rc = CCID_DRIVER_ERR_NO_READER;
+      goto leave;
+    }
+  
+  /* fixme: Do we need to claim and set the interface as
+     determined above? */
+  rc = usb_claim_interface (idev, 0);
+  if (rc)
+    {
+      DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+      rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+      goto leave;
+    }
+  
+ leave:
+  free (ifcdesc_extra);
+  if (rc)
+    {
+      usb_close (handle->idev);
+      handle->idev = NULL;
+    }
+
+  return rc;
+
+}
+
+
 /* Close the reader HANDLE. */
 int 
 ccid_close_reader (ccid_driver_t handle)
@@ -870,34 +967,13 @@ ccid_close_reader (ccid_driver_t handle)
   if (!handle || !handle->idev)
     return 0;
 
-   {
-     int rc;
-     unsigned char msg[100];
-     size_t msglen;
-     unsigned char seqno;
-   
-     msg[0] = PC_to_RDR_IccPowerOff;
-     msg[5] = 0; /* slot */
-     msg[6] = seqno = handle->seqno++;
-     msg[7] = 0; /* RFU */
-     msg[8] = 0; /* RFU */
-     msg[9] = 0; /* RFU */
-     set_msg_len (msg, 0);
-     msglen = 10;
-   
-     rc = bulk_out (handle, msg, msglen);
-     if (!rc)
-        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
-   }
-   
-  usb_release_interface (handle->idev, 0);
-  usb_close (handle->idev);
-  handle->idev = NULL;
+  do_close_reader (handle);
   free (handle->rid);
   free (handle);
   return 0;
 }
 
+
 /* Return False if a card is present and powered. */
 int
 ccid_check_card_presence (ccid_driver_t handle)
@@ -1120,6 +1196,8 @@ ccid_get_atr (ccid_driver_t handle,
   rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
   if (rc)
     return rc;
+
+  handle->powered_off = 0;
   
   if (atr)
     {
@@ -1680,16 +1758,16 @@ main (int argc, char **argv)
   ccid_poll (ccid);
 
 /*   if (!ccid->has_pinpad) */
-    {
-      fputs ("verifying that CHV1 is 123456....\n", stderr);
-      {
-        static unsigned char apdu[] = {0, 0x20, 0, 0x81,
-                                       6, '1','2','3','4','5','6'};
-        rc = ccid_transceive (ccid, apdu, sizeof apdu,
-                              result, sizeof result, &resultlen);
-        print_result (rc, result, resultlen);
-      }
-    }
+/*     { */
+/*       fputs ("verifying that CHV1 is 123456....\n", stderr); */
+/*       { */
+/*         static unsigned char apdu[] = {0, 0x20, 0, 0x81, */
+/*                                        6, '1','2','3','4','5','6'}; */
+/*         rc = ccid_transceive (ccid, apdu, sizeof apdu, */
+/*                               result, sizeof result, &resultlen); */
+/*         print_result (rc, result, resultlen); */
+/*       } */
+/*     } */
 /*   else */
 /*     { */
 /*       fputs ("verifying CHV1 using the PINPad ....\n", stderr); */
index 23562b3..cbadb40 100644 (file)
@@ -78,6 +78,7 @@ typedef struct ccid_driver_s *ccid_driver_t;
 int ccid_set_debug_level (int level);
 char *ccid_get_reader_list (void);
 int ccid_open_reader (ccid_driver_t *handle, const char *readerid);
+int ccid_shutdown_reader (ccid_driver_t handle);
 int ccid_close_reader (ccid_driver_t handle);
 int ccid_get_atr (ccid_driver_t handle,
                   unsigned char *atr, size_t maxatrlen, size_t *atrlen);