On Thu, 2009-01-29 at 00:17 +0100, Tadas Dailyda wrote:
<snip>
> It is also possible to just fork USB interface discovery code from
> openobex to ods. That way we wouldn't break openobex API and ods
> wouldn't have to depend on very recent openobex version (furthermore,
> nobody knows when it would be released anyway).
Using the same code as openobex for the device discovery, and fixing a
few memleaks in the process.
Patch for obex-data-server attached.
Cheers
Index: configure.in
===================================================================
--- configure.in (revision 2477)
+++ configure.in (working copy)
@@ -152,7 +152,7 @@
AC_SUBST(BLUEZ_LIBS)
AC_CHECK_LIB(bluetooth, sdp_extract_seqtype_safe, AC_DEFINE(USE_BLUEZ3FUNCS, [], [We are using Bluez 3.x]))
-PKG_CHECK_MODULES(OPENOBEX, openobex >= $OPENOBEX_REQUIRED)
+PKG_CHECK_MODULES(OPENOBEX, openobex >= $OPENOBEX_REQUIRED libusb)
AC_SUBST(OPENOBEX_CFLAGS)
AC_SUBST(OPENOBEX_LIBS)
Index: src/ods-usb.c
===================================================================
--- src/ods-usb.c (revision 0)
+++ src/ods-usb.c (revision 0)
@@ -0,0 +1,387 @@
+#include <stdio.h> /* perror */
+#include <errno.h> /* errno and EADDRNOTAVAIL */
+#include <string.h>
+#include <usb.h>
+
+#include "ods-usb.h"
+
+#define DEBUG(x...)
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X
+ * used to find data/slave OBEX interface */
+#pragma pack(1)
+struct cdc_union_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+
+ uint8_t bMasterInterface0;
+ uint8_t bSlaveInterface0;
+};
+#pragma pack()
+
+/* CDC class and subclass types */
+#define USB_CDC_CLASS 0x02
+#define USB_CDC_OBEX_SUBCLASS 0x0b
+
+/* class and subclass specific descriptor types */
+#define CDC_HEADER_TYPE 0x00
+#define CDC_CALL_MANAGEMENT_TYPE 0x01
+#define CDC_AC_MANAGEMENT_TYPE 0x02
+#define CDC_UNION_TYPE 0x06
+#define CDC_COUNTRY_TYPE 0x07
+#define CDC_OBEX_TYPE 0x15
+#define CDC_OBEX_SERVICE_ID_TYPE 0x19
+
+/* Interface descriptor */
+#define USB_DT_CS_INTERFACE 0x24
+#define CDC_DATA_INTERFACE_TYPE 0x0a
+
+#define WMC_DEFAULT_OBEX_SERVER_UUID \
+{ 0x02, 0xae, 0xb3, 0x20, \
+0xf6, 0x49, 0x11, 0xda, \
+0x97, 0x4d, 0x08, 0x00, \
+0x20, 0x0c, 0x9a, 0x66 }
+
+#define USB_MAX_STRING_SIZE 256
+#define USB_OBEX_TIMEOUT 10000 /* 10 seconds */
+
+/*
+ * Helper function to usbobex_find_interfaces
+ */
+static void find_eps(struct obex_usb_intf_transport_t *intf, struct usb_interface_descriptor data_intf, int *found_active, int *found_idle)
+{
+ struct usb_endpoint_descriptor *ep0, *ep1;
+
+ if (data_intf.bNumEndpoints == 2) {
+ ep0 = data_intf.endpoint;
+ ep1 = data_intf.endpoint + 1;
+ if ((ep0->bEndpointAddress & USB_ENDPOINT_IN) &&
+ ((ep0->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
+ !(ep1->bEndpointAddress & USB_ENDPOINT_IN) &&
+ ((ep1->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)) {
+ *found_active = 1;
+ intf->data_active_setting = data_intf.bAlternateSetting;
+ intf->data_interface_active_description = data_intf.iInterface;
+ intf->data_endpoint_read = ep0->bEndpointAddress;
+ intf->data_endpoint_write = ep1->bEndpointAddress;
+ }
+ if (!(ep0->bEndpointAddress & USB_ENDPOINT_IN) &&
+ ((ep0->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
+ (ep1->bEndpointAddress & USB_ENDPOINT_IN) &&
+ ((ep1->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)) {
+ *found_active = 1;
+ intf->data_active_setting = data_intf.bAlternateSetting;
+ intf->data_interface_active_description = data_intf.iInterface;
+ intf->data_endpoint_read = ep1->bEndpointAddress;
+ intf->data_endpoint_write = ep0->bEndpointAddress;
+ }
+ }
+ if (data_intf.bNumEndpoints == 0) {
+ *found_idle = 1;
+ intf->data_idle_setting = data_intf.bAlternateSetting;
+ intf->data_interface_idle_description = data_intf.iInterface;
+ }
+}
+
+/*
+ * Helper function to usbobex_find_interfaces
+ */
+static int find_obex_data_interface(unsigned char *buffer, int buflen, struct usb_config_descriptor config, struct obex_usb_intf_transport_t *intf)
+{
+ struct cdc_union_desc *union_header = NULL;
+ int i, a;
+ int found_active = 0;
+ int found_idle = 0;
+
+ if (!buffer) {
+ DEBUG(2,"Weird descriptor references");
+ return -EINVAL;
+ }
+
+ while (buflen > 0) {
+ if (buffer [1] != USB_DT_CS_INTERFACE) {
+ DEBUG(2,"skipping garbage");
+ goto next_desc;
+ }
+ switch (buffer [2]) {
+ case CDC_UNION_TYPE: /* we've found it */
+ if (union_header) {
+ DEBUG(2,"More than one union descriptor, skiping ...");
+ goto next_desc;
+ }
+ union_header = (struct cdc_union_desc *)buffer;
+ break;
+ case CDC_OBEX_TYPE: /* maybe check version */
+ case CDC_OBEX_SERVICE_ID_TYPE: /* This one is handled later */
+ case CDC_HEADER_TYPE:
+ break; /* for now we ignore it */
+ default:
+ DEBUG(2, "Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
+ break;
+ }
+next_desc:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (!union_header) {
+ DEBUG(2,"No union descriptor, giving up\n");
+ return -ENODEV;
+ }
+ /* Found the slave interface, now find active/idle settings and endpoints */
+ intf->data_interface = union_header->bSlaveInterface0;
+ /* Loop through all of the interfaces */
+ for (i = 0; i < config.bNumInterfaces; i++) {
+ /* Loop through all of the alternate settings */
+ for (a = 0; a < config.interface[i].num_altsetting; a++) {
+ /* Check if this interface is OBEX data interface*/
+ /* and find endpoints */
+ if (config.interface[i].altsetting[a].bInterfaceNumber == intf->data_interface)
+ find_eps(intf, config.interface[i].altsetting[a], &found_active, &found_idle);
+ }
+ }
+ if (!found_idle) {
+ DEBUG(2,"No idle setting\n");
+ return -ENODEV;
+ }
+ if (!found_active) {
+ DEBUG(2,"No active setting\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Helper function to usbobex_find_interfaces
+ */
+static int get_intf_string(struct usb_dev_handle *usb_handle, char **string, int id)
+{
+ if (id) {
+ if ((*string = malloc(USB_MAX_STRING_SIZE)) == NULL)
+ return -ENOMEM;
+ *string[0] = '\0';
+ return usb_get_string_simple(usb_handle, id, *string, USB_MAX_STRING_SIZE);
+ }
+
+ return 0;
+}
+
+/*
+ * Helper function to usbobex_find_interfaces
+ */
+static struct obex_usb_intf_transport_t *check_intf(struct usb_device *dev,
+ int c, int i, int a,
+ char *bus, char *device,
+ struct obex_usb_intf_transport_t *current)
+{
+ struct obex_usb_intf_transport_t *next = NULL;
+
+ if ((dev->config[c].interface[i].altsetting[a].bInterfaceClass == USB_CDC_CLASS)
+ && (dev->config[c].interface[i].altsetting[a].bInterfaceSubClass == USB_CDC_OBEX_SUBCLASS)) {
+ int err;
+ unsigned char *buffer = dev->config[c].interface[i].altsetting[a].extra;
+ int buflen = dev->config[c].interface[i].altsetting[a].extralen;
+
+ next = malloc(sizeof(struct obex_usb_intf_transport_t));
+ if (next == NULL)
+ return current;
+ next->device = dev;
+ next->configuration = dev->config[c].bConfigurationValue;
+ next->configuration_description = dev->config[c].iConfiguration;
+ next->control_interface = dev->config[c].interface[i].altsetting[a].bInterfaceNumber;
+ next->control_interface_description = dev->config[c].interface[i].altsetting[a].iInterface;
+ next->control_setting = dev->config[c].interface[i].altsetting[a].bAlternateSetting;
+ next->extra_descriptors = buffer;
+ next->extra_descriptors_len = buflen;
+
+ err = find_obex_data_interface(buffer, buflen, dev->config[c], next);
+ if (err)
+ free(next);
+ else {
+ char path[200], *s, *shortdev;
+
+ /* On MacOS X we might get 002-04a9-3139-00-00 instead of 002 for the dev. */
+ shortdev = strdup (device);
+ s = strchr(shortdev, '-');
+ if (s)
+ *s='\0';
+
+ /* Create the usb: path for the device */
+ snprintf (path, sizeof(path), "usb:%s,%s,%d", bus, shortdev, dev->config[c].interface[i].altsetting[a].bInterfaceNumber);
+ free (shortdev);
+ next->path = strdup (path);
+
+ if (current)
+ current->next = next;
+ next->prev = current;
+ next->next = NULL;
+ current = next;
+ }
+ }
+
+ return current;
+}
+
+/*
+ * Helper function to usbobex_find_interfaces
+ */
+static void find_obex_service_descriptor(unsigned char *buffer, int buflen, obex_usb_intf_service_t **service)
+{
+ if (!buffer) {
+ DEBUG(2, "Weird descriptor references");
+ return ;
+ }
+ while (buflen > 0) {
+ if (buffer[1] != USB_DT_CS_INTERFACE) {
+ DEBUG(2, "skipping garbage");
+ goto next_desc;
+ }
+ switch (buffer[2]) {
+ case CDC_OBEX_SERVICE_ID_TYPE: /* we've found it */
+ if (buflen < 22) /* Check descriptor size */
+ DEBUG(2, "Invalid service id descriptor");
+ else if (*service == NULL) {
+ *service = malloc(sizeof(obex_usb_intf_service_t));
+ if (*service != NULL) {
+ const uint8_t default_uuid[16] = WMC_DEFAULT_OBEX_SERVER_UUID;
+ (*service)->role = buffer[3];
+ memcpy((*service)->uuid, buffer+4, 16);
+ (*service)->version = (buffer[20]<<8)|(buffer[21]);
+ if (memcmp((*service)->uuid, default_uuid, 16) == 0 )
+ (*service)->is_default_uuid = 1;
+ else
+ (*service)->is_default_uuid = 0;
+ }
+ }
+ break;
+ case CDC_OBEX_TYPE: /* maybe check version */
+ case CDC_UNION_TYPE:
+ case CDC_HEADER_TYPE:
+ break;
+ default:
+ DEBUG(2, "Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
+ break;
+ }
+next_desc:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+}
+
+
+/*
+ * Function usbobex_find_interfaces ()
+ *
+ * Find available USBOBEX interfaces on the system
+ */
+int ods_usbobex_find_interfaces(obex_interface_t **interfaces)
+{
+ struct usb_bus *busses;
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ int c, i, a, num;
+ struct obex_usb_intf_transport_t *current = NULL;
+ struct obex_usb_intf_transport_t *tmp = NULL;
+ obex_interface_t *intf_array = NULL;
+ struct usb_dev_handle *usb_handle;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ busses = usb_get_busses();
+
+ for (bus = busses; bus; bus = bus->next) {
+ for (dev = bus->devices; dev; dev = dev->next) {
+ /* Loop through all of the configurations */
+ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+ /* Loop through all of the interfaces */
+ for (i = 0; i < dev->config[c].bNumInterfaces; i++) {
+ /* Loop through all of the alternate settings */
+ for (a = 0; a < dev->config[c].interface[i].num_altsetting; a++) {
+ /* Check if this interface is OBEX */
+ /* and find data interface */
+ current = check_intf(dev, c, i, a, bus->dirname, dev->filename, current);
+ }
+ }
+ }
+ }
+ }
+ num = 0;
+ if (current)
+ num++;
+ while (current && current->prev) {
+ current = current->prev;
+ num++;
+ }
+ intf_array = malloc(sizeof(obex_interface_t) * num);
+ if (intf_array == NULL)
+ goto cleanup_list;
+ memset(intf_array, 0, sizeof(obex_interface_t) * num);
+ num = 0;
+ while (current) {
+ intf_array[num].usb.intf = current;
+ usb_handle = usb_open(current->device);
+ get_intf_string(usb_handle, &intf_array[num].usb.manufacturer,
+ current->device->descriptor.iManufacturer);
+ get_intf_string(usb_handle, &intf_array[num].usb.product,
+ current->device->descriptor.iProduct);
+ get_intf_string(usb_handle, &intf_array[num].usb.serial,
+ current->device->descriptor.iSerialNumber);
+ get_intf_string(usb_handle, &intf_array[num].usb.configuration,
+ current->configuration_description);
+ get_intf_string(usb_handle, &intf_array[num].usb.control_interface,
+ current->control_interface_description);
+ get_intf_string(usb_handle, &intf_array[num].usb.data_interface_idle,
+ current->data_interface_idle_description);
+ get_intf_string(usb_handle, &intf_array[num].usb.data_interface_active,
+ current->data_interface_active_description);
+ intf_array[num].usb.path = current->path;
+ find_obex_service_descriptor(current->extra_descriptors,
+ current->extra_descriptors_len,
+ &intf_array[num].usb.service);
+ usb_close(usb_handle);
+ current = current->next; num++;
+ }
+ *interfaces = intf_array;
+ return num;
+
+cleanup_list:
+ while (current) {
+ tmp = current->next;
+ free(current);
+ current = tmp;
+ }
+ return 0;
+}
+
+/*
+ * Function usbobex_free_interfaces ()
+ *
+ * Free the list of discovered USBOBEX interfaces on the system
+ */
+void ods_usbobex_free_interfaces(int num, obex_interface_t *intf)
+{
+ int i;
+
+ if (intf == NULL)
+ return;
+
+ for (i = 0; i < num; i++) {
+ free(intf[i].usb.manufacturer);
+ free(intf[i].usb.product);
+ free(intf[i].usb.serial);
+ free(intf[i].usb.configuration);
+ free(intf[i].usb.control_interface);
+ free(intf[i].usb.data_interface_idle);
+ free(intf[i].usb.data_interface_active);
+ free(intf[i].usb.service);
+ free(intf[i].usb.path);
+ free(intf[i].usb.intf);
+ }
+
+ free(intf);
+}
+
Index: src/ods-usb.h
===================================================================
--- src/ods-usb.h (revision 0)
+++ src/ods-usb.h (revision 0)
@@ -0,0 +1,35 @@
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+#include <usb.h>
+
+/* Information about a USB OBEX interface present on the system */
+struct obex_usb_intf_transport_t {
+ struct obex_usb_intf_transport_t *prev, *next; /* Next and previous interfaces in the list */
+ struct usb_device *device; /* USB device that has the interface */
+ int configuration; /* Device configuration */
+ int configuration_description; /* Configuration string descriptor number */
+ int control_interface; /* OBEX master interface */
+ int control_setting; /* OBEX master interface setting */
+ int control_interface_description; /* OBEX master interface string descriptor number
+ * If non-zero, use usb_get_string_simple() from
+ * libusb to retrieve human-readable description
+ */
+ unsigned char *extra_descriptors; /* Extra master interface descriptors */
+ int extra_descriptors_len; /* Length of extra descriptors */
+ int data_interface; /* OBEX data/slave interface */
+ int data_idle_setting; /* OBEX data/slave idle setting */
+ int data_interface_idle_description; /* OBEX data/slave interface string descriptor number
+ * in idle setting */
+ int data_active_setting; /* OBEX data/slave active setting */
+ int data_interface_active_description; /* OBEX data/slave interface string descriptor number
+ * in active setting */
+ int data_endpoint_read; /* OBEX data/slave interface read endpoint */
+ int data_endpoint_write; /* OBEX data/slave interface write endpoint */
+ usb_dev_handle *dev_control; /* libusb handler for control interace */
+ usb_dev_handle *dev_data; /* libusb handler for data interface */
+ char *path; /* Path, see path in obex_usb_intf_t */
+};
+
+
+void ods_usbobex_free_interfaces(int num, obex_interface_t *intf);
+int ods_usbobex_find_interfaces(obex_interface_t **interfaces);
Index: src/ods-manager.c
===================================================================
--- src/ods-manager.c (revision 2477)
+++ src/ods-manager.c (working copy)
@@ -49,6 +49,7 @@
#include "ods-session.h"
#include "ods-marshal.h"
#include "ods-manager.h"
+#include "ods-usb.h"
#include "ods-manager-dbus-glue.h"
#define ODS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ODS_TYPE_MANAGER, OdsManagerPrivate))
@@ -821,10 +822,6 @@
return ret;
}
-static void ods_manager_dummy_obex_event(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp)
-{
-}
-
/**
* ods_manager_get_usb_interfaces_num:
* @manager: This class instance
@@ -836,21 +833,19 @@
guint
ods_manager_get_usb_interfaces_num (OdsManager *manager)
{
- obex_t *handle;
obex_interface_t* obex_intf;
guint num_interfaces;
- if(!(handle = OBEX_Init(OBEX_TRANS_USB, ods_manager_dummy_obex_event, 0))) {
- g_warning("%s() OBEX_Init failed\n", __func__);
- return 0;
- }
- num_interfaces = OBEX_FindInterfaces(handle, &obex_intf);
- OBEX_Cleanup(handle);
+ num_interfaces = ods_usbobex_find_interfaces(&obex_intf);
+ ods_usbobex_free_interfaces (num_interfaces, obex_intf);
+
+ g_message ("num interfaces: %d", num_interfaces);
+
return num_interfaces;
}
/**
- * ods_manager_get_usb_interfaces_num:
+ * ods_manager_get_usb_interfaces_info:
* @manager: This class instance
* @interface_number: the number of interface to return information about
*
@@ -861,21 +856,15 @@
GHashTable *
ods_manager_get_usb_interface_info (OdsManager *manager, const gint interface_number)
{
- obex_t *handle;
obex_interface_t* obex_intf;
int interfaces_number;
GHashTable *info;
- info = g_hash_table_new ((GHashFunc)g_str_hash, (GEqualFunc)g_str_equal);
+ info = g_hash_table_new_full ((GHashFunc)g_str_hash, (GEqualFunc)g_str_equal, NULL, (GDestroyNotify) g_free);
- if(!(handle = OBEX_Init(OBEX_TRANS_USB, ods_manager_dummy_obex_event, 0))) {
- g_warning("%s() OBEX_Init failed\n", __func__);
- return info;
- }
- interfaces_number = OBEX_FindInterfaces(handle, &obex_intf);
+ interfaces_number = ods_usbobex_find_interfaces(&obex_intf);
if (interfaces_number <= interface_number) {
g_warning("%d USB interfaces, requested interface %d info\n", interfaces_number, interface_number);
- OBEX_Cleanup(handle);
return info;
}
@@ -893,8 +882,11 @@
g_strdup (obex_intf[interface_number].usb.data_interface_idle));
g_hash_table_insert (info, "DataInterfaceActive",
g_strdup (obex_intf[interface_number].usb.data_interface_active));
- OBEX_Cleanup(handle);
-
+ g_hash_table_insert (info, "Path",
+ g_strdup (obex_intf[interface_number].usb.path));
+
+ ods_usbobex_free_interfaces (interfaces_number, obex_intf);
+
return info;
}
Index: src/Makefile.am
===================================================================
--- src/Makefile.am (revision 2477)
+++ src/Makefile.am (working copy)
@@ -19,6 +19,8 @@
obex_data_server_SOURCES = \
ods-bluez.h \
ods-bluez.c \
+ ods-usb.c \
+ ods-usb.h \
ods-capabilities.h \
ods-capabilities.c \
ods-common.h \
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Openobex-users mailing list
Openobex-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/openobex-users