mtp.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. #include <furi.h>
  2. #include <storage/storage.h>
  3. #include "main.h"
  4. #include "mtp.h"
  5. #include "usb_desc.h"
  6. #define BLOCK_SIZE 65536
  7. // Supported operations (example, add as needed)
  8. uint16_t supported_operations[] = {
  9. MTP_OP_GET_DEVICE_INFO,
  10. MTP_OP_OPEN_SESSION,
  11. MTP_OP_CLOSE_SESSION,
  12. MTP_OP_GET_STORAGE_IDS,
  13. MTP_OP_GET_STORAGE_INFO,
  14. MTP_OP_GET_NUM_OBJECTS,
  15. MTP_OP_GET_OBJECT_HANDLES,
  16. MTP_OP_GET_OBJECT_INFO,
  17. MTP_OP_GET_OBJECT,
  18. MTP_OP_SEND_OBJECT_INFO,
  19. MTP_OP_SEND_OBJECT,
  20. MTP_OP_DELETE_OBJECT,
  21. MTP_OP_GET_DEVICE_PROP_DESC,
  22. MTP_OP_GET_DEVICE_PROP_VALUE};
  23. // Supported device properties (example, add as needed)
  24. uint16_t supported_device_properties[] = {
  25. 0xd402, // Device friendly name
  26. };
  27. uint16_t supported_playback_formats[] = {
  28. MTP_FORMAT_UNDEFINED,
  29. MTP_FORMAT_ASSOCIATION,
  30. };
  31. void merge_path(char* target, char* base, char* name) {
  32. // implement this way since strcat is unavailable
  33. char* ptr = target;
  34. strcpy(target, base);
  35. ptr += strlen(base);
  36. strcpy(ptr, "/");
  37. ptr++;
  38. strcpy(ptr, name);
  39. }
  40. // temporary storage for buffer
  41. MTPDataPersistence persistence;
  42. void mtp_handle_bulk(AppMTP* mtp, uint8_t* buffer, uint32_t length) {
  43. UNUSED(mtp);
  44. if(persistence.left_bytes > 0) {
  45. FURI_LOG_I("MTP", "Left bytes: %ld", persistence.left_bytes);
  46. handle_mtp_data_packet(mtp, buffer, length, 1);
  47. return;
  48. }
  49. if(length < 12) {
  50. FURI_LOG_E("MTP", "Invalid MTP packet");
  51. return;
  52. }
  53. struct MTPHeader* header = (struct MTPHeader*)buffer;
  54. uint16_t type = header->type;
  55. if(type == MTP_TYPE_COMMAND) {
  56. struct MTPContainer* container = (struct MTPContainer*)buffer;
  57. handle_mtp_command(mtp, container);
  58. } else if(type == MTP_TYPE_DATA) {
  59. if(header->len > length) {
  60. persistence.left_bytes = header->len;
  61. }
  62. handle_mtp_data_packet(mtp, buffer, length, 0);
  63. } else if(type == MTP_TYPE_RESPONSE) {
  64. handle_mtp_response(mtp, header);
  65. } else {
  66. FURI_LOG_W("MTP", "Unsupported MTP packet type: %d", type);
  67. }
  68. }
  69. void setup_persistence(struct MTPContainer* container) {
  70. persistence.transaction_id = container->header.transaction_id;
  71. memcpy(persistence.params, container->params, sizeof(uint32_t) * 5);
  72. }
  73. void handle_mtp_data_packet(AppMTP* mtp, uint8_t* buffer, int32_t length, bool cont) {
  74. UNUSED(mtp);
  75. uint8_t* ptr = buffer;
  76. if(!cont) {
  77. struct MTPHeader* header = (struct MTPHeader*)buffer;
  78. if(header->transaction_id != persistence.transaction_id) {
  79. // the params value can not be trusted.
  80. // reset the params
  81. for(int i = 0; i < 5; i++) {
  82. persistence.params[i] = 0;
  83. }
  84. }
  85. persistence.global_buffer = NULL;
  86. uint32_t transaction_id = header->transaction_id;
  87. persistence.op = header->op;
  88. FURI_LOG_I("MTP", "Handling MTP data: 0x%04x", header->op);
  89. FURI_LOG_I("MTP", "Transaction ID: %ld", transaction_id);
  90. FURI_LOG_I("MTP", "Length: %ld", length);
  91. ptr = (uint8_t*)buffer + sizeof(struct MTPHeader);
  92. switch(header->op) {
  93. case MTP_OP_SEND_OBJECT_INFO: {
  94. persistence.global_buffer = malloc(sizeof(uint8_t) * 256);
  95. persistence.buffer_offset = 0;
  96. break;
  97. }
  98. }
  99. }
  100. if(persistence.global_buffer != NULL) {
  101. memcpy(persistence.global_buffer + persistence.buffer_offset, ptr, length);
  102. persistence.buffer_offset += length;
  103. if(persistence.left_bytes > 0) {
  104. persistence.left_bytes -= length;
  105. }
  106. FURI_LOG_I("MTP", "Buffer offset: %ld", persistence.buffer_offset);
  107. FURI_LOG_I("MTP", "Left bytes: %ld", persistence.left_bytes);
  108. if(persistence.left_bytes == 0) {
  109. handle_mtp_data_complete(mtp);
  110. }
  111. }
  112. }
  113. void handle_mtp_data_complete(AppMTP* mtp) {
  114. UNUSED(mtp);
  115. switch(persistence.op) {
  116. case MTP_OP_SEND_OBJECT_INFO: {
  117. struct ObjectInfoHeader* info =
  118. (struct ObjectInfoHeader*)(persistence.global_buffer + sizeof(struct MTPHeader));
  119. uint8_t* ptr =
  120. persistence.global_buffer + sizeof(struct MTPHeader) + sizeof(struct ObjectInfoHeader);
  121. ptr += 4;
  122. char* name = ReadMTPString(ptr);
  123. // if the name is blank, generate random name
  124. if(*name == 0) {
  125. char* random_name = malloc(sizeof(char) * 10);
  126. strcpy(random_name, "file_");
  127. int random = rand() % 1000;
  128. char random_str[4];
  129. itoa(random, random_str, 10);
  130. strcpy(random_name + 5, random_str);
  131. name = random_name;
  132. }
  133. FURI_LOG_I("MTP", "Creating object: %s", name);
  134. uint32_t storage_id = persistence.params[0];
  135. uint32_t parent = persistence.params[1];
  136. char* base_path = get_base_path_from_storage_id(storage_id);
  137. if(base_path == NULL) {
  138. FURI_LOG_E("MTP", "Invalid storage ID: %ld", storage_id);
  139. send_mtp_response(
  140. mtp, 3, MTP_RESP_INVALID_STORAGE_ID, persistence.transaction_id, NULL);
  141. break;
  142. }
  143. if(parent != 0xffffffff) {
  144. base_path = get_path_from_handle(mtp, parent);
  145. if(base_path == NULL) {
  146. FURI_LOG_E("MTP", "Invalid parent handle: %ld", parent);
  147. send_mtp_response(
  148. mtp, 3, MTP_RESP_INVALID_OBJECT_HANDLE, persistence.transaction_id, NULL);
  149. break;
  150. }
  151. }
  152. char* full_path = malloc(sizeof(char) * 256);
  153. merge_path(full_path, base_path, name);
  154. FURI_LOG_I("MTP", "Format: %04x", info->format);
  155. bool is_dir = info->format == MTP_FORMAT_ASSOCIATION;
  156. if(is_dir) {
  157. if(!storage_dir_exists(mtp->storage, full_path)) {
  158. if(!storage_simply_mkdir(mtp->storage, full_path)) {
  159. FURI_LOG_E("MTP", "Failed to create directory: %s", full_path);
  160. send_mtp_response(
  161. mtp, 3, MTP_RESP_GENERAL_ERROR, persistence.transaction_id, NULL);
  162. free(full_path);
  163. break;
  164. }
  165. }
  166. } else {
  167. if(!storage_file_exists(mtp->storage, full_path)) {
  168. // create file
  169. File* file = storage_file_alloc(mtp->storage);
  170. if(!storage_file_open(file, full_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
  171. FURI_LOG_E("MTP", "Failed to create file: %s", full_path);
  172. send_mtp_response(
  173. mtp, 3, MTP_RESP_GENERAL_ERROR, persistence.transaction_id, NULL);
  174. storage_file_free(file);
  175. free(full_path);
  176. break;
  177. }
  178. storage_file_free(file);
  179. }
  180. }
  181. uint32_t handle = issue_object_handle(mtp, full_path);
  182. persistence.params[2] = handle;
  183. free(name);
  184. free(full_path);
  185. send_mtp_response(mtp, 3, MTP_RESP_OK, persistence.transaction_id, persistence.params);
  186. break;
  187. }
  188. default:
  189. FURI_LOG_W("MTP", "Unsupported MTP operation in bulk transfer: 0x%04x", persistence.op);
  190. send_mtp_response(mtp, 3, MTP_RESP_UNKNOWN, persistence.transaction_id, NULL);
  191. break;
  192. }
  193. free(persistence.global_buffer);
  194. persistence.global_buffer = NULL;
  195. }
  196. void handle_mtp_response(AppMTP* mtp, struct MTPHeader* header) {
  197. UNUSED(mtp);
  198. FURI_LOG_I("MTP", "Handling MTP response: 0x%04x", header->op);
  199. FURI_LOG_I("MTP", "Transaction ID: %ld", header->transaction_id);
  200. FURI_LOG_I("MTP", "Has Data: %d", persistence.global_buffer != NULL);
  201. FURI_LOG_I("MTP", "Data length: %ld", persistence.buffer_offset);
  202. }
  203. void handle_mtp_command(AppMTP* mtp, struct MTPContainer* container) {
  204. uint16_t mtp_op = container->header.op;
  205. FURI_LOG_I("MTP", "Handling MTP operation: 0x%04x", mtp_op);
  206. switch(mtp_op) {
  207. case MTP_OP_GET_DEVICE_INFO:
  208. FURI_LOG_I("MTP", "GetDeviceInfo operation");
  209. send_device_info(mtp, container->header.transaction_id);
  210. // Process the GetDeviceInfo operation
  211. break;
  212. case MTP_OP_OPEN_SESSION:
  213. case MTP_OP_CLOSE_SESSION:
  214. //FURI_LOG_I("MTP", "Open/CloseSession operation (STUB)");
  215. send_mtp_response(mtp, 3, MTP_RESP_OK, container->header.transaction_id, NULL);
  216. break;
  217. case MTP_OP_GET_STORAGE_IDS:
  218. FURI_LOG_I("MTP", "GetStorageIDs operation");
  219. send_storage_ids(mtp, container->header.transaction_id);
  220. break;
  221. case MTP_OP_GET_STORAGE_INFO: {
  222. FURI_LOG_I("MTP", "GetStorageInfo operation");
  223. uint8_t* info = malloc(sizeof(uint8_t) * 256);
  224. int length = GetStorageInfo(mtp, container->params[0], info);
  225. send_mtp_response_buffer(
  226. mtp,
  227. MTP_TYPE_DATA,
  228. MTP_OP_GET_STORAGE_INFO,
  229. container->header.transaction_id,
  230. info,
  231. length);
  232. send_mtp_response_buffer(
  233. mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, container->header.transaction_id, NULL, 0);
  234. free(info);
  235. break;
  236. }
  237. case MTP_OP_GET_OBJECT_HANDLES:
  238. FURI_LOG_I("MTP", "GetObjectHandles operation");
  239. if(container->params[1]) {
  240. send_mtp_response_buffer(
  241. mtp,
  242. MTP_TYPE_RESPONSE,
  243. MTP_RESP_SPEC_BY_FORMAT_UNSUPPORTED,
  244. container->header.transaction_id,
  245. NULL,
  246. 0);
  247. break;
  248. } else {
  249. uint8_t* buffer = malloc(sizeof(uint8_t) * 256);
  250. int length = GetObjectHandles(mtp, container->params[0], container->params[2], buffer);
  251. send_mtp_response_buffer(
  252. mtp,
  253. MTP_TYPE_DATA,
  254. MTP_OP_GET_OBJECT_HANDLES,
  255. container->header.transaction_id,
  256. buffer,
  257. length);
  258. send_mtp_response_buffer(
  259. mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, container->header.transaction_id, NULL, 0);
  260. free(buffer);
  261. }
  262. break;
  263. case MTP_OP_GET_OBJECT_INFO: {
  264. FURI_LOG_I("MTP", "GetObjectInfo operation");
  265. uint8_t* buffer = malloc(sizeof(uint8_t) * 512);
  266. int length = GetObjectInfo(mtp, container->params[0], buffer);
  267. if(length < 0) {
  268. send_mtp_response(
  269. mtp,
  270. MTP_TYPE_RESPONSE,
  271. MTP_RESP_INVALID_OBJECT_HANDLE,
  272. container->header.transaction_id,
  273. NULL);
  274. break;
  275. }
  276. send_mtp_response_buffer(
  277. mtp,
  278. MTP_TYPE_DATA,
  279. MTP_OP_GET_OBJECT_INFO,
  280. container->header.transaction_id,
  281. buffer,
  282. length);
  283. free(buffer);
  284. send_mtp_response_buffer(
  285. mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, container->header.transaction_id, NULL, 0);
  286. break;
  287. }
  288. case MTP_OP_DELETE_OBJECT:
  289. FURI_LOG_I("MTP", "DeleteObject operation");
  290. if(DeleteObject(mtp, container->params[0])) {
  291. send_mtp_response(mtp, 3, MTP_RESP_OK, container->header.transaction_id, NULL);
  292. } else {
  293. send_mtp_response(
  294. mtp, 3, MTP_RESP_INVALID_OBJECT_HANDLE, container->header.transaction_id, NULL);
  295. }
  296. break;
  297. case MTP_OP_GET_DEVICE_PROP_VALUE:
  298. FURI_LOG_I("MTP", "GetDevicePropValue operation");
  299. send_device_prop_value(mtp, container->header.transaction_id, container->params[0]);
  300. // Process the GetDevicePropValue operation
  301. break;
  302. case MTP_OP_GET_DEVICE_PROP_DESC:
  303. FURI_LOG_I("MTP", "GetDevicePropDesc operation");
  304. send_device_prop_desc(mtp, container->header.transaction_id, container->params[0]);
  305. // Process the GetDevicePropDesc operation
  306. break;
  307. // Handle bulk transfer specific operations
  308. case MTP_OP_SEND_OBJECT_INFO:
  309. FURI_LOG_I("MTP", "SendObjectInfo operation");
  310. setup_persistence(container);
  311. break;
  312. case MTP_OP_GET_OBJECT: {
  313. FURI_LOG_I("MTP", "GetObject operation");
  314. GetObject(mtp, container->header.transaction_id, container->params[0]);
  315. break;
  316. }
  317. // Handle other bulk operations here...
  318. default:
  319. FURI_LOG_W("MTP", "Unsupported MTP operation in bulk transfer: 0x%04x", mtp_op);
  320. send_mtp_response(mtp, 3, MTP_RESP_UNKNOWN, container->header.transaction_id, NULL);
  321. break;
  322. }
  323. }
  324. void send_storage_ids(AppMTP* mtp, uint32_t transaction_id) {
  325. uint32_t count;
  326. uint32_t storage_ids[3];
  327. GetStorageIDs(mtp, storage_ids, &count);
  328. FURI_LOG_I("MTP", "Sending storage IDs: %ld storages", count);
  329. uint32_t payload[3] = {count, storage_ids[0], storage_ids[1]};
  330. send_mtp_response_buffer(
  331. mtp,
  332. MTP_TYPE_DATA,
  333. MTP_OP_GET_STORAGE_IDS,
  334. transaction_id,
  335. (uint8_t*)payload,
  336. sizeof(uint32_t) * (count + 1));
  337. send_mtp_response_buffer(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL, 0);
  338. }
  339. void send_device_info(AppMTP* mtp, uint32_t transaction_id) {
  340. uint8_t* response = malloc(sizeof(uint8_t) * 256);
  341. int length = BuildDeviceInfo(response);
  342. send_mtp_response_buffer(
  343. mtp, MTP_TYPE_DATA, MTP_OP_GET_DEVICE_INFO, transaction_id, response, length);
  344. send_mtp_response_buffer(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL, 0);
  345. free(response);
  346. }
  347. void send_device_prop_value(AppMTP* mtp, uint32_t transaction_id, uint32_t prop_code) {
  348. uint8_t* response = malloc(sizeof(uint8_t) * 256);
  349. int length = GetDevicePropValue(prop_code, response);
  350. send_mtp_response_buffer(
  351. mtp, MTP_TYPE_DATA, MTP_OP_GET_DEVICE_PROP_VALUE, transaction_id, response, length);
  352. send_mtp_response_buffer(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL, 0);
  353. free(response);
  354. }
  355. void send_device_prop_desc(AppMTP* mtp, uint32_t transaction_id, uint32_t prop_code) {
  356. uint8_t* response = malloc(sizeof(uint8_t) * 256);
  357. int length = GetDevicePropDesc(prop_code, response);
  358. send_mtp_response_buffer(
  359. mtp, MTP_TYPE_DATA, MTP_OP_GET_DEVICE_PROP_DESC, transaction_id, response, length);
  360. send_mtp_response_buffer(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL, 0);
  361. free(response);
  362. }
  363. char* get_path_from_handle(AppMTP* mtp, uint32_t handle) {
  364. FileHandle* current = mtp->handles;
  365. while(current != NULL) {
  366. if(current->handle == handle) {
  367. return current->path;
  368. }
  369. current = current->next;
  370. }
  371. return NULL;
  372. }
  373. uint32_t issue_object_handle(AppMTP* mtp, char* path) {
  374. int handle = 0;
  375. int length = strlen(path);
  376. char* path_store = malloc(sizeof(char) * (length + 1));
  377. strcpy(path_store, path);
  378. if(mtp->handles == NULL) {
  379. mtp->handles = malloc(sizeof(FileHandle));
  380. mtp->handles->handle = handle;
  381. mtp->handles->path = path_store;
  382. mtp->handles->next = NULL;
  383. return handle;
  384. }
  385. FileHandle* current = mtp->handles;
  386. if(strcmp(current->path, path) == 0) {
  387. return current->handle;
  388. }
  389. while(current->next != NULL) {
  390. if(strcmp(current->path, path) == 0) {
  391. return current->handle;
  392. }
  393. current = current->next;
  394. handle++;
  395. }
  396. current->next = malloc(sizeof(FileHandle));
  397. current = current->next;
  398. handle++;
  399. current->handle = handle;
  400. current->path = path_store;
  401. current->next = NULL;
  402. return handle;
  403. }
  404. char* get_base_path_from_storage_id(uint32_t storage_id) {
  405. if(storage_id == INTERNAL_STORAGE_ID) {
  406. return STORAGE_INT_PATH_PREFIX;
  407. } else if(storage_id == EXTERNAL_STORAGE_ID) {
  408. return STORAGE_EXT_PATH_PREFIX;
  409. }
  410. return NULL;
  411. }
  412. int list_and_issue_handles(
  413. AppMTP* mtp,
  414. uint32_t storage_id,
  415. uint32_t association,
  416. uint32_t* handles) {
  417. Storage* storage = mtp->storage;
  418. char* base_path = get_base_path_from_storage_id(storage_id);
  419. if(base_path == NULL) {
  420. base_path = "";
  421. }
  422. File* dir = storage_file_alloc(storage);
  423. if(association == 0xffffffff) {
  424. // count the objects in the root directory
  425. storage_dir_open(dir, base_path);
  426. } else {
  427. char* path = get_path_from_handle(mtp, association);
  428. FURI_LOG_I("MTP", "Association path: %s", path);
  429. if(path == NULL) {
  430. return 0;
  431. }
  432. storage_dir_open(dir, path);
  433. base_path = path;
  434. }
  435. int count = 0;
  436. FileInfo fileinfo;
  437. char* file_name = malloc(sizeof(char) * 256);
  438. char* full_path = malloc(sizeof(char) * 256);
  439. while(storage_dir_read(dir, &fileinfo, file_name, 256)) {
  440. if(file_info_is_dir(&fileinfo)) {
  441. FURI_LOG_I("MTP", "Found directory: %s", file_name);
  442. } else {
  443. FURI_LOG_I("MTP", "Found file: %s", file_name);
  444. }
  445. merge_path(full_path, base_path, file_name);
  446. FURI_LOG_I("MTP", "Full path: %s", full_path);
  447. uint32_t handle = issue_object_handle(mtp, full_path);
  448. if(handles != NULL) {
  449. handles[count] = handle;
  450. }
  451. count++;
  452. }
  453. FURI_LOG_I("MTP", "Getting number of objects in storage %ld", storage_id);
  454. FURI_LOG_I("MTP", "Base path: %s", base_path);
  455. FURI_LOG_I("MTP", "Association: %ld", association);
  456. FURI_LOG_I("MTP", "Number of objects: %d", count);
  457. storage_dir_close(dir);
  458. storage_file_free(dir);
  459. free(file_name);
  460. free(full_path);
  461. return count;
  462. }
  463. struct GetObjectContext {
  464. File* file;
  465. };
  466. int GetObject_callback(void* ctx, uint8_t* buffer, int length) {
  467. struct GetObjectContext* obj_ctx = (struct GetObjectContext*)ctx;
  468. return storage_file_read(obj_ctx->file, buffer, length);
  469. }
  470. void GetObject(AppMTP* mtp, uint32_t transaction_id, uint32_t handle) {
  471. char* path = get_path_from_handle(mtp, handle);
  472. if(path == NULL) {
  473. send_mtp_response(
  474. mtp, MTP_TYPE_RESPONSE, MTP_RESP_INVALID_OBJECT_HANDLE, transaction_id, NULL);
  475. return;
  476. }
  477. FURI_LOG_I("MTP", "Getting object: %s", path);
  478. Storage* storage = mtp->storage;
  479. File* file = storage_file_alloc(storage);
  480. if(!storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
  481. FURI_LOG_E("MTP", "Failed to open file: %s", path);
  482. send_mtp_response(
  483. mtp, MTP_TYPE_RESPONSE, MTP_RESP_INVALID_OBJECT_HANDLE, transaction_id, NULL);
  484. return;
  485. }
  486. uint32_t size = storage_file_size(file);
  487. struct GetObjectContext ctx = {
  488. .file = file,
  489. };
  490. send_mtp_response_stream(
  491. mtp, MTP_TYPE_DATA, MTP_OP_GET_OBJECT, transaction_id, &ctx, GetObject_callback, size);
  492. send_mtp_response(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL);
  493. storage_file_close(file);
  494. storage_file_free(file);
  495. }
  496. int GetObjectInfo(AppMTP* mtp, uint32_t handle, uint8_t* buffer) {
  497. ObjectInfoHeader* header = (ObjectInfoHeader*)buffer;
  498. uint8_t* ptr = buffer + sizeof(ObjectInfoHeader);
  499. char* path = get_path_from_handle(mtp, handle);
  500. if(path == NULL) {
  501. return -1;
  502. }
  503. FURI_LOG_I("MTP", "Getting object info for handle %ld", handle);
  504. FURI_LOG_I("MTP", "Path: %s", path);
  505. header->protection_status = 0;
  506. Storage* storage = mtp->storage;
  507. File* file = storage_file_alloc(storage);
  508. uint16_t length;
  509. FileInfo fileinfo;
  510. FS_Error err = storage_common_stat(storage, path, &fileinfo);
  511. if(err != FSE_OK) {
  512. FURI_LOG_E("MTP", "Failed to get file info: %s", filesystem_api_error_get_desc(err));
  513. return -1;
  514. }
  515. if(memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) {
  516. FURI_LOG_I("MTP", "Object in Internal storage");
  517. header->storage_id = INTERNAL_STORAGE_ID;
  518. } else if(memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) {
  519. FURI_LOG_I("MTP", "Object in External storage");
  520. header->storage_id = EXTERNAL_STORAGE_ID;
  521. } else {
  522. return -1;
  523. }
  524. if(file_info_is_dir(&fileinfo)) {
  525. FURI_LOG_I("MTP", "Directory");
  526. header->format = MTP_FORMAT_ASSOCIATION;
  527. header->association_type = 0x0001; // Generic folder
  528. } else {
  529. FURI_LOG_I("MTP", "Undefined type");
  530. header->format = MTP_FORMAT_UNDEFINED;
  531. }
  532. header->compressed_size = fileinfo.size;
  533. header->thumb_format = 0;
  534. header->thumb_compressed_size = 0;
  535. header->thumb_pix_width = 0;
  536. header->thumb_pix_height = 0;
  537. header->image_pix_width = 0;
  538. header->image_pix_height = 0;
  539. header->image_bit_depth = 0;
  540. /*
  541. // is on root directory (/int or /ext)
  542. if(strchr(path + 1, '/') == NULL) {
  543. header->parent_object = 0;
  544. } else {
  545. char* parent_path = malloc(sizeof(char) * 256);
  546. strcpy(parent_path, path);
  547. char* last_slash = strrchr(parent_path, '/');
  548. *last_slash = '\0';
  549. header->parent_object = issue_object_handle(mtp, parent_path);
  550. free(parent_path);
  551. }
  552. */
  553. char* file_name = strrchr(path, '/');
  554. FURI_LOG_I("MTP", "File name: %s", file_name + 1);
  555. WriteMTPString(ptr, file_name + 1, &length);
  556. ptr += length;
  557. // get created
  558. WriteMTPString(ptr, "20240608T010702", &length);
  559. ptr += length;
  560. // get last modified
  561. WriteMTPString(ptr, "20240608T010702", &length);
  562. ptr += length;
  563. // get keywords
  564. WriteMTPString(ptr, "", &length);
  565. ptr += length;
  566. storage_file_free(file);
  567. return ptr - buffer;
  568. }
  569. char* ReadMTPString(uint8_t* buffer) {
  570. int len16 = *(uint8_t*)buffer;
  571. if(len16 == 0) {
  572. return "";
  573. }
  574. char* str = malloc(sizeof(char) * len16);
  575. uint8_t* base = buffer + 1;
  576. uint16_t* ptr = (uint16_t*)base;
  577. for(int i = 0; i < len16; i++) {
  578. str[i] = *ptr++;
  579. }
  580. return str;
  581. }
  582. int GetNumObjects(AppMTP* mtp, uint32_t storage_id, uint32_t association) {
  583. return list_and_issue_handles(mtp, storage_id, association, NULL);
  584. }
  585. int GetObjectHandles(AppMTP* mtp, uint32_t storage_id, uint32_t association, uint8_t* buffer) {
  586. uint8_t* ptr = buffer;
  587. uint16_t length;
  588. UNUSED(length);
  589. // For now, just return a single object handle
  590. int count = GetNumObjects(mtp, storage_id, association);
  591. *(uint32_t*)ptr = count;
  592. ptr += sizeof(uint32_t);
  593. uint32_t* handles = (uint32_t*)ptr;
  594. length = list_and_issue_handles(mtp, storage_id, association, handles);
  595. ptr += length * sizeof(uint32_t);
  596. return ptr - buffer;
  597. }
  598. int GetDevicePropValue(uint32_t prop_code, uint8_t* buffer) {
  599. uint8_t* ptr = buffer;
  600. uint16_t length;
  601. switch(prop_code) {
  602. case 0xd402:
  603. WriteMTPString(ptr, "Flipper Zero", &length);
  604. ptr += length;
  605. break;
  606. default:
  607. // Unsupported property
  608. break;
  609. }
  610. return ptr - buffer;
  611. }
  612. int GetDevicePropDesc(uint32_t prop_code, uint8_t* buffer) {
  613. uint8_t* ptr = buffer;
  614. uint16_t length;
  615. switch(prop_code) {
  616. case 0xd402:
  617. // Device friendly name
  618. *(uint16_t*)ptr = prop_code;
  619. ptr += 2;
  620. // type is string
  621. *(uint16_t*)ptr = 0xffff;
  622. ptr += 2;
  623. // read-only
  624. *(uint16_t*)ptr = 0x0000;
  625. ptr += 2;
  626. length = GetDevicePropValue(prop_code, ptr);
  627. ptr += length;
  628. length = GetDevicePropValue(prop_code, ptr);
  629. ptr += length;
  630. // no-form
  631. *(uint16_t*)ptr = 0x0000;
  632. ptr += 2;
  633. break;
  634. default:
  635. // Unsupported property
  636. break;
  637. }
  638. return ptr - buffer;
  639. }
  640. void send_mtp_response_stream(
  641. AppMTP* mtp,
  642. uint16_t resp_type,
  643. uint16_t resp_code,
  644. uint32_t transaction_id,
  645. void* callback_context,
  646. int (*callback)(void* ctx, uint8_t* buffer, int length),
  647. uint32_t length) {
  648. int chunk_idx = 0;
  649. size_t buffer_available = MTP_MAX_PACKET_SIZE;
  650. uint8_t* buffer = malloc(sizeof(uint8_t) * buffer_available);
  651. uint8_t* ptr = buffer;
  652. uint32_t sent_length = 0;
  653. FURI_LOG_I("MTP", "Sending MTP response stream: %ld bytes", length);
  654. do {
  655. buffer_available = MTP_MAX_PACKET_SIZE;
  656. ptr = buffer; // reset the pointer
  657. if(chunk_idx == 0) {
  658. struct MTPHeader* hdr = (struct MTPHeader*)buffer;
  659. hdr->len = length + sizeof(*hdr);
  660. hdr->type = resp_type;
  661. hdr->op = resp_code;
  662. hdr->transaction_id = transaction_id;
  663. ptr += sizeof(*hdr);
  664. buffer_available -= sizeof(*hdr);
  665. }
  666. FURI_LOG_I("MTP", "Remaining bytes for packet: %d", buffer_available);
  667. int read_bytes = callback(callback_context, ptr, buffer_available);
  668. uint32_t usb_bytes = (ptr - buffer) + read_bytes;
  669. FURI_LOG_I("MTP", "USB packet size: %ld", usb_bytes);
  670. usbd_ep_write(mtp->dev, MTP_EP_IN_ADDR, buffer, usb_bytes);
  671. sent_length += usb_bytes;
  672. chunk_idx++;
  673. FURI_LOG_I(
  674. "MTP",
  675. "Sent chunk %d (currently sent: %ld/%ld)",
  676. chunk_idx,
  677. sent_length - sizeof(struct MTPHeader),
  678. length);
  679. } while(sent_length < length + sizeof(struct MTPHeader));
  680. free(buffer);
  681. }
  682. int send_mtp_response_buffer_callback(void* ctx, uint8_t* buffer, int size) {
  683. struct MTPResponseBufferContext* context = (struct MTPResponseBufferContext*)ctx;
  684. if(context->buffer == NULL || context->size == 0) {
  685. return 0;
  686. }
  687. uint32_t remaining = context->size - context->sent;
  688. uint32_t to_send = size;
  689. if(remaining < to_send) {
  690. to_send = remaining;
  691. }
  692. memcpy(buffer, context->buffer + context->sent, to_send);
  693. context->sent += to_send;
  694. return to_send;
  695. }
  696. void send_mtp_response_buffer(
  697. AppMTP* mtp,
  698. uint16_t resp_type,
  699. uint16_t resp_code,
  700. uint32_t transaction_id,
  701. uint8_t* buffer,
  702. uint32_t size) {
  703. struct MTPResponseBufferContext* ctx = malloc(sizeof(struct MTPResponseBufferContext));
  704. ctx->buffer = buffer;
  705. ctx->size = size;
  706. ctx->sent = 0;
  707. send_mtp_response_stream(
  708. mtp, resp_type, resp_code, transaction_id, ctx, send_mtp_response_buffer_callback, size);
  709. free(ctx);
  710. }
  711. void send_mtp_response(
  712. AppMTP* mtp,
  713. uint16_t resp_type,
  714. uint16_t resp_code,
  715. uint32_t transaction_id,
  716. uint32_t* params) {
  717. uint32_t response[5] = {0};
  718. if(params != NULL) {
  719. memcpy(response, params, sizeof(uint32_t) * 5);
  720. }
  721. send_mtp_response_buffer(
  722. mtp, resp_type, resp_code, transaction_id, (uint8_t*)response, sizeof(response));
  723. }
  724. int mtp_handle_class_control(AppMTP* mtp, usbd_device* dev, usbd_ctlreq* req) {
  725. UNUSED(dev);
  726. int value = -1;
  727. uint32_t handle = req->wIndex;
  728. uint8_t* buffer = req->data;
  729. uint32_t size = req->wLength;
  730. UNUSED(handle);
  731. UNUSED(buffer);
  732. UNUSED(size);
  733. switch(req->bRequest) {
  734. case MTP_REQ_CANCEL:
  735. // Handle Cancel request
  736. value = 0;
  737. break;
  738. case MTP_REQ_GET_EXT_EVENT_DATA:
  739. // Handle GetExtEventData request
  740. value = 0;
  741. break;
  742. case MTP_REQ_RESET:
  743. // Handle Reset request
  744. mtp->state = MTPStateReady;
  745. value = 0;
  746. break;
  747. case MTP_REQ_GET_DEVICE_STATUS:
  748. // Handle GetDeviceStatus request
  749. struct mtp_device_status* status = (struct mtp_device_status*)req->data;
  750. status->wLength = sizeof(*status);
  751. status->wCode = (mtp->state == MTPStateBusy) ? MTP_RESP_DEVICE_BUSY : MTP_RESP_OK;
  752. value = status->wLength;
  753. break;
  754. default:
  755. // Unsupported request
  756. break;
  757. }
  758. return value;
  759. }
  760. int BuildDeviceInfo(uint8_t* buffer) {
  761. uint8_t* ptr = buffer;
  762. uint16_t length;
  763. // Standard version
  764. *(uint16_t*)ptr = 100;
  765. ptr += sizeof(uint16_t);
  766. // Vendor extension ID
  767. *(uint32_t*)ptr = MTP_VENDOR_EXTENSION_ID;
  768. ptr += sizeof(uint32_t);
  769. // Vendor extension version
  770. *(uint16_t*)ptr = MTP_VENDOR_EXTENSION_VERSION;
  771. ptr += sizeof(uint16_t);
  772. // Vendor extension description
  773. WriteMTPString(ptr, "microsoft.com: 1.0;", &length);
  774. ptr += length;
  775. // Functional mode
  776. *(uint16_t*)ptr = MTP_FUNCTIONAL_MODE;
  777. ptr += sizeof(uint16_t);
  778. // Operations supported
  779. length = sizeof(supported_operations) / sizeof(uint16_t);
  780. *(uint32_t*)ptr = length; // Number of supported operations
  781. ptr += sizeof(uint32_t);
  782. for(int i = 0; i < length; i++) {
  783. *(uint16_t*)ptr = supported_operations[i];
  784. ptr += sizeof(uint16_t);
  785. }
  786. // Supported events (example, add as needed)
  787. *(uint32_t*)ptr = 0; // Number of supported events
  788. ptr += sizeof(uint32_t);
  789. length = sizeof(supported_device_properties) / sizeof(uint16_t);
  790. *(uint32_t*)ptr = length; // Number of supported device properties
  791. ptr += sizeof(uint32_t);
  792. for(int i = 0; i < length; i++) {
  793. *(uint16_t*)ptr = supported_device_properties[i];
  794. ptr += sizeof(uint16_t);
  795. }
  796. // Supported capture formats (example, add as needed)
  797. *(uint32_t*)ptr = 0; // Number of supported capture formats
  798. ptr += sizeof(uint32_t);
  799. // Supported playback formats (example, add as needed)
  800. length = sizeof(supported_playback_formats) / sizeof(uint16_t);
  801. *(uint32_t*)ptr = length; // Number of supported playback formats
  802. ptr += sizeof(uint32_t);
  803. for(int i = 0; i < length; i++) {
  804. *(uint16_t*)ptr = supported_playback_formats[i];
  805. ptr += sizeof(uint16_t);
  806. }
  807. // Manufacturer
  808. WriteMTPString(ptr, USB_MANUFACTURER_STRING, &length);
  809. ptr += length;
  810. // Model
  811. WriteMTPString(ptr, USB_DEVICE_MODEL, &length);
  812. ptr += length;
  813. // Device version
  814. WriteMTPString(ptr, "1.0", &length);
  815. ptr += length;
  816. // Serial number
  817. WriteMTPString(ptr, "HakureiReimu", &length);
  818. ptr += length;
  819. return ptr - buffer;
  820. }
  821. void GetStorageIDs(AppMTP* mtp, uint32_t* storage_ids, uint32_t* count) {
  822. SDInfo sd_info;
  823. FS_Error err = storage_sd_info(mtp->storage, &sd_info);
  824. storage_ids[0] = INTERNAL_STORAGE_ID;
  825. if(err != FSE_OK) {
  826. FURI_LOG_E("MTP", "SD Card not found");
  827. *count = 1; // We have only one storage
  828. return;
  829. }
  830. storage_ids[1] = EXTERNAL_STORAGE_ID;
  831. *count = 2; // We have two storages: internal and external
  832. }
  833. int GetStorageInfo(AppMTP* mtp, uint32_t storage_id, uint8_t* buf) {
  834. MTPStorageInfoHeader* info = (MTPStorageInfoHeader*)buf;
  835. uint8_t* ptr = buf + sizeof(MTPStorageInfoHeader);
  836. uint16_t length;
  837. info->free_space_in_objects = 20ul;
  838. info->filesystem_type = 0x0002; // Generic hierarchical
  839. info->access_capability = 0x0000; // Read-write
  840. FURI_LOG_I("MTP", "Getting storage info for storage ID %04lx", storage_id);
  841. if(storage_id == INTERNAL_STORAGE_ID) {
  842. // Fill in details for internal storage
  843. info->storage_type = 0x0003; // Fixed RAM
  844. // Fill in details for internal storage
  845. uint64_t total_space;
  846. uint64_t free_space;
  847. FS_Error err = storage_common_fs_info(
  848. mtp->storage, STORAGE_INT_PATH_PREFIX, &total_space, &free_space);
  849. if(err != FSE_OK) {
  850. info->max_capacity = 0;
  851. info->free_space_in_bytes = 0;
  852. } else {
  853. info->max_capacity = total_space / BLOCK_SIZE;
  854. info->free_space_in_bytes = free_space / BLOCK_SIZE;
  855. }
  856. WriteMTPString(ptr, "Internal Storage", &length);
  857. ptr += length;
  858. WriteMTPString(ptr, "INT_STORAGE", &length);
  859. ptr += length;
  860. } else if(storage_id == EXTERNAL_STORAGE_ID) {
  861. SDInfo sd_info;
  862. FS_Error err = storage_sd_info(mtp->storage, &sd_info);
  863. // Fill in details for internal storage
  864. info->storage_type = 0x0004; // Removable RAM
  865. if(err != FSE_OK) {
  866. info->max_capacity = 0;
  867. info->free_space_in_bytes = 0;
  868. FURI_LOG_E("MTP", "SD Card not found");
  869. } else {
  870. // Fill in details for external storage
  871. info->max_capacity = (uint64_t)sd_info.kb_total * 1024 / BLOCK_SIZE;
  872. info->free_space_in_bytes = (uint64_t)sd_info.kb_free * 1024 / BLOCK_SIZE;
  873. }
  874. WriteMTPString(ptr, "SD Card", &length);
  875. ptr += length;
  876. WriteMTPString(ptr, "SD_CARD", &length);
  877. ptr += length;
  878. }
  879. // try to convert into big endian???
  880. //info->max_capacity = __builtin_bswap64(info->max_capacity);
  881. //info->free_space_in_bytes = __builtin_bswap64(info->free_space_in_bytes);
  882. return ptr - buf;
  883. }
  884. // Microsoft-style UTF-16LE string:
  885. void WriteMTPString(uint8_t* buffer, const char* str, uint16_t* length) {
  886. uint8_t* ptr = buffer;
  887. uint8_t str_len = strlen(str);
  888. FURI_LOG_I("MTP", "Writing MTP string: %s", str);
  889. FURI_LOG_I("MTP", "String length: %d", str_len);
  890. // extra handling for empty string
  891. if(str_len == 0) {
  892. *ptr = 0x00;
  893. // that's it!
  894. *length = 1;
  895. return;
  896. }
  897. *ptr = str_len + 1; // Length byte (number of characters including the null terminator)
  898. ptr++;
  899. while(*str) {
  900. *ptr++ = *str++;
  901. *ptr++ = 0x00; // UTF-16LE encoding (add null byte for each character)
  902. }
  903. *ptr++ = 0x00; // Null terminator (UTF-16LE)
  904. *ptr++ = 0x00;
  905. FURI_LOG_I("MTP", "String byte length: %d", ptr - buffer);
  906. *length = ptr - buffer;
  907. }
  908. void WriteMTPBEString(uint8_t* buffer, const char* str, uint16_t* length) {
  909. uint8_t* ptr = buffer;
  910. uint8_t str_len = strlen(str);
  911. *ptr++ = str_len + 1; // Length byte (number of characters including the null terminator)
  912. while(*str) {
  913. *ptr++ = 0x00; // UTF-16BE encoding (add null byte for each character)
  914. *ptr++ = *str++;
  915. }
  916. *ptr++ = 0x00; // Null terminator (UTF-16LE)
  917. *ptr++ = 0x00;
  918. *length = ptr - buffer;
  919. }
  920. bool DeleteObject(AppMTP* mtp, uint32_t handle) {
  921. UNUSED(mtp);
  922. FURI_LOG_I("MTP", "Deleting object %ld", handle);
  923. char* path = get_path_from_handle(mtp, handle);
  924. if(path == NULL) {
  925. return false;
  926. }
  927. FileInfo fileinfo;
  928. FS_Error err = storage_common_stat(mtp->storage, path, &fileinfo);
  929. if(err != FSE_OK) {
  930. if(file_info_is_dir(&fileinfo)) {
  931. if(!storage_simply_remove_recursive(mtp->storage, path)) {
  932. return false;
  933. }
  934. } else {
  935. if(storage_common_remove(mtp->storage, path) != FSE_OK) {
  936. return false;
  937. }
  938. }
  939. }
  940. return true;
  941. }