Discussion:
Problem adding a new device using an initializer
Rui Santos
2007-12-14 20:41:11 UTC
Permalink
Hi all,

I currently own a USB 3G mobile device manufactured under the name ZTE
MF620.
At the same time I also own a Huawei USB E220 device.

On 2.6.24-rc5, the Huawei device uses an initializer to switch the
device from a usb-storage to a multi-port mode, that was previously
being done by a userspace application.
I was trying to do the same with the ZTE device, but I'm getting
frustrated. This same ZTE device has a userspace application that also
switches it to a multi-port mode.
Can anyone tell me what I'm doing wrong ?

This is the userspace program ( includes libusb ):
/* This file is generated with usbsnoop2libusb.pl from a usbsnoop log
file. */
/* Latest version of the script should be in
http://iki.fi/lindi/usb/usbsnoop2libusb.pl */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <ctype.h>
#include <usb.h>
#if 0
#include <linux/usbdevice_fs.h>
#define LIBUSB_AUGMENT
#include "libusb_augment.h"
#endif

struct usb_dev_handle *devh;

void release_usb_device(int dummy) {
int ret;
ret = usb_release_interface(devh, 0);
if (!ret)
printf("failed to release interface: %d\n", ret);
usb_close(devh);
if (!ret)
printf("failed to close interface: %d\n", ret);
exit(1);
}

void list_devices() {
struct usb_bus *bus;
for (bus = usb_get_busses(); bus; bus = bus->next) {
struct usb_device *dev;

for (dev = bus->devices; dev; dev = dev->next)
printf("0x%04x 0x%04x\n",
dev->descriptor.idVendor,
dev->descriptor.idProduct);
}
}

struct usb_device *find_device(int vendor, int product) {
struct usb_bus *bus;

for (bus = usb_get_busses(); bus; bus = bus->next) {
struct usb_device *dev;

for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor == vendor
&& dev->descriptor.idProduct == product)
return dev;
}
}
return NULL;
}

void print_bytes(char *bytes, int len) {
int i;
if (len > 0) {
for (i=0; i<len; i++) {
printf("%02x ", (int)((unsigned char)bytes[i]));
}
printf("\"");
for (i=0; i<len; i++) {
printf("%c", isprint(bytes[i]) ? bytes[i] : '.');
}
printf("\"");
}
}


