[Nexus 7 Q&A, Help & Troubleshooting] eric_fri:
Hey everybody

I currently have a Nexus 7 and am playing around with accessory mode using what I have found at ht tp:// android. serverbox. ch/?p=262 (sorry no links allowed for me :( ). The file that he has needed some mods to work, but I have successfully compiled the code and when run, it will put the N7 into accessory mode, and offer up usb audio support to the pc.

Now the snd_usb_audio kernel module loads, it shows up as a USB sound card, and Alsa sees it; however in the AlsaMixer, when I select the sound card it says "This sound device does not have any controls."

I was wondering if anybody has played with this at all or has any insight? I would like the audio to be played out of my pc speakers, but originate from the N7.

In case anybody wants the modified code here it is:

You will need to change the Manufacturer, Model, etc to match what you have in your Android application if you want to use accessory mode to auto launch the app. Otherwise it will load up a warning saying it doesn't know what to do, but should still start accessory mode.

/*
* simplectrl.c
* This file is part of OsciPrime
*
* Copyright (C) 2011 - Manuel Di Cerbo
*
* OsciPrime is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OsciPrime 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OsciPrime; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/

// Google Reference ht tp:// developer. android. com/tools/adk/aoa.html

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

#define IN 0x81
#define OUT 0x07

// Google VID and PID
#define GOOGLE_VID 0x18D1
//#define PID 0x4E22
// N7
#define VID 0x18D1
#define PID 0x4e42

#define ACCESSORY 0x2D00
#define ACCESSORY_ADB 0x2D01
#define AUDIO 0x2D02
#define AUDIO_ADB 0x2D03
#define ACCESSORY_AUDIO 0x2D04
#define ACCESSORY_AUDIO_ADB 0x2D05

#define LEN 2

/*
If you are on Ubuntu you will require libusb as well as the headers...
We installed the headers with "apt-get source libusb"
gcc simplectrl.c -I/usr/include/ -o simplectrl -lusb-1.0 -I/usr/include/ -I/usr/include/libusb-1.0

Tested for Nexus S with Gingerbread 2.3.4
*/

