Dominik Riebeling | eebde2a | 2009-06-08 18:04:10 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Windows MTP Firmware Uploading Implementation |
| 3 | * |
| 4 | * Based on http://opensource.creative.com/mtp_xfer.html |
| 5 | * Edited by Maurus Cuelenaere for Rockbox |
| 6 | * |
| 7 | * Copyright (c) 2009, Maurus Cuelenaere |
| 8 | * All rights reserved. |
| 9 | * |
| 10 | * Redistribution and use in source and binary forms, with or without |
| 11 | * modification, are permitted provided that the following conditions are met: |
| 12 | * * Redistributions of source code must retain the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer. |
| 14 | * * Redistributions in binary form must reproduce the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer in the |
| 16 | * documentation and/or other materials provided with the distribution. |
| 17 | * * Neither the name of the <organization> nor the |
| 18 | * names of its contributors may be used to endorse or promote products |
| 19 | * derived from this software without specific prior written permission. |
| 20 | * |
| 21 | * THIS SOFTWARE IS PROVIDED BY MAURUS CUELENAERE ''AS IS'' AND ANY |
| 22 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 24 | * DISCLAIMED. IN NO EVENT SHALL MAURUS CUELENAERE BE LIABLE FOR ANY |
| 25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | */ |
| 32 | |
| 33 | |
Dominik Riebeling | eebde2a | 2009-06-08 18:04:10 +0000 | [diff] [blame] | 34 | #include <windows.h> |
| 35 | #include "mswmdm_i.c" |
| 36 | #include "mswmdm.h" |
| 37 | #include "sac.h" |
| 38 | #include "scclient.h" |
| 39 | |
| 40 | #include "progresshelper.h" |
| 41 | #include "MTP_DLL.h" |
| 42 | |
| 43 | /* |
| 44 | * Compilation requirements: |
| 45 | * |
| 46 | * Download the Windows Media Format 9.5 SDK |
| 47 | * Add "c:\wmsdk\wmfsdk95\include,c:\wmsdk\wmfsdk95\wmdm\inc" to your inclusion path |
| 48 | * Add "c:\wmsdk\wmfsdk95\lib,c:\wmsdk\wmfsdk95\wmdm\lib" to your library inclusion path |
| 49 | * Link to "mssachlp.lib" |
| 50 | * |
| 51 | */ |
| 52 | |
| 53 | struct mtp_if { |
| 54 | IComponentAuthenticate* pICompAuth; |
| 55 | CSecureChannelClient *pSacClient; |
| 56 | IWMDeviceManager3* pIdvMgr; |
| 57 | bool initialized; |
| 58 | }; |
| 59 | |
| 60 | |
| 61 | extern "C" { |
| 62 | static int mtp_init(struct mtp_if* mtp) |
| 63 | { |
| 64 | HRESULT hr; |
| 65 | mtp->pSacClient = new CSecureChannelClient; |
| 66 | mtp->pIdvMgr = NULL; |
| 67 | mtp->initialized = false; |
| 68 | |
| 69 | /* these are generic keys */ |
| 70 | BYTE abPVK[] = {0x00}; |
| 71 | BYTE abCert[] = {0x00}; |
| 72 | |
| 73 | CoInitialize(NULL); |
| 74 | |
| 75 | /* get an authentication interface */ |
| 76 | hr = CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL, |
| 77 | IID_IComponentAuthenticate, (void **)&mtp->pICompAuth); |
| 78 | if SUCCEEDED(hr) |
| 79 | { |
| 80 | /* create a secure channel client certificate */ |
| 81 | hr = mtp->pSacClient->SetCertificate(SAC_CERT_V1, (BYTE*) abCert, |
| 82 | sizeof(abCert), (BYTE*) abPVK, sizeof(abPVK)); |
| 83 | if SUCCEEDED(hr) |
| 84 | { |
| 85 | /* bind the authentication interface to the secure channel client */ |
| 86 | mtp->pSacClient->SetInterface(mtp->pICompAuth); |
| 87 | |
| 88 | /* trigger communication */ |
| 89 | hr = mtp->pSacClient->Authenticate(SAC_PROTOCOL_V1); |
| 90 | if SUCCEEDED(hr) |
| 91 | { |
| 92 | /* get main interface to media device manager */ |
| 93 | hr = mtp->pICompAuth->QueryInterface(IID_IWMDeviceManager2, |
| 94 | (void**)&mtp->pIdvMgr); |
| 95 | if SUCCEEDED(hr) |
| 96 | { |
| 97 | mtp->initialized = true; |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | else { |
| 103 | CoUninitialize(); |
| 104 | } |
| 105 | return mtp->initialized; |
| 106 | } |
| 107 | |
| 108 | |
| 109 | static int mtp_close(struct mtp_if* mtp) |
| 110 | { |
| 111 | if(mtp->initialized) |
| 112 | { |
| 113 | mtp->pIdvMgr->Release(); |
| 114 | mtp->pICompAuth->Release(); |
| 115 | CoUninitialize(); |
| 116 | mtp->initialized = false; |
| 117 | } |
| 118 | return 0; |
| 119 | } |
| 120 | |
Dominik Riebeling | bc18818 | 2009-06-13 08:12:41 +0000 | [diff] [blame] | 121 | MTP_DLL_API int mtp_description(wchar_t* name, wchar_t* manufacturer, DWORD* version) |
Dominik Riebeling | eebde2a | 2009-06-08 18:04:10 +0000 | [diff] [blame] | 122 | { |
| 123 | HRESULT hr; |
| 124 | int num = 0; |
| 125 | struct mtp_if mtp; |
| 126 | /* zero mtp structure */ |
| 127 | memset(&mtp, 0, sizeof(struct mtp_if)); |
| 128 | |
| 129 | /* initialize interface */ |
| 130 | mtp_init(&mtp); |
| 131 | if(mtp.initialized == false) { |
| 132 | return -1; |
| 133 | } |
| 134 | |
| 135 | /* we now have a media device manager interface... */ |
| 136 | /* enumerate devices... */ |
| 137 | IWMDMEnumDevice *pIEnumDev; |
| 138 | wchar_t pwsString[256]; |
| 139 | hr = mtp.pIdvMgr->EnumDevices2(&pIEnumDev); |
| 140 | if SUCCEEDED(hr) { |
| 141 | hr = pIEnumDev->Reset(); /* Next will now return the first device */ |
| 142 | if SUCCEEDED(hr) { |
| 143 | IWMDMDevice3* pIDevice; |
| 144 | unsigned long ulNumFetched; |
| 145 | hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); |
| 146 | while (SUCCEEDED(hr) && (hr != S_FALSE)) { |
| 147 | /* output device name */ |
| 148 | hr = pIDevice->GetName(pwsString, 256); |
| 149 | if SUCCEEDED(hr) { |
| 150 | wcsncpy_s(name, 256, pwsString, _TRUNCATE); |
| 151 | num++; |
| 152 | } |
| 153 | /* device manufacturer */ |
| 154 | hr = pIDevice->GetManufacturer(pwsString, 256); |
| 155 | if SUCCEEDED(hr) { |
| 156 | wcsncpy_s(manufacturer, 256, pwsString, _TRUNCATE); |
| 157 | } |
| 158 | /* device version -- optional interface so might fail. */ |
| 159 | DWORD ver; |
| 160 | hr = pIDevice->GetVersion(&ver); |
| 161 | if SUCCEEDED(hr) { |
| 162 | *version = ver; |
| 163 | } |
| 164 | else { |
| 165 | *version = 0; |
| 166 | } |
| 167 | |
| 168 | /* move to next device */ |
| 169 | hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); |
| 170 | } |
| 171 | pIEnumDev->Release(); |
| 172 | } |
| 173 | mtp_close(&mtp); |
| 174 | } |
| 175 | return (num > 0) ? num : -1; |
| 176 | } |
| 177 | |
Dominik Riebeling | bc18818 | 2009-06-13 08:12:41 +0000 | [diff] [blame] | 178 | MTP_DLL_API int mtp_sendnk(LPWSTR file, int filesize, void (*callback)(unsigned int progress, unsigned int max)) |
Dominik Riebeling | eebde2a | 2009-06-08 18:04:10 +0000 | [diff] [blame] | 179 | { |
| 180 | HRESULT hr; |
| 181 | bool return_value = false; |
| 182 | struct mtp_if mtp; |
| 183 | /* zero mtp structure */ |
| 184 | memset(&mtp, 0, sizeof(struct mtp_if)); |
| 185 | |
| 186 | /* initialize interface */ |
| 187 | mtp_init(&mtp); |
| 188 | if(mtp.initialized == false) { |
| 189 | return false; |
| 190 | } |
| 191 | /* enumerate devices... */ |
| 192 | IWMDMEnumDevice *pIEnumDev; |
| 193 | hr = mtp.pIdvMgr->EnumDevices2(&pIEnumDev); |
| 194 | if SUCCEEDED(hr) |
| 195 | { |
| 196 | hr = pIEnumDev->Reset(); /* Next will now return the first device */ |
| 197 | if SUCCEEDED(hr) |
| 198 | { |
| 199 | IWMDMDevice3* pIDevice; |
| 200 | unsigned long ulNumFetched; |
| 201 | hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); |
| 202 | while (SUCCEEDED(hr) && (hr != S_FALSE)) |
| 203 | { |
| 204 | /* get storage info */ |
| 205 | DWORD tempDW; |
| 206 | pIDevice->GetType(&tempDW); |
| 207 | if (tempDW & WMDM_DEVICE_TYPE_STORAGE) |
| 208 | { |
| 209 | IWMDMEnumStorage *pIEnumStorage = NULL; |
| 210 | IWMDMStorage *pIStorage = NULL; |
| 211 | IWMDMStorage3 *pIFileStorage = NULL; |
| 212 | hr = pIDevice->EnumStorage(&pIEnumStorage); |
| 213 | if SUCCEEDED(hr) |
| 214 | { |
| 215 | pIEnumStorage->Reset(); |
| 216 | hr = pIEnumStorage->Next(1, (IWMDMStorage **)&pIStorage, &ulNumFetched); |
| 217 | while (SUCCEEDED(hr) && (hr != S_FALSE)) |
| 218 | { |
| 219 | IWMDMStorage3 *pNewStorage; |
| 220 | hr = pIStorage->QueryInterface(IID_IWMDMStorage3, (void **)&pNewStorage); |
| 221 | if SUCCEEDED(hr) |
| 222 | { |
| 223 | IWMDMStorageControl3 *pIWMDMStorageControl; |
| 224 | hr = pNewStorage->QueryInterface(IID_IWMDMStorageControl3, |
| 225 | (void**)&pIWMDMStorageControl); |
| 226 | if SUCCEEDED(hr) |
| 227 | { |
| 228 | IWMDMMetaData *pIWMDMMetaData = NULL; |
| 229 | hr = pNewStorage->CreateEmptyMetadataObject(&pIWMDMMetaData); |
| 230 | if (SUCCEEDED(hr)) |
| 231 | { |
| 232 | DWORD dw = WMDM_FORMATCODE_UNDEFINEDFIRMWARE; |
| 233 | hr = pIWMDMMetaData->AddItem(WMDM_TYPE_DWORD, g_wszWMDMFormatCode, (BYTE *)&dw, sizeof(dw)); |
| 234 | hr = pIWMDMMetaData->AddItem(WMDM_TYPE_STRING, g_wszWMDMFileName, (BYTE *)L"nk.bin", 32); |
| 235 | DWORD ow[2]; |
| 236 | ow[0] = filesize; |
| 237 | ow[1] = 0; |
| 238 | hr = pIWMDMMetaData->AddItem(WMDM_TYPE_QWORD, g_wszWMDMFileSize, (BYTE *)ow, 2 * sizeof(dw)); |
| 239 | if (SUCCEEDED(hr)) |
| 240 | { |
| 241 | IWMDMStorage *pNewObject = NULL; |
| 242 | CProgressHelper *progress = new CProgressHelper(callback); |
| 243 | |
| 244 | hr = pIWMDMStorageControl->Insert3( |
| 245 | WMDM_MODE_BLOCK | WMDM_CONTENT_FILE | WMDM_MODE_PROGRESS, |
| 246 | 0, |
| 247 | file, |
| 248 | NULL, |
| 249 | NULL, |
| 250 | (callback == NULL ? NULL : (IWMDMProgress*)progress), |
| 251 | pIWMDMMetaData, |
| 252 | NULL, |
| 253 | (IWMDMStorage **)&pNewObject); |
| 254 | |
| 255 | if(SUCCEEDED(hr) |
| 256 | || hr == WMDM_S_NOT_ALL_PROPERTIES_APPLIED |
| 257 | || hr == WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED) |
| 258 | { |
| 259 | return_value = true; |
| 260 | hr = S_FALSE; |
| 261 | } |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | } |
| 268 | pIEnumStorage->Release(); |
| 269 | } |
| 270 | |
| 271 | /* move to next device */ |
| 272 | if(!return_value) |
| 273 | hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); |
| 274 | } |
| 275 | pIEnumDev->Release(); |
| 276 | } |
| 277 | mtp_close(&mtp); |
| 278 | } |
| 279 | return return_value ? 1 : 0; |
| 280 | } |
| 281 | |
Dominik Riebeling | bc18818 | 2009-06-13 08:12:41 +0000 | [diff] [blame] | 282 | } |