Android ADK con PC como host USB con libusb, error de transferencia masiva

Estoy tratando de hacer que mi PC sea el host USB para dispositivos Android 2.3.4 para poder desarrollar API sin necesidad de "accesorios" reales. Para hacer esto, necesito establecer la PC como el host USB y el "dispositivo" (en mi caso, un Nexus One con 2.3.4).

Comencé con el código libusb dehttp: //android.serverbox.ch como base para el lado de la PC y el código DemoKit y la documentación de Android en el lado de Android.

Los dos parecen negociar bien la conexión, y la interfaz se "reclama" pero muere en el intento real de transferencia masiva. En OSX, el error es -5 (LIBUSB_ERROR_NOT_FOUND) y en Ubuntu Linux (como root) el error es -1 (LIBUSB_ERROR_IO). (Lanzamientos más recientes de cada uno con libusb 1.0.8 más reciente).

Aquí está el código. Otros comentarios sobre problemas son bienvenidos, aunque esto es principalmente una prueba de concepto, por lo que realmente solo estoy buscando la razón por la que la transferencia masiva no funciona:

#include <stdio.h>
#include <libusb.h>
#include <string.h>

#define ENDPOINT_BULK_IN 0x83
#define ENDPOINT_BULK_OUT 0x03 // Have tried 0x00, 0x01 and 0x02

#define VID 0x18D1
#define PID 0x4E11

#define ACCESSORY_PID 0x2D00
#define ACCESSORY_ADB_PID 0x2D01 // Can't get this to work, if ADB is active, can't get handle on device

/*
ON OSX
gcc adktest.c -I/usr/local/include -o adktest -lusb-1.0.0 -I/usr/local/include -I/usr/local/include/libusb-1.0
ON UBUNTU
gcc adktest.c -I/usr/include -o adktest -lusb-1.0 -I/usr/include -I/usr/include/libusb-1.0

Testing on Nexus One with Gingerbread 2.3.4
*/

static int transferTest();
static int init(void);
static int shutdown(void);
static void error(int code);
static void status(int code);
static int setupAccessory(
const char* manufacturer,
const char* modelName,
const char* description,
const char* version,
const char* uri,
const char* serialNumber);

//static
static struct libusb_device_handle* handle;

int main (int argc, char *argv[]){
if(init() < 0)
    return;

if(setupAccessory(
    "PCHost",
    "PCHost1",
    "Description",
    "1.0",
    "http://www.mycompany.com",
    "SerialNumber") < 0){
    fprintf(stdout, "Error setting up accessory\n");
    shutdown();
    return -1;
};
if(transferTest() < 0){
    fprintf(stdout, "Error in transferTest\n");
    shutdown();
    return -1;
}   
shutdown();
fprintf(stdout, "Finished\n");
return 0;
}

static int transferTest(){
  // TEST BULK IN/OUT
  const static int PACKET_BULK_LEN=64;
  const static int TIMEOUT=5000;
  int r,i;
  int transferred;
  char answer[PACKET_BULK_LEN];
  char question[PACKET_BULK_LEN];
  for (i=0;i<PACKET_BULK_LEN; i++) question[i]=i;

    // ***FAILS HERE***
    r = libusb_bulk_transfer(handle, ENDPOINT_BULK_OUT, question, PACKET_BULK_LEN,
                             &transferred,TIMEOUT);
    if (r < 0) {
        fprintf(stderr, "Bulk write error %d\n", r);
        error(r);
        return r;
    }
    fprintf(stdout, "Wrote %d bytes", r);

    r = libusb_bulk_transfer(handle, ENDPOINT_BULK_IN, answer,PACKET_BULK_LEN,
                             &transferred, TIMEOUT);
    if (r < 0) {
        fprintf(stderr, "Bulk read error %d\n", r);
        error(r);
        return r;
    }
    fprintf(stdout, "Read %d bytes", r);

    if (transferred < PACKET_BULK_LEN) {
        fprintf(stderr, "Bulk transfer short read (%d)\n", r);
        error(r);
        return -1;
    }
    printf("Bulk Transfer Loop Test Result:\n");
    //     for (i=0;i< PACKET_BULK_LEN;i++) printf("%i, %i,\n ",question[i],answer[i]);
    for(i = 0;i < PACKET_BULK_LEN; i++) {
        if(i%8 == 0)
            printf("\n");
        printf("%02x, %02x; ",question[i],answer[i]);
    }
    printf("\n\n");

    return 0;

}


