对OTG的分析:
http://blog.csdn.net/gzshun/article/details/7171781
文章中有提到这部分是在Vold模块中进行处理:
这是一个在线浏览Linux内核源码的网站:http://lxr.linux.no/。
Linux内核早就提供了OTG的驱动,在http://lxr.linux.no/linux+v3.1.6/drivers/usb/gadget/目录下,Linux将usb与otg两个功能模块给独立开了,主要的驱动是file_storage.c,该驱动主要负责终端设备的存储设备节点的操作,比如,从电脑,在该终端的磁盘上面创建文件,都会通过这个驱动来完成存储任务。另外一个驱动主要是负责USB通信的,是结尾为"_udc.c"的驱动源码,该目录下有好几个以"_udc.c"结尾的文件,这是针对不同型号的处理器而增加的,不同厂家提供不同的驱动。
这里只是简单的介绍,Android在vold中处理otg,就是将要共享的磁盘设备写到一个标志文件里面,再广播一下大容量存储连接的状态。
OTG体系架构:
http://blog.csdn.net/srw11/article/details/39154053
对OTG的使用
http://www.crifan.com/android_phone_support_usb_host/
Android OTG功能开发
http://happyboy200032.blog.163.com/blog/static/469031132015265541168/
OTG驱动分析:
http://blog.csdn.net/ling1874/article/details/5758883
驱动分析:
http://blog.csdn.net/fanqipin/article/details/8450694
http://blog.csdn.net/xubin341719/article/details/7707056
http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f7636d918d027fa3c215cc7902155a66e1b821201019d3c0776303ae5e5c9daa702d691765eadb9e871981edd27574de30340141c014&p=882a9645d7d21de70be2966d4c4e92&newp=c9759a46d6c210fc57efdf35554896231610db2151d4d2162e&user=baidu&fm=sc&query=Android+OTG&qid=996d9fd6000ab43f&p1=7
Android4.0 OTG 数据上报过程分析:
http://blog.chinaunix.net/uid-25909619-id-3255681.html
http://blog.csdn.net/kangear/article/details/38140537
OTG应用开发:
http://blog.csdn.net/tianruxishui/article/details/37905313
底层插入上报过程分析:
http://blog.csdn.net/cosmoslhf/article/details/13022923
Android USB/MTP相关
http://blog.csdn.net/kv110/article/details/39934319
Nenux 5支持OTG
http://bbs.gfan.com/android-4257863-1-1.html
HashMap deviceList = manager.getDeviceList();
Iterator deviceIterator = deviceList.values().iterator();
while (deviceIterator.hasNext())
{
UsbDevice device = deviceIterator.next();
if((DEVICE_PID == device.getProductId())
&& (DEVICE_VID == device.getVendorId())
)
{
mUsbDevice = device;
break;
}
}
UsbDeviceConnection connection = manager.openDevice(mUsbDevice);
private void getEndpoint(UsbDeviceConnection connection, UsbInterface intf)
{
if (intf.getEndpoint(1) != null)
{
epOut = intf.getEndpoint(1);
}
if (intf.getEndpoint(0) != null)
{
epIn = intf.getEndpoint(0);
}
}
out = mDeviceConnection.bulkTransfer(epIn, byte2, byte2.length, 0);
/**
* Performs a bulk transaction on the given endpoint.
* The direction of the transfer is determined by the direction of the endpoint.
*
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive
* @param offset the index of the first byte in the buffer to send or receive
* @param length the length of the data to send or receive
* @param timeout in milliseconds
* @return length of data transferred (or zero) for success,
* or negative value for failure
*/
public int bulkTransfer(UsbEndpoint endpoint,
byte[] buffer, int offset, int length, int timeout) {
checkBounds(buffer, offset, length);
return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
}
android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
jint endpoint, jbyteArray buffer, jint start, jint length, jint timeout)
{
struct usb_device* device = get_device_from_object(env, thiz);
if (!device) {
ALOGE("device is closed in native_control_request");
return -1;
}
jbyte* bufferBytes = NULL;
if (buffer) {
bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
}
jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
if (bufferBytes) {
env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
}
return result;
}
8.最后的usb_device_bulk_transfer是Usbhost.c中的函数:
int usb_device_bulk_transfer(struct usb_device *device,
int endpoint,
void* buffer,
int length,
unsigned int timeout)
{
struct usbdevfs_bulktransfer ctrl;
// need to limit request size to avoid EINVAL
if (length > MAX_USBFS_BUFFER_SIZE)
length = MAX_USBFS_BUFFER_SIZE;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.ep = endpoint;
ctrl.len = length;
ctrl.data = buffer;
ctrl.timeout = timeout;
return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
}
/**
* Returns a HashMap containing all USB devices currently attached.
* USB device name is the key for the returned HashMap.
* The result will be empty if no devices are attached, or if
* USB host mode is inactive or unsupported.
*
* @return HashMap containing all connected USB devices.
*/
public HashMap getDeviceList() {
Bundle bundle = new Bundle();
try {
mService.getDeviceList(bundle);
HashMap result = new HashMap();
for (String name : bundle.keySet()) {
result.put(name, (UsbDevice)bundle.get(name));
}
return result;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in getDeviceList", e);
return null;
}
}
/**
* Returns a new instance of this class.
*
* @param context the caller's {@link android.content.Context}
* @return UsbManager instance.
*/
public static UsbManager getInstance(Context context) {
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
return new UsbManager(context, IUsbManager.Stub.asInterface(b));
}
/* Returns a list of all currently attached USB devices (host mdoe) */
@Override
public void getDeviceList(Bundle devices) {
if (mHostManager != null) {
mHostManager.getDeviceList(devices);
}
}
// contains all connected USB devices
private final HashMap mDevices = new HashMap();
...
...
/* Returns a list of all currently attached USB devices */
public void getDeviceList(Bundle devices) {
synchronized (mLock) {
for (String name : mDevices.keySet()) {
devices.putParcelable(name, mDevices.get(name));
}
}
}
/* Called from JNI in monitorUsbHostBus() to report new USB devices */
private void usbDeviceAdded(String deviceName, int vendorID, int productID,
int deviceClass, int deviceSubclass, int deviceProtocol,
/* array of quintuples containing id, class, subclass, protocol
and number of endpoints for each interface */
int[] interfaceValues,
/* array of quadruples containing address, attributes, max packet size
and interval for each endpoint */
int[] endpointValues) {
if (isBlackListed(deviceName) ||
isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
return;
}
synchronized (mLock) {
if (mDevices.get(deviceName) != null) {
Slog.w(TAG, "device already on mDevices list: " + deviceName);
return;
}
int numInterfaces = interfaceValues.length / 5;
Parcelable[] interfaces = new UsbInterface[numInterfaces];
try {
// repackage interfaceValues as an array of UsbInterface
int intf, endp, ival = 0, eval = 0;
for (intf = 0; intf < numInterfaces; intf++) {
int interfaceId = interfaceValues[ival++];
int interfaceClass = interfaceValues[ival++];
int interfaceSubclass = interfaceValues[ival++];
int interfaceProtocol = interfaceValues[ival++];
int numEndpoints = interfaceValues[ival++];
Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
for (endp = 0; endp < numEndpoints; endp++) {
int address = endpointValues[eval++];
int attributes = endpointValues[eval++];
int maxPacketSize = endpointValues[eval++];
int interval = endpointValues[eval++];
endpoints[endp] = new UsbEndpoint(address, attributes,
maxPacketSize, interval);
}
// don't allow if any interfaces are blacklisted
if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) {
return;
}
interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
interfaceSubclass, interfaceProtocol, endpoints);
}
} catch (Exception e) {
// beware of index out of bound exceptions, which might happen if
// a device does not set bNumEndpoints correctly
Slog.e(TAG, "error parsing USB descriptors", e);
return;
}
UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
deviceClass, deviceSubclass, deviceProtocol, interfaces);
mDevices.put(deviceName, device);
getCurrentSettings().deviceAttached(device);
}
}
public class UsbDevice implements Parcelable {
private static final String TAG = "UsbDevice";
private final String mName;
private final int mVendorId;
private final int mProductId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mInterfaces;
}
public class UsbInterface implements Parcelable {
private final int mId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mEndpoints;
}
public class UsbEndpoint implements Parcelable {
private final int mAddress;
private final int mAttributes;
private final int mMaxPacketSize;
private final int mInterval;
}
public void systemReady() {
synchronized (mLock) {
// Create a thread to call into native code to wait for USB host events.
// This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
Runnable runnable = new Runnable() {
public void run() {
monitorUsbHostBus();
}
};
new Thread(null, runnable, "UsbService host thread").start();
}
}
private native void monitorUsbHostBus();
static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv *env, jobject thiz)
{
struct usb_host_context* context = usb_host_init();
if (!context) {
ALOGE("usb_host_init failed");
return;
}
// this will never return so it is safe to pass thiz directly
usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
}
void usb_host_run(struct usb_host_context *context,
usb_device_added_cb added_cb,
usb_device_removed_cb removed_cb,
usb_discovery_done_cb discovery_done_cb,
void *client_data)
{
int done;
done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);
while (!done) {
done = usb_host_read_event(context);
}
} /* usb_host_run() */
int usb_host_load(struct usb_host_context *context,
usb_device_added_cb added_cb,
usb_device_removed_cb removed_cb,
usb_discovery_done_cb discovery_done_cb,
void *client_data)
{
int done = 0;
int i;
context->cb_added = added_cb;
context->cb_removed = removed_cb;
context->data = client_data;
D("Created device discovery thread\n");
/* watch for files added and deleted within USB_FS_DIR */
for (i = 0; i < MAX_USBFS_WD_COUNT; i++)
context->wds[i] = -1;
/* watch the root for new subdirectories */
context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
if (context->wdd < 0) {
fprintf(stderr, "inotify_add_watch failed\n");
if (discovery_done_cb)
discovery_done_cb(client_data);
return done;
}
watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
/* check for existing devices first, after we have inotify set up */
done = find_existing_devices(added_cb, client_data);
if (discovery_done_cb)
done |= discovery_done_cb(client_data);
return done;
} /* usb_host_load() */
method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIII[I[I)V");
static int usb_device_added(const char *devname, void* client_data) {
...
env->CallVoidMethod(thiz, method_usbDeviceAdded,
deviceName, vendorId, productId, deviceClass,
deviceSubClass, protocol, interfaceArray, endpointArray);
...
}
int usb_host_read_event(struct usb_host_context *context)
{
struct inotify_event* event;
char event_buf[512];
char path[100];
int i, ret, done = 0;
int offset = 0;
int wd;
ret = read(context->fd, event_buf, sizeof(event_buf));
if (ret >= (int)sizeof(struct inotify_event)) {
while (offset < ret) {
event = (struct inotify_event*)&event_buf[offset];
done = 0;
wd = event->wd;
if (wd == context->wdd) {
if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
done = find_existing_devices(context->cb_added, context->data);
} else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
if (context->wds[i] >= 0) {
inotify_rm_watch(context->fd, context->wds[i]);
context->wds[i] = -1;
}
}
}
} else if (wd == context->wds[0]) {
i = atoi(event->name);
snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
"new" : "gone", path, i);
if (i > 0 && i < MAX_USBFS_WD_COUNT) {
if (event->mask & IN_CREATE) {
ret = inotify_add_watch(context->fd, path,
IN_CREATE | IN_DELETE);
if (ret >= 0)
context->wds[i] = ret;
done = find_existing_devices_bus(path, context->cb_added,
context->data);
} else if (event->mask & IN_DELETE) {
inotify_rm_watch(context->fd, context->wds[i]);
context->wds[i] = -1;
}
}
} else {
for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
if (wd == context->wds[i]) {
snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
if (event->mask == IN_CREATE) {
D("new device %s\n", path);
done = context->cb_added(path, context->data);
} else if (event->mask == IN_DELETE) {
D("gone device %s\n", path);
done = context->cb_removed(path, context->data);
}
}
}
}
offset += sizeof(struct inotify_event) + event->len;
}
}
return done;
} /* usb_host_read_event() */
struct usb_host_context {
int fd;
usb_device_added_cb cb_added;
usb_device_removed_cb cb_removed;
void *data;
int wds[MAX_USBFS_WD_COUNT];
int wdd;
};