这是一个在线浏览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,就是将要共享的磁盘设备写到一个标志文件里面,再广播一下大容量存储连接的状态。
一、连接电脑;先来看看源码:
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]); }
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; } /*getDiskDevice函数直接返回sd卡的设备号。*/ dev_t d = v->getDiskDevice(); 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)); /*比较重要的在这里,想要实现让电脑识别到Android系统中的sd卡, 那么就必须将sd卡的设备节点路径写到以下文件中去,这样才能打开 大容量存储的功能,也就是OTG*/ if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", 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(); return 0; }
void DirectVolume::handleVolumeShared() { setState(Volume::State_Shared); }
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("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) { SLOGE("Unable to open ums lunfile (%s)", strerror(errno)); return -1; } char ch = 0; /*如果要断开连接,可以在电脑安全删除,然后Android系统会提示用户点击挂载sd卡,因为 在电脑使用sd卡的情况下,手机是不能对sd卡操作的,多处操作磁盘,会造成数据同步错误。 就在断开电脑,进入手机使用模式时,将/sys/devices/platform/usb_mass_storage/lun0/file 写为空了*/ 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(); return 0; } void DirectVolume::handleVolumeUnshared() { setState(Volume::State_Idle); }
if (!rc) { cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false); } else { int erno = errno; rc = ResponseCode::convertFromErrno(); cli->sendMsg(rc, "volume operation failed", true); }