Add implementation of libhusb_get_config_descriptor()
authorKrzysztof Opasiak <k.opasiak@samsung.com>
Tue, 30 Jun 2015 10:09:14 +0000 (12:09 +0200)
committerKrzysztof Opasiak <k.opasiak@samsung.com>
Tue, 30 Jun 2015 12:10:37 +0000 (14:10 +0200)
Add get and free config descriptor functions implementation

Change-Id: Icb87b9cd0965be9ad724b0c3aedbeeb0bdcb6de7
Signed-off-by: Stanislaw Wadas <s.wadas@samsung.com>
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
src/libhusb.c

index 7ad28ea712700981b0d8e328754a31b991b1b24a..57b39bca71fd2ae49ecc23c83e79e6571364688a 100644 (file)
@@ -36,6 +36,7 @@ struct libhusb_context {
 struct libhusb_device {
        struct uref ref;
        libusb_device *lusb_dev;
+       int refcnt;
 };
 
 static inline struct libhusb_device *to_libhusb_device(struct uref *_uref)
@@ -549,19 +550,238 @@ int libhusb_get_device_descriptor(libhusb_device *dev, struct libhusb_device_des
        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,