On Fri, 11 Feb 2005, Marcel Holtmann wrote:

> This was the first look through your code. You should really make sure
> that everything is still working when USB support is not compiled in. I
> think it is a good idea to break your patch up a little bit. One patch
> that adds usbobex.[ch] and the other one for the needed changes in the
> main files.

Hi Marcel,

I have (hopefully) fixed all the problems that you've mentioned (and for 
those that I didn't, the explanations follow). I tried both gcc 3.4, and 
egcs 1.1.2, with and without compiling in USB support - seems to work 
fine.

1. Why is there a whole new structure for usb obex interfaces in a public
header file?

In order to connect to a specific USB OBEX interface with libusb, you need
plenty of data: usb device structure pointer, configuration value, control
and data interface numbers and interface setting numbers for each,
endpoints and so on. It made perfect sense to me to unite all of this in a
structure and make applications pass a pointer to that structure in the
connect function:

int UsbOBEX_TransportConnect(obex_t *self, struct usb_obex_intf*
interface)

There's also an interface discovery function which returns a list of those
interfaces, so that applications wouldn't have to do the discovery
themselves - it's not a trivial thing at all:

struct usb_obex_intf* UsbOBEX_GetInterfaces(obex_t *self)

An example of how this all works from an application's point of view is
provided in obex_test patch.

An even better approach would be to move all transport-specific data 
definitions to a separate obex_transport.h file and replace all the 
various *_TransportConnect functions with a unified one:

int OBEX_TransportConnect(obex_t *self, struct obex_transport* transport)

2. Why +#define OBEX_DEFAULT_MTU_USB 0xffff?

