From: Jinkun Jang Date: Tue, 12 Mar 2013 17:22:03 +0000 (+0900) Subject: Tizen 2.1 base X-Git-Tag: submit/tizen_2.1/20130425.000057~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=07a0861d89a6c0398ce4266dad3f9f0834f6b12d;p=tools%2Flthor.git Tizen 2.1 base --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..bab8cca --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +YoungJin Lee +Wonil Choi +Karol Lewandowski +Rafal Krypa +Jaehoon You diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..25d7c8f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,52 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(lthor C) + +SET(SRCS + lthor.c +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/.) + +SET(VENDOR "samsung") +SET(PACKAGE ${PROJECT_NAME}) +SET(PKGNAME "${PACKAGE}") +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(BINDIR "${PREFIX}/bin") + +SET(PACKAGE_VERSION "1.2") + + +IF("${CMAKE_BUILD_TYPE}" STREQUAL "") + SET(CMAKE_BUILD_TYPE "Release") +ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") +MESSAGE("Build type: ${CMAKE_BUILD_TYPE}") + + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED + libarchive +) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + + +ADD_DEFINITIONS("-DVENDOR=\"${VENDOR}\"") +ADD_DEFINITIONS("-DPACKAGE=\"${PACKAGE}\"") +ADD_DEFINITIONS("-DPACKAGE_NAME=\"${PKGNAME}\"") +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DPACKAGE_VERSION=\"${PACKAGE_VERSION}\"") + +#SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS}) + + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR}) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..4ab29a4 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +lthor (1.0) unstable; urgency=low + + * Initial upload + + -- Ed Bartosh Mon, 12 Nov 2012 19:08:56 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7813681 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 \ No newline at end of file diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..c1c09bc --- /dev/null +++ b/debian/control @@ -0,0 +1,12 @@ +Source: lthor +Section: net +Priority: extra +Maintainer: Ed Bartosh +Build-Depends: debhelper (>= 5), libc6-dev, pkg-config, cmake, libarchive-dev +Standards-Version: 0.0.1 + +Package: lthor +Architecture: any +Depends: ${shlibs:Depends} +Description: Flashing tool for Tizen lunchbox + diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..abde6ef --- /dev/null +++ b/debian/rules @@ -0,0 +1,5 @@ +#!/usr/bin/make -f + +%: + dh $@ + diff --git a/lthor.c b/lthor.c new file mode 100755 index 0000000..27df43d --- /dev/null +++ b/lthor.c @@ -0,0 +1,1246 @@ +/* + * lthor - Tizen Linux Thor Downloader + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thor-proto.h" + +#define USB_VENDOR_SAMSUNG "04e8" +#define USB_DEVICE_Z100 "6601" +#define USB_DEVICE_Z100_DEVGURU "6860" +#define USB_DEVICE_DEVGURU "685d" +#define USB_DEVICE_OLD_DOWNLOADER "1204" + +#define KB (1024) +#define MB (1024*KB) +#define DEFAULT_PKT_SIZE (1*MB) +#define DEFAULT_TIMEOUT (60000) /* 1 minute */ +#define DEFAULT_PORT "/dev/ttyACM0" + +/* data abstraction */ +struct data_src { + size_t (*get_data_length)(struct data_src *src); + size_t (*get_data_block)(struct data_src *src, void *data, size_t len); + const char* (*get_data_name)(struct data_src *src); +}; + +int opt_verbose = 0; +int opt_test = 0; +size_t trans_unit_size = DEFAULT_PKT_SIZE; + +static void dump(const char *msg, void *bytes, int len) +{ + int i; + + if (!opt_verbose) + return; + + fprintf(stderr, "%s :", msg); + for (i=0; itv_usec < atv->tv_usec) { + diff = btv->tv_sec - atv->tv_sec - 1; + diff += (double)(1*1000*1000 - atv->tv_usec + + btv->tv_usec)/(1000*1000); + } else { + diff = btv->tv_sec - atv->tv_sec; + diff += (double)(btv->tv_usec - atv->tv_usec)/(1000*1000); + } + + return diff; +} + +int send_chunks(int fd, struct data_src *senddata, size_t size) +{ + unsigned char *chunk; + struct data_res_pkt resp; + size_t n = 0; + int chunksize, chunk_number = 1; + struct timeval stv, etv, ltv; + int r; + + chunk = malloc(trans_unit_size); + if (chunk == NULL) { + fprintf(stderr, "Unable to allocate memory.\n"); + return -1; + } + + if (opt_verbose) + fprintf(stderr, "Downloading: %zd bytes\n", size); + + gettimeofday(&stv, NULL); + memcpy(<v, &stv, sizeof(struct timeval)); + + while (n < size) { + if (size - n >= trans_unit_size) + chunksize = trans_unit_size; + else + chunksize = size - n; + + chunksize = senddata->get_data_block(senddata, chunk, chunksize); + if (chunksize <= 0) { + fprintf(stderr, "\nline %d: Broken tar archive - check download!\n", __LINE__); + exit(1); + } + + if (opt_verbose) + fprintf(stderr, "read %d bytes\n", chunksize); + + assert(chunksize > 0 && chunksize <= trans_unit_size); + memset(&chunk[chunksize], 0, trans_unit_size - chunksize); + + if (opt_verbose) + fprintf(stderr, "sending %zd/%zd\n", n + chunksize, size); + + r = write(fd, chunk, trans_unit_size); + if (r != trans_unit_size) { + fprintf(stderr, "line %d: failed to send data\n", __LINE__); + free(chunk); + return -1; + } + + memset(&resp, 0, DATA_RES_PKT_SIZE); + r = serial_read(fd, &resp, DATA_RES_PKT_SIZE, DEFAULT_TIMEOUT); + if (r != DATA_RES_PKT_SIZE) { + fprintf(stderr, "line %d: read failed %d\n", __LINE__, r); + free(chunk); + return -1; + } + + if (resp.cnt != chunk_number) { + printf("\nsending %zd/%zd : sequence wrong %08x, expected %08x\n", + n, size, resp.cnt, chunk_number); + //return -1; + } + + n += chunksize; + + if (opt_verbose) { + printf("response %08x %08x\n", resp.ack, resp.cnt); + + } else { + int now = n/KB; + int total = size/KB; + char progress [4] = { '-', '\\', '|', '/' }; + char c = progress[(now/30)%4]; + double elaps; + + gettimeofday(&etv, NULL); + if (n >= size) { + elaps = timediff(&stv, &etv); + fprintf(stderr, "\x1b[1A\x1b[16C%c sending %6dk/%6dk %3d%% block %-6d", + c, now, total, ((now*100)/total), chunk_number); + fprintf(stderr, " [avg %.2f MB/s]\n", (double)(size/elaps)/(MB)); + } else { + elaps = timediff(<v, &etv); + memcpy(<v, &etv, sizeof(struct timeval)); + fprintf(stderr, "\x1b[1A\x1b[16C%c sending %6dk/%6dk %3d%% block %-6d", + c, now, total, ((now*100)/total), chunk_number); + fprintf(stderr, " [%.2f MB/s]\n", (double)(chunksize/elaps)/(MB)); + } + } + chunk_number++; + } + + free(chunk); + + return 0; +} + +/* + * function that doesn't wait for response data, used by standard requests and + * REQ_PIT_DATA_START, which doesn't want a response + */ +int write_request(int fd, request_type req_id, int req_sub_id, + int *idata, int icnt, char **sdata, int scnt) +{ + struct rqt_pkt req; + int r, i; + + assert(icnt <= sizeof(req.int_data)/sizeof(req.int_data[0])); + assert(icnt >= 0); + assert(scnt <= sizeof(req.str_data)/sizeof(req.str_data[0])); + assert(scnt >= 0); + + memset(&req, 0, sizeof(req)); + + req.id = req_id; + req.sub_id = req_sub_id; + + if (idata) { + for (i=0; i= 0) + dump("recv", &resp, sizeof resp); + if (r != sizeof resp) { + fprintf(stderr, "line %d: failed to receive data r = %d\n", + __LINE__, r); + return -1; + } + + if (pres) + memcpy(pres, &resp, RES_PKT_SIZE); + + if (resp.ack != 0) { + fprintf(stderr, "line %d: ack reports fail. ack = %d\n", + __LINE__, resp.ack); + return -1; + } + + return resp.ack; +} + +int send_request(int fd, request_type req_id, int req_sub_id, int *idata, int icnt) +{ + return send_request_timeout(fd, req_id, req_sub_id, idata, icnt, + NULL, 0, NULL, DEFAULT_TIMEOUT); +} + +int request_reboot(int fd) +{ + int r; + r = send_request(fd, RQT_CMD, RQT_CMD_REBOOT, NULL, 0); + if (r) + fprintf(stderr, "RQT_CMD_REBOOT, status = %08x\n", r); + return r; +} + +int thor_handshake(int fd) +{ + char buffer[4]; + int r; + + r = write(fd, "THOR", 4); + if (r != 4) { + fprintf(stderr, "line %d: failed to write signature bytes\n", + __LINE__); + return -1; + } + + r = serial_read(fd, buffer, 4, DEFAULT_TIMEOUT); + if (r != 4) { + fprintf(stderr, "line %d: failed to read signature bytes\n", + __LINE__); + return -1; + } + + if (memcmp(buffer, "ROHT", 4)) { + fprintf(stderr, "line %d: signature byte mismatch\n", __LINE__); + return -1; + } + + return 0; +} + +int getfile(const char *devpath, char *buffer, size_t bufsize) +{ + int fd, r = 0; + + fd = open(devpath, O_RDONLY); + if (fd >= 0) { + r = read(fd, buffer, bufsize - 1); + if (r < 0) + r = 0; + close(fd); + } + else if (opt_verbose) + fprintf(stderr, "failed to open %s\n", devpath); + if (r && buffer[r - 1] == '\n') + r--; + buffer[r] = 0; + return r; +} + +/* + * Given USB path, return tty name + * FIXME: probably should look up the /dev from device major:minor + * There seems to be two styles of device name: + * 1. /sys/bus/usb/devices/1-2/1-2\:2.0/tty/ttyACM0/dev + * 2. /sys/bus/usb/devices/1-2/1-2\:2.0/tty:ttyACM0 + */ +char *device_from_usb_tty_directory(const char *usbpath) +{ + static char ttypath[0x400]; + static char devpath[0x400]; + char *ret = NULL; + DIR *d; + + strcpy(ttypath, usbpath); + strcat(ttypath, "/tty"); + + d = opendir(ttypath); + if (d) { + if (opt_verbose) + fprintf(stderr, "listing %s:\n", ttypath); + + /* device name is under tty directory */ + while (!ret) { + struct dirent *de; + + de = readdir(d); + if (!de) + break; + + if (opt_verbose) + fprintf(stderr, "%s\n", de->d_name); + + if (de->d_name[0] == '.') + continue; + + strcpy(devpath, "/dev/"); + strcat(devpath, de->d_name); + + ret = devpath; + } + } else { + /* device name is in directory */ + d = opendir(usbpath); + if (!d) + return NULL; + + if (opt_verbose) + fprintf(stderr, "listing %s:\n", usbpath); + + while (!ret) { + struct dirent *de; + + de = readdir(d); + if (!de) + break; + + if (opt_verbose) + fprintf(stderr, "%s\n", de->d_name); + + if (strncmp(de->d_name, "tty:", 4)) + continue; + + strcpy(devpath, "/dev/"); + strcat(devpath, &de->d_name[4]); + + ret = devpath; + } + } + + closedir(d); + + if (ret) { + fprintf(stderr, "USB port is detected : %s\n\n", ret); + } else { + fprintf(stderr, "USB port is " + "\x1b[0;31;1mnot\x1b[0m detected !\n\n", ret); + } + + return ret; +} + +const char* find_usb_device(void) +{ + DIR *d; + char *p; + char buffer[11]; + const char *dirname = "/sys/bus/usb/devices"; + char usbpath[0x400]; + char usbdir[0x100]; + char *tty = NULL; + + d = opendir(dirname); + if (!d) + return NULL; + + while (1) { + struct dirent *de; + + de = readdir(d); + if (!de) + break; + + if (de->d_name[0] == '.') + continue; + + strcpy(usbdir, de->d_name); + strcpy(usbpath, dirname); + strcat(usbpath, "/"); + strcat(usbpath, usbdir); + strcat(usbpath, "/"); + p = &usbpath[strlen(usbpath)]; + + /* match the vendor ID */ + strcat(p, "idVendor"); + getfile(usbpath, buffer, sizeof buffer); + if (opt_verbose) + fprintf(stderr, "vendorId = >%s< %zd\n", buffer, + strlen(buffer)); + if (strcmp(buffer, USB_VENDOR_SAMSUNG)) + continue; + + /* match the product ID */ + strcpy(p, "idProduct"); + getfile(usbpath, buffer, sizeof buffer); + if (opt_verbose) + fprintf(stderr, "product = >%s< %zd\n", buffer, + strlen(buffer)); + + if (!strcmp(buffer, USB_DEVICE_OLD_DOWNLOADER)) + fprintf(stderr, "Old bootloader detected!\n"); + + /* supported product ID */ + if (strcmp(buffer, USB_DEVICE_Z100) && + strcmp(buffer, USB_DEVICE_Z100_DEVGURU) && + strcmp(buffer, USB_DEVICE_DEVGURU)) + continue; + + if (opt_verbose) + fprintf(stderr, "found %s:%s!\n", USB_VENDOR_SAMSUNG, + buffer); + closedir(d); + + p[0] = 0x00; + d = opendir(usbpath); + if (opt_verbose) + fprintf(stderr, "at %s\n", usbpath); + while ((de = readdir(d))) { + if (strlen(de->d_name) < strlen(usbdir)) + continue; + if (de->d_type != DT_DIR) + continue; + if (strncmp(de->d_name, usbdir, strlen(usbdir))) + continue; + + strcpy(p, de->d_name); + if (opt_verbose) + fprintf(stderr, "search for tty on %s\n", usbpath); + tty = device_from_usb_tty_directory(usbpath); + if (tty) + break; + } + + closedir(d); + if ((opt_verbose) && (!tty)) + fprintf(stderr, "idVendor and idProduct are matched" + "but no tty description\n"); + + return tty; + } + + closedir(d); + + if (opt_verbose) + fprintf(stderr, "No USB device found with matching " + "idVendor and idProduct\n" ); + + return NULL; +} + + +int open_port(const char *portname, int wait) +{ + int once = 0; + int fd; + int r; + struct termios tios; + const char *dev; + + if (opt_test) + return open("/dev/null", O_RDWR); + + while (1) { + if (!portname) + dev = find_usb_device(); + else + dev = portname; + + if (!wait && dev == NULL) { + fprintf(stderr, "line %d: device not found\n", __LINE__); + return -1; + } + + if (dev) { + fd = open(dev, O_RDWR); + if (fd == -1) { + perror("port open error!!\n"); + return -1; + } + break; + } + + if (!once) { + if (!wait) + return -1; + printf("\nUSB port is not detected yet... \n"); + printf("Make sure phone(device) should be in a download mode \n"); + printf("before connecting phone to PC with USB cable.\n"); + printf("(How to enter download mode : press + key)\n\n"); + once = 1; + } + sleep(1); + } + + r = tcgetattr(fd, &tios); + if (r < 0) { + fprintf(stderr, "line %d: tcgetattr failed\n", __LINE__); + close(fd); + return -1; + } + + /* + * Firmware BUG alert!!! + * Flow control (RTS/CTS) should be disabled, because + * the firmware doesn't deal with it properly. + */ + cfmakeraw(&tios); + r = tcsetattr(fd, TCSANOW, &tios); + if (r < 0) { + fprintf(stderr, "line %d: tcsetattr failed\n", __LINE__); + close(fd); + return -1; + } + + r = tcflush(fd, TCIOFLUSH); + if (r < 0) { + fprintf(stderr, "line %d: tcflush failed\n", __LINE__); + close(fd); + return -1; + } + + r = thor_handshake(fd); + if (r < 0) { + fprintf(stderr, "line %d: handshake failed\n", __LINE__); + close(fd); + return -1; + } + + return fd; +} + +int wait_and_open_port(const char *portname) +{ + return open_port(portname, 1); +} + +/* + * Write a data source (file) into a partition + * + * data_src abstraction provided so sending a single file + * from a non-tar source is possible one day + */ +int download_single_file(int fd, struct data_src *senddata, int filetype) +{ + int r; + size_t filesize; + const char *filename; + struct res_pkt resp; + int32_t int_data[2]; + + filesize = senddata->get_data_length(senddata); + filename = senddata->get_data_name(senddata); + + int_data[0] = filetype; + int_data[1] = filesize; + r = send_request_timeout(fd, RQT_DL, RQT_DL_FILE_INFO, int_data, 2, + (char **)&filename, 1, &resp, DEFAULT_TIMEOUT); + if (r < 0) { + fprintf(stderr, "RQT_DL_FILE_INFO, status = %08x\n", r); + return -1; + } + trans_unit_size = resp.int_data[0]; + + r = send_request(fd, RQT_DL, RQT_DL_FILE_START, NULL, 0); + if (r < 0) { + fprintf(stderr, "RQT_DL_FILE_START, status = %08x\n", r); + return -1; + } + + r = send_chunks(fd, senddata, filesize); + if (r < 0) { + fprintf(stderr, "send_chunks(), status = %08x\n", r); + return -1; + } + + r = send_request(fd, RQT_DL, RQT_DL_FILE_END, NULL, 0); + if (r < 0) { + fprintf(stderr, "RQT_DL_FILE_END, status = %08x\n", r); + return -1; + } + + return 0; +} + +struct file_data_src { + struct data_src src; + int fd; + const char* filename; + size_t filesize; +}; + +size_t file_get_data_length(struct data_src *src) +{ + struct file_data_src *filedata = (struct file_data_src *) src; + + return filedata->filesize; +} + +size_t file_get_data_block(struct data_src *src, void *data, size_t len) +{ + struct file_data_src *filedata = (struct file_data_src *) src; + + return read(filedata->fd, data, len); +} + +const char *file_get_data_name(struct data_src *src) +{ + struct file_data_src *filedata = (struct file_data_src *) src; + + return filedata->filename; +} + +int filedata_open(struct file_data_src *filedata, const char *filename) +{ + int r; + char *basefile; + + if (!filedata) + return -1; + + memset((void*)filedata, 0x00, sizeof(struct file_data_src)); + + r = open(filename, O_RDONLY); + if (r < 0) + return r; + + filedata->fd = r; + + /* According to the man page basename() might modify the argument or + * return a pointer to statically allocated memory. Thus two strdup()s */ + basefile = strdup(filename); + filedata->filename = strdup(basename(basefile)); + free(basefile); + + filedata->filesize = lseek(filedata->fd, 0, SEEK_END); + lseek(filedata->fd, 0, SEEK_SET); + + filedata->src.get_data_length = &file_get_data_length; + filedata->src.get_data_block = &file_get_data_block; + filedata->src.get_data_name = &file_get_data_name; + + return r; +} + +int filedata_close(struct file_data_src *filedata) +{ + close(filedata->fd); + free((void *)filedata->filename); + return 0; +} + +struct tar_data_src { + struct data_src src; + struct archive *ar; + struct archive_entry *ae; +}; + +size_t te_get_data_length(struct data_src *src) +{ + struct tar_data_src *tardata = (struct tar_data_src *) src; + + return archive_entry_size(tardata->ae); +} + +size_t te_get_data_block(struct data_src *src, void *data, size_t len) +{ + struct tar_data_src *tardata = (struct tar_data_src *) src; + + return archive_read_data(tardata->ar, data, len); +} + +const char *te_get_data_name(struct data_src *src) +{ + struct tar_data_src *tardata = (struct tar_data_src *) src; + + return archive_entry_pathname(tardata->ae); +} + +int tardata_open(struct tar_data_src *tardata, const char *tarfile) +{ + int r; + + /* open the tar archive */ + tardata->ar = archive_read_new(); + + archive_read_support_format_tar(tardata->ar); + archive_read_support_compression_gzip(tardata->ar); + archive_read_support_compression_bzip2(tardata->ar); + + if (!strcmp(tarfile, "-")) + r = archive_read_open_FILE(tardata->ar, stdin); + else + r = archive_read_open_filename(tardata->ar, tarfile, 512); + + if (r) { + fprintf(stderr, "line %d: failed to open %s\n", __LINE__, tarfile); + return r; + } + + tardata->src.get_data_length = &te_get_data_length; + tardata->src.get_data_block = &te_get_data_block; + tardata->src.get_data_name = &te_get_data_name; + tardata->ae = NULL; + + return r; +} + +const char *tardata_next(struct tar_data_src *tardata) +{ + int64_t partsize; + int r; + + r = archive_read_next_header(tardata->ar, &tardata->ae); + if (r == ARCHIVE_EOF) + return NULL; + + if (r != ARCHIVE_OK) { + fprintf(stderr, "line %d: archive_read_next_header error %d\n", + __LINE__, r); + return NULL; + } + + partsize = archive_entry_size(tardata->ae); + if (partsize > SIZE_MAX) { + /* + * FIXME: fix source (and maybe firmware) to deal with files + * bigger than 4G + */ + fprintf(stderr, "line %d: Large file %llx (>4GB) is not" + " supported\n", __LINE__, (unsigned long long) + partsize); + return NULL; + } + + return archive_entry_pathname(tardata->ae); +} + +int tardata_close(struct tar_data_src *tardata) +{ + archive_read_close(tardata->ar); + archive_read_finish(tardata->ar); + return 0; +} + +int get_entry_size_in_tar(const char *tarfile, unsigned long long *total) +{ + struct tar_data_src tardata; + const char *filename; + int r; + + r = tardata_open(&tardata, tarfile); + if (r < 0) { + fprintf(stderr, "line %d: failed to open %s\n", __LINE__, + tarfile); + return r; + } + + *total = 0; + + while (1) { + size_t size = 0; + + filename = tardata_next(&tardata); + if (!filename) + break; + + size = tardata.src.get_data_length(&tardata.src); + printf("[\x1b[0;32;1m%s\x1b[0m]\t%zuk\n", filename, size/KB); + + *total += size; + } + + tardata_close(&tardata); + + return 0; +} + +int download_pitfile(int fd, const char *pitfile) +{ + struct file_data_src filedata; + int r; + + r = filedata_open(&filedata, pitfile); + if (r < 0) { + fprintf(stderr, "line %d: failed to open %s\n", __LINE__, pitfile); + return r; + } + + + printf("[\x1b[0;32;1m%s\x1b[0m]\n", pitfile); + r = download_single_file(fd, &filedata.src, BINARY_TYPE_PIT); + if (r < 0) { + fprintf(stderr, "line %d: failed to download %s\n", __LINE__, + pitfile); + return r; + } + + fprintf(stderr, "\n%s completed\n", pitfile); + + filedata_close(&filedata); + + return r; +} + +int download_single_tarfile(int fd, const char *tarfile) +{ + struct tar_data_src tardata; + const char *filename; + int r; + + r = tardata_open(&tardata, tarfile); + if (r < 0) { + fprintf(stderr, "line %d: failed to open %s\n", __LINE__, tarfile); + return r; + } + + while (1) { + filename = tardata_next(&tardata); + if (!filename) + break; + + printf("[\x1b[0;32;1m%s\x1b[0m]\n", filename); + r = download_single_file(fd, &tardata.src, BINARY_TYPE_NORMAL); + if (r < 0) { + fprintf(stderr, "line %d: failed to download %s\n", + __LINE__, filename); + break; + } + } + + fprintf(stderr, "\n%s completed\n", tarfile); + + tardata_close(&tardata); + + return r; +} + +int process_download(const char *portname, const char *pitfile, char **tarfilelist) +{ + int r; + char **tfl; + off_t pit_length = 0; + int fd; + unsigned long long total; + + /* now connect to the target */ + fd = wait_and_open_port(portname); + if (fd < 0) { + fprintf(stderr, "line %d: failed to open port %s\n", __LINE__, + portname); + return -1; + } + + total = 0; + tfl = tarfilelist; + while (tfl && *tfl) { + unsigned long long len = 0; + printf("\x1b[0;33;1m%s :\x1b[0m\n", *tfl); + if (get_entry_size_in_tar(*tfl, &len) < 0) { + perror("Error"); + close(fd); + return -1; + } + total += len; + tfl++; + } + + if (pitfile) { + pit_length = file_size(pitfile); + if (pit_length < 0) { + fprintf(stderr, "line %d: failed to get pit length\n" + , __LINE__); + close(fd); + return -1; + } + total += pit_length; + printf("\x1b[0;33;1m%s : \x1b[0m%zuk\n", pitfile, + (size_t)pit_length/KB); + } + printf("-------------------------\n"); + printf("\t\x1b[0;33;1mtotal\x1b[0m :\t%.2fMB\n\n", (double)total/MB); + + /* for updating progress bar in the target */ + r = send_request(fd, RQT_DL, RQT_DL_INIT, (int*)&total, 1); + /* + * FIXME : if total > SIZE_MAX then DL_INIT must change it's protocol to + * send/receive 64bit size data. + */ + if (r) { + fprintf(stderr, "RQT_DL_INIT, status = %08x\n", r); + close(fd); + return -1; + } + + if (pitfile) { + fprintf(stderr, "\nDownload PIT file : %s\n\n", pitfile); + r = download_pitfile(fd, pitfile); + if (r < 0) { + fprintf(stderr, "failed to download %s\n", pitfile); + close(fd); + return r; + } + } + + while (tarfilelist && *tarfilelist) { + fprintf(stderr, "\nDownload files from %s\n\n", *tarfilelist); + r = download_single_tarfile(fd, *tarfilelist); + if (r < 0) { + fprintf(stderr, "failed to download %s\n", *tarfilelist); + close(fd); + return r; + } + tarfilelist++; + } + + r = send_request(fd, RQT_DL, RQT_DL_EXIT, NULL, 0); + if (r) { + fprintf(stderr, "\x1b[0;33;1mmissing RQT_DL_EXIT response " + "from broken bootloader\x1b[0m\n"); + } + + fprintf(stderr, "\nrequest target reboot : "); + + r = request_reboot(fd); + if (r) + fprintf(stderr, "\x1b[0;31;1mfailed\x1b[0m\n"); + else + fprintf(stderr, "\x1b[0;32;1msuccess\x1b[0m\n"); + + close(fd); + + return 0; +} + +/* Check if LHOR protocol is in working state */ +int check_proto(const char *portname) +{ + int fd; + /* int r; + struct res_pkt resp;*/ + + /* connect to the target */ + fd = open_port(portname, 0); + if (fd < 0) + return -1; + + /* Below I commented out my attempt to check if LHOR protocol is enabled + * by quering protocol version. + * The main problem is that I didn't find a way to 'close' the session, + * to put protocol into previous state. + * */ + + /* + r = thor_handshake(fd); + if (r < 0) { + fprintf(stderr, "line %d: handshake failed\n", __LINE__); + return -1; + } + + r = send_request_timeout(fd, RQT_INFO, RQT_INFO_VER_PROTOCOL, NULL, 0, NULL, 0, &resp, DEFAULT_TIMEOUT); + if (r) { + fprintf(stderr, "RQT_INFO_VER_PROTOCOL, status = %08x\n", r); + return -1; + } */ + + /* Here should be some code, which closes protocol session, resets it somehow */ + + close(fd); + + return 0; +} + +int test_tar_entry(struct data_src *tardata) +{ + static unsigned char *chunk; + size_t n = 0, size; + int chunksize; + + chunk = (unsigned char*)malloc(trans_unit_size); + if (chunk == NULL) { + fprintf(stderr, "Unable to allocate memory.\n"); + return -1; + } + + size = tardata->get_data_length(tardata); + while (n < size) { + if (size - n >= trans_unit_size) + chunksize = trans_unit_size; + else + chunksize = size - n; + + chunksize = tardata->get_data_block(tardata, chunk, chunksize); + if (chunksize <= 0) { + free(chunk); + return -1; + } + + if (!(chunksize <= trans_unit_size && chunksize > 0)) { + free(chunk); + return -1; + } + + if ((n/chunksize)%4 == 0) + fprintf(stderr, "."); + + n += chunksize; + } + + free(chunk); + + return 0; +} + +int test_tar_file(const char *tarfile) +{ + struct tar_data_src tardata; + const char *filename; + int r = 0; + + fprintf(stderr, "tar %s\n", tarfile); + + r = tardata_open(&tardata, tarfile); + if (r < 0) { + fprintf(stderr, "line %d: failed to open %s\n", __LINE__, tarfile); + return r; + } + + while (1) { + filename = tardata_next(&tardata); + if (!filename) + break; + + fprintf(stderr, " entry %s ", filename); + + r = test_tar_entry(&tardata.src); + if (r) { + fprintf(stderr, "bad\n"); + break; + } + + fprintf(stderr, "\n"); + } + + tardata_close(&tardata); + + return r; +} + + +int test_tar_file_list(char **tarfilelist) +{ + int r; + + while (*tarfilelist) { + char *tarfile = *tarfilelist; + + r = test_tar_file(tarfile); + if (r < 0) + fprintf(stderr, "failed to load %s\n", *tarfilelist); + tarfilelist++; + } + + return 0; +} + +void usage(const char *exename) +{ + fprintf(stderr, "%s: [-t] [-v] [-i] [-d port] [-p pitfile] [tar] [tar] ..\n", + exename); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *exename, *portname, *pitfile; + int opt; + int opt_check = 0; + + exename = argv[0]; + + opt = 1; + + pitfile = NULL; + portname = NULL; + + printf("\n"); + printf("Linux Thor downloader, version %s \n", PACKAGE_VERSION); + printf("Authors: YoungJin Lee , " + "Jaehoon You \n\n"); + + while (opt < argc) { + /* check if we're verbose */ + if (!strcmp(argv[opt], "-v")) { + opt_verbose = 1; + opt++; + continue; + } + + if (!strcmp(argv[opt], "-t")) { + opt_test = 1; + opt++; + continue; + } + + if (!strcmp(argv[opt], "-c")) { + opt_check = 1; + opt++; + continue; + } + + if (!strcmp(argv[opt], "-p")) { + pitfile = argv[opt+1]; + opt += 2; + continue; + } + + if (!strcmp(argv[opt], "-d") && (opt+1) < argc) { + portname = argv[opt+1]; + opt += 2; + continue; + } + + break; + } + + if (opt_test) + return test_tar_file_list(&argv[opt]); + + if (opt_check) + return check_proto(portname); + + if ((pitfile)&&(opt == argc)) + return process_download(portname, pitfile, NULL); + + if (opt < argc) + return process_download(portname, pitfile, &argv[opt]); + + usage(exename); + return 0; +} + diff --git a/packaging/Makefile b/packaging/Makefile new file mode 100644 index 0000000..4ffb78c --- /dev/null +++ b/packaging/Makefile @@ -0,0 +1,19 @@ +PKG_NAME := lthor +SPECFILE = $(addsuffix .spec, $(PKG_NAME)) +PKG_VERSION := $(shell grep '^Version: ' $(SPECFILE)|awk '{print $$2}') + +TARBALL := $(PKG_NAME)_$(PKG_VERSION).tar.gz + +tarball: + @cd .. && git archive --prefix $(PKG_NAME)-$(PKG_VERSION)/ HEAD \ + | gzip > packaging/$(TARBALL) + +dsc: tarball + $(eval MD5=$(shell md5sum $(TARBALL) | sed "s/ / $(shell stat -c '%s' $(TARBALL)) /")) + @sed -i 's/^Version:.*/Version: $(PKG_VERSION)/' $(PKG_NAME).dsc + @sed -i 's/ [a-f0-9]\+ [0-9]\+ $(PKG_NAME).*tar.*/ $(MD5)/' $(PKG_NAME).dsc + +clean: + @rm -f $(PKG_NAME)_*.tar.gz + +all: clean tarball dsc diff --git a/packaging/lthor.changes b/packaging/lthor.changes new file mode 100644 index 0000000..26dd435 --- /dev/null +++ b/packaging/lthor.changes @@ -0,0 +1,5 @@ +------------------------------------------------------------------- +Tue Nov 6 16:32:56 UTC 2012 - eduard.bartosh@intel.com + +- Initial packaging + diff --git a/packaging/lthor.dsc b/packaging/lthor.dsc new file mode 100644 index 0000000..e4e4e6e --- /dev/null +++ b/packaging/lthor.dsc @@ -0,0 +1,10 @@ +Format: 1.0 +Source: lthor +Binary: lthor +Architecture: any +Version: 1.0 +Maintainer: Ed Bartosh +Standards-Version: 3.7.2 +Build-Depends: debhelper (>= 7), pkg-config, cmake, libarchive-dev +Files: + 58f2bac971d05de313cd5d9ca3e60c9b 9259 lthor_1.0.tar.gz diff --git a/packaging/lthor.spec b/packaging/lthor.spec new file mode 100644 index 0000000..3873610 --- /dev/null +++ b/packaging/lthor.spec @@ -0,0 +1,44 @@ +# +# spec file for cats-core +# +Name: lthor +Summary: Flashing tool for Tizen lunchbox +Version: 1.0 +Release: 1 +Group: Development/Tools/Other +License: Samsung reserved +URL: https://download.tizendev.org/tools/lthor/ +Source0: %{name}_%{version}.tar.gz + +BuildRequires: libarchive-devel +BuildRequires: cmake +BuildRequires: pkg-config + +%description +Tool for downloading binaries from a Linux host PC to a target phone. +It uses a USB cable as a physical communication medium. +It is prerequisite that the boot-loader should support download protocol +which is compatible with 'lthor'. + +%prep +%setup -q + +%build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr . +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +%clean +rm -rf %{buildroot} + +%post + +%files +%defattr(-,root,root) +%{_bindir}/%{name} + +%changelog + diff --git a/thor-proto.h b/thor-proto.h new file mode 100644 index 0000000..0b8ee39 --- /dev/null +++ b/thor-proto.h @@ -0,0 +1,78 @@ +#ifndef __THOR_PROTO_H__ +#define __THOR_PROTO_H__ + +typedef enum { + RQT_INFO = 200, + RQT_CMD, + RQT_DL, + RQT_UL, +} request_type; + +/* Request Data */ +/* RQT_INFO */ +enum { + RQT_INFO_VER_PROTOCOL = 1, + RQT_INFO_VER_HW, + RQT_INFO_VER_BOOT, + RQT_INFO_VER_KERNEL, + RQT_INFO_VER_PLATFORM, + RQT_INFO_VER_CSC, +}; + +/* RQT_CMD */ +enum { + RQT_CMD_REBOOT = 1, + RQT_CMD_POWEROFF, +}; + +/* RQT_DL */ +enum { + RQT_DL_INIT = 1, + RQT_DL_FILE_INFO, + RQT_DL_FILE_START, + RQT_DL_FILE_END, + RQT_DL_EXIT, +}; + +/* RQT_UL */ +enum { + RQT_UL_INIT = 1, + RQT_UL_START, + RQT_UL_END, + RQT_UL_EXIT, +}; + +enum __binary_type { + BINARY_TYPE_NORMAL = 0, + BINARY_TYPE_PIT, +}; + +struct rqt_pkt { + int32_t id; /* Request Group ID. */ + int32_t sub_id; /* Request Data ID. */ + int32_t int_data[14]; /* Int. Datas. */ + char str_data[5][32]; /* Str. Data. */ + char md5[32]; /* MD5 Checksum. */ +}; + + +struct res_pkt { + int32_t id; /* Response Group ID == Request Group ID. */ + int32_t sub_id; /* Response Data ID == Request Data ID. */ + int32_t ack; /* Ack. */ + int32_t int_data[5]; /* Int. Datas. */ + char str_data[3][32]; /* Str. Data. */ +}; + + +struct data_res_pkt { + int32_t ack; /* Ack. */ + int32_t cnt; /* Int. Datas. */ +}; + + +#define RQT_PKT_SIZE sizeof(struct rqt_pkt) +#define RES_PKT_SIZE sizeof(struct res_pkt) +#define DATA_RES_PKT_SIZE sizeof(struct data_res_pkt) + +#endif /* __THOR_PROTO_H__ */