int main(int argc, char **argv) {
int ret, vendor, product;
struct usb_device *dev;
char buf[65536], *endptr;
#if 0
usb_urb *isourb;
struct timeval isotv;
char isobuf[32768];
#endif

sleep(5);

usb_init();
usb_set_debug(255);
usb_find_busses();
usb_find_devices();

/* if (argc!=3) {
printf("usage: %s vendorID productID\n", argv[0]);
printf("ID numbers of currently attached devices:\n");
list_devices();
exit(1);
}
vendor = strtol(argv[1], &endptr, 16);
if (*endptr != '\0') {
printf("invalid vendor id\n");
exit(1);
}
product = strtol(argv[2], &endptr, 16);
if (*endptr != '\0') {
printf("invalid product id\n");
exit(1);
}*/

/* printf("ZTE MF620 USB modem\n"); */
vendor = 0x19d2;
product = 0x2000;
dev = find_device(vendor, product);
assert(dev);

devh = usb_open(dev);
assert(devh);

signal(SIGTERM, release_usb_device);

ret = usb_get_driver_np(devh, 0, buf, sizeof(buf));
/* printf("usb_get_driver_np returned %d\n", ret); */
if (ret == 0) {
/* printf("interface 0 already claimed by driver \"%s\", attempting
to detach it\n", buf); */
ret = usb_detach_kernel_driver_np(devh, 0);
/* printf("usb_detach_kernel_driver_np returned %d\n", ret); */
}
ret = usb_claim_interface(devh, 0);
if (ret != 0) {
/* printf("claim failed with error %d\n", ret); */
exit(1);
}

ret = usb_set_altinterface(devh, 0);
assert(ret >= 0);

ret = usb_get_descriptor(devh, 0x0000001, 0x0000000, buf, 0x0000012);
/* printf("1 get descriptor returned %d, bytes: ", ret); */
print_bytes(buf, ret);
/* printf("\n"); */
usleep(4*1000);
ret = usb_get_descriptor(devh, 0x0000002, 0x0000000, buf, 0x0000009);
/* printf("2 get descriptor returned %d, bytes: ", ret); */
print_bytes(buf, ret);
/* printf("\n"); */
usleep(4*1000);
ret = usb_get_descriptor(devh, 0x0000002, 0x0000000, buf, 0x0000020);
/* printf("3 get descriptor returned %d, bytes: ", ret); */
print_bytes(buf, ret);
/* printf("\n"); */
usleep(4*1000);
ret = usb_release_interface(devh, 0);
/* if (ret != 0) printf("failed to release interface before
set_configuration: %d\n", ret); */
ret = usb_set_configuration(devh, 0x0000001);
/* printf("4 set configuration returned %d\n", ret); */
ret = usb_claim_interface(devh, 0);
if (ret != 0) printf("claim after set_configuration failed with error
%d\n", ret);
ret = usb_set_altinterface(devh, 0);
/* printf("4 set alternate setting returned %d\n", ret); */
usleep(63*1000);
ret = usb_set_altinterface(devh, 0);
/* printf("5 set alternate setting returned %d\n", ret); */
usleep(62*1000);
ret = usb_control_msg(devh, USB_TYPE_CLASS + USB_RECIP_INTERFACE +
USB_ENDPOINT_IN, 0x00000fe, 0x0000000, 0x0000000, buf, 0x0000001, 1000);
/* printf("6 control msg returned %d, bytes: ", ret); */
print_bytes(buf, ret);
/* printf("\n"); */
usleep(4*1000);

/*memcpy(buf,
"\x55\x53\x42\x43\xe8\x48\xef\x81\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
0x000001f);
ret = usb_bulk_write(devh, 0x00000004, buf, 0x000001f, 1000);
printf("548 bulk write returned %d, bytes: ", ret);
print_bytes(buf, ret);
printf("\n");
usleep(2*1000);
ret = usb_bulk_read(devh, 0x00000083, buf, 0x000000d, 1000);
printf("549 bulk read returned %d, bytes: ", ret);
print_bytes(buf, ret);
printf("\n");
usleep(3*1000);*/

memcpy(buf,
"\x55\x53\x42\x43\x08\xf0\x10\x82\x00\x00\x00\x00\x00\x00\x0a\x85\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00",
0x000001f);
ret = usb_bulk_write(devh, 0x00000004, buf, 0x000001f, 1000);
/* printf("550 bulk write returned %d, bytes: ", ret); */
print_bytes(buf, ret);
/* printf("\n"); */
usleep(1*1000);
ret = usb_bulk_read(devh, 0x00000083, buf, 0x000000d, 1000);
/* printf("551 bulk read returned %d, bytes: ", ret); */
print_bytes(buf, ret);
/* printf("\n"); */
usleep(2*1000);

usb_resetep(devh, 0x83);

ret = usb_release_interface(devh, 0);
assert(ret == 0);
ret = usb_close(devh);
assert(ret == 0);
return 0;
}

This is the Kernel initializer I'm trying to add at
drivers/usb/storage/initializers.c that is not working:

int usb_stor_zte_mf620_init(struct us_data *us)
{
int result;

us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0xFE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
0x0, 0x0, us->iobuf, 0x1, 1000);
US_DEBUGP("usb_control_msg performing result is %d\n", result);
msleep(4);
memcpy(us->iobuf, "\x55\x53\x42\x43\x08\xf0\x10\x82\x00\x00\x00\x00"
"\x00\x00\x0a\x85\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x00\x00\x00\x00\x00\x00", 0x1F);
usb_stor_bulk_transfer_buf(us, us->send_ctrl_pipe, us->iobuf, 0x1F,
NULL);
usb_stor_Bulk_reset(us);
return (result ? 0 : -1);

This is also placed at drivers/usb/storage/unusual_devs.h :

UNUSUAL_DEV( 0x19d2, 0x2000, 0x0000, 0x0000,
"Qualcomm ZTE MF620",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_zte_mf620_init,
0),


NOTE: In order for userspace application to succeed in changing the ZTE
to multi-port mode, it has to be called before the USB device finishes
to "settle".

Thanks for your help,
Rui Santos


-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
linux-usb-***@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
Alan Stern
2007-12-14 20:59:31 UTC
Permalink
Post by Rui Santos
Hi all,
I currently own a USB 3G mobile device manufactured under the name ZTE
MF620.
At the same time I also own a Huawei USB E220 device.
On 2.6.24-rc5, the Huawei device uses an initializer to switch the
device from a usb-storage to a multi-port mode, that was previously
being done by a userspace application.
I was trying to do the same with the ZTE device, but I'm getting
frustrated. This same ZTE device has a userspace application that also
switches it to a multi-port mode.
Can anyone tell me what I'm doing wrong ?
...
Post by Rui Santos
ret = usb_control_msg(devh, USB_TYPE_CLASS + USB_RECIP_INTERFACE +
USB_ENDPOINT_IN, 0x00000fe, 0x0000000, 0x0000000, buf, 0x0000001, 1000);
...
Post by Rui Santos
This is the Kernel initializer I'm trying to add at
int usb_stor_zte_mf620_init(struct us_data *us)
{
int result;
us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0xFE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
0x0, 0x0, us->iobuf, 0x1, 1000);
If this is supposed to be an IN transfer (judging by the
USB_ENDPOINT_IN and USB_DIR_IN constants) then you should use
us->recv_ctrl_pipe instead of us->send_ctrl_pipe.

Alan Stern


-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
linux-usb-***@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Loading...