<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15499">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add small program to play with how Linux reacts to hubs with many ports<br><br>Change-Id: Ic3d2bec3f55f4d9e13183795c5825723f9427476<br>---<br>M ccid/Makefile<br>A ccid/hub_create_gadget.sh<br>A ccid/hub_main_functionfs.c<br>A ccid/hub_remove_gadget.sh<br>4 files changed, 589 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/99/15499/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/ccid/Makefile b/ccid/Makefile</span><br><span>index 3258967..0fadd22 100644</span><br><span>--- a/ccid/Makefile</span><br><span>+++ b/ccid/Makefile</span><br><span>@@ -3,6 +3,9 @@</span><br><span> ccid_functionfs: ccid_main_functionfs.o ccid_proto.o ccid_device.o ccid_slot_sim.o</span><br><span>    $(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc -laio</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+hub_functionfs: hub_main_functionfs.o</span><br><span style="color: hsl(120, 100%, 40%);">+  $(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc -laio</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> %.o: %.c</span><br><span>      $(CC) $(CFLAGS) -o $@ -c $^</span><br><span> </span><br><span>diff --git a/ccid/hub_create_gadget.sh b/ccid/hub_create_gadget.sh</span><br><span>new file mode 100755</span><br><span>index 0000000..3689c9f</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/hub_create_gadget.sh</span><br><span>@@ -0,0 +1,48 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/bin/bash</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GADGET_NAME=osmo-hub</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GADGET_CONFIGFS=/sys/kernel/config/usb_gadget</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+die() {</span><br><span style="color: hsl(120, 100%, 40%);">+        echo ERROR: $1</span><br><span style="color: hsl(120, 100%, 40%);">+        exit 2</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+modprobe configfs</span><br><span style="color: hsl(120, 100%, 40%);">+modprobe usb_f_fs</span><br><span style="color: hsl(120, 100%, 40%);">+modprobe dummy_hcd is_high_speed=0 is_super_speed=0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d $GADGET_CONFIGFS ] || die "usb_gadget configfs not mounted"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+gadgetdir="$GADGET_CONFIGFS/$GADGET_NAME"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# create gadget</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d $gadgetdir ] || mkdir $gadgetdir || die "Cannot create $gadgetdir. Permission problem?"</span><br><span style="color: hsl(120, 100%, 40%);">+set -e -x</span><br><span style="color: hsl(120, 100%, 40%);">+cd $gadgetdir</span><br><span style="color: hsl(120, 100%, 40%);">+echo 0x2342 > idVendor</span><br><span style="color: hsl(120, 100%, 40%);">+echo 0x4200 > idProduct</span><br><span style="color: hsl(120, 100%, 40%);">+echo 0x09 > bDeviceClass</span><br><span style="color: hsl(120, 100%, 40%);">+echo 1 > bDeviceProtocol</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d strings/0x409 ] || mkdir strings/0x409</span><br><span style="color: hsl(120, 100%, 40%);">+echo 2342 > strings/0x409/serialnumber</span><br><span style="color: hsl(120, 100%, 40%);">+echo "sysmocom GmbH" > strings/0x409/manufacturer</span><br><span style="color: hsl(120, 100%, 40%);">+echo "sysmoHUB" > strings/0x409/product</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# create config</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d configs/c.1 ] || mkdir configs/c.1</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d configs/c.1/strings/0x409 ] || mkdir configs/c.1/strings/0x409</span><br><span style="color: hsl(120, 100%, 40%);">+echo "sysmoHUB config" > configs/c.1/strings/0x409/configuration</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d functions/ffs.usb0 ] || mkdir functions/ffs.usb0</span><br><span style="color: hsl(120, 100%, 40%);">+[ -e configs/c.1/ffs.usb0 ] || ln -s functions/ffs.usb0 configs/c.1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ -d /dev/ffs-hub ] || mkdir /dev/ffs-hub</span><br><span style="color: hsl(120, 100%, 40%);">+[ -e /dev/ffs-hub/ep0 ] || mount -t functionfs usb0 /dev/ffs-hub/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# enable device, only works after program has opened EP FDs</span><br><span style="color: hsl(120, 100%, 40%);">+#echo dummy_udc.0 > UDC</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/ccid/hub_main_functionfs.c b/ccid/hub_main_functionfs.c</span><br><span>new file mode 100644</span><br><span>index 0000000..c019cde</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/hub_main_functionfs.c</span><br><span>@@ -0,0 +1,505 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <endian.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <signal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <linux/usb/functionfs.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <linux/usb/ch11.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if __BYTE_ORDER == __LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+#define cpu_to_le16(x)  (x)</span><br><span style="color: hsl(120, 100%, 40%);">+#define cpu_to_le32(x)  (x)</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+#define cpu_to_le16(x)  ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))</span><br><span style="color: hsl(120, 100%, 40%);">+#define cpu_to_le32(x)  \</span><br><span style="color: hsl(120, 100%, 40%);">+ ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >>  8) | \</span><br><span style="color: hsl(120, 100%, 40%);">+    (((x) & 0x0000ff00u) <<  8) | (((x) & 0x000000ffu) << 24))</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define le32_to_cpu(x)  le32toh(x)</span><br><span style="color: hsl(120, 100%, 40%);">+#define le16_to_cpu(x)  le16toh(x)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+    DUSB,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Actual USB Descriptors</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct usb_functionfs_descs_head_v2 header;</span><br><span style="color: hsl(120, 100%, 40%);">+   __le32 fs_count;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct usb_interface_descriptor intf;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct usb_endpoint_descriptor_no_audio ep_int;</span><br><span style="color: hsl(120, 100%, 40%);">+       } __attribute__ ((packed)) fs_descs;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed)) descriptors = {</span><br><span style="color: hsl(120, 100%, 40%);">+      .header = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),</span><br><span style="color: hsl(120, 100%, 40%);">+                .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_ALL_CTRL_RECIP),</span><br><span style="color: hsl(120, 100%, 40%);">+             .length = cpu_to_le32(sizeof(descriptors)),</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    .fs_count = cpu_to_le32(2),</span><br><span style="color: hsl(120, 100%, 40%);">+   .fs_descs = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .intf = {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .bLength = sizeof(descriptors.fs_descs.intf),</span><br><span style="color: hsl(120, 100%, 40%);">+                 .bDescriptorType = USB_DT_INTERFACE,</span><br><span style="color: hsl(120, 100%, 40%);">+                  .bNumEndpoints = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .bInterfaceClass = USB_CLASS_HUB,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .iInterface = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+              },</span><br><span style="color: hsl(120, 100%, 40%);">+            .ep_int = {</span><br><span style="color: hsl(120, 100%, 40%);">+                   .bLength = sizeof(descriptors.fs_descs.ep_int),</span><br><span style="color: hsl(120, 100%, 40%);">+                       .bDescriptorType = USB_DT_ENDPOINT,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .bEndpointAddress = 1 | USB_DIR_IN,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .bmAttributes = USB_ENDPOINT_XFER_INT,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .wMaxPacketSize = 64,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .bInterval = 12,</span><br><span style="color: hsl(120, 100%, 40%);">+              },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define STR_INTERFACE_ "Osmocom USB Hub"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct usb_functionfs_strings_head header;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              __le16 code;</span><br><span style="color: hsl(120, 100%, 40%);">+          const char str1[sizeof(STR_INTERFACE_)];</span><br><span style="color: hsl(120, 100%, 40%);">+      } __attribute__((packed)) lang0;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed)) strings = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .header = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),</span><br><span style="color: hsl(120, 100%, 40%);">+               .length = cpu_to_le32(sizeof(strings)),</span><br><span style="color: hsl(120, 100%, 40%);">+               .str_count = cpu_to_le32(1),</span><br><span style="color: hsl(120, 100%, 40%);">+          .lang_count = cpu_to_le32(1),</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    .lang0 = {</span><br><span style="color: hsl(120, 100%, 40%);">+            cpu_to_le16(0x0409), /* en-us */</span><br><span style="color: hsl(120, 100%, 40%);">+              STR_INTERFACE_,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct usb2_hub_desc_header {</span><br><span style="color: hsl(120, 100%, 40%);">+     __u8 bDescLength;</span><br><span style="color: hsl(120, 100%, 40%);">+     __u8 bDescriptorType;</span><br><span style="color: hsl(120, 100%, 40%);">+ __u8 bNbrPorts;</span><br><span style="color: hsl(120, 100%, 40%);">+       __le16 wHubCharacteristics;</span><br><span style="color: hsl(120, 100%, 40%);">+   __u8 bPwrOn2PwrGood;</span><br><span style="color: hsl(120, 100%, 40%);">+  __u8 bHubContrCurrent;</span><br><span style="color: hsl(120, 100%, 40%);">+        __u8 data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define NUM_PORTS  31</span><br><span style="color: hsl(120, 100%, 40%);">+#define HDESC_ARR_BYTES     ((NUM_PORTS + 1 + 7) / 8)</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct usb2_hub_desc_header hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t DeviceRemovable[HDESC_ARR_BYTES];</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t PortPwrCtrlMask[HDESC_ARR_BYTES];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed)) hub_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .hdr = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .bDescLength = sizeof(hub_desc),</span><br><span style="color: hsl(120, 100%, 40%);">+              .bDescriptorType = USB_DT_HUB,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bNbrPorts = NUM_PORTS,</span><br><span style="color: hsl(120, 100%, 40%);">+               .wHubCharacteristics = cpu_to_le16(0x0001),</span><br><span style="color: hsl(120, 100%, 40%);">+           .bPwrOn2PwrGood = 100,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bHubContrCurrent = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * USB FunctionFS interface</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <fcntl.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef FUNCTIONFS_SUPPORTS_POLL</span><br><span style="color: hsl(120, 100%, 40%);">+#include <libaio.h></span><br><span style="color: hsl(120, 100%, 40%);">+struct aio_help {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct iocb *iocb;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* usb function handle */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ufunc_handle {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fd ep0;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_fd ep_int;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head ep_int_queue;</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef FUNCTIONFS_SUPPORTS_POLL</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fd aio_evfd;</span><br><span style="color: hsl(120, 100%, 40%);">+      io_context_t aio_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct aio_help aio_int;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ep_int_cb(struct osmo_fd *ofd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DUSB, LOGL_DEBUG, "%s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string ffs_evt_type_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    { FUNCTIONFS_BIND,      "BIND" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { FUNCTIONFS_UNBIND,    "UNBIND" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { FUNCTIONFS_ENABLE,    "ENABLE" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { FUNCTIONFS_DISABLE,   "DISABLE" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { FUNCTIONFS_SETUP,     "SETUP" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { FUNCTIONFS_SUSPEND,   "SUSPEND" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { FUNCTIONFS_RESUME,    "RESUME" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, NULL }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* local, stand-alone definition of a USB control request */</span><br><span style="color: hsl(120, 100%, 40%);">+struct _usb_ctrl_req {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t bRequestType;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bRequest;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t wValue;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t wIndex;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t wLength;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* class requests from the USB 2.0 hub spec, table 11-15 */</span><br><span style="color: hsl(120, 100%, 40%);">+#define HUB_CLASS_REQ(dir, type, request) ((((dir) | (type)) << 8) | (request))</span><br><span style="color: hsl(120, 100%, 40%);">+/* GetBusState and SetHubDescriptor are optional, omitted */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ClearHubFeature         HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_CLEAR_FEATURE)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ClearPortFeature        HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_CLEAR_FEATURE)</span><br><span style="color: hsl(120, 100%, 40%);">+#define GetHubDescriptor        HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, USB_REQ_GET_DESCRIPTOR)</span><br><span style="color: hsl(120, 100%, 40%);">+#define GetHubStatus            HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, USB_REQ_GET_STATUS)</span><br><span style="color: hsl(120, 100%, 40%);">+#define GetPortStatus           HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, USB_REQ_GET_STATUS)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SetHubFeature           HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_SET_FEATURE)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SetPortFeature          HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_SET_FEATURE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct value_string hub_class_spec_req_vals[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(USB_REQ_CLEAR_FEATURE),</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_VALUE_STRING(USB_REQ_GET_DESCRIPTOR),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(USB_REQ_GET_STATUS),</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_VALUE_STRING(USB_REQ_SET_FEATURE),</span><br><span style="color: hsl(120, 100%, 40%);">+       { 0, NULL }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CCID_CTRL_RET_INVALID     -1</span><br><span style="color: hsl(120, 100%, 40%);">+#define CCID_CTRL_RET_UNKNOWN     -2</span><br><span style="color: hsl(120, 100%, 40%);">+#define CCID_CTRL_RET_OK  0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Handle [class specific] CTRL request. We assume the caller has already verified that the</span><br><span style="color: hsl(120, 100%, 40%);">+ *  request was made to the correct interface as well as it is a class-specific request.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ci CCID Instance for which CTRL request was received</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctrl_req buffer holding the 8 bytes CTRL transfer header</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] data_in data to be returned to the host in the IN transaction (if any)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns CCID_CTRL_RET_OK, CCID_CTRL_RET_INVALID or CCID_CTRL_RET_UNKNOWN</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int hub_handle_ctrl(void *ci, const uint8_t *ctrl_req, const uint8_t **data_in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const struct _usb_ctrl_req *req = (const struct _usb_ctrl_req *) ctrl_req;</span><br><span style="color: hsl(120, 100%, 40%);">+    static uint16_t status[2];</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DUSB, LOGL_NOTICE, "CTRL bmReqT=0x%02X bRequest=%s, wValue=0x%04X, wIndex=0x%04X, wLength=%d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               req->bRequestType, get_value_string(hub_class_spec_req_vals, req->bRequest),</span><br><span style="color: hsl(120, 100%, 40%);">+            req->wValue, req->wIndex, req->wLength);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (req->bRequestType & 0x7f) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case USB_RT_HUB:</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (req->bRequest) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case USB_REQ_GET_DESCRIPTOR:</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (req->wIndex != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            LOGP(DUSB, LOGL_ERROR, "GET_DESC wIndex invalid\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                                return CCID_CTRL_RET_INVALID;</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (0) // ctrl_req->wValue != FIXME</span><br><span style="color: hsl(120, 100%, 40%);">+                                return CCID_CTRL_RET_INVALID;</span><br><span style="color: hsl(120, 100%, 40%);">+                 *data_in = (const uint8_t *) &hub_desc;</span><br><span style="color: hsl(120, 100%, 40%);">+                   return sizeof(hub_desc);</span><br><span style="color: hsl(120, 100%, 40%);">+              case USB_REQ_CLEAR_FEATURE:</span><br><span style="color: hsl(120, 100%, 40%);">+                   switch (req->wValue) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     case C_HUB_LOCAL_POWER:</span><br><span style="color: hsl(120, 100%, 40%);">+                       case C_HUB_OVER_CURRENT:</span><br><span style="color: hsl(120, 100%, 40%);">+                              return CCID_CTRL_RET_OK;</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case USB_REQ_GET_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+                      status[0] = cpu_to_le16(HUB_STATUS_LOCAL_POWER);</span><br><span style="color: hsl(120, 100%, 40%);">+                      status[1] = cpu_to_le16(0);</span><br><span style="color: hsl(120, 100%, 40%);">+                   *data_in = (const uint8_t *) status;</span><br><span style="color: hsl(120, 100%, 40%);">+                  return sizeof(status);</span><br><span style="color: hsl(120, 100%, 40%);">+                case USB_REQ_SET_FEATURE:</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (req->wValue > 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                            return CCID_CTRL_RET_INVALID;</span><br><span style="color: hsl(120, 100%, 40%);">+                 return CCID_CTRL_RET_OK;</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case USB_RT_PORT:</span><br><span style="color: hsl(120, 100%, 40%);">+             switch (req->bRequest) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case USB_REQ_CLEAR_FEATURE:</span><br><span style="color: hsl(120, 100%, 40%);">+                   switch (req->wValue) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     case USB_PORT_FEAT_CONNECTION:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case USB_PORT_FEAT_ENABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+                    case USB_PORT_FEAT_SUSPEND:</span><br><span style="color: hsl(120, 100%, 40%);">+                   case USB_PORT_FEAT_OVER_CURRENT:</span><br><span style="color: hsl(120, 100%, 40%);">+                      case USB_PORT_FEAT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                     case USB_PORT_FEAT_L1:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case USB_PORT_FEAT_POWER:</span><br><span style="color: hsl(120, 100%, 40%);">+                     case USB_PORT_FEAT_LOWSPEED:</span><br><span style="color: hsl(120, 100%, 40%);">+                  case USB_PORT_FEAT_C_CONNECTION:</span><br><span style="color: hsl(120, 100%, 40%);">+                      case USB_PORT_FEAT_C_ENABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+                  case USB_PORT_FEAT_C_SUSPEND:</span><br><span style="color: hsl(120, 100%, 40%);">+                 case USB_PORT_FEAT_C_OVER_CURRENT:</span><br><span style="color: hsl(120, 100%, 40%);">+                    case USB_PORT_FEAT_C_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                   case USB_PORT_FEAT_TEST:</span><br><span style="color: hsl(120, 100%, 40%);">+                      case USB_PORT_FEAT_C_PORT_L1:</span><br><span style="color: hsl(120, 100%, 40%);">+                         return CCID_CTRL_RET_OK;</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case USB_REQ_GET_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+                      status[0] = cpu_to_le16(0);</span><br><span style="color: hsl(120, 100%, 40%);">+                   status[1] = cpu_to_le16(0);</span><br><span style="color: hsl(120, 100%, 40%);">+                   *data_in = (const uint8_t *) status;</span><br><span style="color: hsl(120, 100%, 40%);">+                  return sizeof(status);</span><br><span style="color: hsl(120, 100%, 40%);">+                case USB_REQ_SET_FEATURE:</span><br><span style="color: hsl(120, 100%, 40%);">+                     //selector = wIndex >> 8</span><br><span style="color: hsl(120, 100%, 40%);">+                        //port = wIndex & 0xff</span><br><span style="color: hsl(120, 100%, 40%);">+                    return CCID_CTRL_RET_OK;</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CCID_CTRL_RET_UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_setup(int fd, const struct usb_ctrlrequest *setup)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const uint8_t *data_in = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DUSB, LOGL_NOTICE, "EP0 SETUP bRequestType=0x%02x, bRequest=0x%02x wValue=0x%04x, "</span><br><span style="color: hsl(120, 100%, 40%);">+            "wIndex=0x%04x, wLength=%u\n", setup->bRequestType, setup->bRequest,</span><br><span style="color: hsl(120, 100%, 40%);">+          le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex), le16_to_cpu(setup->wLength));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = hub_handle_ctrl(NULL, (const uint8_t *) setup, &data_in);</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CCID_CTRL_RET_INVALID:</span><br><span style="color: hsl(120, 100%, 40%);">+           if (setup->bRequestType & USB_DIR_IN)</span><br><span style="color: hsl(120, 100%, 40%);">+                  read(fd, NULL, 0); /* cause stall */</span><br><span style="color: hsl(120, 100%, 40%);">+          else</span><br><span style="color: hsl(120, 100%, 40%);">+                  write(fd, NULL, 0); /* cause stall */</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CCID_CTRL_RET_UNKNOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* FIXME: is this correct behavior? */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (setup->bRequestType & USB_DIR_IN)</span><br><span style="color: hsl(120, 100%, 40%);">+                  write(fd, NULL, 0); /* send ZLP */</span><br><span style="color: hsl(120, 100%, 40%);">+            else</span><br><span style="color: hsl(120, 100%, 40%);">+                  read(fd, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              if (setup->bRequestType & USB_DIR_IN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        uint16_t len = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (setup->wLength < len)</span><br><span style="color: hsl(120, 100%, 40%);">+                               len = setup->wLength;</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DUSB, LOGL_NOTICE, "Writing %u: %s\n", len, osmo_hexdump_nospc(data_in, len));</span><br><span style="color: hsl(120, 100%, 40%);">+                 write(fd, data_in, le16_to_cpu(len));</span><br><span style="color: hsl(120, 100%, 40%);">+         } else</span><br><span style="color: hsl(120, 100%, 40%);">+                        read(fd, NULL, 0); /* FIXME: control OUT? */</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ep_0_cb(struct osmo_fd *ofd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ufunc_handle *uh = (struct ufunc_handle *) ofd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (what & BSC_FD_READ) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct usb_functionfs_event evt;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = read(ofd->fd, (uint8_t *)&evt, sizeof(evt));</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc < sizeof(evt))</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -23;</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DUSB, LOGL_NOTICE, "EP0 %s\n", get_value_string(ffs_evt_type_names, evt.type));</span><br><span style="color: hsl(120, 100%, 40%);">+                switch (evt.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case FUNCTIONFS_ENABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+                       //aio_refill_out(uh);</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case FUNCTIONFS_SETUP:</span><br><span style="color: hsl(120, 100%, 40%);">+                        handle_setup(ofd->fd, &evt.u.setup);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef FUNCTIONFS_SUPPORTS_POLL</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* dequeue the next msgb from ep_int_queue and set up AIO for it */</span><br><span style="color: hsl(120, 100%, 40%);">+static void dequeue_aio_write_int(struct ufunc_handle *uh)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct aio_help *ah = &uh->aio_int;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *d;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ah->msg)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     d = msgb_dequeue(&uh->ep_int_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!d)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ah->iocb);</span><br><span style="color: hsl(120, 100%, 40%);">+     ah->msg = d;</span><br><span style="color: hsl(120, 100%, 40%);">+       io_prep_pwrite(ah->iocb, uh->ep_int.fd, msgb_data(d), msgb_length(d), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       io_set_eventfd(ah->iocb, uh->aio_evfd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = io_submit(uh->aio_ctx, 1, &ah->iocb);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int evfd_cb(struct osmo_fd *ofd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ufunc_handle *uh = (struct ufunc_handle *) ofd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct io_event evt[1];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint64_t ev_cnt;</span><br><span style="color: hsl(120, 100%, 40%);">+      int i, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = read(ofd->fd, &ev_cnt, sizeof(ev_cnt));</span><br><span style="color: hsl(120, 100%, 40%);">+   assert(rc == sizeof(ev_cnt));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = io_getevents(uh->aio_ctx, 1, 1, evt, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DUSB, LOGL_ERROR, "error in io_getevents(): %d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < rc; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int fd = evt[i].obj->aio_fildes;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (fd == uh->ep_int.fd) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* interrupt endpoint AIO has completed. This means the IRQ transfer</span><br><span style="color: hsl(120, 100%, 40%);">+                   * which we generated has reached the host */</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGP(DUSB, LOGL_DEBUG, "IRQ AIO completed, free()ing msgb\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                      msgb_free(uh->aio_int.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                        uh->aio_int.msg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                    dequeue_aio_write_int(uh);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ep0_init(struct ufunc_handle *uh)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* open control endpoint and write descriptors to it */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = open("ep0", O_RDWR);</span><br><span style="color: hsl(120, 100%, 40%);">+   assert(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fd_setup(&uh->ep0, rc, BSC_FD_READ, &ep_0_cb, uh, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_register(&uh->ep0);</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = write(uh->ep0.fd, &descriptors, sizeof(descriptors));</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc != sizeof(descriptors)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DUSB, LOGL_ERROR, "Cannot write descriptors: %s\n", strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = write(uh->ep0.fd, &strings, sizeof(strings));</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc != sizeof(strings)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DUSB, LOGL_ERROR, "Cannot write strings: %s\n", strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* open other endpoint file descriptors */</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&uh->ep_int_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = open("ep1", O_RDWR);</span><br><span style="color: hsl(120, 100%, 40%);">+   assert(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fd_setup(&uh->ep_int, rc, 0, &ep_int_cb, uh, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef FUNCTIONFS_SUPPORTS_POLL</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fd_register(&uh->ep_int);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef FUNCTIONFS_SUPPORTS_POLL</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/eventfd.h></span><br><span style="color: hsl(120, 100%, 40%);">+     /* for some absolutely weird reason, gadgetfs+functionfs don't support</span><br><span style="color: hsl(120, 100%, 40%);">+     * the standard methods of non-blocking I/o (select/poll).  We need to</span><br><span style="color: hsl(120, 100%, 40%);">+         * work around using Linux AIO, which is not to be confused with POSIX AIO! */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      memset(&uh->aio_ctx, 0, sizeof(uh->aio_ctx));</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = io_setup(1, &uh->aio_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* create an eventfd, which will be marked readable once some AIO completes */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = eventfd(0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fd_setup(&uh->aio_evfd, rc, BSC_FD_READ, &evfd_cb, uh, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fd_register(&uh->aio_evfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     uh->aio_int.iocb = malloc(sizeof(struct iocb));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct log_info_cat log_info_cat[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   [DUSB] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "USB",</span><br><span style="color: hsl(120, 100%, 40%);">+              .description = "USB Transport",</span><br><span style="color: hsl(120, 100%, 40%);">+             .enabled = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+         .loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct log_info log_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .cat = log_info_cat,</span><br><span style="color: hsl(120, 100%, 40%);">+  .num_cat = ARRAY_SIZE(log_info_cat),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *tall_main_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void signal_handler(int signal)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (signal) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case SIGUSR1:</span><br><span style="color: hsl(120, 100%, 40%);">+         talloc_report_full(tall_main_ctx, stderr);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ufunc_handle ufh = (struct ufunc_handle) { 0, };</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     tall_main_ctx = talloc_named_const(NULL, 0, "hub_main_functionfs");</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_talloc_ctx_init(tall_main_ctx, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_init_logging2(tall_main_ctx, &log_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   signal(SIGUSR1, &signal_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (argc < 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+            fprintf(stderr, "You have to specify the mount-path of the functionfs\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          exit(2);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   chdir(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = ep0_init(&ufh);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "Error %d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+          exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/ccid/hub_remove_gadget.sh b/ccid/hub_remove_gadget.sh</span><br><span>new file mode 100755</span><br><span>index 0000000..e206d6f</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/hub_remove_gadget.sh</span><br><span>@@ -0,0 +1,33 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/bin/bash</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GADGET_NAME=osmo-hub</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GADGET_CONFIGFS=/sys/kernel/config/usb_gadget</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+set -e</span><br><span style="color: hsl(120, 100%, 40%);">+set -x</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+gadgetdir="$GADGET_CONFIGFS/$GADGET_NAME"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# unmount the endpoints from the filesystem</span><br><span style="color: hsl(120, 100%, 40%);">+umount /dev/ffs-hub</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# detach from USB gadget/bus</span><br><span style="color: hsl(120, 100%, 40%);">+echo "" > "$gadgetdir/UDC" || true</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# remove function from config</span><br><span style="color: hsl(120, 100%, 40%);">+rm "$gadgetdir/configs/c.1/ffs.usb0"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# remove strings in config</span><br><span style="color: hsl(120, 100%, 40%);">+rmdir "$gadgetdir/configs/c.1/strings/0x409"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# remove config</span><br><span style="color: hsl(120, 100%, 40%);">+rmdir "$gadgetdir/configs/c.1"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# remove function</span><br><span style="color: hsl(120, 100%, 40%);">+rmdir "$gadgetdir/functions/ffs.usb0"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# remove strings in gadget</span><br><span style="color: hsl(120, 100%, 40%);">+rmdir "$gadgetdir/strings/0x409"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rmdir $gadgetdir</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15499">change 15499</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15499"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ccid-firmware </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ic3d2bec3f55f4d9e13183795c5825723f9427476 </div>
<div style="display:none"> Gerrit-Change-Number: 15499 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>