当前位置: 代码迷 >> Android >> USB On-The-Go and Embedded Host
  详细解决方案

USB On-The-Go and Embedded Host

热度:473   发布时间:2016-04-28 07:35:22.0
四极管:android4.0 实现U盘挂载PC (一)

 

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.

详细英文文档请查看:

http://www.usb.org/developers/onthego/。

下面具体看代码:

先看vold:android在vold里处理otg。即将设备写到一个标志文件,再进行广播大容量存储的状态。

vim  /vold/CommandListener.cpp

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,                                                      int argc, char **argv) {    dumpArgs(argc, argv, -1);    if (argc < 2) {        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);        return 0;    }    VolumeManager *vm = VolumeManager::Instance();    int rc = 0;    if (!strcmp(argv[1], "list")) {        return vm->listVolumes(cli);    } else if (!strcmp(argv[1], "debug")) {        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);            return 0;        }        vm->setDebug(!strcmp(argv[2], "on") ? true : false);    } else if (!strcmp(argv[1], "mount")) {        if (argc != 3) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);            return 0;        }        rc = vm->mountVolume(argv[2]);    } else if (!strcmp(argv[1], "unmount")) {        if (argc < 3 || argc > 4 ||           ((argc == 4 && strcmp(argv[3], "force")) &&            (argc == 4 && strcmp(argv[3], "force_and_revert")))) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);            return 0;        }        bool force = false;        bool revert = false;        if (argc >= 4 && !strcmp(argv[3], "force")) {            force = true;        } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {            force = true;            revert = true;        }        rc = vm->unmountVolume(argv[2], force, revert);    } else if (!strcmp(argv[1], "format")) {        if (argc != 3) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);            return 0;        }        rc = vm->formatVolume(argv[2]);    } 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]);    //该函数判断SD卡状态,若不存在或处于忙状态,怎返回失败值。    } else if (!strcmp(argv[1], "unshare")) {        if (argc != 4) {            cli->sendMsg(ResponseCode::CommandSyntaxError,                    "Usage: volume unshare <path> <method>", false);            return 0;        }        rc = vm->unshareVolume(argv[2], argv[3]);    } else if (!strcmp(argv[1], "shared")) {        bool enabled = false;        if (argc != 4) {            cli->sendMsg(ResponseCode::CommandSyntaxError,                    "Usage: volume shared <path> <method>", false);            return 0;        }        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {            cli->sendMsg(                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);        } else {            cli->sendMsg(ResponseCode::ShareEnabledResult,                    (enabled ? "Share enabled" : "Share disabled"), false);        }        return 0;    } else {        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);    }    if (!rc) {        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);    } else {        int erno = errno;        rc = ResponseCode::convertFromErrno();        cli->sendMsg(rc, "volume operation failed", true);    }    return 0;}

往下继续:

vi ./VolumeManager.cpp

 

#define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"


1、连接PC机

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卡的设备号,部分版本使用函数getDiskDevice函数名*/    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机识别到设备上的SD卡或者Iland,那么就必须将SD卡的设备节点路径写到以下文件中去,这样才能打开大容量存储功能*/    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);
    /**handleVolumeShared 函数在Volume中,是一个虚函数,在子类DirectVolume中实现,也就是广播ums状态/    v->handleVolumeShared();
    /*注:adnroid4.0以上版本增加了以下判断*/    if (mUmsSharingCount++ == 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;}


2、断开PC机

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;    }    /*2.3版本使用ums模式,断开连接时可以在PC端进行断开,android设备会自动挂载SD,这是使用ums的弊端,PC和androd设备不能同时对SD卡进行操作。andorid4.0以上版本升级为MTP模式,可以同时操作,后期再升级。
	断开电脑,进行android设备端操作时,会将MASS_STORAGE_FILE_PATH写为空*/    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);    /*同连接状态一样,断开U盘挂载模式*/
    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、在处理好后,vold将继续向上Framework汇报处理结果

    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {        char *buffer;        asprintf(&buffer, "%s %s %d",                 (*i)->getLabel(), (*i)->getMountpoint(),                 (*i)->getState());        cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);        free(buffer);    }    cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);

以vold为突破点,继续往下看,看看kernel如何处理。


  相关解决方案