[cpp]
USB On-The-Go and Embedded Host
Virtually every portable device now uses USB for PC connectivity. As these products increase in popularity, there is a growing need for them to communicate both with USB peripherals and directly with each other when a PC is not available. There is also an increase in the number of other, non-PC hosts (Embedded Hosts) which support USB in order to connect to USB peripherals.
先看android VOLD:
[cpp]
root@ubuntu:/cm10/4.2/system/vold# ls
[cpp]
Android.mk Devmapper.h logwrapper.c Process.cpp Volume.cpp
Asec.h DirectVolume.cpp Loop.cpp Process.h Volume.h
CleanSpec.mk DirectVolume.h Loop.h ResponseCode.cpp VolumeManager.cpp
CommandListener.cpp Ext4.cpp main.cpp ResponseCode.h VolumeManager.h
CommandListener.h Ext4.h NetlinkHandler.cpp tests Xwarp.cpp
cryptfs.c Fat.cpp NetlinkHandler.h vdc.c Xwarp.h
cryptfs.h Fat.h NetlinkManager.cpp VoldCommand.cpp
Devmapper.cpp hash.h NetlinkManager.h VoldCommand.h
簡單梳理一下,在vold中處理otg,將需要與PC機共享的磁盤設備寫到一個文件裡面,作為一個標志,再廣播給上層,傳播一個大容量存儲的狀態。
查看源碼:
[cpp]
vi ./CommandListener.cpp
[cpp]
#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file" //標志文件
1、連接PC部分。
在該函數中做分支解析:
[cpp]
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv)
[cpp]
else if (!strcmp(argv[1], "share")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: volume share <path> <method>", false);
return 0;
}
rc = vm->shareVolume(argv[2], argv[3]); //進入shareVolume函數對各狀態進行判斷,其中可判斷INAND或SD卡狀態,如果不存在或者忙狀態,則返回錯誤值。
具體看看shareVolume函數如何實現:
[cpp]
vi VoldCommand.cpp
[cpp]
int VolumeManager::shareVolume(const char *label, const char *method) {
Volume *v = lookupVolume(label);
if (!v) {
errno = ENOENT;
return -1;
}
/*
* Eventually, we'll want to support additional share back-ends,
* some of which may work while the media is mounted. For now,
* we just support UMS
*/
if (strcmp(method, "ums")) {
errno = ENOSYS;
return -1;
}
if (v->getState() == Volume::State_NoMedia) {
errno = ENODEV;
return -1;
}
if (v->getState() != Volume::State_Idle) {
// You need to unmount manually befoe sharing
errno = EBUSY;
return -1;
}
if (mVolManagerDisabled) {
errno = EBUSY;
return -1;
}
/*getShareDevice函數直接返回SD卡的設備號,部分版本該函數為getDiskDeve*/
dev_t d = v->getShareDevice();
if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
// This volume does not support raw disk access
errno = EINVAL;
return -1;
}
int fd;
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
MAJOR(d), MINOR(d));
/*重要的文件讀寫函數在這裡體現,PC機欲識別android設備中的存儲器,需將SD卡的設備節點路徑寫到MASS_STORAGE_FILE_PATH 文件中去,打開大容量存儲功能*/
if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
return -1;
}
if (write(fd, nodepath, strlen(nodepath)) < 0) {
SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
close(fd);
return -1;
}
close(fd);
v->handleVolumeShared(); /*該函數在Volume中,在子類DirectVolume中實現,廣播ums狀態。*/
if (mUmsSharingCount++ == 0) { /*4.0以上的版本增加了一下的判斷*/
FILE* fp;
mSavedDirtyRatio = -1; // in case we fail
if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
char line[16];
if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
fprintf(fp, "%d\n", mUmsDirtyRatio);
} else {
SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
}
fclose(fp);
} else {
SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
}
}
return 0;
}
二、斷開PC部分
[cpp]
int VolumeManager::unshareVolume(const char *label, const char *method) {
Volume *v = lookupVolume(label);
if (!v) {
errno = ENOENT;
return -1;
}
if (strcmp(method, "ums")) {
errno = ENOSYS;
return -1;
}
if (v->getState() != Volume::State_Shared) {
errno = EINVAL;
return -1;
}
int fd;
if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
return -1;
}
/*斷開連接,使用ums模式,磁盤不能多處操作,只能使用PC或者只是使用android設備,將控制權交給PC機,斷開時將MASS_STORAGE_FILE_PATH 寫為空值。後期升級為MTP方式,可實現同時控制。*/
char ch = 0;
if (write(fd, &ch, 1) < 0) {
SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
close(fd);
return -1;
}
close(fd);
/*和連接電腦一樣,如下函數為廣播OTG斷開狀態*/
v->handleVolumeUnshared();
if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
FILE* fp;
if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
fprintf(fp, "%d\n", mSavedDirtyRatio);
fclose(fp);
} else {
SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
}
mSavedDirtyRatio = -1;
}
return 0;
}
3、將狀態廣播Framework
[cpp]
vi ./CommandListener.cpp
[cpp]
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
} else {
int erno = errno;
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "volume operation failed", true);
}
接下來往kernel方向分析傳入的接口。