/* * Windows MTP Firmware Uploading Implementation * * Based on http://opensource.creative.com/mtp_xfer.html * Edited by Maurus Cuelenaere for Rockbox * * Copyright (c) 2009, Maurus Cuelenaere * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY MAURUS CUELENAERE ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL MAURUS CUELENAERE BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "mswmdm_i.c" #include "mswmdm.h" #include "sac.h" #include "scclient.h" #include "progresshelper.h" #include "MTP_DLL.h" /* * Compilation requirements: * * Download the Windows Media Format 9.5 SDK * Add "c:\wmsdk\wmfsdk95\include,c:\wmsdk\wmfsdk95\wmdm\inc" to your inclusion path * Add "c:\wmsdk\wmfsdk95\lib,c:\wmsdk\wmfsdk95\wmdm\lib" to your library inclusion path * Link to "mssachlp.lib" * */ struct mtp_if { IComponentAuthenticate* pICompAuth; CSecureChannelClient *pSacClient; IWMDeviceManager3* pIdvMgr; bool initialized; }; extern "C" { static int mtp_init(struct mtp_if* mtp) { HRESULT hr; mtp->pSacClient = new CSecureChannelClient; mtp->pIdvMgr = NULL; mtp->initialized = false; /* these are generic keys */ BYTE abPVK[] = {0x00}; BYTE abCert[] = {0x00}; CoInitialize(NULL); /* get an authentication interface */ hr = CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL, IID_IComponentAuthenticate, (void **)&mtp->pICompAuth); if SUCCEEDED(hr) { /* create a secure channel client certificate */ hr = mtp->pSacClient->SetCertificate(SAC_CERT_V1, (BYTE*) abCert, sizeof(abCert), (BYTE*) abPVK, sizeof(abPVK)); if SUCCEEDED(hr) { /* bind the authentication interface to the secure channel client */ mtp->pSacClient->SetInterface(mtp->pICompAuth); /* trigger communication */ hr = mtp->pSacClient->Authenticate(SAC_PROTOCOL_V1); if SUCCEEDED(hr) { /* get main interface to media device manager */ hr = mtp->pICompAuth->QueryInterface(IID_IWMDeviceManager2, (void**)&mtp->pIdvMgr); if SUCCEEDED(hr) { mtp->initialized = true; } } } } else { CoUninitialize(); } return mtp->initialized; } static int mtp_close(struct mtp_if* mtp) { if(mtp->initialized) { mtp->pIdvMgr->Release(); mtp->pICompAuth->Release(); CoUninitialize(); mtp->initialized = false; } return 0; } MTP_DLL_API int mtp_description(wchar_t* name, wchar_t* manufacturer, DWORD* version) { HRESULT hr; int num = 0; struct mtp_if mtp; /* zero mtp structure */ memset(&mtp, 0, sizeof(struct mtp_if)); /* initialize interface */ mtp_init(&mtp); if(mtp.initialized == false) { return -1; } /* we now have a media device manager interface... */ /* enumerate devices... */ IWMDMEnumDevice *pIEnumDev; wchar_t pwsString[256]; hr = mtp.pIdvMgr->EnumDevices2(&pIEnumDev); if SUCCEEDED(hr) { hr = pIEnumDev->Reset(); /* Next will now return the first device */ if SUCCEEDED(hr) { IWMDMDevice3* pIDevice; unsigned long ulNumFetched; hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); while (SUCCEEDED(hr) && (hr != S_FALSE)) { /* output device name */ hr = pIDevice->GetName(pwsString, 256); if SUCCEEDED(hr) { wcsncpy_s(name, 256, pwsString, _TRUNCATE); num++; } /* device manufacturer */ hr = pIDevice->GetManufacturer(pwsString, 256); if SUCCEEDED(hr) { wcsncpy_s(manufacturer, 256, pwsString, _TRUNCATE); } /* device version -- optional interface so might fail. */ DWORD ver; hr = pIDevice->GetVersion(&ver); if SUCCEEDED(hr) { *version = ver; } else { *version = 0; } /* move to next device */ hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); } pIEnumDev->Release(); } mtp_close(&mtp); } return (num > 0) ? num : -1; } MTP_DLL_API int mtp_sendnk(LPWSTR file, int filesize, void (*callback)(unsigned int progress, unsigned int max)) { HRESULT hr; bool return_value = false; struct mtp_if mtp; /* zero mtp structure */ memset(&mtp, 0, sizeof(struct mtp_if)); /* initialize interface */ mtp_init(&mtp); if(mtp.initialized == false) { return false; } /* enumerate devices... */ IWMDMEnumDevice *pIEnumDev; hr = mtp.pIdvMgr->EnumDevices2(&pIEnumDev); if SUCCEEDED(hr) { hr = pIEnumDev->Reset(); /* Next will now return the first device */ if SUCCEEDED(hr) { IWMDMDevice3* pIDevice; unsigned long ulNumFetched; hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); while (SUCCEEDED(hr) && (hr != S_FALSE)) { /* get storage info */ DWORD tempDW; pIDevice->GetType(&tempDW); if (tempDW & WMDM_DEVICE_TYPE_STORAGE) { IWMDMEnumStorage *pIEnumStorage = NULL; IWMDMStorage *pIStorage = NULL; IWMDMStorage3 *pIFileStorage = NULL; hr = pIDevice->EnumStorage(&pIEnumStorage); if SUCCEEDED(hr) { pIEnumStorage->Reset(); hr = pIEnumStorage->Next(1, (IWMDMStorage **)&pIStorage, &ulNumFetched); while (SUCCEEDED(hr) && (hr != S_FALSE)) { IWMDMStorage3 *pNewStorage; hr = pIStorage->QueryInterface(IID_IWMDMStorage3, (void **)&pNewStorage); if SUCCEEDED(hr) { IWMDMStorageControl3 *pIWMDMStorageControl; hr = pNewStorage->QueryInterface(IID_IWMDMStorageControl3, (void**)&pIWMDMStorageControl); if SUCCEEDED(hr) { IWMDMMetaData *pIWMDMMetaData = NULL; hr = pNewStorage->CreateEmptyMetadataObject(&pIWMDMMetaData); if (SUCCEEDED(hr)) { DWORD dw = WMDM_FORMATCODE_UNDEFINEDFIRMWARE; hr = pIWMDMMetaData->AddItem(WMDM_TYPE_DWORD, g_wszWMDMFormatCode, (BYTE *)&dw, sizeof(dw)); hr = pIWMDMMetaData->AddItem(WMDM_TYPE_STRING, g_wszWMDMFileName, (BYTE *)L"nk.bin", 32); DWORD ow[2]; ow[0] = filesize; ow[1] = 0; hr = pIWMDMMetaData->AddItem(WMDM_TYPE_QWORD, g_wszWMDMFileSize, (BYTE *)ow, 2 * sizeof(dw)); if (SUCCEEDED(hr)) { IWMDMStorage *pNewObject = NULL; CProgressHelper *progress = new CProgressHelper(callback); hr = pIWMDMStorageControl->Insert3( WMDM_MODE_BLOCK | WMDM_CONTENT_FILE | WMDM_MODE_PROGRESS, 0, file, NULL, NULL, (callback == NULL ? NULL : (IWMDMProgress*)progress), pIWMDMMetaData, NULL, (IWMDMStorage **)&pNewObject); if(SUCCEEDED(hr) || hr == WMDM_S_NOT_ALL_PROPERTIES_APPLIED || hr == WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED) { return_value = true; hr = S_FALSE; } } } } } } } pIEnumStorage->Release(); } /* move to next device */ if(!return_value) hr = pIEnumDev->Next(1, (IWMDMDevice **)&pIDevice, &ulNumFetched); } pIEnumDev->Release(); } mtp_close(&mtp); } return return_value ? 1 : 0; } }