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

Reply via email to