diff -uNr -X patchignore.txt openobex/apps/ChangeLog openobex-usb/apps/ChangeLog --- openobex/apps/ChangeLog 2002-11-15 11:49:12.000000000 +0200 +++ openobex-usb/apps/ChangeLog 2005-12-03 12:55:40.000000000 +0200 @@ -1,3 +1,7 @@ +2005-08-30 Alex Kanavin + + * Add client-side USB support and interface discovery + 2002-11-15 Marcel Holtmann * Add Bluetooth server support diff -uNr -X patchignore.txt openobex/apps/src/obex_test.c openobex-usb/apps/src/obex_test.c --- openobex/apps/src/obex_test.c 2002-11-15 23:18:29.000000000 +0200 +++ openobex-usb/apps/src/obex_test.c 2005-12-18 23:08:22.000000000 +0200 @@ -155,13 +155,15 @@ { char cmd[10]; int end = 0; - int cobex = FALSE, tcpobex = FALSE, btobex = FALSE, r320 = FALSE; + int cobex = FALSE, tcpobex = FALSE, btobex = FALSE, r320 = FALSE, usbobex = FALSE; obex_t *handle; #ifdef HAVE_BLUETOOTH bdaddr_t bdaddr; uint8_t channel; #endif + obex_interface_t *obex_intf; + struct context global_context = {0,}; #ifndef _WIN32 @@ -181,7 +183,8 @@ tcpobex = TRUE; if( (argc >= 2) && (strcmp(argv[1], "-b") == 0 ) ) btobex = TRUE; - + if( (argc >= 2) && (strcmp(argv[1], "-u") == 0 ) ) + usbobex = TRUE; if(cobex) { #ifndef _WIN32 @@ -262,6 +265,46 @@ printf("Not implemented in Win32 yet.\n"); #endif // _WIN32 } + else if(usbobex) { + int i, interfaces_number, intf_num; + switch (argc) { + case 2: + printf("Using USB transport, querying available interfaces\n"); + if(! (handle = OBEX_Init(OBEX_TRANS_USB, obex_event, 0))) { + perror( "OBEX_Init failed"); + exit(0); + } + interfaces_number = OBEX_FindInterfaces(handle, &obex_intf); + for (i=0; i < interfaces_number; i++) + printf("Interface %d: %s %s %s\n", i, + obex_intf[i].usb.manufacturer, + obex_intf[i].usb.product, + obex_intf[i].usb.control_interface); + printf("Use '%s -u interface_number' to run interactive OBEX test client\n", argv[0]); + OBEX_Cleanup(handle); + exit(0); + break; + case 3: + intf_num = atoi(argv[2]); + printf("Using USB transport \n"); + if(! (handle = OBEX_Init(OBEX_TRANS_USB, obex_event, 0))) { + perror( "OBEX_Init failed"); + exit(0); + } + + interfaces_number = OBEX_FindInterfaces(handle, &obex_intf); + if (intf_num >= interfaces_number) { + printf( "Invalid interface number\n"); + exit(0); + } + obex_intf += intf_num; + + break; + default: + printf("Wrong number of arguments\n"); + exit(0); + } + } else { printf("Using IrDA transport\n"); if(! (handle = OBEX_Init(OBEX_TRANS_IRDA, obex_event, 0))) { @@ -321,6 +364,12 @@ printf("Transport not found! (Bluetooth)\n"); #endif } + if (usbobex) { + if (OBEX_InterfaceConnect(handle, obex_intf) < 0) { + printf("Transport connect error! (USB)\n"); + break; + } + } else { if(IrOBEX_TransportConnect(handle, IR_SERVICE) < 0) { printf("Transport connect error! (IrDA)\n"); diff -uNr -X patchignore.txt openobex/lib/ChangeLog openobex-usb/lib/ChangeLog --- openobex/lib/ChangeLog 2005-12-03 12:51:50.000000000 +0200 +++ openobex-usb/lib/ChangeLog 2005-12-18 22:54:51.000000000 +0200 @@ -1,3 +1,7 @@ +2005-12-18 Alex Kanavin + + * Support for USB transport layer and USB interface discovery + 2005-12-02 Johan Hedberg * Add OBEX_SuspendRequest() and OBEX_ResumeRequest() functions for diff -uNr -X patchignore.txt openobex/lib/acinclude.m4 openobex-usb/lib/acinclude.m4 --- openobex/lib/acinclude.m4 2005-11-15 22:55:03.000000000 +0200 +++ openobex-usb/lib/acinclude.m4 2005-12-18 23:08:59.000000000 +0200 @@ -47,3 +47,30 @@ fi fi ]) + +dnl +dnl USB_HOOK (script-if-usb-found, failflag) +dnl +dnl if failflag is "failure" it aborts if obex is not found. +dnl + +AC_DEFUN([USB_HOOK],[ + AC_CACHE_CHECK([for USB support],am_cv_usb_found,[ + + AC_TRY_COMPILE([#include ], + [struct usb_dev_handle *dev;], + am_cv_usb_found=yes, + am_cv_usb_found=no)]) + + if test $am_cv_usb_found = yes; then + AC_DEFINE(HAVE_USB,1,[Define if system supports USB]) + USB_LIBS="-lusb" + fi + AC_SUBST(USB_LIBS) + ]) + +]) + +AC_DEFUN([USB_CHECK], [ + USB_HOOK([],failure) +]) diff -uNr -X patchignore.txt openobex/lib/configure.in openobex-usb/lib/configure.in --- openobex/lib/configure.in 2005-11-15 22:55:03.000000000 +0200 +++ openobex-usb/lib/configure.in 2005-12-03 12:55:40.000000000 +0200 @@ -38,6 +38,7 @@ IRDA_CHECK BLUETOOTH_CHECK +USB_CHECK dnl Configure debug facilities AC_ARG_WITH(debug,[ --with-debug=level Debug level], diff -uNr -X patchignore.txt openobex/lib/src/Makefile.am openobex-usb/lib/src/Makefile.am --- openobex/lib/src/Makefile.am 2002-10-28 23:51:18.000000000 +0200 +++ openobex-usb/lib/src/Makefile.am 2005-12-03 12:55:40.000000000 +0200 @@ -22,7 +22,8 @@ inobex.c inobex.h \ btobex.c btobex.h \ netbuf.c netbuf.h \ - irda.h irda_wrap.h + irda.h irda_wrap.h \ + usbobex.c usbobex.h libopenobex_la_LDFLAGS = \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ @@ -32,4 +33,6 @@ INCLUDES = -I$(top_srcdir)/src +libopenobex_la_LIBADD = @USB_LIBS@ + EXTRA_DIST = obex.sym obex.def makefile.msc win32compat.c windeps.dep diff -uNr -X patchignore.txt openobex/lib/src/obex.c openobex-usb/lib/src/obex.c --- openobex/lib/src/obex.c 2005-12-03 12:51:50.000000000 +0200 +++ openobex-usb/lib/src/obex.c 2005-12-18 23:12:22.000000000 +0200 @@ -55,6 +55,9 @@ #ifdef HAVE_IRDA #include "irobex.h" #endif +#ifdef HAVE_USB +#include "usbobex.h" +#endif #ifdef HAVE_BLUETOOTH #include "btobex.h" #else @@ -69,6 +72,7 @@ * %OBEX_TRANS_INET : Use regular TCP/IP socket * %OBEX_TRANS_CUSTOM : Use user provided transport * %OBEX_TRANS_BLUETOOTH: Use regular Bluetooth RFCOMM socket (need the BlueZ stack) + * %OBEX_TRANS_USB: Use USB transport (libusb needed) * If you use %OBEX_TRANS_CUSTOM you must register your own * transport with OBEX_RegisterCTransport() * @eventcb: Function pointer to your event callback. @@ -121,25 +125,32 @@ /* Init transport */ self->trans.type = transport; self->trans.connected = FALSE; + + /* Safe values. + * Both self->mtu_rx and self->mtu_tx_max can be increased by app + * self->mtu_tx will be whatever the other end sneds us - Jean II */ + /* Set MTU to the maximum, if using USB transport - Alex Kanavin */ + if (transport == OBEX_TRANS_USB) { + self->mtu_rx = OBEX_MAXIMUM_MTU; + self->mtu_tx = OBEX_MINIMUM_MTU; + self->mtu_tx_max = OBEX_MAXIMUM_MTU; + } else { + self->mtu_rx = OBEX_DEFAULT_MTU; + self->mtu_tx = OBEX_MINIMUM_MTU; + self->mtu_tx_max = OBEX_DEFAULT_MTU; + } /* Allocate message buffers */ /* It's safe to allocate them smaller than OBEX_MAXIMUM_MTU * because netbuf will realloc data as needed. - Jean II */ - self->rx_msg = g_netbuf_new(OBEX_DEFAULT_MTU); + self->rx_msg = g_netbuf_new(self->mtu_rx); if (self->rx_msg == NULL) goto out_err; - self->tx_msg = g_netbuf_new(OBEX_DEFAULT_MTU); + self->tx_msg = g_netbuf_new(self->mtu_tx_max); if (self->tx_msg == NULL) goto out_err; - /* Safe values. - * Both self->mtu_rx and self->mtu_tx_max can be increased by app - * self->mtu_tx will be whatever the other end sneds us - Jean II */ - self->mtu_rx = OBEX_DEFAULT_MTU; - self->mtu_tx = OBEX_MINIMUM_MTU; - self->mtu_tx_max = OBEX_DEFAULT_MTU; - #ifndef _WIN32 /* Ignore SIGPIPE. Otherwise send() will raise it and the app will quit */ signal(SIGPIPE, SIG_IGN); @@ -192,7 +203,8 @@ if (self->rx_msg) g_netbuf_free(self->rx_msg); - + + OBEX_FreeInterfaces(self); free(self); } @@ -1077,3 +1089,81 @@ return obex_transport_connect_request(self); } +/** + * OBEX_InterfaceConnect - Connect USB interface + * @self: OBEX handle + * @interface: USB interface to connect to + * + * An easier connect function to connect to a discovered interface (currently + * USB OBEX only). + */ +int OBEX_InterfaceConnect(obex_t *self, obex_interface_t *interface) +{ + DEBUG(4, "\n"); + + obex_return_val_if_fail(self != NULL, -1); + + if (self->object) { + DEBUG(1, "We are busy.\n"); + return -EBUSY; + } + + obex_return_val_if_fail(interface != NULL, -1); + switch (self->trans.type) { + case OBEX_TRANS_USB: + obex_return_val_if_fail(interface->usb.interface != NULL, -1); +#ifdef HAVE_USB + usbobex_prepare_connect(self, interface->usb.interface); + return obex_transport_connect_request(self); +#else + return -ESOCKTNOSUPPORT; +#endif /* HAVE_USB */ + default: + return -ESOCKTNOSUPPORT; + } +} + +/** + * OBEX_FindInterfaces - Get a list of OBEX interfaces on the system + * @self: OBEX handle + * @interfaces: A list of OBEX interfaces + * + * Gets a list of OBEX interfaces, or NULL if there are none. + */ +int OBEX_FindInterfaces(obex_t *self, obex_interface_t **interfaces) +{ + DEBUG(4, "\n"); + OBEX_FreeInterfaces(self); + switch (self->trans.type) { + case OBEX_TRANS_USB: +#ifdef HAVE_USB + self->interfaces_number = usbobex_find_interfaces(&self->interfaces); +#endif + break; + default: + break; + } + *interfaces = self->interfaces; + return self->interfaces_number; +} + +/** + * OBEX_FreeInterfaces - free memory allocated to OBEX interface structures + * @self: OBEX handle + * + * Frees memory allocated to OBEX interface structures after it has been + * allocated by OBEX_FindInterfaces. + */ +void OBEX_FreeInterfaces(obex_t *self) +{ + switch (self->trans.type) { + case OBEX_TRANS_USB: +#ifdef HAVE_USB + usbobex_free_interfaces(self->interfaces_number, self->interfaces); +#endif + break; + default: + break; + } + self->interfaces_number = 0; +} diff -uNr -X patchignore.txt openobex/lib/src/obex.def openobex-usb/lib/src/obex.def --- openobex/lib/src/obex.def 2005-12-03 12:51:50.000000000 +0200 +++ openobex-usb/lib/src/obex.def 2005-12-18 22:51:57.000000000 +0200 @@ -40,3 +40,6 @@ BtOBEX_ServerRegister BtOBEX_TransportConnect FdOBEX_TransportSetup +OBEX_InterfaceConnect +OBEX_FindInterfaces +OBEX_FreeInterfaces diff -uNr -X patchignore.txt openobex/lib/src/obex.h openobex-usb/lib/src/obex.h --- openobex/lib/src/obex.h 2005-12-03 12:51:50.000000000 +0200 +++ openobex-usb/lib/src/obex.h 2005-12-18 23:12:41.000000000 +0200 @@ -136,4 +136,10 @@ */ int FdOBEX_TransportSetup(obex_t *self, int rfd, int wfd, int mtu); +/* + * OBEX interface discovery API + */ + int OBEX_FindInterfaces(obex_t *self, obex_interface_t **interfaces); + int OBEX_InterfaceConnect(obex_t *self, obex_interface_t *interface); + void OBEX_FreeInterfaces(obex_t *self); #endif diff -uNr -X patchignore.txt openobex/lib/src/obex.sym openobex-usb/lib/src/obex.sym --- openobex/lib/src/obex.sym 2005-12-03 12:51:50.000000000 +0200 +++ openobex-usb/lib/src/obex.sym 2005-12-18 22:52:26.000000000 +0200 @@ -39,3 +39,6 @@ BtOBEX_ServerRegister BtOBEX_TransportConnect FdOBEX_TransportSetup +OBEX_InterfaceConnect +OBEX_FindInterfaces +OBEX_FreeInterfaces diff -uNr -X patchignore.txt openobex/lib/src/obex_const.h openobex-usb/lib/src/obex_const.h --- openobex/lib/src/obex_const.h 2005-11-15 22:55:03.000000000 +0200 +++ openobex-usb/lib/src/obex_const.h 2005-12-18 23:14:15.000000000 +0200 @@ -47,6 +47,33 @@ void * customdata; } obex_ctrans_t; +/* USB-specific OBEX interface information */ +typedef struct { + /* Manufacturer, e.g. Nokia */ + char *manufacturer; + /* Product, e.g. Nokia 6680 */ + char *product; + /* Product serial number */ + char *serial; + /* USB device configuration description */ + char *configuration; + /* Control interface description */ + char *control_interface; + /* Idle data interface description, typically empty */ + char *data_interface_idle; + /* Active data interface description, typically empty */ + char *data_interface_active; + /* Internal information for the transport layer in the library */ + struct obex_usb_intf_transport_t *interface; +} obex_usb_intf_t; + +/* Generic OBEX interface information */ +typedef union { + /* USB-specific OBEX interface information */ + obex_usb_intf_t usb; +// obex_bluetooth_intf_t bt; // to be added +} obex_interface_t; + #define OBEX_CLIENT 0 #define OBEX_SERVER 1 @@ -81,6 +108,7 @@ #define OBEX_TRANS_CUSTOM 3 #define OBEX_TRANS_BLUETOOTH 4 #define OBEX_TRANS_FD 5 +#define OBEX_TRANS_USB 6 /* Standard headers */ #define OBEX_HDR_COUNT 0xc0 /* Number of objects (used by connect) */ diff -uNr -X patchignore.txt openobex/lib/src/obex_main.h openobex-usb/lib/src/obex_main.h --- openobex/lib/src/obex_main.h 2002-11-22 21:06:11.000000000 +0200 +++ openobex-usb/lib/src/obex_main.h 2005-12-18 23:17:20.000000000 +0200 @@ -139,6 +139,10 @@ obex_transport_t trans; /* Transport being used */ obex_ctrans_t ctrans; + + obex_interface_t *interfaces; /* Array of discovered interfaces */ + int interfaces_number; /* Number of discovered interfaces */ + void * userdata; /* For user */ }; diff -uNr -X patchignore.txt openobex/lib/src/obex_transport.c openobex-usb/lib/src/obex_transport.c --- openobex/lib/src/obex_transport.c 2002-11-22 21:06:12.000000000 +0200 +++ openobex-usb/lib/src/obex_transport.c 2005-12-03 13:42:35.000000000 +0200 @@ -43,6 +43,9 @@ #ifdef HAVE_BLUETOOTH #include "btobex.h" #endif /*HAVE_BLUETOOTH*/ +#ifdef HAVE_USB +#include "usbobex.h" +#endif /*HAVE_USB*/ #include "obex_transport.h" @@ -64,6 +67,9 @@ ret = -1; } } + else if (self->trans.type == OBEX_TRANS_USB) { + ret = obex_data_indication(self, NULL, 0); + } else { struct timeval time; fd_set fdset; @@ -205,7 +211,11 @@ if (self->fd >= 0 && self->writefd >= 0) ret = 0; break; - +#ifdef HAVE_USB + case OBEX_TRANS_USB: + ret = usbobex_connect_request(self); + break; +#endif /*HAVE_USB*/ default: DEBUG(4, "Transport not implemented!\n"); break; @@ -250,6 +260,11 @@ /* no real disconnect on a file */ self->fd = self->writefd = -1; break; +#ifdef HAVE_USB + case OBEX_TRANS_USB: + usbobex_disconnect_request(self); + break; +#endif /*HAVE_USB*/ default: DEBUG(4, "Transport not implemented!\n"); break; @@ -289,7 +304,8 @@ break; #endif /*HAVE_BLUETOOTH*/ case OBEX_TRANS_FD: - /* no real listen on the file */ + case OBEX_TRANS_USB: + /* no real listen on the file or USB */ ret = 0; break; default: @@ -330,7 +346,8 @@ break; #endif /*HAVE_BLUETOOTH*/ case OBEX_TRANS_FD: - /* no real server on a file */; + case OBEX_TRANS_USB: + /* no real server on a file or USB */; break; default: DEBUG(4, "Transport not implemented!\n"); @@ -389,6 +406,16 @@ case OBEX_TRANS_FD: actual = do_write(self->writefd, msg, self->trans.mtu); break; +#ifdef HAVE_USB + case OBEX_TRANS_USB: + if (self->trans.connected != TRUE) + break; + DEBUG(4, "Endpoint %d\n", self->trans.self.usb.interface->data_endpoint_write); + actual = usb_bulk_write(self->trans.self.usb.dev_data, + self->trans.self.usb.data_endpoint_write, + msg->data, msg->len, USB_OBEX_TIMEOUT); + break; +#endif /*HAVE_USB*/ case OBEX_TRANS_CUSTOM: DEBUG(4, "Custom write\n"); if(self->ctrans.write) @@ -427,6 +454,16 @@ case OBEX_TRANS_FD: actual = read(self->fd, msg->tail, max); break; +#ifdef HAVE_USB + case OBEX_TRANS_USB: + if (self->trans.connected != TRUE) + break; + DEBUG(4, "Endpoint %d\n", self->trans.self.usb.interface->data_endpoint_read); + actual = usb_bulk_read(self->trans.self.usb.dev_data, + self->trans.self.usb.data_endpoint_read, + msg->tail, self->mtu_rx, USB_OBEX_TIMEOUT); + break; +#endif /*HAVE_USB*/ case OBEX_TRANS_CUSTOM: if(buflen > max) { memcpy(msg->tail, buf, max); diff -uNr -X patchignore.txt openobex/lib/src/obex_transport.h openobex-usb/lib/src/obex_transport.h --- openobex/lib/src/obex_transport.h 2004-03-05 11:48:49.000000000 +0200 +++ openobex-usb/lib/src/obex_transport.h 2005-12-18 22:36:44.000000000 +0200 @@ -43,6 +43,9 @@ #include #include #endif /*HAVE_BLUETOOTH*/ +#ifdef HAVE_USB +#include "usbobex.h" +#endif /*HAVE_USB*/ #include "obex_main.h" @@ -54,6 +57,9 @@ #ifdef HAVE_BLUETOOTH struct sockaddr_rc rfcomm; #endif /*HAVE_BLUETOOTH*/ +#ifdef HAVE_USB + struct obex_usb_intf_transport_t usb; +#endif /*HAVE_USB*/ } saddr_t; typedef struct obex_transport { diff -uNr -X patchignore.txt openobex/lib/src/usbobex.c openobex-usb/lib/src/usbobex.c --- openobex/lib/src/usbobex.c 1970-01-01 02:00:00.000000000 +0200 +++ openobex-usb/lib/src/usbobex.c 2005-12-18 23:24:34.000000000 +0200 @@ -0,0 +1,414 @@ +/*************************************<******************************** + * + * Filename: usbobex.c + * Version: 0.1 + * Description: USB OBEX, USB transport for OBEX + * Status: Experimental. + * Author: Alex Kanavin + * + * 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 +#endif + +#ifdef HAVE_USB + +/* Linux case */ + +#include +#include +#include /* perror */ +#include /* errno and EADDRNOTAVAIL */ +#include +#include + +#include + +#include +#include + +/* + * Function usbobex_prepare_connect (self, interface) + * + * Prepare for USB OBEX connect + * + */ +void usbobex_prepare_connect(obex_t *self, struct obex_usb_intf_transport_t *intf) +{ +#ifndef _WIN32 + self->trans.self.usb = *intf; +#endif /* _WIN32 */ +} + +/* + * 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_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, 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; + + 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; +} + +/* + * Function usbobex_find_interfaces () + * + * Find available USBOBEX interfaces on the system + */ +int 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, 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.interface = 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); + 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 usbobex_free_interfaces(int num, obex_interface_t *intf) +{ + int i; + if (intf == NULL) + return; + for (i=0; i++; itrans.self.usb.dev_control = usb_open(self->trans.self.usb.device); + self->trans.self.usb.dev_data = usb_open(self->trans.self.usb.device); + + ret = usb_set_configuration(self->trans.self.usb.dev_control, self->trans.self.usb.configuration); + if (ret < 0) { + DEBUG(4, "Can't set configuration %d", ret); + goto err1; + } + + ret = usb_claim_interface(self->trans.self.usb.dev_control, self->trans.self.usb.control_interface); + if (ret < 0) { + DEBUG(4, "Can't claim control interface %d", ret); + goto err1; + } + + ret = usb_set_altinterface(self->trans.self.usb.dev_control, self->trans.self.usb.control_setting); + if (ret < 0) { + DEBUG(4, "Can't set control setting %d", ret); + goto err2; + } + + ret = usb_claim_interface(self->trans.self.usb.dev_data, self->trans.self.usb.data_interface); + if (ret < 0) { + DEBUG(4, "Can't claim data interface %d", ret); + goto err2; + } + + ret = usb_set_altinterface(self->trans.self.usb.dev_data, self->trans.self.usb.data_active_setting); + if (ret < 0) { + DEBUG(4, "Can't set data active setting %d", ret); + goto err3; + } + self->trans.mtu = OBEX_MAXIMUM_MTU; + DEBUG(2, "transport mtu=%d\n", self->trans.mtu); + return 1; + +err3: + usb_release_interface(self->trans.self.usb.dev_data, self->trans.self.usb.data_interface); +err2: + usb_release_interface(self->trans.self.usb.dev_control, self->trans.self.usb.control_interface); +err1: + usb_close(self->trans.self.usb.dev_data); + usb_close(self->trans.self.usb.dev_control); + return ret; + +#endif /* _WIN32 */ +} + +/* + * Function usbobex_link_disconnect_request (self) + * + * Shutdown the USB link + * + */ +int usbobex_disconnect_request(obex_t *self) +{ + int ret; + if (self->trans.connected == FALSE) + return 0; +#ifndef _WIN32 + DEBUG(4, "\n"); + ret = usb_set_altinterface(self->trans.self.usb.dev_data, self->trans.self.usb.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.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.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_USB */ diff -uNr -X patchignore.txt openobex/lib/src/usbobex.h openobex-usb/lib/src/usbobex.h --- openobex/lib/src/usbobex.h 1970-01-01 02:00:00.000000000 +0200 +++ openobex-usb/lib/src/usbobex.h 2005-12-18 23:18:36.000000000 +0200 @@ -0,0 +1,94 @@ +/********************************************************************* + * + * Filename: usbobex.h + * Version: + * Description: + * Status: Experimental. + * Author: Alex Kanavin + * + * 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" + +/* 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 + */ + 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 */ +}; + +/* "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 + +#define USB_MAX_STRING_SIZE 256 +#define USB_OBEX_TIMEOUT 10000 /* 10 seconds */ + +void usbobex_prepare_connect(obex_t *self, struct obex_usb_intf_transport_t *intf); +int usbobex_connect_request(obex_t *self); +int usbobex_disconnect_request(obex_t *self); +int usbobex_find_interfaces(obex_interface_t **interfaces); +void usbobex_free_interfaces(int num, obex_interface_t *intf); +#endif