~ubuntu-branches/ubuntu/wily/isight-firmware-tools/wily

« back to all changes in this revision

Viewing changes to src/extract.c

  • Committer: Bazaar Package Importer
  • Author(s): Nobuhiro Iwamatsu
  • Date: 2011-02-28 00:25:09 UTC
  • mfrom: (7.2.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110228002509-obidj53lavuirx81
Tags: 1.5.93-1
* New upstream release.
* Change to 3.0 (quilt).
* Disable hal (Closes: 605783).
* Drop all pathces. Some patches was applied to upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 * along with this program; if not, write to the Free Software
24
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25
25
 * MA 02110-1301, USA
 
26
 *
 
27
 *
 
28
 *
 
29
 * 
 
30
 * - First version had hardcoded offset, with a SHA1 sum check
 
31
 *   (Ronald)
 
32
 *   
 
33
 * - Second version, multiple sha1sum were handled with their offset
 
34
 *   (Étienne)
 
35
 *   
 
36
 * - Third version, we search for a preambule in driver and extract
 
37
 *   the firmware (Étienne, idea from Jeroen van der Vegt)
26
38
 */
27
39
 
28
40
#ifdef HAVE_CONFIG_H
37
49
#include <glib/gstdio.h>
38
50
 
39
51
/*
40
 
 * Foreach file identified by their sha1sum, we store the offset where
41
 
 * the firmware begin in the file.
42
 
 *
43
 
 * If a file does not work, you may need to add an entry here. To find
44
 
 * the offset in the driver file, use a hexadecimal editor (e.g. ghex)
45
 
 * and search for "USBSend". You will find data like this :
46
 
 *
47
 
 * "start USBSend #4 returned 0x%x.....X.....4.~.........%\"
48
 
 *                                                  ^
49
 
 *
50
 
 * Each period means 0x00. The firmware start at the ^ sign
51
 
 * position. Read the offset and store in in this array. The tool must
52
 
 * output the sha1sum of the file, use this to fill the .sha1sum
53
 
 * field.
54
 
 *
55
 
 */
56
 
 
57
 
struct offset {
58
 
        gchar *desc;
59
 
        unsigned char sha1sum[20];
60
 
        long offset;
61
 
};
62
 
 
63
 
static const struct offset offsets[] = {
64
 
        { "Mac OS X.6 MacBook 1,1",
65
 
          .sha1sum      = { 0x32, 0xcc, 0xa3, 0x17, 0xae, 0x54, 0xb5, 0x1c,
66
 
                            0x4c, 0xfa, 0x66, 0x4d, 0x0d, 0xa0, 0x47, 0xe9,
67
 
                            0x11, 0x01, 0xf9, 0x1e },
68
 
          .offset       = 0x20D8,
69
 
        },
70
 
        { "Mac OS X.6 MacBook 5,2",
71
 
          .sha1sum      = { 0x06, 0x2d, 0x20, 0xde, 0x72, 0xb9, 0x6a, 0x24,
72
 
                            0xb7, 0x41, 0xc9, 0x51, 0xda, 0x04, 0x5d, 0xd7,
73
 
                            0x81, 0x9c, 0x7b, 0xc8 },
74
 
          .offset       = 0x20D8,
75
 
        },
76
 
        { "Mac OS X.6 MacBook Unibody",
77
 
          .sha1sum      = { 0xcd, 0x38, 0xe9, 0x08, 0x06, 0xae, 0x06, 0xec,
78
 
                            0xe0, 0x5b, 0x47, 0x26, 0x04, 0x3b, 0xef, 0xec,
79
 
                            0x40, 0x15, 0x73, 0x4d },
80
 
          .offset       = 0x20d8,
81
 
        },
82
 
        { "Mac OS X.5.7",
83
 
          .sha1sum      = { 0x95, 0x6b, 0xf7, 0x0d, 0xa9, 0x03, 0xa0, 0xb4,
84
 
                            0x8b, 0x41, 0x44, 0x87, 0x61, 0xa0, 0xff, 0xd2,
85
 
                            0xd6, 0x93, 0xa2, 0x90 },
86
 
          .offset       = 0x20D8
87
 
        },
88
 
        { "Mac OS X.5.6",
89
 
          .sha1sum      = { 0xa1, 0x7c, 0xfe, 0xe1, 0xaa, 0x48, 0x83, 0xf6,
90
 
                            0x63, 0xb9, 0xf8, 0x95, 0x2d, 0x15, 0x6a, 0xe2,
91
 
                            0x8f, 0x90, 0xd9, 0x11 },
92
 
          .offset       = 0x20D8
93
 
        },
94
 
        { "Mac OS X.5.5",
95
 
          .sha1sum      = { 0x62, 0xe8, 0xed, 0xa7, 0x67, 0xa8, 0x37, 0x4f,
96
 
                            0x1b, 0x13, 0xc4, 0x61, 0xdd, 0x60, 0x8c, 0x84,
97
 
                            0xf3, 0xc8, 0xc0, 0x24 },
98
 
          .offset       = 0x20D8
99
 
        },
100
 
        { "Mac OS X.5.x (Macbook Air)",
101
 
          .sha1sum      = { 0xbd, 0x5d, 0xc3, 0xff, 0xf3, 0xa6, 0x5f, 0x35,
102
 
                            0xa6, 0xb8, 0xa1, 0x81, 0x40, 0x29, 0x8c, 0x06,
103
 
                            0x94, 0xb3, 0xed, 0xc6 },
104
 
          .offset       = 0x20D8
105
 
        },
106
 
        { "Mac OS X.5.5",
107
 
          .sha1sum      = { 0xf9, 0x91, 0xab, 0x81, 0xf8, 0x98, 0x8f, 0x41,
108
 
                            0x6f, 0x2d, 0xf0, 0x79, 0x2d, 0xf7, 0x60, 0x2c,
109
 
                            0x82, 0x01, 0x2b, 0xeb },
110
 
          .offset       = 0x20D8
111
 
        },
112
 
        { "Mac OS X.5.2",
113
 
          .sha1sum      = { 0x89, 0x84, 0x60, 0x94, 0x2e, 0x12, 0x65, 0xa3, 
114
 
                            0x57, 0xb5, 0xac, 0x86, 0x82, 0x4a, 0xf2, 0xd4,
115
 
                            0xa4, 0xf7, 0x3b, 0x98 },
116
 
          .offset       = 0x20D8
117
 
        },
118
 
        { "Mac OS X.5.1 late 2007",
119
 
          .sha1sum      = { 0x1c, 0x60, 0xef, 0x27, 0xd5, 0x72, 0x21, 0xcf,
120
 
                            0x3d, 0x76, 0x68, 0x7a, 0x49, 0x73, 0xec, 0x72,
121
 
                            0xff, 0x6f, 0xa1, 0x03 },
122
 
          .offset       = 0x20D8
123
 
        },
124
 
        { "Mac OS X.5.1 driver 1.0.9",
125
 
          .sha1sum      = { 0xa1, 0x7b, 0x71, 0xc0, 0xe6, 0x3b, 0xd3, 0x87,
126
 
                            0x82, 0x10, 0x88, 0xdb, 0x3a, 0x66, 0x5b, 0xb8,
127
 
                            0x7a, 0xdc, 0xa2, 0x08 },
128
 
          .offset       = 0xC404
129
 
        },
130
 
        { "Mac OS X.5.1",
131
 
          .sha1sum      = { 0xb6, 0x9f, 0x49, 0xd3, 0xfa, 0x68, 0x58, 0x41,
132
 
                            0x63, 0x24, 0xc3, 0x90, 0xef, 0xfe, 0x14, 0x33,
133
 
                            0x6a, 0x1d, 0xdb, 0x0b },
134
 
          .offset       = 0xC404
135
 
        },
136
 
        { "Mac OS X.4 intel",
137
 
          .sha1sum      = { 0x01, 0xe2, 0x91, 0xd5, 0x29, 0xe7, 0xc1, 0x8d,
138
 
                            0xee, 0xa2, 0xeb, 0xa2, 0x52, 0xd1, 0x81, 0x14,
139
 
                            0xe0, 0x96, 0x27, 0x6e },
140
 
          .offset       = 0x2060
141
 
        },
142
 
        { "Mac OS X unknown version",
143
 
          .sha1sum      = { 0xc6, 0xc9, 0x4d, 0xd7, 0x7b, 0x86, 0x4f, 0x8b,
144
 
                            0x2d, 0x31, 0xab, 0xf3, 0xcb, 0x2d, 0xe4, 0xc9,
145
 
                            0xd1, 0x39, 0xe1, 0xbf },
146
 
          .offset       = 0x1434
147
 
        },
148
 
        { "Mac OS X unknown version",
149
 
          .sha1sum      = { 0xa1, 0x4c, 0x15, 0x9b, 0x17, 0x6d, 0x27, 0xa6,
150
 
                            0xe9, 0x8d, 0xcb, 0x5d, 0xea, 0x5d, 0x78, 0xb8,
151
 
                            0x1e, 0x15, 0xad, 0x41 },
152
 
          .offset       = 0x23D8
153
 
        },
154
 
        { "Mac OS X unknown version",
155
 
          .sha1sum      = { 0x86, 0x43, 0x0c, 0x04, 0xf9, 0xb6, 0x7c, 0x5c,
156
 
                            0x3d, 0x84, 0x40, 0x91, 0x38, 0xa7, 0x67, 0x98,
157
 
                            0x27, 0x02, 0x5e, 0xc2 },
158
 
          .offset       = 0x1434
159
 
        },
160
 
        { "Mac OS X.4.10 PPC64",
161
 
          .sha1sum      = { 0xde, 0xf7, 0xf4, 0xf0, 0x08, 0xd7, 0x8f, 0x39,
162
 
                            0x3f, 0x95, 0x94, 0x6f, 0xbf, 0x85, 0xd7, 0xb1,
163
 
                            0xbd, 0xdc, 0x41, 0x11 },
164
 
          .offset       = 0x1318
165
 
        },
166
 
};
167
 
 
168
 
/*
169
52
 * The vanilla firmware have bugs in USB Interface descriptor
170
53
 * values. We override buggy value with correct one. Those value are
171
54
 * triplet, we replace 0xFF 0xFF 0xFF by specific value.
177
60
};
178
61
 
179
62
/* From linux-2.6:linux/usb/ch9.J */
180
 
#define USB_CLASS_VIDEO                 0x0e
 
63
#define USB_CLASS_VIDEO                 0x0E
 
64
#define USB_CLASS_MISC                  0xEF
 
65
#define USB_PROTOCOL_IFACE_ASSOC        0x01
181
66
 
182
67
/* From linux-uvc: uvcvideo.h */
183
68
#define SC_VIDEOCONTROL                 0x01
186
71
#define PC_PROTOCOL_UNDEFINED           0x00
187
72
 
188
73
static struct patch patches[] = {
 
74
        { N_("Fix device descriptor"),
 
75
          .offset       = 0x2352,
 
76
          .value        = { USB_CLASS_MISC,
 
77
                            0x02,
 
78
                            USB_PROTOCOL_IFACE_ASSOC }
 
79
        },
 
80
        { N_("Fix interface assocation descriptor"),
 
81
          .offset       = 0x2373,
 
82
          .value        = { 0x08, 0x0b, 0x00 }
 
83
        },
 
84
        { N_("Fix video interface collection"),
 
85
          .offset       = 0x2377,
 
86
          .value        = { USB_CLASS_VIDEO,
 
87
                            SC_VIDEO_INTERFACE_COLLECTION,
 
88
                            PC_PROTOCOL_UNDEFINED }
 
89
        },
 
90
        { N_("Fix video streaming device qualifier"),
 
91
          .offset       = 0x2364,
 
92
          .value        = { USB_CLASS_VIDEO,
 
93
                            SC_VIDEOSTREAMING,
 
94
                            PC_PROTOCOL_UNDEFINED }
 
95
        },
189
96
        { N_("Fix video control interface descriptor"),
190
97
          .offset       = 0x2380,
191
98
          .value        = { USB_CLASS_VIDEO,
198
105
                            SC_VIDEOSTREAMING,
199
106
                            PC_PROTOCOL_UNDEFINED }
200
107
        },
201
 
        /* needs to be checked */
202
 
        { N_("Fix video streaming device qualifier"),
203
 
          .offset       = 0x2364,
204
 
          .value        = { USB_CLASS_VIDEO,
205
 
                            SC_VIDEOSTREAMING,
206
 
                            PC_PROTOCOL_UNDEFINED }
207
 
        },
208
108
};
209
109
 
210
110
/* OPTIONS */
237
137
 
238
138
/* IMPLEMENTATION */
239
139
 
240
 
static unsigned char*
241
 
get_sha1sum(char*filename)
242
 
{
243
 
        unsigned char *digest;
244
 
        GMappedFile *file;
245
 
        GError *gerr = NULL;
246
 
 
247
 
        digest = g_malloc0 (gcry_md_get_algo_dlen (GCRY_MD_SHA1));
248
 
        if (!(file = g_mapped_file_new (filename, FALSE, &gerr))) {
249
 
                g_error(_("Unable to open driver: %s"),
250
 
                        gerr ? gerr->message : "?");
251
 
                return NULL;
252
 
        }
253
 
        gcry_md_hash_buffer (GCRY_MD_SHA1, digest,
254
 
                             g_mapped_file_get_contents (file),
255
 
                             g_mapped_file_get_length (file));
256
 
        g_mapped_file_free (file);
257
 
 
258
 
        return digest;
259
 
}
260
 
 
261
 
static gchar*
262
 
sha1sum_string(unsigned char*digest)
263
 
{
264
 
        gchar *sha1sum = "";
265
 
        gint i;
266
 
 
267
 
        for (i = 0; i < 20; i++) {
268
 
                sha1sum = g_strdup_printf("%s %02x", sha1sum, digest[i]);
269
 
        }
270
 
        return sha1sum;
271
 
}
272
 
 
273
 
static const struct offset*
274
 
find_offset(unsigned char*digest)
275
 
{
276
 
        gint n;
277
 
 
278
 
        for (n = 0; n < G_N_ELEMENTS (offsets); n++)
279
 
                if (!memcmp (offsets[n].sha1sum, digest, 20))
280
 
                        break;
281
 
 
282
 
        if (n == G_N_ELEMENTS (offsets)) {
283
 
                g_warning(_("Unknown driver. Please report it to %s with "
284
 
                            "machine description and Mac OS X version."),
285
 
                          PACKAGE_BUGREPORT);
286
 
                return NULL;
287
 
        } else {
288
 
                /* translators : %s is the known origin of the driver */
289
 
                g_message(_("Found %s driver"),
290
 
                          offsets[n].desc);
291
 
                return &offsets[n];
292
 
        }
293
 
}
 
140
/*
 
141
 * To find the offset in the driver file, use a hexadecimal editor
 
142
 * (e.g. ghex) and search for "USBSend". You will find data like
 
143
 * this :
 
144
 *
 
145
 * "start USBSend #4 returned 0x%x.....X.....4.~.........%\"
 
146
 *                                                  ^
 
147
 *
 
148
 * Each period means 0x00. The firmware start at the ^ sign
 
149
 * position. Read the offset and store in in this array. The tool must
 
150
 * output the sha1sum of the file, use this to fill the .sha1sum
 
151
 * field.
 
152
 */
 
153
static glong
 
154
seek_offset(const gchar* filename)
 
155
{
 
156
        gint fd;
 
157
        glong pos;
 
158
        /* This is the preambule of the firmware in the driver file */
 
159
        const guchar needle[8] = {0xC2, 0x34, 0x06, 0x7E,
 
160
                                  0x05, 0x00, 0x00, 0x00};
 
161
        guint read_len, chunk_len = 8;
 
162
        guint offset = 8;
 
163
        guchar* chunk = g_new0(guchar, chunk_len);
 
164
 
 
165
        if ((fd = g_open (filename, O_RDONLY)) == -1) {
 
166
                g_error(_("Unable to open %s."), filename);
 
167
                pos = -1;
 
168
                goto end;
 
169
        }
 
170
 
 
171
        for (pos = 0x1000; pos < 0xD000; pos++) {
 
172
                if (lseek(fd, pos, SEEK_SET) != pos) {
 
173
                        g_error(_("Failed to seek %s at position %x."),
 
174
                                filename, (guint) pos);
 
175
                        break;
 
176
                }
 
177
 
 
178
                if ((read_len = read(fd, chunk, chunk_len)) != chunk_len) {
 
179
                        g_error(_("Failed to read %s at position %x."),
 
180
                                filename, (guint) pos);
 
181
                        break;
 
182
                }
 
183
 
 
184
                if (memcmp(needle, chunk, chunk_len) == 0) {
 
185
                        pos+= offset;
 
186
                        g_message(_("Found firmware signature at offset 0x%X."),
 
187
                                  (guint) pos);
 
188
                        goto end_fd;
 
189
                }
 
190
        }
 
191
        pos = -1;
 
192
 
 
193
 
 
194
 end_fd:
 
195
        close(fd);
 
196
 end:
 
197
        g_free(chunk);
 
198
        return pos;
 
199
}
 
200
 
294
201
 
295
202
/* extract firmware from filename at offset to output, checking the
296
203
   format. */
332
239
                }
