MTP: Add support for sending events to the host when objects are added and removed

Change-Id: Ia1d5232b919c644c670ff9ca651eca92b3f9ad42
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 174ea36..4659709 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -23,6 +23,7 @@
                   MtpDataPacket.cpp                     \
                   MtpDebug.cpp                          \
                   MtpDevice.cpp                         \
+                  MtpEventPacket.cpp                    \
                   MtpDeviceInfo.cpp                     \
                   MtpObjectInfo.cpp                     \
                   MtpPacket.cpp                         \
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
new file mode 100644
index 0000000..651761e
--- /dev/null
+++ b/media/mtp/MtpEventPacket.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MtpEventPacket"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <f_mtp.h>
+
+#include "MtpEventPacket.h"
+
+namespace android {
+
+MtpEventPacket::MtpEventPacket()
+    :   MtpPacket(512)
+{
+}
+
+MtpEventPacket::~MtpEventPacket() {
+}
+
+#ifdef MTP_DEVICE
+int MtpEventPacket::write(int fd) {
+    struct mtp_event    event;
+
+    putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+    putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_EVENT);
+
+    event.data = mBuffer;
+    event.length = mPacketSize;
+    int ret = ::ioctl(fd, MTP_SEND_EVENT, (unsigned long)&event);
+    return (ret < 0 ? ret : 0);
+}
+#endif
+
+#ifdef MTP_HOST
+    // read our buffer from the given endpoint
+int MtpEventPacket::read(struct usb_endpoint *ep) {
+    int ret = transfer(ep, mBuffer, mBufferSize);
+     if (ret >= 0)
+        mPacketSize = ret;
+    else
+        mPacketSize = 0;
+    return ret;
+}
+#endif
+
+}  // namespace android
+
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
new file mode 100644
index 0000000..30ae869
--- /dev/null
+++ b/media/mtp/MtpEventPacket.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MTP_EVENT_PACKET_H
+#define _MTP_EVENT_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+class MtpEventPacket : public MtpPacket {
+
+public:
+                        MtpEventPacket();
+    virtual             ~MtpEventPacket();
+
+#ifdef MTP_DEVICE
+    // write our data to the given file descriptor
+    int                 write(int fd);
+#endif
+
+#ifdef MTP_HOST
+    // read our buffer from the given endpoint
+    int                 read(struct usb_endpoint *ep);
+#endif
+
+    inline MtpEventCode     getEventCode() const { return getContainerCode(); }
+    inline void             setEventCode(MtpEventCode code)
+                                                     { return setContainerCode(code); }
+};
+
+}; // namespace android
+
+#endif // _MTP_EVENT_PACKET_H
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index e8f09fa..fda5f8f 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -73,6 +73,11 @@
 //    MTP_OPERATION_SKIP,
 };
 
+static const MtpEventCode kSupportedEventCodes[] = {
+    MTP_EVENT_OBJECT_ADDED,
+    MTP_EVENT_OBJECT_REMOVED,
+};
+
 static const MtpObjectProperty kSupportedObjectProperties[] = {
     MTP_PROPERTY_STORAGE_ID,
     MTP_PROPERTY_OBJECT_FORMAT,
@@ -239,6 +244,24 @@
     return NULL;
 }
 
+void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
+    LOGD("sendObjectAdded %d\n", handle);
+    mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
+    mEvent.setTransactionID(mRequest.getTransactionID());
+    mEvent.setParameter(1, handle);
+    int ret = mEvent.write(mFD);
+    LOGD("mEvent.write returned %d\n", ret);
+}
+
+void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
+    LOGD("sendObjectRemoved %d\n", handle);
+    mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
+    mEvent.setTransactionID(mRequest.getTransactionID());
+    mEvent.setParameter(1, handle);
+    int ret = mEvent.write(mFD);
+    LOGD("mEvent.write returned %d\n", ret);
+}
+
 void MtpServer::initObjectProperties() {
     mObjectProperties.push(new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT16));
     mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16));
@@ -326,7 +349,8 @@
     mData.putUInt16(0); //Functional Mode
     mData.putAUInt16(kSupportedOperationCodes,
             sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
-    mData.putEmptyArray(); // Events Supported
+    mData.putAUInt16(kSupportedEventCodes,
+            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
     mData.putEmptyArray(); // Device Properties Supported
     mData.putEmptyArray(); // Capture Formats
     mData.putAUInt16(kSupportedPlaybackFormats,
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 37b1cbe..aff973a 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -20,6 +20,7 @@
 #include "MtpRequestPacket.h"
 #include "MtpDataPacket.h"
 #include "MtpResponsePacket.h"
+#include "MtpEventPacket.h"
 #include "mtp.h"
 
 #include "MtpUtils.h"
@@ -52,6 +53,7 @@
     MtpRequestPacket    mRequest;
     MtpDataPacket       mData;
     MtpResponsePacket   mResponse;
+    MtpEventPacket      mEvent;
 
     MtpStorageList      mStorages;
 
@@ -77,6 +79,9 @@
     MtpProperty*        getObjectProperty(MtpPropertyCode propCode);
     MtpProperty*        getDeviceProperty(MtpPropertyCode propCode);
 
+    void                sendObjectAdded(MtpObjectHandle handle);
+    void                sendObjectRemoved(MtpObjectHandle handle);
+
 private:
     void                initObjectProperties();
 
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index ec0f867..2a895a7 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -28,6 +28,7 @@
 
 typedef uint16_t MtpOperationCode;
 typedef uint16_t MtpResponseCode;
+typedef uint16_t MtpEventCode;
 typedef uint32_t MtpSessionID;
 typedef uint32_t MtpStorageID;
 typedef uint32_t MtpTransactionID;
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
index c1c9aef..426c6b5 100644
--- a/media/mtp/f_mtp.h
+++ b/media/mtp/f_mtp.h
@@ -32,6 +32,13 @@
 	size_t		length;
 };
 
+struct mtp_event {
+	/* size of the event */
+	size_t		length;
+	/* event data to send */
+	void  		*data;
+};
+
 /* Sends the specified file range to the host */
 #define MTP_SEND_FILE              _IOW('M', 0, struct mtp_file_range)
 /* Receives data from the host and writes it to a file.
@@ -40,5 +47,7 @@
 #define MTP_RECEIVE_FILE           _IOW('M', 1, struct mtp_file_range)
 /* Sets the driver mode to either MTP or PTP */
 #define MTP_SET_INTERFACE_MODE     _IOW('M', 2, int)
+/* Sends an event to the host via the interrupt endpoint */
+#define MTP_SEND_EVENT             _IOW('M', 3, struct mtp_event)
 
 #endif /* __LINUX_USB_F_MTP_H */