作者:gzshun. 原创作品,转载请标明出处!
来源:http://blog.csdn.net/gzshun
OTG是on-the-go的简称,是2001年由USB Implementers Forum公布,主要应用于各种不同的设备或移动设备间的联接,进行数据交换。特别是PDA、移动电话、消费类设备。改变如数码照相机、摄像机、打印机等设备间多种不同制式连接器,多达7种制式的存储卡间数据交换的不便。
对OTG介绍比较详细的在USB的官网,详细请见英文文档:
http://www.usb.org/developers/onthego/。以下是官网的一个简要的介绍,贴出来看看:
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.
The USB On-The-Go and Embedded Host Supplements addresses these scenarios by allowing portable devices and non-PC hosts to have the following enhancements:
Targeted host capability to communicate with selected other USB peripherals
Support for direct connections between OTG devices
Power saving features to preserve battery life
Revision 2.0 of the USB On-The-Go and Embedded Host Supplement to the USB 2.0 Specification applies to products operating at low-speed, full-speed and high-speed and is released, including applicable ECNs and errata, as part of the USB 2.0 Specification package. The corresponding OTG Adopters Agreement is also available.
Revision 1.0 of the USB On-The-Go and Embedded Host Supplement to the USB 3.0 Specification enhances these scenarios by adding SuperSpeed capability to USB On-The-Go and is released as part of the USB 3.0 Specification package. The corresponding Adopters Agreement for USB OTG 3.0 is the USB 3.0 Adopters Agreement.
这里写得很清楚,OTG主要是实现可移动设备点对点的数据共享,不需要再依赖于PC机第三方的识别或者操作。平时经常从电脑下载MP3格式的音乐到phone or Pad,都是经过USB线来连接电脑,电脑可以识别到设备里面的存储设备,或者手机与手机的连接,这就是OTG功能。
这是一个在线浏览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]);
}
进入shareVolume函数中,该函数判断一下sd卡的状态,如果不存在设备,或者sd卡不是出于空闲状态,那么就返回失败。
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;
}
如果有Android手机的用户,可以看到系统中存在/sys/devices/platform/usb_mass_storage/lun0/file这么一个文件,Java层可能没有权限访问该文件。最近发现,Java想要访问系统的文件,或者操作命令都要赋以最高权限(0777)才能访问或执行,真是麻烦。
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);
}
这里已经分析完在CommandListener::VolumeCmd::runCommand函数的实现的所有操作了,然后程序将命令的执行结果通知Framework,源码:
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
} else {
int erno = errno;
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "volume operation failed", true);
}
磁盘操作的命令圆满结束,下一篇文章继续分析Framework与vold的通信。待续。