<p>laforge <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15499">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
laforge: Looks good to me, approved
</div><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;"><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-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>