USB suspend/resume change.
authorNIIBE Yutaka <gniibe@fsij.org>
Tue, 14 Nov 2017 03:59:18 +0000 (12:59 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Tue, 14 Nov 2017 03:59:18 +0000 (12:59 +0900)
ChangeLog
chopstx
src/gnuk.h
src/main.c
src/usb-ccid.c
src/usb_ctrl.c
src/usb_desc.c

index 001952c..9d68cbe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2017-11-14  NIIBE Yutaka  <gniibe@fsij.org>
+
+       * src/usb-ccid.c (ccid_usb_reset): Remove
+       (usb_event_handle): Return value change to notify
+       caller about needs for going out of the loop.
+       Support USB suspend/resume.
+       (ccid_thread): Supporting USB suspend, sleep forever with
+       timeout_p = NULL.
+
+       * src/main.c (main): Add USB_DEVICE_STATE_ prefix.
+       * src/usb_ctrl.c: Likewise.
+       (usb_device_reset): Don't call ccid_usb_reset.
+       (usb_set_configuration, usb_set_interface): Likewise.
+
+       * src/usb_desc.c (device_desc): bcdUSB = 2.0, supporting
+       suspend/resume.
+
+2017-11-13  NIIBE Yutaka  <gniibe@fsij.org>
+
+       * src/usb_ctrl.c: Use new const USB_DEVICE_STATE_*
+       * src/main.c (main): Likewise.
+       * src/usb-ccid.c: Likewise.
+       (INTR_REQ_USB): Remove.  Use the definition
+       in usb-lld.h.
+
 2017-11-08  NIIBE Yutaka  <gniibe@fsij.org>
 
        * src/openpgp-do.c (gpg_do_kdf_check): New.
diff --git a/chopstx b/chopstx
index 96d2a81..5ac8a1f 160000 (submodule)
--- a/chopstx
+++ b/chopstx
@@ -1 +1 @@
-Subproject commit 96d2a81331a43c920045ba0d3850caffac85a123
+Subproject commit 5ac8a1f251fecb24acb43953f7d4b0c38b2cc572
index 74c3eb4..1f0be6c 100644 (file)
@@ -22,15 +22,12 @@ extern struct apdu apdu;
 #define CARD_CHANGE_REMOVE 1
 #define CARD_CHANGE_TOGGLE 2
 void ccid_card_change_signal (int how);
-void ccid_usb_reset (int);
 
 /* CCID thread */
 #define EV_RX_DATA_READY   1 /* USB Rx data available  */
 #define EV_EXEC_FINISHED   2 /* OpenPGP Execution finished */
 #define EV_TX_FINISHED     4 /* CCID Tx finished  */
-#define EV_CARD_CHANGE         8
-#define EV_USB_SET_INTERFACE  16
-#define EV_USB_DEVICE_RESET   32
+#define EV_CARD_CHANGE     8
 
 /* OpenPGPcard thread */
 #define EV_PINPAD_INPUT_DONE      1
index 4c62d9d..6fad946 100644 (file)
@@ -329,7 +329,7 @@ main (int argc, const char *argv[])
 
   while (1)
     {
-      if (bDeviceState != UNCONNECTED)
+      if (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
        break;
 
       chopstx_usec_wait (250*1000);
index 656f695..1b05860 100644 (file)
@@ -1513,14 +1513,6 @@ ccid_card_change_signal (int how)
     eventflag_signal (&c->ccid_comm, EV_CARD_CHANGE);
 }
 
-void
-ccid_usb_reset (int full)
-{
-  struct ccid *c = &ccid;
-
-  eventflag_signal (&c->ccid_comm,
-                   full ? EV_USB_DEVICE_RESET : EV_USB_SET_INTERFACE);
-}
 
 #ifdef GNU_LINUX_EMULATION
 static uint8_t endp2_tx_buf[2];
@@ -1555,13 +1547,6 @@ ccid_notify_slot_change (struct ccid *c)
 #define GPG_THREAD_TERMINATED 0xffff
 
 
-#ifdef GNU_LINUX_EMULATION
-#include <signal.h>
-#define INTR_REQ_USB SIGUSR1
-#else
-#define INTR_REQ_USB 20
-#endif
-
 extern uint32_t bDeviceState;
 extern void usb_device_reset (struct usb_dev *dev);
 extern int usb_setup (struct usb_dev *dev);
@@ -1573,7 +1558,12 @@ extern int usb_get_status_interface (struct usb_dev *dev);
 
 extern int usb_get_descriptor (struct usb_dev *dev);
 
-static void
+/*
+ * Return 0 for normal USB event
+ *       -1 for USB reset
+ *        1 for SET_INTERFACE or SET_CONFIGURATION
+ */
+static int
 usb_event_handle (struct usb_dev *dev)
 {
   uint8_t ep_num;
@@ -1582,76 +1572,100 @@ usb_event_handle (struct usb_dev *dev)
   e = usb_lld_event_handler (dev);
   ep_num = USB_EVENT_ENDP (e);
 
+  /* Transfer to endpoint (not control endpoint) */
   if (ep_num != 0)
     {
       if (USB_EVENT_TXRX (e))
        usb_tx_done (ep_num, USB_EVENT_LEN (e));
       else
        usb_rx_ready (ep_num, USB_EVENT_LEN (e));
+      return 0;
     }
-  else
-    switch (USB_EVENT_ID (e))
-      {
-      case USB_EVENT_DEVICE_RESET:
-       usb_device_reset (dev);
-       break;
 
-      case USB_EVENT_DEVICE_ADDRESSED:
-       bDeviceState = ADDRESSED;
-       break;
+  /* Control endpoint */
+  switch (USB_EVENT_ID (e))
+    {
+    case USB_EVENT_DEVICE_RESET:
+      usb_device_reset (dev);
+      return -1;
 
-      case USB_EVENT_GET_DESCRIPTOR:
-       if (usb_get_descriptor (dev) < 0)
-         usb_lld_ctrl_error (dev);
-       break;
+    case USB_EVENT_DEVICE_ADDRESSED:
+      bDeviceState = USB_DEVICE_STATE_ADDRESSED;
+      break;
 
-      case USB_EVENT_SET_CONFIGURATION:
-       if (usb_set_configuration (dev) < 0)
-         usb_lld_ctrl_error (dev);
-       break;
+    case USB_EVENT_GET_DESCRIPTOR:
+      if (usb_get_descriptor (dev) < 0)
+       usb_lld_ctrl_error (dev);
+      break;
 
-      case USB_EVENT_SET_INTERFACE:
-       if (usb_set_interface (dev) < 0)
-         usb_lld_ctrl_error (dev);
-       break;
+    case USB_EVENT_SET_CONFIGURATION:
+      if (usb_set_configuration (dev) < 0)
+       usb_lld_ctrl_error (dev);
+      else
+       {
+         if (bDeviceState == USB_DEVICE_STATE_ADDRESSED)
+           /* de-Configured */
+           return -1;
+         else
+           /* Configured */
+           return 1;
+       }
+      break;
 
-      case USB_EVENT_CTRL_REQUEST:
-       /* Device specific device request.  */
-       if (usb_setup (dev) < 0)
-         usb_lld_ctrl_error (dev);
-       break;
+    case USB_EVENT_SET_INTERFACE:
+      if (usb_set_interface (dev) < 0)
+       usb_lld_ctrl_error (dev);
+      else
+       return 1;
+      break;
 
-      case USB_EVENT_GET_STATUS_INTERFACE:
-       if (usb_get_status_interface (dev) < 0)
-         usb_lld_ctrl_error (dev);
-       break;
+    case USB_EVENT_CTRL_REQUEST:
+      /* Device specific device request.  */
+      if (usb_setup (dev) < 0)
+       usb_lld_ctrl_error (dev);
+      break;
 
-      case USB_EVENT_GET_INTERFACE:
-       if (usb_get_interface (dev) < 0)
-         usb_lld_ctrl_error (dev);
-       break;
+    case USB_EVENT_GET_STATUS_INTERFACE:
+      if (usb_get_status_interface (dev) < 0)
+       usb_lld_ctrl_error (dev);
+      break;
 
-      case USB_EVENT_SET_FEATURE_DEVICE:
-      case USB_EVENT_SET_FEATURE_ENDPOINT:
-      case USB_EVENT_CLEAR_FEATURE_DEVICE:
-      case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
-       usb_lld_ctrl_ack (dev);
-       break;
+    case USB_EVENT_GET_INTERFACE:
+      if (usb_get_interface (dev) < 0)
+       usb_lld_ctrl_error (dev);
+      break;
 
-      case USB_EVENT_CTRL_WRITE_FINISH:
-       /* Control WRITE transfer finished.  */
-       usb_ctrl_write_finish (dev);
-       break;
+    case USB_EVENT_SET_FEATURE_DEVICE:
+    case USB_EVENT_SET_FEATURE_ENDPOINT:
+    case USB_EVENT_CLEAR_FEATURE_DEVICE:
+    case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
+      usb_lld_ctrl_ack (dev);
+      break;
 
-      case USB_EVENT_OK:
-      case USB_EVENT_DEVICE_SUSPEND:
-      default:
-       break;
-      }
+    case USB_EVENT_CTRL_WRITE_FINISH:
+      /* Control WRITE transfer finished.  */
+      usb_ctrl_write_finish (dev);
+      break;
+
+    case USB_EVENT_DEVICE_SUSPEND:
+      bDeviceState |= USB_DEVICE_STATE_SUSPEND;
+      break;
+
+    case USB_EVENT_DEVICE_WAKEUP:
+      bDeviceState &= ~USB_DEVICE_STATE_SUSPEND;
+      break;
+
+    case USB_EVENT_OK:
+    default:
+      break;
+    }
+
+  return 0;
 }
 
 static void
-poll_event_intr (uint32_t *timeout, struct eventflag *ev, chopstx_intr_t *intr)
+poll_event_intr (uint32_t *timeout_p,
+                struct eventflag *ev, chopstx_intr_t *intr)
 {
   chopstx_poll_cond_t poll_desc;
   struct chx_poll_head *pd_array[2] = {
@@ -1660,7 +1674,7 @@ poll_event_intr (uint32_t *timeout, struct eventflag *ev, chopstx_intr_t *intr)
   };
 
   eventflag_prepare_poll (ev, &poll_desc);
-  chopstx_poll (timeout, 2, pd_array);
+  chopstx_poll (timeout_p, 2, pd_array);
 }
 
 void *
@@ -1670,6 +1684,7 @@ ccid_thread (void *arg)
   uint32_t timeout;
   struct usb_dev dev;
   struct ccid *c = &ccid;
+  uint32_t *timeout_p;
 
   (void)arg;
 
@@ -1680,7 +1695,7 @@ ccid_thread (void *arg)
   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
   usb_event_handle (&dev);     /* For old SYS < 3.0 */
 
device_reset:
+ reset:
   {
     struct ep_in *epi = &endpoint_in;
     struct ep_out *epo = &endpoint_out;
@@ -1692,50 +1707,46 @@ ccid_thread (void *arg)
     ccid_init (c, epi, epo, a);
   }
 
-  while (bDeviceState != CONFIGURED)
+  timeout = USB_CCID_TIMEOUT;
+  if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
     {
-      poll_event_intr (NULL, &c->ccid_comm, &interrupt);
-      if (interrupt.ready)
-       usb_event_handle (&dev);
-
-      eventflag_get (&c->ccid_comm);
-      /* Ignore event while not-configured.  */
+      ccid_prepare_receive (c);
+      ccid_notify_slot_change (c);
     }
 
- interface_reset:
-  timeout = USB_CCID_TIMEOUT;
-  ccid_prepare_receive (c);
-  ccid_notify_slot_change (c);
   while (1)
     {
       eventmask_t m;
 
-      poll_event_intr (&timeout, &c->ccid_comm, &interrupt);
-      if (interrupt.ready)
-       {
-         usb_event_handle (&dev);
-         continue;
-       }
-
-      timeout = USB_CCID_TIMEOUT;
-      m = eventflag_get (&c->ccid_comm);
+      if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
+       timeout_p = &timeout;
+      else
+       timeout_p = NULL;
 
-      if (m == EV_USB_DEVICE_RESET)
+      poll_event_intr (timeout_p, &c->ccid_comm, &interrupt);
+      if (interrupt.ready)
        {
+         if (usb_event_handle (&dev) == 0)
+           continue;
+
+         /* RESET handling:
+          * (1) After DEVICE_RESET, it needs to re-start out of the loop.
+          * (2) After SET_INTERFACE, the endpoint is reset to RX_NAK.
+          *     It needs to prepare receive again.
+          */
          if (c->application)
            {
              chopstx_cancel (c->application);
              chopstx_join (c->application, NULL);
              c->application = 0;
            }
-         goto device_reset;
+         goto reset;
        }
-      else if (m == EV_USB_SET_INTERFACE)
-       /* Upon receival of SET_INTERFACE, the endpoint is reset to RX_NAK.
-        * Thus, we need to prepare receive again.
-        */
-       goto interface_reset;
-      else if (m == EV_CARD_CHANGE)
+
+      timeout = USB_CCID_TIMEOUT;
+      m = eventflag_get (&c->ccid_comm);
+
+      if (m == EV_CARD_CHANGE)
        {
          if (c->ccid_state == CCID_STATE_NOCARD)
            /* Inserted!  */
@@ -1820,7 +1831,7 @@ ccid_thread (void *arg)
     }
 
   /* Loading reGNUal.  */
-  while (bDeviceState != UNCONNECTED)
+  while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
     {
       chopstx_intr_wait (&interrupt);
       usb_event_handle (&dev);
index e9335b7..3be3242 100644 (file)
@@ -87,7 +87,7 @@ vcom_port_data_setup (struct usb_dev *dev)
 #include "usb-msc.h"
 #endif
 
-uint32_t bDeviceState = UNCONNECTED; /* USB device status */
+uint32_t bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
 
 #define USB_HID_REQ_GET_REPORT   1
 #define USB_HID_REQ_GET_IDLE     2
@@ -218,8 +218,7 @@ usb_device_reset (struct usb_dev *dev)
   for (i = 0; i < NUM_INTERFACES; i++)
     gnuk_setup_endpoints_for_interface (dev, i, 1);
 
-  bDeviceState = ATTACHED;
-  ccid_usb_reset (1);
+  bDeviceState = USB_DEVICE_STATE_ATTACHED;
 }
 
 #define USB_CCID_REQ_ABORT                     0x01
@@ -414,7 +413,7 @@ usb_ctrl_write_finish (struct usb_dev *dev)
          if (*ccid_state_p != CCID_STATE_EXITED)
            return;
 
-         bDeviceState = UNCONNECTED;
+         bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
          usb_lld_prepare_shutdown (); /* No further USB communication */
          led_blink (LED_GNUK_EXEC);    /* Notify the main.  */
        }
@@ -476,7 +475,7 @@ usb_set_configuration (struct usb_dev *dev)
       usb_lld_set_configuration (dev, 1);
       for (i = 0; i < NUM_INTERFACES; i++)
        gnuk_setup_endpoints_for_interface (dev, i, 0);
-      bDeviceState = CONFIGURED;
+      bDeviceState = USB_DEVICE_STATE_CONFIGURED;
     }
   else if (current_conf != dev->dev_req.value)
     {
@@ -486,8 +485,7 @@ usb_set_configuration (struct usb_dev *dev)
       usb_lld_set_configuration (dev, 0);
       for (i = 0; i < NUM_INTERFACES; i++)
        gnuk_setup_endpoints_for_interface (dev, i, 1);
-      bDeviceState = ADDRESSED;
-      ccid_usb_reset (1);
+      bDeviceState = USB_DEVICE_STATE_ADDRESSED;
     }
 
   /* Do nothing when current_conf == value */
@@ -509,7 +507,6 @@ usb_set_interface (struct usb_dev *dev)
   else
     {
       gnuk_setup_endpoints_for_interface (dev, interface, 0);
-      ccid_usb_reset (0);
       return usb_lld_ctrl_ack (dev);
     }
 }
index 8031088..2995acc 100644 (file)
@@ -65,7 +65,7 @@ static const
 uint8_t device_desc[] = {
   18,   /* bLength */
   DEVICE_DESCRIPTOR,     /* bDescriptorType */
-  0x10, 0x01,   /* bcdUSB = 1.1 */
+  0x00, 0x02,            /* bcdUSB = 2.0 */
   0x00,   /* bDeviceClass: 0 means deferred to interface */
   0x00,   /* bDeviceSubClass */
   0x00,   /* bDeviceProtocol */