A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1061 lines 29 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2015 by Cástor Muñoz 11 * 12 * based on: 13 * ipoddfu_c by user890104 14 * xpwn/pwnmetheus2 15 * 16 * This program is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU General Public License 18 * as published by the Free Software Foundation; either version 2 19 * of the License, or (at your option) any later version. 20 * 21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 22 * KIND, either express or implied. 23 * 24 ****************************************************************************/ 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <stdbool.h> 30#include <string.h> 31#ifdef WIN32 32#include <windows.h> 33#include <setupapi.h> 34#endif 35#ifdef USE_LIBUSBAPI 36#include <libusb-1.0/libusb.h> 37#endif 38#ifdef __APPLE__ 39#include <CoreFoundation/CoreFoundation.h> 40#include <IOKit/IOCFPlugIn.h> 41#include <IOKit/usb/IOUSBLib.h> 42#endif 43 44#include "mks5lboot.h" 45 46 47#ifdef WIN32 48#define sleep_ms(ms) Sleep(ms) 49#else 50#include <time.h> 51static void sleep_ms(unsigned int ms) 52{ 53 struct timespec req; 54 req.tv_sec = ms / 1000; 55 req.tv_nsec = (ms % 1000) * 1000000; 56 nanosleep(&req, NULL); 57} 58#endif 59 60static void put_uint32le(unsigned char* p, uint32_t x) 61{ 62 p[0] = x & 0xff; 63 p[1] = (x >> 8) & 0xff; 64 p[2] = (x >> 16) & 0xff; 65 p[3] = (x >> 24) & 0xff; 66} 67 68/* 69 * CRC32 functions 70 * Based on public domain implementation by Finn Yannick Jacobs. 71 * 72 * Written and copyright 1999 by Finn Yannick Jacobs 73 * No rights were reserved to this, so feel free to 74 * manipulate or do with it, what you want or desire :) 75 */ 76 77/* crc32table[] built by crc32_init() */ 78static uint32_t crc32table[256]; 79 80/* Calculate crc32 */ 81static uint32_t crc32(void *data, unsigned int len, uint32_t previousCrc32) 82{ 83 uint32_t crc = ~previousCrc32; 84 unsigned char *d = (unsigned char*) data; 85 while (len--) 86 crc = (crc >> 8) ^ crc32table[(crc & 0xFF) ^ *d++]; 87 return ~crc; 88} 89 90/* Calculate crc32table */ 91static void crc32_init() 92{ 93 uint32_t poly = 0xEDB88320L; 94 uint32_t crc; 95 int i, j; 96 for (i = 0; i < 256; ++i) 97 { 98 crc = i; 99 for (j = 0; j < 8; ++j) 100 crc = (crc >> 1) ^ ((crc & 1) ? poly : 0); 101 crc32table[i] = crc; 102 } 103} 104 105/* USB */ 106#define APPLE_VID 0x05AC 107 108struct pid_info { 109 int pid; 110 int mode; /* 0->DFU, 1->WTF */ 111 char *desc; 112}; 113 114struct pid_info known_pids[] = 115{ 116 /* DFU */ 117 { 0x1220, 0, "Nano 2G" }, 118 { 0x1223, 0, "Nano 3G / Classic" }, 119 { 0x1224, 0, "Shuffle 3G" }, 120 { 0x1225, 0, "Nano 4G" }, 121 { 0x1231, 0, "Nano 5G" }, 122 { 0x1232, 0, "Nano 6G" }, 123 { 0x1233, 0, "Shuffle 4G" }, 124 { 0x1234, 0, "Nano 7G" }, 125 /* WTF */ 126 { 0x1240, 1, "Nano 2G" }, 127 { 0x1241, 1, "Classic 1G" }, 128 { 0x1242, 1, "Nano 3G" }, 129 { 0x1243, 1, "Nano 4G" }, 130 { 0x1245, 1, "Classic 2G" }, 131 { 0x1246, 1, "Nano 5G" }, 132 { 0x1247, 1, "Classic 3G" }, 133 { 0x1248, 1, "Nano 6G" }, 134 { 0x1249, 1, "Nano 7G" }, 135 { 0x124a, 1, "Nano 7G" }, 136 { 0x1250, 1, "Classic 4G" }, 137}; 138#define N_KNOWN_PIDS (sizeof(known_pids)/sizeof(struct pid_info)) 139 140struct usbControlSetup { 141 uint8_t bmRequestType; 142 uint8_t bRequest; 143 uint16_t wValue; 144 uint16_t wIndex; 145 uint16_t wLength; 146} __attribute__ ((packed)); 147#define USB_CS_SZ (sizeof(struct usbControlSetup)) 148 149struct usbStatusData { 150 uint8_t bStatus; 151 uint8_t bwPollTimeout0; 152 uint8_t bwPollTimeout1; 153 uint8_t bwPollTimeout2; 154 uint8_t bState; 155 uint8_t iString; 156} __attribute__ ((packed)); 157 158 159/* 160 * DFU API 161 */ 162#define DFU_PKT_SZ 2048 /* must be pow2 <= wTransferSize (2048) */ 163 164/* DFU 1.1 specs */ 165typedef enum { 166 appIDLE = 0, 167 appDETACH = 1, 168 dfuIDLE = 2, 169 dfuDNLOAD_SYNC = 3, 170 dfuDNBUSY = 4, 171 dfuDNLOAD_IDLE = 5, 172 dfuMANIFEST_SYNC = 6, 173 dfuMANIFEST = 7, 174 dfuMANIFEST_WAIT_RESET = 8, 175 dfuUPLOAD_IDLE = 9, 176 dfuERROR = 10 177} DFUState; 178 179typedef enum { 180 errNONE = 0, 181 errTARGET = 1, 182 errFILE = 2, 183 errWRITE = 3, 184 errERASE = 4, 185 errCHECK_ERASED = 5, 186 errPROG = 6, 187 errVERIFY = 7, 188 errADDRESS = 8, 189 errNOTDONE = 9, 190 errFIRMWARE = 10, 191 errVENDOR = 11, 192 errUSBR = 12, 193 errPOR = 13, 194 errUNKNOWN = 14, 195 errSTALLEDPKT = 15 196} DFUStatus; 197 198typedef enum { 199 DFU_DETACH = 0, 200 DFU_DNLOAD = 1, 201 DFU_UPLOAD = 2, 202 DFU_GETSTATUS = 3, 203 DFU_CLRSTATUS = 4, 204 DFU_GETSTATE = 5, 205 DFU_ABORT = 6 206} DFURequest; 207 208typedef enum { 209 DFUAPIFail = 0, 210 DFUAPISuccess, 211} dfuAPIResult; 212 213struct dfuDev { 214 struct dfuAPI *api; 215 int found_pid; 216 int detached; 217 char descr[256]; 218 dfuAPIResult res; 219 char err[256]; 220 /* API private */ 221#ifdef WIN32 222 HANDLE fh; 223 HANDLE ph; 224 DWORD ec; /* winapi error code */ 225#endif 226#ifdef USE_LIBUSBAPI 227 libusb_context* ctx; 228 libusb_device_handle* devh; 229 int rc; /* libusb return code */ 230#endif 231#ifdef __APPLE__ 232 IOUSBDeviceInterface** dev; 233 kern_return_t kr; 234#endif 235}; 236 237struct dfuAPI { 238 char *name; 239 dfuAPIResult (*open_fn)(struct dfuDev*, int*); 240 dfuAPIResult (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*); 241 dfuAPIResult (*reset_fn)(struct dfuDev*); 242 void (*close_fn)(struct dfuDev*); 243}; 244 245 246/* 247 * DFU API low-level (specific) functions 248 */ 249static bool dfu_check_id(int vid, int pid, int *pid_list) 250{ 251 int *p; 252 if (vid != APPLE_VID) 253 return 0; 254 for (p = pid_list; *p; p++) 255 if (*p == pid) 256 return 1; 257 return 0; 258} 259 260/* adds extra DFU request error info */ 261static void dfu_add_reqerrstr(struct dfuDev *dfuh, struct usbControlSetup *cs) 262{ 263 snprintf(dfuh->err + strlen(dfuh->err), 264 sizeof(dfuh->err) - strlen(dfuh->err), " (cs=%02x/%d/%d/%d/%d)", 265 cs->bmRequestType, cs->bRequest, cs->wValue, cs->wIndex, cs->wLength); 266} 267 268#ifdef WIN32 269static bool dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success) 270{ 271 dfuh->res = (success) ? DFUAPISuccess : DFUAPIFail; 272 if (!success) { 273 dfuh->ec = GetLastError(); 274 snprintf(dfuh->err, sizeof(dfuh->err), "%s error %ld", str, dfuh->ec); 275 } 276 return success; 277} 278 279static dfuAPIResult dfu_winapi_request(struct dfuDev *dfuh, 280 struct usbControlSetup* cs, void* data) 281{ 282 unsigned char buf[USB_CS_SZ + DFU_PKT_SZ]; 283 DWORD rdwr; 284 bool rc; 285 286 memcpy(buf, cs, USB_CS_SZ); 287 288 if (cs->bmRequestType & 0x80) 289 { 290 rc = ReadFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL); 291 memcpy(data, buf+USB_CS_SZ, cs->wLength); 292 dfu_winapi_chkrc(dfuh, "DFU request failed: ReadFile()", rc); 293 } 294 else 295 { 296 memcpy(buf+USB_CS_SZ, data, cs->wLength); 297 rc = WriteFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL); 298 dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc); 299 } 300 if (!rc) 301 dfu_add_reqerrstr(dfuh, cs); 302 303 return dfuh->res; 304} 305 306static dfuAPIResult dfu_winapi_reset(struct dfuDev *dfuh) 307{ 308 DWORD bytesReturned; 309 bool rc = DeviceIoControl(dfuh->fh, 310 0x22000c, NULL, 0, NULL, 0, &bytesReturned, NULL); 311 dfu_winapi_chkrc(dfuh, 312 "Could not reset USB device: DeviceIoControl()", rc); 313 return dfuh->res; 314} 315 316static void dfu_winapi_close(struct dfuDev *dfuh) 317{ 318 if (dfuh->fh != INVALID_HANDLE_VALUE) { 319 CloseHandle(dfuh->fh); 320 dfuh->fh = INVALID_HANDLE_VALUE; 321 } 322 if (dfuh->ph != INVALID_HANDLE_VALUE) { 323 CloseHandle(dfuh->ph); 324 dfuh->ph = INVALID_HANDLE_VALUE; 325 } 326} 327 328static const GUID GUID_AAPLDFU = 329 { 0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; 330 331static dfuAPIResult dfu_winapi_open(struct dfuDev *dfuh, int *pid_list) 332{ 333 const GUID *guid = &GUID_AAPLDFU; 334 HDEVINFO devinfo = NULL; 335 SP_DEVICE_INTERFACE_DETAIL_DATA_A* details = NULL; 336 SP_DEVICE_INTERFACE_DATA iface; 337 char *path = NULL; 338 DWORD i, size; 339 bool rc; 340 341 dfuh->fh = 342 dfuh->ph = INVALID_HANDLE_VALUE; 343 dfuh->found_pid = 0; 344 dfuh->res = DFUAPISuccess; 345 dfuh->ec = 0; 346 347 /* Get DFU path */ 348 devinfo = SetupDiGetClassDevsA(guid, NULL, NULL, 349 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 350 if (!dfu_winapi_chkrc(dfuh, "SetupDiGetClassDevsA()", 351 (devinfo != INVALID_HANDLE_VALUE))) 352 goto error; 353 354 iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 355 356 for (i = 0; SetupDiEnumDeviceInterfaces(devinfo, NULL, guid, i, &iface); i++) 357 { 358 int vid, pid; 359 360 SetupDiGetDeviceInterfaceDetailA(devinfo, &iface, NULL, 0, &size, NULL); 361 362 if (details) free(details); 363 details = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(size); 364 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); 365 rc = SetupDiGetDeviceInterfaceDetailA(devinfo, &iface, details, size, NULL, NULL); 366 if (!dfu_winapi_chkrc(dfuh, "SetupDiGetDeviceInterfaceDetailA()", rc)) 367 goto error; 368 369 CharUpperA(details->DevicePath); 370 if (sscanf(details->DevicePath, "%*4cUSB#VID_%04x&PID_%04x%*s", &vid, &pid) != 2) 371 continue; 372 if (!dfu_check_id(vid, pid, pid_list)) 373 continue; 374 375 if (path) free(path); 376 path = malloc(size - sizeof(DWORD) + 16); 377 memcpy(path, details->DevicePath, size - sizeof(DWORD)); 378 379 dfuh->fh = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 380 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 381 if (!dfu_winapi_chkrc(dfuh, "CreateFileA(fh)", (dfuh->fh != INVALID_HANDLE_VALUE))) 382 goto error; 383 384 strcat(path, "\\PIPE0"); 385 dfuh->ph = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 386 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 387 if (!dfu_winapi_chkrc(dfuh, "CreateFileA(ph)", (dfuh->ph != INVALID_HANDLE_VALUE))) 388 goto error; 389 390 /* ok */ 391 snprintf(dfuh->descr, sizeof(dfuh->descr), "%s", details->DevicePath); 392 dfuh->found_pid = pid; 393 goto bye; 394 } 395 396 if (!dfu_winapi_chkrc(dfuh, "SetupDiEnumDeviceInterfaces()", 397 (GetLastError() == ERROR_NO_MORE_ITEMS))) 398 goto error; 399 400 /* no devices found */ 401 402bye: 403 if (path) free(path); 404 if (details) free(details); 405 if (devinfo) SetupDiDestroyDeviceInfoList(devinfo); 406 return dfuh->res; 407 408error: 409 dfu_winapi_close(dfuh); 410 goto bye; 411} 412#endif /* WIN32 */ 413 414#ifdef USE_LIBUSBAPI 415static bool dfu_libusb_chkrc(struct dfuDev *dfuh, char *str) 416{ 417 dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? DFUAPIFail : DFUAPISuccess; 418 if (dfuh->res == DFUAPIFail) 419 snprintf(dfuh->err, sizeof(dfuh->err), 420 "%s: %s", str, libusb_error_name(dfuh->rc)); 421 return (dfuh->res == DFUAPISuccess); 422} 423 424static dfuAPIResult dfu_libusb_request(struct dfuDev *dfuh, 425 struct usbControlSetup *cs, void *data) 426{ 427 dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType, 428 cs->bRequest, cs->wValue, cs->wIndex, data, cs->wLength, 500); 429 if (!dfu_libusb_chkrc(dfuh, "DFU request failed")) 430 dfu_add_reqerrstr(dfuh, cs); 431 return dfuh->res; 432} 433 434static dfuAPIResult dfu_libusb_reset(struct dfuDev *dfuh) 435{ 436 dfuh->rc = libusb_reset_device(dfuh->devh); 437 dfu_libusb_chkrc(dfuh, "Could not reset USB device"); 438 return dfuh->res; 439} 440 441static void dfu_libusb_close(struct dfuDev *dfuh) 442{ 443 if (dfuh->devh) { 444 libusb_release_interface(dfuh->devh, 0); 445 if (dfuh->detached) 446 libusb_attach_kernel_driver(dfuh->devh, 0); 447 libusb_close(dfuh->devh); 448 dfuh->devh = NULL; 449 } 450 if (dfuh->ctx) { 451 libusb_exit(dfuh->ctx); 452 dfuh->ctx = NULL; 453 } 454} 455 456static dfuAPIResult dfu_libusb_open(struct dfuDev *dfuh, int *pid_list) 457{ 458 struct libusb_device_descriptor desc; 459 libusb_device **devs = NULL, *dev; 460 int n_devs, i; 461 462 dfuh->devh = NULL; 463 dfuh->found_pid = 0; 464 dfuh->detached = 0; 465 dfuh->res = DFUAPISuccess; 466 467 dfuh->rc = libusb_init(&(dfuh->ctx)); 468 if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) { 469 dfuh->ctx = NULL; /* invalidate ctx (if any) */ 470 goto error; 471 } 472 473 n_devs = 474 dfuh->rc = libusb_get_device_list(dfuh->ctx, &devs); 475 if (!dfu_libusb_chkrc(dfuh, "Could not get USB device list")) 476 goto error; 477 478 for (i = 0; i < n_devs; ++i) 479 { 480 dev = devs[i]; 481 482 /* Note: since libusb-1.0.16 (LIBUSB_API_VERSION >= 0x01000102) 483 this function always succeeds. */ 484 if (libusb_get_device_descriptor(dev, &desc) != LIBUSB_SUCCESS) 485 continue; /* Unable to get device descriptor */ 486 487 if (!dfu_check_id(desc.idVendor, desc.idProduct, pid_list)) 488 continue; 489 490 dfuh->rc = libusb_open(dev, &(dfuh->devh)); 491 if (!dfu_libusb_chkrc(dfuh, "Could not open USB device")) 492 goto error; 493 494 dfuh->rc = libusb_set_configuration(dfuh->devh, 1); 495 if (!dfu_libusb_chkrc(dfuh, "Could not set USB configuration")) 496 goto error; 497 498 dfuh->rc = libusb_kernel_driver_active(dfuh->devh, 0); 499 if (dfuh->rc != LIBUSB_ERROR_NOT_SUPPORTED) { 500 if (!dfu_libusb_chkrc(dfuh, "Could not get USB driver status")) 501 goto error; 502 if (dfuh->rc == 1) { 503 dfuh->rc = libusb_detach_kernel_driver(dfuh->devh, 0); 504 if (!dfu_libusb_chkrc(dfuh, "Could not detach USB driver")) 505 goto error; 506 dfuh->detached = 1; 507 } 508 } 509 510 dfuh->rc = libusb_claim_interface(dfuh->devh, 0); 511 if (!dfu_libusb_chkrc(dfuh, "Could not claim USB interface")) 512 goto error; 513 514 /* ok */ 515 snprintf(dfuh->descr, sizeof(dfuh->descr), 516 "[%04x:%04x] at bus %d, device %d, USB ver. %04x", 517 desc.idVendor, desc.idProduct, libusb_get_bus_number(dev), 518 libusb_get_device_address(dev), desc.bcdUSB); 519 dfuh->found_pid = desc.idProduct; 520 break; 521 } 522 523bye: 524 if (devs) 525 libusb_free_device_list(devs, 1); 526 if (!dfuh->found_pid) 527 dfu_libusb_close(dfuh); 528 return dfuh->res; 529 530error: 531 goto bye; 532} 533#endif /* USE_LIBUSBAPI */ 534 535#ifdef __APPLE__ 536static bool dfu_iokit_chkrc(struct dfuDev *dfuh, char *str) 537{ 538 dfuh->res = (dfuh->kr == kIOReturnSuccess) ? DFUAPISuccess : DFUAPIFail; 539 if (dfuh->res == DFUAPIFail) 540 snprintf(dfuh->err, sizeof(dfuh->err), 541 "%s: error %08x", str, dfuh->kr); 542 return (dfuh->res == DFUAPISuccess); 543} 544 545static dfuAPIResult dfu_iokit_request(struct dfuDev *dfuh, 546 struct usbControlSetup *cs, void *data) 547{ 548 IOUSBDevRequest req; 549 req.bmRequestType = cs->bmRequestType; 550 req.bRequest = cs->bRequest; 551 req.wValue = cs->wValue; 552 req.wIndex = cs->wIndex; 553 req.wLength = cs->wLength; 554 req.pData = data; 555 556 dfuh->kr = (*(dfuh->dev))->DeviceRequest(dfuh->dev, &req); 557 if (!dfu_iokit_chkrc(dfuh, "DFU request failed")) 558 dfu_add_reqerrstr(dfuh, cs); 559 560 return dfuh->res; 561} 562 563static dfuAPIResult dfu_iokit_reset(struct dfuDev *dfuh) 564{ 565 dfuh->kr = (*(dfuh->dev))->ResetDevice(dfuh->dev); 566#if 0 567 /* On 10.11+ ResetDevice() returns no error but does not perform 568 * any reset, just a kernel log message. 569 * USBDeviceReEnumerate() could be used as a workaround. 570 */ 571 dfuh->kr = (*(dfuh->dev))->USBDeviceReEnumerate(dfuh->dev, 0); 572#endif 573 dfu_iokit_chkrc(dfuh, "Could not reset USB device"); 574 return dfuh->res; 575} 576 577static void dfu_iokit_close(struct dfuDev *dfuh) 578{ 579 if (dfuh->dev) { 580 (*(dfuh->dev))->USBDeviceClose(dfuh->dev); 581 (*(dfuh->dev))->Release(dfuh->dev); 582 dfuh->dev = NULL; 583 } 584} 585 586static dfuAPIResult dfu_iokit_open(struct dfuDev *dfuh, int *pid_list) 587{ 588 kern_return_t kr; 589 CFMutableDictionaryRef usb_matching_dict = 0; 590 io_object_t usbDevice; 591 io_iterator_t usb_iterator = IO_OBJECT_NULL; 592 IOCFPlugInInterface **plugInInterface = NULL; 593 IOUSBDeviceInterface **dev = NULL; 594 HRESULT result; 595 SInt32 score; 596 UInt16 vendor; 597 UInt16 product; 598 UInt16 release; 599 600 dfuh->dev = NULL; 601 dfuh->found_pid = 0; 602 dfuh->res = DFUAPISuccess; 603 604 usb_matching_dict = IOServiceMatching(kIOUSBDeviceClassName); 605 dfuh->kr = IOServiceGetMatchingServices( 606 kIOMasterPortDefault, usb_matching_dict, &usb_iterator); 607 if (!dfu_iokit_chkrc(dfuh, "Could not get matching services")) 608 goto error; 609 610 while ((usbDevice = IOIteratorNext(usb_iterator))) 611 { 612 /* Create an intermediate plug-in */ 613 kr = IOCreatePlugInInterfaceForService(usbDevice, 614 kIOUSBDeviceUserClientTypeID, 615 kIOCFPlugInInterfaceID, 616 &plugInInterface, 617 &score); 618 IOObjectRelease(usbDevice); 619 620 if ((kIOReturnSuccess != kr) || !plugInInterface) 621 continue; /* Unable to create a plugin */ 622 623 /* Now create the device interface */ 624 result = (*plugInInterface)->QueryInterface(plugInInterface, 625 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), 626 (LPVOID*)&dev); 627 (*plugInInterface)->Release(plugInInterface); 628 629 if (result || !dev) 630 continue; /* Couldn't create a device interface */ 631 632 kr = (*dev)->GetDeviceVendor(dev, &vendor); 633 kr = (*dev)->GetDeviceProduct(dev, &product); 634 kr = (*dev)->GetDeviceReleaseNumber(dev, &release); 635 636 if (!dfu_check_id(vendor, product, pid_list)) { 637 (*dev)->Release(dev); 638 continue; 639 } 640 641 /* Device found, open it */ 642 dfuh->kr = (*dev)->USBDeviceOpen(dev); 643 if (!dfu_iokit_chkrc(dfuh, "Could not open USB device")) { 644 (*dev)->Release(dev); 645 goto error; 646 } 647 648 /* ok */ 649 dfuh->found_pid = product; 650 dfuh->dev = dev; 651 snprintf(dfuh->descr, sizeof(dfuh->descr), 652 "[%04x:%04x] release: %d", vendor, product, release); 653 break; 654 } 655 656bye: 657 if (usb_iterator != IO_OBJECT_NULL) 658 IOObjectRelease(usb_iterator); 659 return dfuh->res; 660 661error: 662 goto bye; 663} 664#endif /* __APPLE__ */ 665 666/* list of suported APIs */ 667static struct dfuAPI api_list[] = 668{ 669#ifdef WIN32 670 { "winapi", 671 dfu_winapi_open, 672 dfu_winapi_request, 673 dfu_winapi_reset, 674 dfu_winapi_close }, 675#endif 676#ifdef USE_LIBUSBAPI 677 { "libusb", 678 dfu_libusb_open, 679 dfu_libusb_request, 680 dfu_libusb_reset, 681 dfu_libusb_close }, 682#endif 683#ifdef __APPLE__ 684 { "IOKit", 685 dfu_iokit_open, 686 dfu_iokit_request, 687 dfu_iokit_reset, 688 dfu_iokit_close }, 689#endif 690}; 691#define N_DFU_APIS (sizeof(api_list)/sizeof(struct dfuAPI)) 692 693 694/* 695 * DFU API common functions 696 */ 697static int DEBUG_DFUREQ = 0; 698 699static dfuAPIResult dfuapi_request(struct dfuDev *dfuh, 700 struct usbControlSetup *cs, void *data) 701{ 702 if (!DEBUG_DFUREQ) 703 return dfuh->api->dfureq_fn(dfuh, cs, data); 704 705 /* DEBUG */ 706 707 /* previous state */ 708 unsigned char ste = 0; 709 struct usbControlSetup css = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(ste) }; 710 if (dfuh->api->dfureq_fn(dfuh, &css, &ste) != DFUAPISuccess) { 711 snprintf(dfuh->err + strlen(dfuh->err), sizeof(dfuh->err) - 712 strlen(dfuh->err), " [DEBUG_DFUREQ ERROR: state=%d]", ste); 713 goto error; 714 } 715 716 dfuh->api->dfureq_fn(dfuh, cs, data); 717 fprintf(stderr, "[DEBUG]: REQ: ste=%d, cs=%2x/%d/%d/%d/%d -> %s", 718 ste, cs->bmRequestType, cs->bRequest, cs->wValue, 719 cs->wIndex, cs->wLength, 720 (dfuh->res == DFUAPISuccess) ? "ok" : "ERROR"); 721 if (cs->bRequest == DFU_GETSTATE) 722 fprintf(stderr, " (state=%d)", *((unsigned char*)(data))); 723 if (cs->bRequest == DFU_GETSTATUS) { 724 struct usbStatusData *sd = (struct usbStatusData*)data; 725 fprintf(stderr, " (status=%d, polltmo=%d, state=%d)", sd->bStatus, 726 (sd->bwPollTimeout2 << 16) | (sd->bwPollTimeout1 << 8) | 727 (sd->bwPollTimeout0), sd->bState); 728 } 729 fputc('\n', stderr); 730 fflush(stderr); 731 732bye: 733 return dfuh->res; 734error: 735 goto bye; 736} 737 738static dfuAPIResult dfuapi_req_getstatus(struct dfuDev *dfuh, 739 DFUStatus *status, int *poll_tmo /*ms*/, 740 DFUState *state) 741{ 742 struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 }; 743 struct usbControlSetup cs = { 0xA1, DFU_GETSTATUS, 0, 0, sizeof(sd) }; 744 dfuapi_request(dfuh, &cs, &sd); 745 if (status) *status = sd.bStatus; 746 if (state) *state = sd.bState; 747 if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) | 748 (sd.bwPollTimeout1 << 8) | (sd.bwPollTimeout0); 749 return dfuh->res; 750} 751 752static dfuAPIResult dfuapi_req_getstate(struct dfuDev *dfuh, DFUState *state) 753{ 754 unsigned char sts = 0; 755 struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) }; 756 dfuapi_request(dfuh, &cs, &sts); 757 if (state) *state = sts; 758 return dfuh->res; 759} 760 761static dfuAPIResult dfuapi_req_dnload(struct dfuDev* dfuh, uint16_t blknum, 762 uint16_t len, unsigned char *data) 763{ 764 struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len }; 765 return dfuapi_request(dfuh, &cs, data); 766} 767 768/* not used */ 769#if 0 770static dfuAPIResult dfuapi_req_upload(struct dfuDev* dfuh, 771 uint16_t blknum, uint16_t len, unsigned char *data) 772{ 773 struct usbControlSetup cs = { 0xA1, DFU_UPLOAD, blknum, 0, len }; 774 return dfuapi_request(dfuh, &cs, data); 775} 776 777static dfuAPIResult dfuapi_req_clrstatus(struct dfuDev* dfuh) 778{ 779 struct usbControlSetup cs = { 0x21, DFU_CLRSTATUS, 0, 0, 0 }; 780 return dfuapi_request(dfuh, &cs, NULL); 781} 782 783static dfuAPIResult dfuapi_req_abort(struct dfuDev* dfuh) 784{ 785 struct usbControlSetup cs = { 0x21, DFU_ABORT, 0, 0, 0 }; 786 return dfuapi_request(dfuh, &cs, NULL); 787} 788 789/* not implemented on DFU8702 */ 790static dfuAPIResult dfuapi_req_detach(struct dfuDev* dfuh, int tmo) 791{ 792 struct usbControlSetup cs = { 0x21, DFU_DETACH, tmo, 0, 0 }; 793 return dfuapi_request(dfuh, &cs, NULL); 794} 795#endif 796 797static dfuAPIResult dfuapi_reset(struct dfuDev *dfuh) 798{ 799 return dfuh->api->reset_fn(dfuh); 800} 801 802static dfuAPIResult dfuapi_send_packet(struct dfuDev* dfuh, uint16_t blknum, 803 uint16_t len, unsigned char *data, DFUStatus *status, 804 int *poll_tmo, DFUState *state, DFUState *pre_state) 805{ 806 if (dfuapi_req_dnload(dfuh, blknum, len, data) != DFUAPISuccess) 807 goto error; 808 809 /* device is in dfuDLSYNC state, waiting for a GETSTATUS request 810 * to enter the next state, if she respond with dfuDLBUSY then 811 * we must wait to resend the GETSTATUS request */ 812 813 if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess) 814 goto error; 815 816 if (*state == dfuDNBUSY) { 817 if (*poll_tmo) 818 sleep_ms(*poll_tmo); 819 if (pre_state) 820 if (dfuapi_req_getstate(dfuh, pre_state) != DFUAPISuccess) 821 goto error; 822 if (dfuapi_req_getstatus(dfuh, status, poll_tmo, state) != DFUAPISuccess) 823 goto error; 824 } 825 826bye: 827 return dfuh->res; 828error: 829 goto bye; 830} 831 832static void dfuapi_set_err(struct dfuDev *dfuh, char *str) 833{ 834 dfuh->res = DFUAPIFail; 835 strncpy(dfuh->err, str, sizeof(dfuh->err)); 836} 837 838static dfuAPIResult dfuapi_open(struct dfuDev *dfuh, int pid) 839{ 840 int pid_l[N_KNOWN_PIDS+1] = { 0 }; 841 struct dfuAPI *api; 842 unsigned i, p; 843 844 /* fill pid list */ 845 if (pid) 846 pid_l[0] = pid; 847 else 848 for (p = 0; p < N_KNOWN_PIDS; p++) 849 pid_l[p] = known_pids[p].pid; 850 851 for (i = 0; i < N_DFU_APIS; i++) 852 { 853 api = &api_list[i]; 854 if (api->open_fn(dfuh, pid_l) != DFUAPISuccess) 855 goto error; 856 if (dfuh->found_pid) { 857 /* ok */ 858 dfuh->api = api; 859 printf("[INFO] %s: found %s\n", api->name, dfuh->descr); 860 for (p = 0; p < N_KNOWN_PIDS; p++) { 861 if (known_pids[p].pid == dfuh->found_pid) { 862 printf("[INFO] iPod %s, mode: %s\n", known_pids[p].desc, 863 known_pids[p].mode ? "WTF" : "DFU"); 864 break; 865 } 866 } 867 fflush(stdout); 868 goto bye; 869 } 870 printf("[INFO] %s: no DFU devices found\n", api->name); 871 fflush(stdout); 872 } 873 874 /* error */ 875 dfuapi_set_err(dfuh, "DFU device not found"); 876 877bye: 878 return dfuh->res; 879error: 880 goto bye; 881} 882 883static void dfuapi_destroy(struct dfuDev *dfuh) 884{ 885 if (dfuh) { 886 if (dfuh->api) 887 dfuh->api->close_fn(dfuh); 888 free(dfuh); 889 } 890} 891 892static struct dfuDev *dfuapi_create(void) 893{ 894 return calloc(sizeof(struct dfuDev), 1); 895} 896 897 898/* 899 * app level functions 900 */ 901static int ipoddfu_download_file(struct dfuDev* dfuh, 902 unsigned char *data, unsigned long size) 903{ 904 unsigned int blknum, len, remaining; 905 int poll_tmo; 906 DFUStatus status; 907 DFUState state; 908 909 if (dfuapi_req_getstate(dfuh, &state) != DFUAPISuccess) 910 goto error; 911 912 if (state != dfuIDLE) { 913 dfuapi_set_err(dfuh, "Could not start DFU download: not idle"); 914 goto error; 915 } 916 917 blknum = 0; 918 remaining = size; 919 while (remaining) 920 { 921 len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ; 922 923 if (dfuapi_send_packet(dfuh, blknum, len, data + blknum*DFU_PKT_SZ, 924 &status, &poll_tmo, &state, NULL) != DFUAPISuccess) 925 goto error; 926 927 if (state != dfuDNLOAD_IDLE) { 928 dfuapi_set_err(dfuh, "DFU download aborted: unexpected state"); 929 goto error; 930 } 931 932 remaining -= len; 933 blknum++; 934 } 935 936 /* send ZLP */ 937 DFUState pre_state = appIDLE; /* dummy state */ 938 if (dfuapi_send_packet(dfuh, blknum, 0, NULL, 939 &status, &poll_tmo, &state, &pre_state) != DFUAPISuccess) { 940 if (pre_state == dfuMANIFEST_SYNC) 941 goto ok; /* pwnaged .dfu file */ 942 goto error; 943 } 944 945 if (state != dfuMANIFEST) { 946 if (status == errFIRMWARE) 947 dfuapi_set_err(dfuh, "DFU download failed: corrupt firmware"); 948 else 949 dfuapi_set_err(dfuh, "DFU download failed: unexpected state"); 950 goto error; 951 } 952 953 /* wait for manifest stage */ 954 if (poll_tmo) 955 sleep_ms(poll_tmo); 956 957 if (dfuapi_req_getstatus(dfuh, &status, NULL, &state) != DFUAPISuccess) 958 goto ok; /* 1223 .dfu file */ 959 960 /* XXX: next code never tested */ 961 962 if (state != dfuMANIFEST_WAIT_RESET) { 963 if (status == errVERIFY) 964 dfuapi_set_err(dfuh, "DFU manifest failed: wrong FW verification"); 965 else 966 dfuapi_set_err(dfuh, "DFU manifest failed: unexpected state"); 967 goto error; 968 } 969 970 if (dfuapi_reset(dfuh) != DFUAPISuccess) 971 goto error; 972 973ok: 974 return 1; 975error: 976 return 0; 977} 978 979/* exported functions */ 980int ipoddfu_send(int pid, unsigned char *data, int size, 981 char* errstr, int errstrsize) 982{ 983 struct dfuDev *dfuh; 984 unsigned char *buf; 985 uint32_t checksum; 986 int ret = 1; /* ok */ 987 988 dfuh = dfuapi_create(); 989 990 buf = malloc(size+4); 991 if (!buf) { 992 dfuapi_set_err(dfuh, "Could not allocate memory for DFU buffer"); 993 goto error; 994 } 995 996 if (memcmp(data, IM3_IDENT, 4)) { 997 dfuapi_set_err(dfuh, "Bad DFU image data"); 998 goto error; 999 } 1000 1001 crc32_init(); 1002 checksum = crc32(data, size, 0); 1003 memcpy(buf, data, size); 1004 put_uint32le(buf+size, ~checksum); 1005 1006 if (dfuapi_open(dfuh, pid) != DFUAPISuccess) 1007 goto error; 1008 1009 if (!ipoddfu_download_file(dfuh, buf, size+4)) 1010 goto error; 1011 1012bye: 1013 if (buf) free(buf); 1014 dfuapi_destroy(dfuh); 1015 return ret; 1016 1017error: 1018 ret = 0; 1019 if (errstr) 1020 snprintf(errstr, errstrsize, "[ERR] %s", dfuh->err); 1021 goto bye; 1022} 1023 1024/* search for the DFU device and gets its DFUState */ 1025int ipoddfu_scan(int pid, int *state, int reset, 1026 char* errstr, int errstrsize) 1027{ 1028 struct dfuDev *dfuh; 1029 int ret = 1; /* ok */ 1030 1031 dfuh = dfuapi_create(); 1032 1033 if (dfuapi_open(dfuh, pid) != DFUAPISuccess) 1034 goto error; 1035 1036 if (reset) 1037 if (dfuapi_reset(dfuh) != DFUAPISuccess) 1038 goto error; 1039 1040 if (state) { 1041 DFUState sts; 1042 if (dfuapi_req_getstate(dfuh, &sts) != DFUAPISuccess) 1043 goto error; 1044 *state = (int)sts; 1045 } 1046 1047bye: 1048 dfuapi_destroy(dfuh); 1049 return ret; 1050 1051error: 1052 ret = 0; 1053 if (errstr) 1054 snprintf(errstr, errstrsize, "[ERR] %s", dfuh->err); 1055 goto bye; 1056} 1057 1058void ipoddfu_debug(int debug) 1059{ 1060 DEBUG_DFUREQ = debug; 1061}