blob: 8d10c27a8d6968da95c45e91fe67a9118831e844 [file] [log] [blame]
Mike Lockwood16864ba2010-05-11 17:16:59 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mike Lockwood5ed68d22010-05-25 19:08:48 -040017#define LOG_TAG "MtpClient"
Mike Lockwoodb14e5882010-06-29 18:11:52 -040018
19#include "MtpDebug.h"
20#include "MtpClient.h"
21#include "MtpDevice.h"
Mike Lockwood5ed68d22010-05-25 19:08:48 -040022
Mike Lockwood16864ba2010-05-11 17:16:59 -040023#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <sys/ioctl.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <errno.h>
30
31#include <usbhost/usbhost.h>
Mike Lockwood5ed68d22010-05-25 19:08:48 -040032#include <linux/version.h>
33#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
34#include <linux/usb/ch9.h>
35#else
36#include <linux/usb_ch9.h>
37#endif
Mike Lockwood16864ba2010-05-11 17:16:59 -040038
Mike Lockwood7850ef92010-05-14 10:10:36 -040039namespace android {
40
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040041class MtpClientThread : public Thread {
42private:
43 MtpClient* mClient;
44
45public:
46 MtpClientThread(MtpClient* client)
47 : mClient(client)
48 {
49 }
50
51 virtual bool threadLoop() {
52 return mClient->threadLoop();
53 }
54};
55
56
Mike Lockwood5ed68d22010-05-25 19:08:48 -040057MtpClient::MtpClient()
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040058 : mThread(NULL),
59 mUsbHostContext(NULL),
60 mDone(false)
Mike Lockwood16864ba2010-05-11 17:16:59 -040061{
Mike Lockwood16864ba2010-05-11 17:16:59 -040062}
63
64MtpClient::~MtpClient() {
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040065 usb_host_cleanup(mUsbHostContext);
Mike Lockwood16864ba2010-05-11 17:16:59 -040066}
67
Mike Lockwood5ed68d22010-05-25 19:08:48 -040068bool MtpClient::start() {
Mike Lockwood941f1132010-07-20 09:48:35 -040069 Mutex::Autolock autoLock(mMutex);
70
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040071 if (mThread)
Mike Lockwood16864ba2010-05-11 17:16:59 -040072 return true;
Mike Lockwood5ed68d22010-05-25 19:08:48 -040073
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040074 mUsbHostContext = usb_host_init();
75 if (!mUsbHostContext)
Mike Lockwood16864ba2010-05-11 17:16:59 -040076 return false;
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040077
78 mThread = new MtpClientThread(this);
79 mThread->run("MtpClientThread");
Mike Lockwood941f1132010-07-20 09:48:35 -040080 // wait for the thread to do initial device discovery before returning
81 mThreadStartCondition.wait(mMutex);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040082
Mike Lockwood5ed68d22010-05-25 19:08:48 -040083 return true;
84}
85
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040086void MtpClient::stop() {
87 mDone = true;
88}
89
Mike Lockwood941f1132010-07-20 09:48:35 -040090MtpDevice* MtpClient::getDevice(int id) {
91 for (int i = 0; i < mDeviceList.size(); i++) {
92 MtpDevice* device = mDeviceList[i];
93 if (device->getID() == id)
94 return device;
95 }
96 return NULL;
97}
98
Mike Lockwoodcff0ef92010-07-01 11:32:08 -040099bool MtpClient::usbDeviceAdded(const char *devname) {
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400100 struct usb_descriptor_header* desc;
101 struct usb_descriptor_iter iter;
102
103 struct usb_device *device = usb_device_open(devname);
104 if (!device) {
105 LOGE("usb_device_open failed\n");
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400106 return mDone;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400107 }
108
109 usb_descriptor_iter_init(device, &iter);
110
111 while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
112 if (desc->bDescriptorType == USB_DT_INTERFACE) {
113 struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
114
115 if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
116 interface->bInterfaceSubClass == 1 && // Still Image Capture
117 interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470)
118 {
119 LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
120 usb_device_get_product_name(device));
121
122 // interface should be followed by three endpoints
123 struct usb_endpoint_descriptor *ep;
124 struct usb_endpoint_descriptor *ep_in_desc = NULL;
125 struct usb_endpoint_descriptor *ep_out_desc = NULL;
126 struct usb_endpoint_descriptor *ep_intr_desc = NULL;
127 for (int i = 0; i < 3; i++) {
128 ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
129 if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
130 LOGE("endpoints not found\n");
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400131 return mDone;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400132 }
133 if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
134 if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
135 ep_in_desc = ep;
136 else
137 ep_out_desc = ep;
138 } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
139 ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
140 ep_intr_desc = ep;
141 }
142 }
143 if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
144 LOGE("endpoints not found\n");
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400145 return mDone;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400146 }
147
148 struct usb_endpoint *ep_in = usb_endpoint_open(device, ep_in_desc);
149 struct usb_endpoint *ep_out = usb_endpoint_open(device, ep_out_desc);
150 struct usb_endpoint *ep_intr = usb_endpoint_open(device, ep_intr_desc);
151
152 if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
153 LOGE("usb_device_claim_interface failed\n");
154 usb_endpoint_close(ep_in);
155 usb_endpoint_close(ep_out);
156 usb_endpoint_close(ep_intr);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400157 return mDone;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400158 }
159
160 MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
161 ep_in, ep_out, ep_intr);
162 mDeviceList.add(mtpDevice);
163 mtpDevice->initialize();
164 deviceAdded(mtpDevice);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400165 return mDone;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400166 }
167 }
168 }
169
170 usb_device_close(device);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400171 return mDone;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400172}
173
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400174bool MtpClient::usbDeviceRemoved(const char *devname) {
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400175 for (int i = 0; i < mDeviceList.size(); i++) {
176 MtpDevice* device = mDeviceList[i];
177 if (!strcmp(devname, device->getDeviceName())) {
178 deviceRemoved(device);
179 mDeviceList.removeAt(i);
180 delete device;
181 LOGD("Camera removed!\n");
182 break;
183 }
184 }
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400185 return mDone;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400186}
187
Mike Lockwood941f1132010-07-20 09:48:35 -0400188bool MtpClient::usbDiscoveryDone() {
189 Mutex::Autolock autoLock(mMutex);
190 mThreadStartCondition.signal();
191 return mDone;
192}
193
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400194bool MtpClient::threadLoop() {
Mike Lockwood941f1132010-07-20 09:48:35 -0400195 usb_host_run(mUsbHostContext, usb_device_added, usb_device_removed, usb_discovery_done, this);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400196 return false;
197}
198
199int MtpClient::usb_device_added(const char *devname, void* client_data) {
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400200 LOGD("usb_device_added %s\n", devname);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400201 return ((MtpClient *)client_data)->usbDeviceAdded(devname);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400202}
203
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400204int MtpClient::usb_device_removed(const char *devname, void* client_data) {
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400205 LOGD("usb_device_removed %s\n", devname);
Mike Lockwoodcff0ef92010-07-01 11:32:08 -0400206 return ((MtpClient *)client_data)->usbDeviceRemoved(devname);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400207}
208
Mike Lockwood941f1132010-07-20 09:48:35 -0400209int MtpClient::usb_discovery_done(void* client_data) {
210 LOGD("usb_discovery_done\n");
211 return ((MtpClient *)client_data)->usbDiscoveryDone();
212}
213
Mike Lockwood7850ef92010-05-14 10:10:36 -0400214} // namespace android