--- /dev/null
+
+ 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.
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <errno.h>
+#include <dirent.h>
+#include <libgen.h>
+
+#include <archive.h>
+#include <archive_entry.h>
+
+#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; i<len; i++) {
+ if (i && (0==i%16))
+ fprintf(stderr, " ");
+ fprintf(stderr, "%02x%c", ((unsigned char*)bytes)[i],
+ ((len == i+1) || (i+1)%16==0) ? '\n': ' ');
+ }
+}
+
+static off_t file_size(const char *filename)
+{
+ struct stat st;
+ if (stat(filename, &st) < 0)
+ return -1;
+
+ return st.st_size;
+}
+
+int serial_read(int fd, void *addr, size_t len, int timeout)
+{
+ unsigned char *p = addr;
+ int n = 0, r;
+
+ while (n < len) {
+ struct pollfd fds;
+ fds.fd = fd;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ r = poll(&fds, 1, timeout);
+ if (r < 0) {
+ fprintf(stderr, "line %d: poll failed\n", __LINE__);
+ return -1;
+ }
+
+ if (r == 0) {
+ if (opt_verbose)
+ fprintf(stderr, "line %d: timeout after reading %d bytes\n", __LINE__, n);
+ return n;
+ }
+
+ if (!(fds.revents & POLLIN)) {
+ fprintf(stderr, "line %d: poll returned non-read event %08x\n", __LINE__, fds.revents);
+ continue;
+ }
+
+ r = read(fd, &p[n], len - n);
+ if (r < 0) {
+ fprintf(stderr, "line %d: read failed\n", __LINE__);
+ return -1;
+ }
+
+ n += r;
+ }
+
+ return n;
+}
+
+static double timediff (struct timeval *atv, struct timeval *btv)
+{
+ double diff;
+
+ if (btv->tv_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<icnt; i++)
+ req.int_data[i] = idata[i];
+ }
+
+ if (sdata) {
+ for (i=0; i<scnt; i++)
+ strcpy(req.str_data[i],sdata[i]);
+ }
+
+ dump("send", &req, 0x20);
+
+ r = write(fd, &req, RQT_PKT_SIZE);
+ if (r != RQT_PKT_SIZE) {
+ fprintf(stderr, "line %d: failed to send data r = %d\n",
+ __LINE__, r);
+ return -1;
+ }
+
+ return 0;
+}
+
+int send_request_timeout(int fd, request_type req_id, int req_sub_id,
+ int *idata, int icnt, char **sdata, int scnt, struct res_pkt *pres, int timeout)
+{
+ struct res_pkt resp;
+ int r;
+
+ r = write_request(fd, req_id, req_sub_id, idata, icnt, sdata, scnt);
+ if (r < 0) {
+ fprintf(stderr, "line %d: failed to write request r = %d\n",
+ __LINE__, r);
+ return -1;
+ }
+
+ r = serial_read(fd, &resp, sizeof resp, timeout);
+ if (r >= 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 <volume-down> + <power> 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 <yj0701.lee@samsung.com>, "
+ "Jaehoon You <jaehoon.you@samsung.com>\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;
+}
+