上一篇基本把pc端连接mtp协议走的内核路径过了一遍,还有部分细节不完善,但整体流程还是走的usb驱动逻辑。这是后话。简而言之,pc在内核平没有专门为MTP设计什么东西。解析MTP协议的逻辑还是放在了用户态。通过D-bus连通usb驱动,对数据进行mtp协议解析。为了详细了解mtp具体做了什么,我从手机端研究了MTP在内核中的实现。
一、/dev/mtp_usb
真正意义上的MTP驱动位于手机一侧。注册了 /dev/mtp_usb字符设备。

read write 接口实现了控制命令的传输和写入。也就是说当有远端的文件请求是,手机端是通过这里发送给手机测用户态服务的。
void MtpServer::run() {
// 将mFD赋值给fd,fd就是“/dev/mtp_usb”的句柄
int fd = mFD;
while (1) {
// 读取“/dev/mtp_usb”
int ret = mRequest.read(fd);
...
// 获取“MTP操作码”
MtpOperationCode operation = mRequest.getOperationCode();
MtpTransactionID transaction = mRequest.getTransactionID();
...
// 在handleRequest()中,根据读取的指令作出相应的处理
if (handleRequest()) {
...
}
}
...
}
二、文件数据的读取
为了在得到请求后顺利吧数据发送到远端PC上。手机端利用了启动的Mtp_server。
bool MtpServer::handleRequest() {
undefined
Mutex::Autolock autoLock(mMutex);
MtpOperationCode operation = mRequest.getOperationCode();
MtpResponseCode response;
mResponse.reset();
if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
undefined
mSendObjectHandle = kInvalidObjectHandle;
}
switch (operation) {
undefined
case MTP_OPERATION_GET_DEVICE_INFO:
response = doGetDeviceInfo();
break;
case MTP_OPERATION_OPEN_SESSION:
response = doOpenSession();
break;
case MTP_OPERATION_CLOSE_SESSION:
response = doCloseSession();
break;
...
case MTP_OPERATION_GET_OBJECT: //read
response = doGetObject();-------------------------------
break;
case MTP_OPERATION_SEND_OBJECT:
response = doSendObject();------------------------------
break;
...
}
if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
return false;
mResponse.setResponseCode(response);
return true;
}
如上,请求指令会进入MTP_OPERATION_GET_OBJECT。进行文件数据发送。用户态不会打开文件,而是通过句柄传递,/dev/mtp_usb ioctl传递指令, 内核直接读取文件数据,加入usb设备的数据队列。
MtpResponseCode MtpServer::doGetObject() {
undefined
...
// 根据handle获取文件的路径(pathBuf)、大小(fileLength)和“格式”。
int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
if (result != MTP_RESPONSE_OK)
return result;
// 将文件路径转换为const char*类型。
const char* filePath = (const char *)pathBuf;
// 将文件的信息传递给mfr,mfr是kernel的一个结构体;最终将mfr传递给kernel。
mtp_file_range mfr;
mfr.fd = open(filePath, O_RDONLY); // 设置“文件句柄”。
if (mfr.fd < 0) {
undefined
return MTP_RESPONSE_GENERAL_ERROR;
}
mfr.offset = 0; // 设置“文件偏移”
mfr.length = fileLength;
mfr.command = mRequest.getOperationCode(); // 设置“command”
mfr.transaction_id = mRequest.getTransactionID(); // 设置“transaction ID”
// 通过ioctl将文件传给kernel。
int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);--------
// 关闭文件
close(mfr.fd);
...
}
static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value)
{
if (code == MTP_SEND_FILE_WITH_HEADER) {
work = &dev->send_file_work;
dev->xfer_send_header = 1;
dev->xfer_command = mfr.command;
dev->xfer_transaction_id = mfr.transaction_id;
} else if (code == MTP_SEND_FILE) {
work = &dev->send_file_work;-------------------------------
dev->xfer_send_header = 0;
} else {
work = &dev->receive_file_work;
}
static void send_file_work(struct work_struct *data)
{
// 获取dev结构体
struct mtp_dev *dev = container_of(data, struct mtp_dev,
send_file_work);

5228

被折叠的 条评论
为什么被折叠?



