blob: 04587853b9c37cb3cc15d6cfea65c6504ccc6faa [file] [log] [blame]
Dave Chapman71cdf002007-10-20 09:11:34 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
12 * USB code based on ifp-line - http://ifp-driver.sourceforge.net
13 *
14 * ifp-line is (C) Pavel Kriz, Jun Yamishiro and Joe Roback and
15 * licensed under the GPL (v2)
16 *
17 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000018 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
Dave Chapman71cdf002007-10-20 09:11:34 +000022 *
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
25 *
26 ****************************************************************************/
27
Dave Chapman71cdf002007-10-20 09:11:34 +000028#include <stdio.h>
29#include <inttypes.h>
30#include <usb.h>
31#include <string.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
35#include <fcntl.h>
36
Dave Chapman28c5ba82007-10-27 07:53:42 +000037#define MAX_FIRMWARESIZE (10*1024*1024) /* Arbitrary limit (for safety) */
Dave Chapman71cdf002007-10-20 09:11:34 +000038
Dave Chapman164b8f62007-10-31 17:52:50 +000039/* For win32 compatibility: */
40#ifndef O_BINARY
41#define O_BINARY 0
42#endif
43
Dave Chapman71cdf002007-10-20 09:11:34 +000044struct device_t
45{
46 char* name;
47 char* label;
Dave Chapman11251f42007-10-21 11:00:28 +000048 uint16_t productid;
Dave Chapman71cdf002007-10-20 09:11:34 +000049 uint32_t loadaddr;
Dave Chapman2c816d12007-10-20 21:00:34 +000050 uint32_t sdcfg;
Dave Chapman71cdf002007-10-20 09:11:34 +000051};
52
53static struct device_t devices[] =
54{
Dave Chapman738a8972007-10-27 11:55:38 +000055 {"c100", "Sansa C100 series", 0xb021, 0x20000000, 0x42e97010 },
Robert Menes02512be2009-05-07 20:49:03 +000056 {"m200", "Sansa M200 series", 0xb021, 0x20000000, 0x42e97010 },
Dave Chapman28c5ba82007-10-27 07:53:42 +000057 {"cowond2", "Cowon D2", 0xb011, 0x20000000, 0xa2e92010 },
Bertrik Sikkend0ffa932010-11-10 18:55:59 +000058 {"cowonj3", "Cowon J3", 0xb057, 0x20000000, 0xaaac7800 },
Dave Chapmancdcca872010-05-02 09:42:51 +000059 {"cowons9", "Cowon S9", 0xb057, 0x20000000, 0xa1102800 },
Dave Chapman11251f42007-10-21 11:00:28 +000060 {"iaudio6", "iAudio 6", 0xb021, 0x20000000, 0x62e97010 },
61 {"iaudio7", "iAudio 7", 0xb021, 0x20000000, 0x62e97010 },
Dave Chapman1b39f2e2008-02-07 20:53:20 +000062 {"logikdax", "Logik DAX 1GB DAB/MP3 player", 0xb021, 0x20000000, 0x52e97410 },
Dave Chapman5b3627f2008-10-05 00:36:12 +000063 {"x20", "iRiver X20", 0xb051, 0x20000000, 0x02e92010 },
Dave Chapman7d189352008-02-23 20:47:40 +000064 {"ypp2", "Samsung YP-P2", 0xb011, 0x20000000, 0x22e92010 },
Dave Chapman9ce02612008-02-23 20:50:26 +000065 {"ypk3", "Samsung YP-K3", 0xb021, 0x20000000, 0x62e92018 },
Dave Chapman71cdf002007-10-20 09:11:34 +000066};
67
68#define NUM_DEVICES ((sizeof(devices) / sizeof(struct device_t)))
69
70int find_device(char* devname)
71{
72 unsigned int i = 0;
73
74 while ((i < NUM_DEVICES) && (strcmp(devices[i].name,devname)))
75 i++;
76
77 if (i==NUM_DEVICES)
78 return -1;
79 else
80 return i;
81}
82
83void print_devices(void)
84{
85 unsigned int i;
86
87 printf("Valid devices are:\n");
88 for (i=0; i<NUM_DEVICES; i++)
89 {
90 printf(" %10s - %s\n",devices[i].name,devices[i].label);
91 }
92}
93
94/* USB IDs for USB Boot Mode */
95#define TCC_VENDORID 0x140e
Dave Chapman71cdf002007-10-20 09:11:34 +000096
97#define TCC_BULK_TO 1
98#define TOUT 5000
99#define PACKET_SIZE 64 /* Number of bytes to send in one write */
100
101#ifndef MAX
102#define MAX(a,b) (((a)>(b))?(a):(b))
103#endif
104
105static void put_int32le(uint32_t x, char* p)
106{
107 p[0] = x & 0xff;
108 p[1] = (x >> 8) & 0xff;
109 p[2] = (x >> 16) & 0xff;
110 p[3] = (x >> 24) & 0xff;
111}
112
113int upload_app(usb_dev_handle* dh, int device, char* p, int len)
114{
115 char buf[PACKET_SIZE];
116 int err;
117 int i;
118
Dave Chapman2c816d12007-10-20 21:00:34 +0000119 /* Send the header - Destination address, length and SDCFG value */
Dave Chapman71cdf002007-10-20 09:11:34 +0000120 memset(buf, 0, PACKET_SIZE);
121
122 put_int32le(0xf0000000, buf); /* Unknown - always the same */
123 put_int32le(len / PACKET_SIZE, buf + 4);
124 put_int32le(devices[device].loadaddr, buf + 8);
Dave Chapman2c816d12007-10-20 21:00:34 +0000125 put_int32le(devices[device].sdcfg, buf + 12);
Dave Chapman71cdf002007-10-20 09:11:34 +0000126
127 err = usb_bulk_write(dh, TCC_BULK_TO, buf, PACKET_SIZE, TOUT);
128
129 if (err < 0)
130 {
131 fprintf(stderr,"[ERR] Error writing header\n");
132 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
133 return -1;
134 }
135
136 /* Now send the data, PACKET_SIZE bytes at a time. */
137
138 for (i=0 ; i < (len / PACKET_SIZE) ; i++)
139 {
140 err = usb_bulk_write(dh, TCC_BULK_TO, p, PACKET_SIZE, TOUT);
141
142 if (err < 0)
143 {
144 fprintf(stderr,"[ERR] Error writing data\n");
145 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
146 return -1;
147 }
148
149 p += PACKET_SIZE;
150 }
151
152 return 0;
153}
154
155
156/* The main function */
157
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000158int do_patching(int device, char* buf, int len)
Dave Chapman71cdf002007-10-20 09:11:34 +0000159{
160 struct usb_bus *busses;
161 struct usb_bus *bus;
162 struct usb_device *tmp_dev;
163 struct usb_device *dev = NULL;
164 usb_dev_handle *dh;
165 int err;
166
167 fprintf(stderr,"[INFO] Searching for TCC device...\n");
168
169 usb_init();
170 if(usb_find_busses() < 0) {
171 fprintf(stderr, "[ERR] Could not find any USB busses.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000172 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000173 }
174
175 if (usb_find_devices() < 0) {
176 fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000177 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000178 }
179
180 /* C calling convention, it's not nice to use global stuff */
181 busses = usb_get_busses();
182
183 for (bus = busses; bus; bus = bus->next) {
184 for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) {
185 //printf("Found Vendor %04x Product %04x\n",tmp_dev->descriptor.idVendor, tmp_dev->descriptor.idProduct);
186 if (tmp_dev->descriptor.idVendor == TCC_VENDORID &&
Dave Chapman11251f42007-10-21 11:00:28 +0000187 tmp_dev->descriptor.idProduct == devices[device].productid) {
Dave Chapman71cdf002007-10-20 09:11:34 +0000188
189 dev = tmp_dev;
190 goto found;
191
192 }
193 }
194 }
195
196 if (dev == NULL) {
197 fprintf(stderr, "[ERR] TCC device not found.\n");
198 fprintf(stderr, "[ERR] Ensure your TCC device is in USB boot mode and run tcctool again.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000199 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000200 }
201
202found:
203 if ( (dh = usb_open(dev)) == NULL) {
204 fprintf(stderr,"[ERR] Unable to open TCC device.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000205 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000206 }
207
208 err = usb_set_configuration(dh, 1);
209
210 if (err < 0) {
211 fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err);
212 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000213 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000214 }
215
216 /* "must be called" written in the libusb documentation */
217 err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
218 if (err < 0) {
219 fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err);
220 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000221 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000222 }
223
224 fprintf(stderr,"[INFO] Found TCC device, uploading application.\n");
225
226 /* Now we can transfer the application to the device. */
227
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000228 if ( (err = upload_app(dh, device, buf, len)) < 0)
Dave Chapman71cdf002007-10-20 09:11:34 +0000229 {
230 fprintf(stderr,"[ERR] Upload of application failed.\n");
231 }
232 else
233 {
234 fprintf(stderr,"[INFO] Patching application uploaded successfully!\n");
235 }
236
237 /* release claimed interface */
238 usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
Dave Chapman71cdf002007-10-20 09:11:34 +0000239 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000240
241 return err < 0 ? -1: 0;
Dave Chapman71cdf002007-10-20 09:11:34 +0000242}
243
244off_t filesize(int fd) {
245 struct stat buf;
246
247 if (fstat(fd,&buf) < 0) {
248 perror("[ERR] Checking filesize of input file");
249 return -1;
250 } else {
251 return(buf.st_size);
252 }
253}
254
255void print_usage(void)
256{
257 printf("Usage: tcctool -d devicename firmware.bin\n");
258}
259
260int main(int argc, char* argv[])
261{
262 char* buf;
Dave Chapman3d300292008-10-12 18:10:39 +0000263 int n,len,padded_len;
Dave Chapman71cdf002007-10-20 09:11:34 +0000264 int fd;
265 int device;
266
Dave Chapman9de9b9d2010-05-02 09:54:14 +0000267 printf("tcctool " VERSION " - (C) 2007-2010 Dave Chapman\n");
Dave Chapman71cdf002007-10-20 09:11:34 +0000268 printf("This is free software; see the source for copying conditions. There is NO\n");
269 printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
270
271 if (argc != 4)
272 {
273 print_usage();
Dave Chapman28c5ba82007-10-27 07:53:42 +0000274 print_devices();
Dave Chapman71cdf002007-10-20 09:11:34 +0000275 return 1;
276 }
277
278 if (strcmp(argv[1],"-d"))
279 {
280 print_usage();
Dave Chapman28c5ba82007-10-27 07:53:42 +0000281 print_devices();
Dave Chapman71cdf002007-10-20 09:11:34 +0000282 return 2;
283 }
284
285 device = find_device(argv[2]);
286
287 if (device < 0)
288 {
289 printf("[ERR] Unknown device \"%s\"\n",argv[2]);
290 print_devices();
291 return 3;
292 }
293
294 printf("[INFO] Using device \"%s\"\n",devices[device].label);
Dave Chapman164b8f62007-10-31 17:52:50 +0000295 fd = open(argv[3], O_RDONLY|O_BINARY);
Dave Chapman71cdf002007-10-20 09:11:34 +0000296 if (fd < 0)
297 {
298 printf("[ERR] Could not open %s\n", argv[3]);
299 return 4;
300 }
301
302 len = filesize(fd);
303
304 if (len > MAX_FIRMWARESIZE)
305 {
306 printf("[ERR] Firmware file too big\n");
307 close(fd);
308 return 5;
309 }
310
Dave Chapman3d300292008-10-12 18:10:39 +0000311 /* Round len up to multiple of PACKET_SIZE */
312 padded_len = (len + PACKET_SIZE) & ~(PACKET_SIZE-1);
313
314 buf = malloc(padded_len);
Dave Chapman71cdf002007-10-20 09:11:34 +0000315 if (buf == NULL)
316 {
317 printf("[ERR] Could not allocate memory.\n");
318 close(fd);
319 return 6;
320 }
321
322 n = read(fd, buf, len);
323 if (n != len)
324 {
325 printf("[ERR] Short read.\n");
326 close(fd);
327 return 7;
328 }
329 close(fd);
330
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000331 if (do_patching(device, buf, padded_len))
332 {
333 return 8;
334 }
Dave Chapman71cdf002007-10-20 09:11:34 +0000335
336 return 0;
337}