static int mainPhase();
static int init(void);
static int deInit(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;
static char stop;
static char success = 0;

int main (int argc, char *argv[]) {
if(init() < 0)
return;
//doTransfer();
if(setupAccessory(
"Manufacturer",
"Model",
"Description",
"Version",
"ht tp:// example. com",
"Serial Number"
) < 0) {
fprintf(stdout, "Error setting up accessory\n");
deInit();
return -1;
};
if(mainPhase() < 0) {
fprintf(stdout, "Error during main phase\n");
deInit();
return -1;
}
deInit();
fprintf(stdout, "Done, no errors\n");
return 0;
}

static int mainPhase() {
unsigned char buffer[500000];
int response = 0;
static int transferred;

response = libusb_bulk_transfer(handle,IN,buffer,16384, &transferred,0);
if(response < 0) {
error(response);return -1;
}

response = libusb_bulk_transfer(handle,IN,buffer,500000, &transferred,0);
if(response < 0) {
error(response);return -1;
}

}

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 deInit() {
//TODO free all transfers individually...
//if(ctrlTransfer != NULL)
//	libusb_free_transfer(ctrlTransfer);
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;
int tries = 5;

// GetProtocol lookup from Device
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 :(

fprintf(stdout,"Sending Manufacturer\n");
response = libusb_control_transfer(handle, 0x40, 52, 0, 0, (char*)manufacturer, strlen(manufacturer), 0);
if(response < 0) {
error(response);
return -1;
}
fprintf(stdout,"Sending Model\n");
response = libusb_control_transfer(handle, 0x40, 52, 0, 1, (char*)modelName, strlen(modelName)+1, 0);
if(response < 0) {
error(response);
return -1;
}
fprintf(stdout,"Sending Description\n");
response = libusb_control_transfer(handle, 0x40, 52, 0, 2, (char*)description,strlen(description)+1, 0);
if(response < 0) {
error(response);
return -1;
}
fprintf(stdout,"Sending Version\n");
response = libusb_control_transfer(handle, 0x40, 52, 0, 3, (char*)version,strlen(version)+1, 0);
if(response < 0) {
error(response);
return -1;
}
fprintf(stdout,"Sending URI\n");
response = libusb_control_transfer(handle, 0x40, 52, 0, 4, (char*)uri,strlen(uri)+1, 0);
if(response < 0) {
error(response);
return -1;
}
fprintf(stdout,"Sending Serial Number\n");
response = libusb_control_transfer(handle, 0x40, 52, 0, 5, (char*)serialNumber,strlen(serialNumber)+1, 0);
if(response < 0) {
error(response);
return -1;
}
fprintf(stdout,"Requesting Audio\n");
response = libusb_control_transfer(handle, 0x40, 58, 1, 0, NULL, 0, 0);
if(response < 0) {
error(response);
return -1;
}

fprintf(stdout,"Accessory Identification sent\n", devVersion);
// requst device start into accessory mode
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) {
fprintf(stdout,"Handle good\n");
libusb_release_interface (handle, 0);
}

for(;;) {//attempt to connect to new VID and PID, if that doesn't work try ACCESSORY_ADB
tries--;
fprintf(stdout,"Attempting to connect using Google VID \n");
if((handle = libusb_open_device_with_vid_pid(NULL, GOOGLE_VID, ACCESSORY_AUDIO_ADB)) == 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;
}

static void error(int code) {
fprintf(stdout,"\n");
switch(code) {
case LIBUSB_ERROR_IO:
fprintf(stdout,"Error: LIBUSB_ERROR_IO\nInput/output error.\n");
break;
case LIBUSB_ERROR_INVALID_PARAM:
fprintf(stdout,"Error: LIBUSB_ERROR_INVALID_PARAM\nInvalid parameter.\n");
break;
case LIBUSB_ERROR_ACCESS:
fprintf(stdout,"Error: LIBUSB_ERROR_ACCESS\nAccess denied (insufficient permissions).\n");
break;
case LIBUSB_ERROR_NO_DEVICE:
fprintf(stdout,"Error: LIBUSB_ERROR_NO_DEVICE\nNo such device (it may have been disconnected).\n");
break;
case LIBUSB_ERROR_NOT_FOUND:
fprintf(stdout,"Error: LIBUSB_ERROR_NOT_FOUND\nEntity not found.\n");
break;
case LIBUSB_ERROR_BUSY:
fprintf(stdout,"Error: LIBUSB_ERROR_BUSY\nResource busy.\n");
break;
case LIBUSB_ERROR_TIMEOUT:
fprintf(stdout,"Error: LIBUSB_ERROR_TIMEOUT\nOperation timed out.\n");
break;
case LIBUSB_ERROR_OVERFLOW:
fprintf(stdout,"Error: LIBUSB_ERROR_OVERFLOW\nOverflow.\n");
break;
case LIBUSB_ERROR_PIPE:
fprintf(stdout,"Error: LIBUSB_ERROR_PIPE\nPipe error.\n");
break;
case LIBUSB_ERROR_INTERRUPTED:
fprintf(stdout,"Error:LIBUSB_ERROR_INTERRUPTED\nSystem call interrupted (perhaps due to signal).\n");
break;
case LIBUSB_ERROR_NO_MEM:
fprintf(stdout,"Error: LIBUSB_ERROR_NO_MEM\nInsufficient memory.\n");
break;
case LIBUSB_ERROR_NOT_SUPPORTED:
fprintf(stdout,"Error: LIBUSB_ERROR_NOT_SUPPORTED\nOperation not supported or unimplemented on this platform.\n");
break;
case LIBUSB_ERROR_OTHER:
fprintf(stdout,"Error: LIBUSB_ERROR_OTHER\nOther error.\n");
break;
default:
fprintf(stdout, "Error: unkown error\n");
}
}

static void status(int code) {
fprintf(stdout,"\n");
switch(code) {
case LIBUSB_TRANSFER_COMPLETED:
fprintf(stdout,"Success: LIBUSB_TRANSFER_COMPLETED\nTransfer completed.\n");
break;
case LIBUSB_TRANSFER_ERROR:
fprintf(stdout,"Error: LIBUSB_TRANSFER_ERROR\nTransfer failed.\n");
break;
case LIBUSB_TRANSFER_TIMED_OUT:
fprintf(stdout,"Error: LIBUSB_TRANSFER_TIMED_OUT\nTransfer timed out.\n");
break;
case LIBUSB_TRANSFER_CANCELLED:
fprintf(stdout,"Error: LIBUSB_TRANSFER_CANCELLED\nTransfer was cancelled.\n");
break;
case LIBUSB_TRANSFER_STALL:
fprintf(stdout,"Error: LIBUSB_TRANSFER_STALL\nFor bulk/interrupt endpoints: halt condition detected (endpoint stalled).\nFor control endpoints: control request not supported.\n");
break;
case LIBUSB_TRANSFER_NO_DEVICE:
fprintf(stdout,"Error: LIBUSB_TRANSFER_NO_DEVICE\nDevice was disconnected.\n");
break;
case LIBUSB_TRANSFER_OVERFLOW:
fprintf(stdout,"Error: LIBUSB_TRANSFER_OVERFLOW\nDevice sent more data than requested.\n");
break;
default:
fprintf(stdout,"Error: unknown error\nTry again(?)\n");
break;
}
}

Thanks

Eric