From: Alex K. <ak...@se...> - 2005-03-02 15:24:23
|
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 <ak...@se...> + * + * 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 <ak...@se...> + * + * 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 |