333
240
                len = (data[0] << 8) | data[1];
334
241
                req = (data[2] << 8) | data[3];
335
 
                if (len == 0x8001)
336
 
                        break; /* success */
337
 
                else if (len == 0)
 
242
                if (len == 0x8001) {
 
243
                        break;  /* success */
 
244
                } else if (len == 0)
338
245
                        continue;
339
246
                else if (len < 0 || len >= 1024) {
340
247
                        g_error(_("Invalid firmware data_length %d, "
359
266
        return 0;
360
267
}
361
268
 
 
269
static gint
 
270
firmware_version(int fd, guchar* version)
 
271
{
 
272
        guint read_len;
 
273
 
 
274
        if (lseek(fd, 4, SEEK_SET) == -1)
 
275
                g_error(_("Failed to find firmware version, unable to patch it"));
 
276
                
 
277
        if ((read_len = read(fd, version, 3)) != 3)
 
278
                g_error(_("Failed to read firmware version, unable to patch it"));
 
279
 
 
280
        g_message(_("Firmware version %d.%d.%d (0x%02X.0x%02X.0x%02X)"),
 
281
                  version[0], version[1], version[2],
 
282
                  version[0], version[1], version[2]);
 
283
 
 
284
        return 0;
 
285
}
 
286
 
362
287
static int
363
288
patch(char *filename)
364
289
{
365
290
        int fd, i, n, ret = 0;
 
291
        guchar version[3];
366
292
 
367
293
        if ((fd = g_open(filename, O_RDWR)) == -1) {
368
294
                g_error(_("Error while opening firmware file for patching."));
369
295
                return -1;
370
296
        }
371
297
 
 
298
        firmware_version(fd, version);
 
299
 
372
300
        n = G_N_ELEMENTS(patches);
373
301
        for (i = 0; i < n; i++) {
374
302
                g_message(_("Apply patch %i : %s"),
375
303
                          i, gettext(patches[i].desc));
 
304
 
376
305
                if (lseek(fd, patches[i].offset, SEEK_SET) == -1) {
377
306
                        g_error(_("Unable to patch the firmware."));
378
307
                        ret = -1;
397
326
        GOptionContext *context;
398
327
        GError *error = NULL;
399
328
        int status = 0;
400
 
        gchar *sha1sum;
401
329
        gchar *pathname;
402
 
        unsigned char*digest;
403
 
        const struct offset *offset;
404
 
        
 
330
        glong offset;
 
331
 
405
332
#if ENABLE_NLS                                  \
406
333
        /* ??????? */
407
334
        setlocale(LC_ALL, "");
437
364
                        error->message); /* howto translate? */
438
365
                fprintf(stderr, g_option_context_get_help(context,
439
366
                                                          FALSE, NULL));
440
 
        }
441
 
 
442
 
        if (g_access(driver_filename, R_OK)) {
 
367
                return 1;
 
368
        }
 
369
 
 
370
        if (driver_filename == NULL) {
 
371
          fprintf(stderr, _("Option -a is mandatory. See --help.\n"));
 
372
          return 1;
 
373
        }
 
374
 
 
375
        if (g_access(driver_filename, R_OK | F_OK)) {
443
376
                g_error(_("Unable to read driver %s."), driver_filename);
 
377
                return 1;
444
378
        }
445
379
 
446
380
        pathname = g_build_filename(firmware_dir, firmware_filename, NULL);
447
381
        g_option_context_free(context);
448
382
 
449
 
        /* check sha1sum on firmware, to prevent loading crap into the
450
 
         * iSight and thus possibly damaging it. */
451
 
        digest = get_sha1sum(driver_filename);
452
 
        if (!digest) {
453
 
                return -1;
454
 
        }
455
 
 
456
 
        sha1sum = sha1sum_string(digest);
457
 
        offset = find_offset(digest);
458
 
 
459
 
        if (!offset)
 
383
        /* search */
 
384
        offset = seek_offset(driver_filename);
 
385
 
 
386
        if (offset <= 0)
460
387
                g_error(_("Unable to find firmware in the file."));
461
388
 
462
389
        /* extract */
463
 
        status = extract(driver_filename, offset->offset, pathname);
 
390
        status = extract(driver_filename, offset, pathname);
464
391
        if (!status)
465
392
                g_message(_("Firmware extracted successfully in %s"), pathname);
466
393
 
471
398
        else
472
399
                g_error(_("Failed to apply patches to %s"), pathname);
473
400
 
474
 
        g_free(digest);
475
 
        g_free(sha1sum);
476
 
 
477
401
        return status;
478
402
}