Because USB is fast, and it makes sense to set the MTU to the maximum and
then lower it if the phone says so in its CONNECT response - openobex does
this automatically. Nokia 6630 returns 0xffff MTU, 7610 suggests
4000 bytes MTU (and won't work with anything less, btw), and it's all
totally transparent to the application.

So here's the new version of the patch, first the part that adds usbobex.c 
and .h.

-- 
Alexander

Homepage: http://www.sensi.org/~ak/
 
diff -uNr -x configure -x aclocal.m4 -x autom4te.cache -x 'config.*' -x depcomp 
-x doc -x INSTALL -x install-sh -x libtool -x ltmain.sh -x m4macros -x Makefile 
-x Makefile.in -x missing -x mkinstalldirs -x '*.lo' -x '*.Plo' -x '*.la*' -x 
.libs -x 'stamp*' -x CVS -x '*.o' -x openobex-config lib/src/usbobex.c 
lib-usb/src/usbobex.c
--- lib/src/usbobex.c   1970-01-01 02:00:00.000000000 +0200
+++ lib-usb/src/usbobex.c       2005-02-23 22:48:24.000000000 +0200
@@ -0,0 +1,344 @@
+/*************************************<********************************
+ *                
+ * Filename:      usbobex.c
+ * Version:       0.1
+ * Description:   USB OBEX, USB transport for OBEX
+ * Status:        Experimental.
+ * Author:        Alex Kanavin <[EMAIL PROTECTED]>
+ * 
+ *     Copyright (c) 2005 Alex Kanavin, All Rights Reserved.
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU Lesser General Public
+ *     License as published by the Free Software Foundation; either
+ *     version 2 of the License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     Lesser General Public License for more details.
+ *
+ *     You should have received a copy of the GNU Lesser General Public
+ *     License along with this library; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA  02111-1307  USA
+ *     
+ ********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_USB
+
+/* Linux case */
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>             /* perror */
+#include <errno.h>             /* errno and EADDRNOTAVAIL */
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <usb.h>
+
+#include <obex_main.h>
+#include <usbobex.h>
+
+
+/*
+ * Function usbobex_prepare_connect (self, interface)
+ *
+ *    Prepare for USB OBEX connect
+ *
+ */
+void usbobex_prepare_connect(obex_t *self, struct usb_obex_intf *intf)
+{
+#ifndef _WIN32
+       self->trans.self.usb.interface = intf;
+#endif /* _WIN32 */
+}
+
+/*
+ * Function usbobex_find_interfaces ()
+ *
+ *    Find available USBOBEX interfaces on the system
+ */
+struct usb_obex_intf* usbobex_find_interfaces()
+{
+       struct usb_bus *busses;
+       struct usb_bus *bus;
+       struct usb_device *dev;
+       int c, i, a;
+       struct usb_obex_intf *current = NULL;
+ 
+       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, current);
+                                       }
+                               }
+                       }
+               }
+       }
+       while (current && current->prev)
+               current = current->prev;
+       return current;
+}
+
+/*
+ * Helper function to usbobex_find_interfaces 
+ */
+struct usb_obex_intf* check_intf(struct usb_device* dev, int c, int i, int a, 
struct usb_obex_intf* current)
+{
+       struct usb_obex_intf *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 usb_obex_intf));
+               if (next == NULL)
+                       return current;
+               next->device = dev;
+               next->configuration = dev->config[c].bConfigurationValue;
+               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;
+
+               err = find_obex_data_interface(buffer, buflen, dev->config[c], 
next);
+               if (err)
+                       free(next);
+               else {
+                       if (current)
+                               current->next = next;
+                       next->prev = current;
+                       next->next = NULL;
+                       current = next;
+               }
+       }
+       return current;
+}
+
+/*
+ * Helper function to usbobex_find_interfaces 
+ */
+int find_obex_data_interface(unsigned char* buffer, int buflen, struct 
usb_config_descriptor config, struct usb_obex_intf* 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_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 
+ */
+void find_eps(struct usb_obex_intf* 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;
+       }
+}
+
+
+/*
+ * Function usbobex_connect_request (self)
+ *
+ *    Open the USB connection
+ *
+ */
+int usbobex_connect_request(obex_t *self)
+{
+       int ret;
+#ifndef _WIN32
+       int mtu = 0;
+       //int len = sizeof(int);
+
+       DEBUG(4, "\n");
+
+       self->trans.self.usb.dev_control = 
usb_open(self->trans.self.usb.interface->device);
+       self->trans.self.usb.dev_data = 
usb_open(self->trans.self.usb.interface->device);
+
+       ret = usb_claim_interface(self->trans.self.usb.dev_control, 
self->trans.self.usb.interface->control_interface);
+       if (ret < 0) {
+               DEBUG(4, "Can't claim control interface %d", ret);
+               return ret;
+       }
+
+       ret = usb_claim_interface(self->trans.self.usb.dev_data, 
self->trans.self.usb.interface->data_interface);
+       if (ret < 0) {
+               DEBUG(4, "Can't claim data interface %d", ret);
+               usb_release_interface(self->trans.self.usb.dev_control, 
self->trans.self.usb.interface->control_interface);
+               return ret;
+       }
+
+       ret = usb_set_configuration(self->trans.self.usb.dev_control, 
self->trans.self.usb.interface->configuration);
+       if (ret < 0) {
+               DEBUG(4, "Can't set configuration %d", ret);
+               goto err;
+       }
+       
+       ret = usb_set_altinterface(self->trans.self.usb.dev_control, 
self->trans.self.usb.interface->control_setting);
+       if (ret < 0) {
+               DEBUG(4, "Can't set control setting %d", ret);
+               goto err;
+       }
+
+       ret = usb_set_altinterface(self->trans.self.usb.dev_data, 
self->trans.self.usb.interface->data_active_setting);
+       if (ret < 0) {
+               DEBUG(4, "Can't set data active setting %d", ret);
+               goto err;
+       }
+
+       mtu = OBEX_DEFAULT_MTU_USB;
+       self->trans.mtu = mtu;
+
+       DEBUG(2, "transport mtu=%d\n", mtu);
+
+       return 1;
+
+err:
+       usb_release_interface(self->trans.self.usb.dev_data, 
self->trans.self.usb.interface->data_interface);   
+       usb_release_interface(self->trans.self.usb.dev_control, 
self->trans.self.usb.interface->control_interface);
+       return ret;
+
+#endif /* _WIN32 */
+}
+
+/*
+ * Function usbobex_link_disconnect_request (self)
+ *
+ *    Shutdown the USB link
+ *
+ */
+int usbobex_disconnect_request(obex_t *self)
+{
+       int ret;
+#ifndef _WIN32
+       DEBUG(4, "\n");
+       if (!self->trans.self.usb.interface)
+               return 0;
+       ret = usb_set_altinterface(self->trans.self.usb.dev_data, 
self->trans.self.usb.interface->data_idle_setting);;
+       if (ret < 0)
+               DEBUG(4, "Can't set data idle setting %d", ret);
+       ret = usb_release_interface(self->trans.self.usb.dev_data, 
self->trans.self.usb.interface->data_interface);
+       if (ret < 0) 
+               DEBUG(4, "Can't release data interface %d", ret);
+       ret = usb_release_interface(self->trans.self.usb.dev_control, 
self->trans.self.usb.interface->control_interface);
+       if (ret < 0) 
+               DEBUG(4, "Can't release control interface %d", ret);
+       ret = usb_close(self->trans.self.usb.dev_data);
+       if (ret < 0)
+               DEBUG(4, "Can't close data interface %d", ret);
+       ret = usb_close(self->trans.self.usb.dev_control);
+       if (ret < 0)
+               DEBUG(4, "Can't close control interface %d", ret);
+
+#endif /* _WIN32 */
+       return ret;     
+}
+
+
+#endif /* HAVE_BLUETOOTH */
diff -uNr -x configure -x aclocal.m4 -x autom4te.cache -x 'config.*' -x depcomp 
-x doc -x INSTALL -x install-sh -x libtool -x ltmain.sh -x m4macros -x Makefile 
-x Makefile.in -x missing -x mkinstalldirs -x '*.lo' -x '*.Plo' -x '*.la*' -x 
.libs -x 'stamp*' -x CVS -x '*.o' -x openobex-config lib/src/usbobex.h 
lib-usb/src/usbobex.h
--- lib/src/usbobex.h   1970-01-01 02:00:00.000000000 +0200
+++ lib-usb/src/usbobex.h       2005-02-22 00:45:39.000000000 +0200
@@ -0,0 +1,75 @@
+/*********************************************************************
+ *                
+ * Filename:      usbobex.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Alex Kanavin <[EMAIL PROTECTED]>
+ * 
+ *     Copyright (c) 2005 Alex Kanavin, All Rights Reserved.
+ *     
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU Lesser General Public
+ *     License as published by the Free Software Foundation; either
+ *     version 2 of the License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     Lesser General Public License for more details.
+ *
+ *     You should have received a copy of the GNU Lesser General Public
+ *     License along with this library; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA  02111-1307  USA
+ *     
+ ********************************************************************/
+
+#ifndef USBOBEX_H
+#define USBOBEX_H
+
+#include "obex_const.h"
+#include "usb.h"
+
+struct addr_usb {
+       struct usb_obex_intf* interface;
+       usb_dev_handle* dev_control;
+       usb_dev_handle* dev_data;
+};
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X
+ * used to find data/slave OBEX interface */
+struct cdc_union_desc {
+       u_int8_t      bLength;
+       u_int8_t      bDescriptorType;
+       u_int8_t      bDescriptorSubType;
+
+       u_int8_t      bMasterInterface0;
+       u_int8_t      bSlaveInterface0;
+} __attribute__ ((packed));
+
+/* 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
+
+/* Interface descriptor */
+#define USB_DT_CS_INTERFACE            0x24
+#define CDC_DATA_INTERFACE_TYPE                0x0a
+
+
+void usbobex_prepare_connect(obex_t *self, struct usb_obex_intf* intf);
+int usbobex_connect_request(obex_t *self);
+int usbobex_disconnect_request(obex_t *self);
+struct usb_obex_intf* usbobex_find_interfaces();
+int find_obex_data_interface(unsigned char* buffer, int buflen, struct 
usb_config_descriptor config, struct usb_obex_intf* intf);
+struct usb_obex_intf* check_intf(struct usb_device* dev, int c, int i, int a, 
struct usb_obex_intf* current);
+void find_eps(struct usb_obex_intf* intf, struct usb_interface_descriptor 
data_intf, int* found_active, int* found_idle);
+#endif



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to