static int init(){
libusb_init(NULL);
if((handle = libusb_open_device_with_vid_pid(NULL, VID, PID)) == NULL){
    fprintf(stdout, "Problem acquiring handle\n");
    return -1;
}
libusb_claim_interface(handle, 0);  

return 0;
}

static int shutdown(){
if(handle != NULL)
    libusb_release_interface (handle, 0);
libusb_exit(NULL);
return 0;
}

static int setupAccessory(
const char* manufacturer,
const char* modelName,
const char* description,
const char* version,
const char* uri,
const char* serialNumber){

unsigned char ioBuffer[2];
int devVersion;
int response;

response = libusb_control_transfer(
    handle, //handle
    0xC0, //bmRequestType
    51, //bRequest
    0, //wValue
    0, //wIndex
    ioBuffer, //data
    2, //wLength
    0 //timeout
);

if(response < 0){error(response);return-1;}

devVersion = ioBuffer[1] << 8 | ioBuffer[0];
fprintf(stdout,"Version Code Device: %d\n", devVersion);

usleep(1000);//sometimes hangs on the next transfer :(

response = libusb_control_transfer(handle,0x40,52,0,0,(char*)manufacturer,strlen(manufacturer),0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,1,(char*)modelName,strlen(modelName)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,2,(char*)description,strlen(description)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,3,(char*)version,strlen(version)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,4,(char*)uri,strlen(uri)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,5,(char*)serialNumber,strlen(serialNumber)+1,0);
if(response < 0){error(response);return -1;}

fprintf(stdout,"Accessory Identification sent\n", devVersion);

response = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
if(response < 0){error(response);return -1;}

fprintf(stdout,"Attempted to put device into accessory mode\n", devVersion);

if(handle != NULL)
    libusb_release_interface (handle, 0);

int tries = 4;
for(;;){
    tries--;
    if((handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL){
        if(tries < 0){
            return -1;
        }
    }else{
        break;
    }
    sleep(1);
}

libusb_claim_interface(handle, 0);
fprintf(stdout, "Interface claimed, ready to transfer data\n");
return 0;
}

// error reporting function left out for brevity

Y aquí está la aplicación de Android:

package com.cengen.android.pchost;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends Activity implements Runnable
{
  private final Logger logger = LoggerFactory.getLogger("PCHost");

  private UsbManager usbManager;

  UsbAccessory accessory;
  ParcelFileDescriptor accessoryFileDescriptor;
  FileInputStream accessoryInput;
  FileOutputStream accessoryOutput;

  private final BroadcastReceiver usbBroadcastReceiver = new BroadcastReceiver()
  {
    public void onReceive(Context context, Intent intent)
    {
      String action = intent.getAction();
      if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action))
      {
        synchronized (this)
        {
          accessory = UsbManager.getAccessory(intent);
        }
      }
      else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action))
      {
        UsbAccessory accessory = UsbManager.getAccessory(intent);
        if (accessory != null)
        {
          // call your method that cleans up and closes communication with the accessory
        }
      }
    }
  };

  Handler messageHandler = new Handler()
  {
    @Override
    public void handleMessage(Message msg)
    {
      switch (msg.what)
      {
        case 1:
          logger.info("Got message type {}", msg.what);
//              SendFileMessage m = (SendFileMessage) msg.obj;
//              handleSendFile(m);
        break;
        case 2:
          logger.info("Got message type {}", msg.what);
//              SendFileMessage m = (SendFileMessage) msg.obj;
//              handleSendFile(m);
        break;
        case 3:
          logger.info("Got message type {}", msg.what);
//              SendFileMessage m = (SendFileMessage) msg.obj;
//              handleSendFile(m);
        break;
      }
    }
  };

  /**
   * Main USB reading loop, processing incoming data from accessory and parsing
   * it into messages via the defined format.
   */
  public void run()
  {
    int ret = 0;
    byte[] buffer = new byte[16384];
    int i;

    while (ret >= 0)
    {
      try
      {
        ret = accessoryInput.read(buffer);
        logger.debug("Read {} bytes.", ret);
      }
      catch (IOException e)
      {
        logger.debug("Exception in USB accessory input reading", e);
        break;
      }

      i = 0;
      while (i < ret)
      {
        int len = ret - i;

        switch (buffer[i])
        {
          case 0x1:
            if (len >= 3)
            {
              Message m = Message.obtain(messageHandler, 1);
//                      m.obj = new MessageTypeOne(buffer[i + 1], buffer[i + 2]);
              messageHandler.sendMessage(m);
            }
            i += 3;
            break;

          case 0x4:
            if (len >= 3)
            {
              Message m = Message.obtain(messageHandler, 1);
//                      m.obj = new MessageTypeTwo(buffer[i + 1], buffer[i + 2]);
              messageHandler.sendMessage(m);
            }
            i += 3;
            break;

          default:
            logger.debug("unknown msg: " + buffer[i]);
            i = len;
            break;
        }
      }

    }
  }

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);

    usbManager = UsbManager.getInstance(this);

    IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
    registerReceiver(usbBroadcastReceiver, filter);

    if (getLastNonConfigurationInstance() != null)
    {
      accessory = (UsbAccessory) getLastNonConfigurationInstance();
      openAccessory(accessory);
    }
    setContentView(R.layout.main);
  }

  @Override
  public Object onRetainNonConfigurationInstance()
  {
    return accessory != null ? accessory : super.onRetainNonConfigurationInstance();
  }

 @Override
 public void onResume()
 {
   super.onResume();

   Intent intent = getIntent();
   if (accessoryInput != null && accessoryOutput != null)
     return;

   // TODO: verify, docs don't do this simple thing, not sure why?
   UsbAccessory accessory = UsbManager.getAccessory(intent);
   if (accessory != null)
     openAccessory(accessory);
   else
     logger.error("Failed to resume accessory.");
 }

  @Override
  public void onPause()
  {
    super.onPause();
    closeAccessory();
  }

  @Override
  public void onDestroy()
  {
    unregisterReceiver(usbBroadcastReceiver);
    super.onDestroy();
  }

  private void openAccessory(UsbAccessory accessory)
  {
    accessoryFileDescriptor = usbManager.openAccessory(accessory);
    if (accessoryFileDescriptor != null)
    {
      this.accessory = accessory;
      FileDescriptor fd = accessoryFileDescriptor.getFileDescriptor();
      accessoryInput = new FileInputStream(fd);
      accessoryOutput = new FileOutputStream(fd);
      Thread thread = new Thread(null, this, "AndroidPCHost");
      thread.start();
      logger.debug("accessory opened");
      // TODO: enable USB operations in the app
    }
    else
    {
      logger.debug("accessory open fail");
    }
  }

  private void closeAccessory()
  {
    // TODO: disable USB operations in the app
    try
    {
      if (accessoryFileDescriptor != null)
        accessoryFileDescriptor.close();
    }
    catch (IOException e)
    {}
    finally
    {
      accessoryFileDescriptor = null;
      accessory = null;
    }
  }
}

Y el manifiesto (incluido el filtro de intención para que se asocie y autorice automáticamente el dispositivo, según los documentos):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.mycompany.android.pchost"
      android:versionCode="1"
      android:versionName="1.0">
  <uses-feature android:name="android.hardware.usb.accessory" />
  <uses-sdk android:minSdkVersion="10" />
  <application android:label="@string/app_name" android:icon="@drawable/icon">
    <uses-library android:name="com.android.future.usb.accessory" />
        <activity android:name="MainActivity"
                  android:label="@string/app_name"
                  android:launchMode="singleInstance">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
          <intent-filter>
              <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
          </intent-filter>

          <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
              android:resource="@xml/accessory_filter" />

        </activity>
    </application>
</manifest> 

Respuestas a la pregunta(2)

Su respuesta a la pregunta