struct libhusb_device {
struct uref ref;
libusb_device *lusb_dev;
+ int refcnt;
};
static inline struct libhusb_device *to_libhusb_device(struct uref *_uref)
return descriptor;
}
-int libhusb_get_config_descriptor(libhusb_device *dev, uint8_t config_index,
- struct libhusb_cfg_descriptor **config)
+static void free_ep_desc(struct libhusb_endpoint_descriptor *ep_desc)
{
- int ret = 0;
+ free((void *)ep_desc->extra);
+}
- /* TODO implement */
+static void free_interface_desc(struct libhusb_interface_descriptor *int_desc)
+{
+ int i;
- return ret;
+ free((void *)int_desc->extra);
+
+ for (i = 0; i < int_desc->bNumEndpoints; ++i)
+ free_ep_desc(int_desc->endpoint + i);
+ free(int_desc->endpoint);
+}
+
+static void free_interface(struct libhusb_interface *interface)
+{
+ int i;
+
+ for (i = 0; i < interface->num_altsetting; ++i)
+ free_interface_desc(interface->altsetting + i);
+ free(interface->altsetting);
}
void libhusb_free_config_descriptor(struct libhusb_cfg_descriptor *config)
{
- /* TODO implement */
+ int i;
+
+ free((void *)config->extra);
+
+ for (i = 0; i < config->bNumInterfaces; ++i)
+ free_interface(config->interface + i);
+ free(config->interface);
+
+ free(config);
+}
+
+static int dump_extra(const unsigned char *src, int src_len,
+ const unsigned char **dest, int *dest_len)
+{
+ int ret = LIBHUSB_ERROR_NO_MEM;
+ unsigned char *extra = NULL;
+ int extra_length = 0;
+
+ if (src_len > 0) {
+ extra_length = src_len;
+ extra = malloc(extra_length);
+ if (!extra)
+ goto out;
+
+ memcpy(extra, src, extra_length);
+ }
+
+ *dest = extra;
+ *dest_len = extra_length;
+ ret = 0;
+out:
+ return ret;
+}
+
+static int dump_ep_desc(struct libhusb_endpoint_descriptor *dest,
+ const struct libusb_endpoint_descriptor *src)
+{
+ int ret = LIBHUSB_ERROR_NO_MEM;
+
+#define COPY_FIELD(field) (dest->field = src->field)
+ COPY_FIELD(bLength);
+ COPY_FIELD(bDescriptorType);
+ COPY_FIELD(bEndpointAddress);
+ COPY_FIELD(bmAttributes);
+ COPY_FIELD(wMaxPacketSize);
+ COPY_FIELD(bInterval);
+ COPY_FIELD(bRefresh);
+ COPY_FIELD(bSynchAddress);
+#undef COPY_FIELD
+
+ ret = dump_extra(src->extra, src->extra_length,
+ &(dest->extra), &(dest->extra_length));
+
+ return ret;
+}
+
+static int dump_interface_desc(struct libhusb_interface_descriptor *dest,
+ const struct libusb_interface_descriptor *src)
+{
+ int i;
+ int ret = LIBHUSB_ERROR_NO_MEM;
+ struct libhusb_endpoint_descriptor *eps;
+
+#define COPY_FIELD(field) (dest->field = src->field)
+ COPY_FIELD(bLength);
+ COPY_FIELD(bDescriptorType);
+ COPY_FIELD(bInterfaceNumber);
+ COPY_FIELD(bAlternateSetting);
+ COPY_FIELD(bNumEndpoints);
+ COPY_FIELD(bInterfaceClass);
+ COPY_FIELD(bInterfaceSubClass);
+ COPY_FIELD(bInterfaceProtocol);
+ COPY_FIELD(iInterface);
+#undef COPY_FIELD
+
+ eps = calloc(dest->bNumEndpoints, sizeof(*eps));
+ if (!eps)
+ goto out;
+
+ for (i = 0; i < dest->bNumEndpoints; ++i) {
+ ret = dump_ep_desc(eps + i, src->endpoint + i);
+ if (ret != 0)
+ goto free_eps;
+ }
+
+ ret = dump_extra(src->extra, src->extra_length,
+ &(dest->extra), &(dest->extra_length));
+ if (ret)
+ goto free_eps;
+
+ dest->endpoint = eps;
+
+ return 0;
+
+free_eps:
+ while (--i >= 0)
+ free_ep_desc(eps + i);
+ free(eps);
+out:
+ return ret;
+}
+
+static int dump_interface(struct libhusb_interface *dest,
+ const struct libusb_interface *src)
+{
+ int i;
+ int ret = LIBHUSB_ERROR_NO_MEM;
+ struct libhusb_interface_descriptor *int_descs;
+
+ dest->num_altsetting = src->num_altsetting;
+ int_descs = calloc(dest->num_altsetting, sizeof(*int_descs));
+ if (!int_descs)
+ goto out;
+
+ for (i = 0; i < dest->num_altsetting; ++i) {
+ ret = dump_interface_desc(int_descs + i, src->altsetting + i);
+ if (ret != 0)
+ goto free_int_desc;
+ }
+
+ dest->altsetting = int_descs;
+
+ return 0;
+
+free_int_desc:
+ while (--i <= 0)
+ free_interface_desc(int_descs + i);
+ free(int_descs);
+out:
+ return ret;
+}
+
+static int dump_config_desc(struct libhusb_cfg_descriptor *dest,
+ const struct libusb_config_descriptor *src)
+{
+ int ret = LIBHUSB_ERROR_NO_MEM;
+ int i;
+ struct libhusb_interface *interfaces;
+
+#define COPY_FIELD(field) (dest->field = src->field)
+ COPY_FIELD(bLength);
+ COPY_FIELD(bDescriptorType);
+ COPY_FIELD(wTotalLength);
+ COPY_FIELD(bNumInterfaces);
+ COPY_FIELD(bConfigurationValue);
+ COPY_FIELD(iConfiguration);
+ COPY_FIELD(bmAttributes);
+ COPY_FIELD(MaxPower);
+#undef COPY_FIELD
+
+ interfaces = calloc(dest->bNumInterfaces, sizeof(*interfaces));
+ if (!interfaces)
+ goto out;
+
+ for (i = 0; i < dest->bNumInterfaces; ++i) {
+ ret = dump_interface(interfaces + i, src->interface + i);
+ if (ret != 0)
+ goto free_interfaces;
+ }
+
+ ret = dump_extra(src->extra, src->extra_length,
+ &(dest->extra), &(dest->extra_length));
+ if (ret)
+ goto free_interfaces;
+
+ dest->interface = interfaces;
+
+ return 0;
+
+free_interfaces:
+ while (--i >= 0)
+ free_interface(interfaces + i);
+ free(interfaces);
+out:
+ return ret;
+}
+
+int libhusb_get_config_descriptor(libhusb_device *dev, uint8_t config_index,
+ struct libhusb_cfg_descriptor **config)
+{
+ int ret;
+ struct libusb_config_descriptor *lcfg_desc;
+ struct libhusb_cfg_descriptor *cfg_desc;
+
+ ret = libusb_get_config_descriptor(dev->lusb_dev,
+ config_index, &lcfg_desc);
+ if (ret < 0) {
+ ret = translate_error(ret);
+ goto out;
+ }
+
+ cfg_desc = malloc(sizeof(*cfg_desc));
+ if (!cfg_desc) {
+ ret = LIBHUSB_ERROR_NO_MEM;
+ goto free_lcfg_desc;
+ }
+
+ ret = dump_config_desc(cfg_desc, lcfg_desc);
+ if (ret != 0)
+ free(cfg_desc);
+
+free_lcfg_desc:
+ libusb_free_config_descriptor(lcfg_desc);
+out:
+ return ret;
}
int libhusb_get_string_descriptor_ascii(libhusb_device_handle *handle,