blob: 9fd9863e8ac455a821bb8a672d1f8fd13ad5ed70 [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 },
Dave Chapmancdcca872010-05-02 09:42:51 +000058 {"cowons9", "Cowon S9", 0xb057, 0x20000000, 0xa1102800 },
Dave Chapman11251f42007-10-21 11:00:28 +000059 {"iaudio6", "iAudio 6", 0xb021, 0x20000000, 0x62e97010 },
60 {"iaudio7", "iAudio 7", 0xb021, 0x20000000, 0x62e97010 },
Dave Chapman1b39f2e2008-02-07 20:53:20 +000061 {"logikdax", "Logik DAX 1GB DAB/MP3 player", 0xb021, 0x20000000, 0x52e97410 },
Dave Chapman5b3627f2008-10-05 00:36:12 +000062 {"x20", "iRiver X20", 0xb051, 0x20000000, 0x02e92010 },
Dave Chapman7d189352008-02-23 20:47:40 +000063 {"ypp2", "Samsung YP-P2", 0xb011, 0x20000000, 0x22e92010 },
Dave Chapman9ce02612008-02-23 20:50:26 +000064 {"ypk3", "Samsung YP-K3", 0xb021, 0x20000000, 0x62e92018 },
Dave Chapman71cdf002007-10-20 09:11:34 +000065};
66
67#define NUM_DEVICES ((sizeof(devices) / sizeof(struct device_t)))
68
69int find_device(char* devname)
70{
71 unsigned int i = 0;
72
73 while ((i < NUM_DEVICES) && (strcmp(devices[i].name,devname)))
74 i++;
75
76 if (i==NUM_DEVICES)
77 return -1;
78 else
79 return i;
80}
81
82void print_devices(void)
83{
84 unsigned int i;
85
86 printf("Valid devices are:\n");
87 for (i=0; i<NUM_DEVICES; i++)
88 {
89 printf(" %10s - %s\n",devices[i].name,devices[i].label);
90 }
91}
92
93/* USB IDs for USB Boot Mode */
94#define TCC_VENDORID 0x140e
Dave Chapman71cdf002007-10-20 09:11:34 +000095
96#define TCC_BULK_TO 1
97#define TOUT 5000
98#define PACKET_SIZE 64 /* Number of bytes to send in one write */
99
100#ifndef MAX
101#define MAX(a,b) (((a)>(b))?(a):(b))
102#endif
103
104static void put_int32le(uint32_t x, char* p)
105{
106 p[0] = x & 0xff;
107 p[1] = (x >> 8) & 0xff;
108 p[2] = (x >> 16) & 0xff;
109 p[3] = (x >> 24) & 0xff;
110}
111
112int upload_app(usb_dev_handle* dh, int device, char* p, int len)
113{
114 char buf[PACKET_SIZE];
115 int err;
116 int i;
117
Dave Chapman2c816d12007-10-20 21:00:34 +0000118 /* Send the header - Destination address, length and SDCFG value */
Dave Chapman71cdf002007-10-20 09:11:34 +0000119 memset(buf, 0, PACKET_SIZE);
120
121 put_int32le(0xf0000000, buf); /* Unknown - always the same */
122 put_int32le(len / PACKET_SIZE, buf + 4);
123 put_int32le(devices[device].loadaddr, buf + 8);
Dave Chapman2c816d12007-10-20 21:00:34 +0000124 put_int32le(devices[device].sdcfg, buf + 12);
Dave Chapman71cdf002007-10-20 09:11:34 +0000125
126 err = usb_bulk_write(dh, TCC_BULK_TO, buf, PACKET_SIZE, TOUT);
127
128 if (err < 0)
129 {
130 fprintf(stderr,"[ERR] Error writing header\n");
131 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
132 return -1;
133 }
134
135 /* Now send the data, PACKET_SIZE bytes at a time. */
136
137 for (i=0 ; i < (len / PACKET_SIZE) ; i++)
138 {
139 err = usb_bulk_write(dh, TCC_BULK_TO, p, PACKET_SIZE, TOUT);
140
141 if (err < 0)
142 {
143 fprintf(stderr,"[ERR] Error writing data\n");
144 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
145 return -1;
146 }
147
148 p += PACKET_SIZE;
149 }
150
151 return 0;
152}
153
154
155/* The main function */
156
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000157int do_patching(int device, char* buf, int len)
Dave Chapman71cdf002007-10-20 09:11:34 +0000158{
159 struct usb_bus *busses;
160 struct usb_bus *bus;
161 struct usb_device *tmp_dev;
162 struct usb_device *dev = NULL;
163 usb_dev_handle *dh;
164 int err;
165
166 fprintf(stderr,"[INFO] Searching for TCC device...\n");
167
168 usb_init();
169 if(usb_find_busses() < 0) {
170 fprintf(stderr, "[ERR] Could not find any USB busses.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000171 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000172 }
173
174 if (usb_find_devices() < 0) {
175 fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000176 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000177 }
178
179 /* C calling convention, it's not nice to use global stuff */
180 busses = usb_get_busses();
181
182 for (bus = busses; bus; bus = bus->next) {
183 for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) {
184 //printf("Found Vendor %04x Product %04x\n",tmp_dev->descriptor.idVendor, tmp_dev->descriptor.idProduct);
185 if (tmp_dev->descriptor.idVendor == TCC_VENDORID &&
Dave Chapman11251f42007-10-21 11:00:28 +0000186 tmp_dev->descriptor.idProduct == devices[device].productid) {
Dave Chapman71cdf002007-10-20 09:11:34 +0000187
188 dev = tmp_dev;
189 goto found;
190
191 }
192 }
193 }
194
195 if (dev == NULL) {
196 fprintf(stderr, "[ERR] TCC device not found.\n");
197 fprintf(stderr, "[ERR] Ensure your TCC device is in USB boot mode and run tcctool again.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000198 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000199 }
200
201found:
202 if ( (dh = usb_open(dev)) == NULL) {
203 fprintf(stderr,"[ERR] Unable to open TCC device.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000204 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000205 }
206
207 err = usb_set_configuration(dh, 1);
208
209 if (err < 0) {
210 fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err);
211 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000212 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000213 }
214
215 /* "must be called" written in the libusb documentation */
216 err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
217 if (err < 0) {
218 fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err);
219 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000220 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000221 }
222
223 fprintf(stderr,"[INFO] Found TCC device, uploading application.\n");
224
225 /* Now we can transfer the application to the device. */
226
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000227 if ( (err = upload_app(dh, device, buf, len)) < 0)
Dave Chapman71cdf002007-10-20 09:11:34 +0000228 {
229 fprintf(stderr,"[ERR] Upload of application failed.\n");
230 }
231 else
232 {
233 fprintf(stderr,"[INFO] Patching application uploaded successfully!\n");
234 }
235
236 /* release claimed interface */
237 usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
Dave Chapman71cdf002007-10-20 09:11:34 +0000238 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000239
240 return err < 0 ? -1: 0;
Dave Chapman71cdf002007-10-20 09:11:34 +0000241}
242
243off_t filesize(int fd) {
244 struct stat buf;
245
246 if (fstat(fd,&buf) < 0) {
247 perror("[ERR] Checking filesize of input file");
248 return -1;
249 } else {
250 return(buf.st_size);
251 }
252}
253
254void print_usage(void)
255{
256 printf("Usage: tcctool -d devicename firmware.bin\n");
257}
258
259int main(int argc, char* argv[])
260{
261 char* buf;
Dave Chapman3d300292008-10-12 18:10:39 +0000262 int n,len,padded_len;
Dave Chapman71cdf002007-10-20 09:11:34 +0000263 int fd;
264 int device;
265
Dave Chapman9de9b9d2010-05-02 09:54:14 +0000266 printf("tcctool " VERSION " - (C) 2007-2010 Dave Chapman\n");
Dave Chapman71cdf002007-10-20 09:11:34 +0000267 printf("This is free software; see the source for copying conditions. There is NO\n");
268 printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
269
270 if (argc != 4)
271 {
272 print_usage();
Dave Chapman28c5ba82007-10-27 07:53:42 +0000273 print_devices();
Dave Chapman71cdf002007-10-20 09:11:34 +0000274 return 1;
275 }
276
277 if (strcmp(argv[1],"-d"))
278 {
279 print_usage();
Dave Chapman28c5ba82007-10-27 07:53:42 +0000280 print_devices();
Dave Chapman71cdf002007-10-20 09:11:34 +0000281 return 2;
282 }
283
284 device = find_device(argv[2]);
285
286 if (device < 0)
287 {
288 printf("[ERR] Unknown device \"%s\"\n",argv[2]);
289 print_devices();
290 return 3;
291 }
292
293 printf("[INFO] Using device \"%s\"\n",devices[device].label);
Dave Chapman164b8f62007-10-31 17:52:50 +0000294 fd = open(argv[3], O_RDONLY|O_BINARY);
Dave Chapman71cdf002007-10-20 09:11:34 +0000295 if (fd < 0)
296 {
297 printf("[ERR] Could not open %s\n", argv[3]);
298 return 4;
299 }
300
301 len = filesize(fd);
302
303 if (len > MAX_FIRMWARESIZE)
304 {
305 printf("[ERR] Firmware file too big\n");
306 close(fd);
307 return 5;
308 }
309
Dave Chapman3d300292008-10-12 18:10:39 +0000310 /* Round len up to multiple of PACKET_SIZE */
311 padded_len = (len + PACKET_SIZE) & ~(PACKET_SIZE-1);
312
313 buf = malloc(padded_len);
Dave Chapman71cdf002007-10-20 09:11:34 +0000314 if (buf == NULL)
315 {
316 printf("[ERR] Could not allocate memory.\n");
317 close(fd);
318 return 6;
319 }
320
321 n = read(fd, buf, len);
322 if (n != len)
323 {
324 printf("[ERR] Short read.\n");
325 close(fd);
326 return 7;
327 }
328 close(fd);
329
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000330 if (do_patching(device, buf, padded_len))
331 {
332 return 8;
333 }
Dave Chapman71cdf002007-10-20 09:11:34 +0000334
335 return 0;
336}