indent before checkin
[libftdi] / ftdi / ftdi.c
CommitLineData
a3da1d95
GE
1/***************************************************************************
2 ftdi.c - description
3 -------------------
4 begin : Fri Apr 4 2003
5 copyright : (C) 2003 by Intra2net AG
5fdb1cb1 6 email : opensource@intra2net.com
a3da1d95
GE
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU Lesser General Public License *
13 * version 2.1 as published by the Free Software Foundation; *
14 * *
15 ***************************************************************************/
16
17#include <usb.h>
d9f0cce7 18
a3da1d95
GE
19#include "ftdi.h"
20
948f9ada
TJ
21/* ftdi_init return codes:
22 0: all fine
6d9aa99f 23 -1: couldn't allocate read buffer
948f9ada 24*/
a3da1d95
GE
25int ftdi_init(struct ftdi_context *ftdi) {
26 ftdi->usb_dev = NULL;
27 ftdi->usb_timeout = 5000;
28
29 ftdi->baudrate = -1;
30 ftdi->bitbang_enabled = 0;
31
948f9ada
TJ
32 ftdi->readbuffer = NULL;
33 ftdi->readbuffer_offset = 0;
34 ftdi->readbuffer_remaining = 0;
35 ftdi->writebuffer_chunksize = 4096;
36
a3da1d95
GE
37 ftdi->error_str = NULL;
38
948f9ada
TJ
39 // all fine. Now allocate the readbuffer
40 return ftdi_read_data_set_chunksize(ftdi, 4096);
41}
42
43
44void ftdi_deinit(struct ftdi_context *ftdi) {
45 if (ftdi->readbuffer != NULL) {
d9f0cce7
TJ
46 free(ftdi->readbuffer);
47 ftdi->readbuffer = NULL;
948f9ada 48 }
a3da1d95
GE
49}
50
51
52void ftdi_set_usbdev (struct ftdi_context *ftdi, usb_dev_handle *usb) {
53 ftdi->usb_dev = usb;
54}
55
56
57/* ftdi_usb_open return codes:
58 0: all fine
59 -1: usb_find_busses() failed
60 -2: usb_find_devices() failed
61 -3: usb device not found
62 -4: unable to open device
63 -5: unable to claim device
64 -6: reset failed
65 -7: set baudrate failed
66*/
67int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product) {
68 struct usb_bus *bus;
69 struct usb_device *dev;
70
71 usb_init();
72
73 if (usb_find_busses() < 0) {
74 ftdi->error_str = "usb_find_busses() failed";
75 return -1;
76 }
77
78 if (usb_find_devices() < 0) {
79 ftdi->error_str = "usb_find_devices() failed";
80 return -2;
81 }
82
83 for (bus = usb_busses; bus; bus = bus->next) {
84 for (dev = bus->devices; dev; dev = dev->next) {
85 if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) {
86 ftdi->usb_dev = usb_open(dev);
87 if (ftdi->usb_dev) {
88 if (usb_claim_interface(ftdi->usb_dev, 0) != 0) {
89 ftdi->error_str = "unable to claim usb device. You can still use it though...";
90 return -5;
91 }
92
93 if (ftdi_usb_reset (ftdi) != 0)
d9f0cce7 94 return -6;
a3da1d95
GE
95
96 if (ftdi_set_baudrate (ftdi, 9600) != 0)
d9f0cce7 97 return -7;
a3da1d95
GE
98
99 return 0;
100 } else {
101 ftdi->error_str = "usb_open() failed";
102 return -4;
103 }
104 }
105 }
106
107 }
108
109 // device not found
110 return -3;
111}
112
113
114int ftdi_usb_reset(struct ftdi_context *ftdi) {
115 if (usb_control_msg(ftdi->usb_dev, 0x40, 0, 0, 0, NULL, 0, ftdi->usb_timeout) != 0) {
116 ftdi->error_str = "FTDI reset failed";
117 return -1;
118 }
119
bfcee05b
TJ
120 ftdi->readbuffer_offset = 0;
121 ftdi->readbuffer_remaining = 0;
122
a3da1d95
GE
123 return 0;
124}
125
a60be878
TJ
126int ftdi_usb_purge_buffers(struct ftdi_context *ftdi) {
127 if (usb_control_msg(ftdi->usb_dev, 0x40, 0, 1, 0, NULL, 0, ftdi->usb_timeout) != 0) {
128 ftdi->error_str = "FTDI purge of RX buffer failed";
129 return -1;
130 }
d9f0cce7 131
bfcee05b
TJ
132 ftdi->readbuffer_offset = 0;
133 ftdi->readbuffer_remaining = 0;
a60be878
TJ
134
135 if (usb_control_msg(ftdi->usb_dev, 0x40, 0, 2, 0, NULL, 0, ftdi->usb_timeout) != 0) {
136 ftdi->error_str = "FTDI purge of TX buffer failed";
137 return -1;
138 }
139
140 return 0;
141}
a3da1d95
GE
142
143/* ftdi_usb_close return codes
144 0: all fine
145 -1: usb_release failed
146 -2: usb_close failed
147*/
148int ftdi_usb_close(struct ftdi_context *ftdi) {
149 int rtn = 0;
150
151 if (usb_release_interface(ftdi->usb_dev, 0) != 0)
152 rtn = -1;
153
154 if (usb_close (ftdi->usb_dev) != 0)
155 rtn = -2;
156
157 return rtn;
158}
159
160
161/*
162 ftdi_set_baudrate return codes:
163 0: all fine
164 -1: invalid baudrate
165 -2: setting baudrate failed
166*/
167int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate) {
168 unsigned short ftdi_baudrate;
169
170 if (ftdi->bitbang_enabled) {
171 baudrate = baudrate*4;
172 }
173
174 switch (baudrate) {
175 case 300:
176 ftdi_baudrate = 0x2710;
177 break;
178 case 600:
179 ftdi_baudrate = 0x1388;
180 break;
181 case 1200:
182 ftdi_baudrate = 0x09C4;
183 break;
184 case 2400:
185 ftdi_baudrate = 0x04E2;
186 break;
187 case 4800:
188 ftdi_baudrate = 0x0271;
189 break;
190 case 9600:
191 ftdi_baudrate = 0x4138;
192 break;
193 case 19200:
194 ftdi_baudrate = 0x809C;
195 break;
196 case 38400:
197 ftdi_baudrate = 0xC04E;
198 break;
199 case 57600:
200 ftdi_baudrate = 0x0034;
201 break;
202 case 115200:
203 ftdi_baudrate = 0x001A;
204 break;
205 case 230400:
206 ftdi_baudrate = 0x000D;
207 break;
208 case 460800:
209 ftdi_baudrate = 0x4006;
210 break;
211 case 921600:
212 ftdi_baudrate = 0x8003;
213 break;
214 default:
215 ftdi->error_str = "Unknown baudrate. Note: bitbang baudrates are automatically multiplied by 4";
216 return -1;
217 }
218
219 if (usb_control_msg(ftdi->usb_dev, 0x40, 3, ftdi_baudrate, 0, NULL, 0, ftdi->usb_timeout) != 0) {
220 ftdi->error_str = "Setting new baudrate failed";
221 return -2;
222 }
223
224 ftdi->baudrate = baudrate;
225 return 0;
226}
227
228
be5d7eec 229int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size) {
a3da1d95
GE
230 int ret;
231 int offset = 0;
232 while (offset < size) {
948f9ada 233 int write_size = ftdi->writebuffer_chunksize;
a3da1d95
GE
234
235 if (offset+write_size > size)
236 write_size = size-offset;
237
238 ret=usb_bulk_write(ftdi->usb_dev, 2, buf+offset, write_size, ftdi->usb_timeout);
cbabb7d3 239 if (ret == -1) {
d9f0cce7 240 ftdi->error_str = "bulk write failed";
a3da1d95 241 return -1;
d9f0cce7 242 }
a3da1d95
GE
243
244 offset += write_size;
245 }
246
247 return 0;
248}
249
250
948f9ada
TJ
251int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) {
252 ftdi->writebuffer_chunksize = chunksize;
253 return 0;
254}
255
256
257int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) {
258 *chunksize = ftdi->writebuffer_chunksize;
259 return 0;
260}
cbabb7d3 261
948f9ada
TJ
262
263int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size) {
264 int offset = 0, ret = 1;
d9f0cce7 265
948f9ada
TJ
266 // everything we want is still in the readbuffer?
267 if (size <= ftdi->readbuffer_remaining) {
d9f0cce7
TJ
268 memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size);
269
270 // Fix offsets
271 ftdi->readbuffer_remaining -= size;
272 ftdi->readbuffer_offset += size;
273
274 // printf("Returning bytes from buffer: %d - remaining: %d\n", size, ftdi->readbuffer_remaining);
275
276 return size;
979a145c 277 }
d9f0cce7 278
948f9ada
TJ
279 // something still in the readbuffer, but not enough to satisfy 'size'?
280 if (ftdi->readbuffer_remaining != 0) {
d9f0cce7 281 memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, ftdi->readbuffer_remaining);
979a145c 282
d9f0cce7 283 // printf("Got bytes from buffer: %d\n", ftdi->readbuffer_remaining);
948f9ada 284
d9f0cce7
TJ
285 // Fix offset
286 offset += ftdi->readbuffer_remaining;
948f9ada 287 }
d9f0cce7 288
948f9ada 289 // do the actual USB read
cbabb7d3 290 while (offset < size && ret > 0) {
d9f0cce7
TJ
291 ftdi->readbuffer_remaining = 0;
292 ftdi->readbuffer_offset = 0;
293 ret = usb_bulk_read (ftdi->usb_dev, 0x81, ftdi->readbuffer, ftdi->readbuffer_chunksize, ftdi->usb_timeout);
cbabb7d3 294
d9f0cce7
TJ
295 if (ret == -1) {
296 ftdi->error_str = "bulk read failed";
cbabb7d3 297 return -1;
d9f0cce7
TJ
298 }
299
300 if (ret > 2) {
301 // skip FTDI status bytes.
302 // Maybe stored in the future to enable modem use
303 ftdi->readbuffer_offset += 2;
304 ret -= 2;
305 } else if (ret <= 2) {
306 // no more data to read?
307 return offset;
308 }
309
310 if (ret > 0) {
311 // data still fits in buf?
312 if (offset+ret <= size) {
313 memcpy (buf+offset, ftdi->readbuffer+ftdi->readbuffer_offset, ret);
314 offset += ret;
315
316 if (offset == size)
317 return offset;
318 } else {
319 // only copy part of the data or size <= readbuffer_chunksize
320 int part_size = size-offset;
321 memcpy (buf+offset, ftdi->readbuffer+ftdi->readbuffer_offset, part_size);
322
323 ftdi->readbuffer_offset += part_size;
324 ftdi->readbuffer_remaining = ret-part_size;
325 offset += part_size;
326
327 // printf("Returning part: %d - size: %d - offset: %d - ret: %d - remaining: %d\n", part_size, size, offset, ret, ftdi->readbuffer_remaining);
328
329 return offset;
330 }
331 }
cbabb7d3
TJ
332 }
333
948f9ada
TJ
334 // never reached
335 return -2;
a3da1d95
GE
336}
337
338
948f9ada
TJ
339int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) {
340 // Invalidate all remaining data
341 ftdi->readbuffer_offset = 0;
342 ftdi->readbuffer_remaining = 0;
343
344 unsigned char *new_buf;
345 if ((new_buf = (unsigned char *)realloc(ftdi->readbuffer, chunksize)) == NULL) {
d9f0cce7
TJ
346 ftdi->error_str = "out of memory for readbuffer";
347 return -1;
948f9ada 348 }
d9f0cce7 349
948f9ada
TJ
350 ftdi->readbuffer = new_buf;
351 ftdi->readbuffer_chunksize = chunksize;
352
353 return 0;
354}
355
356
357int ftdi_readt_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) {
358 *chunksize = ftdi->readbuffer_chunksize;
359 return 0;
360}
361
362
363
a3da1d95
GE
364int ftdi_enable_bitbang(struct ftdi_context *ftdi, unsigned char bitmask) {
365 unsigned short usb_val;
366
d9f0cce7
TJ
367 usb_val = bitmask; // low byte: bitmask
368 usb_val += 1 << 8; // high byte: enable flag
a3da1d95
GE
369 if (usb_control_msg(ftdi->usb_dev, 0x40, 0x0B, usb_val, 0, NULL, 0, ftdi->usb_timeout) != 0) {
370 ftdi->error_str = "Unable to enter bitbang mode. Perhaps not a BM type chip?";
371 return -1;
372 }
373
374 ftdi->bitbang_enabled = 1;
375 return 0;
376}
377
378
379int ftdi_disable_bitbang(struct ftdi_context *ftdi) {
380 if (usb_control_msg(ftdi->usb_dev, 0x40, 0x0B, 0, 0, NULL, 0, ftdi->usb_timeout) != 0) {
381 ftdi->error_str = "Unable to leave bitbang mode. Perhaps not a BM type chip?";
382 return -1;
383 }
384
385 ftdi->bitbang_enabled = 0;
386 return 0;
387}
388
389
390int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins) {
391 unsigned short usb_val;
392 if (usb_control_msg(ftdi->usb_dev, 0xC0, 0x0C, 0, 0, (char *)&usb_val, 1, ftdi->usb_timeout) != 1) {
393 ftdi->error_str = "Read pins failed";
394 return -1;
395 }
396
397 *pins = (unsigned char)usb_val;
398 return 0;
399}
400
401
402int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency) {
403 unsigned short usb_val;
404
405 if (latency < 1) {
d9f0cce7
TJ
406 ftdi->error_str = "Latency out of range. Only valid for 1-255";
407 return -1;
a3da1d95
GE
408 }
409
d79d2e68 410 usb_val = latency;
a3da1d95 411 if (usb_control_msg(ftdi->usb_dev, 0x40, 0x09, usb_val, 0, NULL, 0, ftdi->usb_timeout) != 0) {
d9f0cce7
TJ
412 ftdi->error_str = "Unable to set latency timer";
413 return -2;
a3da1d95
GE
414 }
415 return 0;
416}
417
418
419int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency) {
420 unsigned short usb_val;
f14c8bc6 421 if (usb_control_msg(ftdi->usb_dev, 0xC0, 0x0A, 0, 0, (char *)&usb_val, 1, ftdi->usb_timeout) != 1) {
a3da1d95
GE
422 ftdi->error_str = "Reading latency timer failed";
423 return -1;
424 }
425
426 *latency = (unsigned char)usb_val;
427 return 0;
428}
429
430
b8aa7b35
TJ
431void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom) {
432 eeprom->vendor_id = 0403;
433 eeprom->product_id = 6001;
d9f0cce7 434
b8aa7b35
TJ
435 eeprom->self_powered = 1;
436 eeprom->remote_wakeup = 1;
437 eeprom->BM_type_chip = 1;
d9f0cce7 438
b8aa7b35
TJ
439 eeprom->in_is_isochronous = 0;
440 eeprom->out_is_isochronous = 0;
441 eeprom->suspend_pull_downs = 0;
d9f0cce7 442
b8aa7b35
TJ
443 eeprom->use_serial = 0;
444 eeprom->change_usb_version = 0;
445 eeprom->usb_version = 200;
446 eeprom->max_power = 0;
d9f0cce7 447
b8aa7b35
TJ
448 eeprom->manufacturer = NULL;
449 eeprom->product = NULL;
450 eeprom->serial = NULL;
451}
452
453
454/*
455 ftdi_eeprom_build return codes:
8ed61121 456 positive value: used eeprom size
b8aa7b35
TJ
457 -1: eeprom size (128 bytes) exceeded by custom strings
458*/
459int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) {
460 unsigned char i, j;
461 unsigned short checksum, value;
462 unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
463 int size_check;
464
465 if (eeprom->manufacturer != NULL)
d9f0cce7 466 manufacturer_size = strlen(eeprom->manufacturer);
b8aa7b35 467 if (eeprom->product != NULL)
d9f0cce7 468 product_size = strlen(eeprom->product);
b8aa7b35 469 if (eeprom->serial != NULL)
d9f0cce7 470 serial_size = strlen(eeprom->serial);
b8aa7b35 471
d9f0cce7
TJ
472 size_check = 128; // eeprom is 128 bytes
473 size_check -= 28; // 28 are always in use (fixed)
b8aa7b35
TJ
474 size_check -= manufacturer_size*2;
475 size_check -= product_size*2;
476 size_check -= serial_size*2;
477
478 // eeprom size exceeded?
479 if (size_check < 0)
d9f0cce7 480 return (-1);
b8aa7b35
TJ
481
482 // empty eeprom
483 memset (output, 0, 128);
484
485 // Addr 00: Stay 00 00
486 // Addr 02: Vendor ID
487 output[0x02] = eeprom->vendor_id;
488 output[0x03] = eeprom->vendor_id >> 8;
489
490 // Addr 04: Product ID
491 output[0x04] = eeprom->product_id;
492 output[0x05] = eeprom->product_id >> 8;
493
494 // Addr 06: Device release number (0400h for BM features)
495 output[0x06] = 0x00;
d9f0cce7 496
b8aa7b35 497 if (eeprom->BM_type_chip == 1)
d9f0cce7 498 output[0x07] = 0x04;
b8aa7b35 499 else
d9f0cce7 500 output[0x07] = 0x02;
b8aa7b35
TJ
501
502 // Addr 08: Config descriptor
503 // Bit 1: remote wakeup if 1
504 // Bit 0: self powered if 1
505 //
506 j = 0;
507 if (eeprom->self_powered == 1)
d9f0cce7 508 j = j | 1;
b8aa7b35 509 if (eeprom->remote_wakeup == 1)
d9f0cce7 510 j = j | 2;
b8aa7b35
TJ
511 output[0x08] = j;
512
513 // Addr 09: Max power consumption: max power = value * 2 mA
d9f0cce7
TJ
514 output[0x09] = eeprom->max_power;
515 ;
516
b8aa7b35
TJ
517 // Addr 0A: Chip configuration
518 // Bit 7: 0 - reserved
519 // Bit 6: 0 - reserved
520 // Bit 5: 0 - reserved
521 // Bit 4: 1 - Change USB version
522 // Bit 3: 1 - Use the serial number string
523 // Bit 2: 1 - Enable suspend pull downs for lower power
524 // Bit 1: 1 - Out EndPoint is Isochronous
525 // Bit 0: 1 - In EndPoint is Isochronous
526 //
527 j = 0;
528 if (eeprom->in_is_isochronous == 1)
d9f0cce7 529 j = j | 1;
b8aa7b35 530 if (eeprom->out_is_isochronous == 1)
d9f0cce7 531 j = j | 2;
b8aa7b35 532 if (eeprom->suspend_pull_downs == 1)
d9f0cce7 533 j = j | 4;
b8aa7b35 534 if (eeprom->use_serial == 1)
d9f0cce7 535 j = j | 8;
b8aa7b35 536 if (eeprom->change_usb_version == 1)
d9f0cce7 537 j = j | 16;
b8aa7b35 538 output[0x0A] = j;
d9f0cce7 539
b8aa7b35
TJ
540 // Addr 0B: reserved
541 output[0x0B] = 0x00;
d9f0cce7 542
b8aa7b35
TJ
543 // Addr 0C: USB version low byte when 0x0A bit 4 is set
544 // Addr 0D: USB version high byte when 0x0A bit 4 is set
545 if (eeprom->change_usb_version == 1) {
546 output[0x0C] = eeprom->usb_version;
d9f0cce7 547 output[0x0D] = eeprom->usb_version >> 8;
b8aa7b35
TJ
548 }
549
550
551 // Addr 0E: Offset of the manufacturer string + 0x80
552 output[0x0E] = 0x14 + 0x80;
553
554 // Addr 0F: Length of manufacturer string
555 output[0x0F] = manufacturer_size*2 + 2;
556
557 // Addr 10: Offset of the product string + 0x80, calculated later
558 // Addr 11: Length of product string
559 output[0x11] = product_size*2 + 2;
560
561 // Addr 12: Offset of the serial string + 0x80, calculated later
562 // Addr 13: Length of serial string
563 output[0x13] = serial_size*2 + 2;
564
565 // Dynamic content
a862ddcf 566 output[0x14] = manufacturer_size*2 + 2;
d9f0cce7
TJ
567 output[0x15] = 0x03; // type: string
568
b8aa7b35 569 i = 0x16, j = 0;
d9f0cce7 570
b8aa7b35
TJ
571 // Output manufacturer
572 for (j = 0; j < manufacturer_size; j++) {
d9f0cce7
TJ
573 output[i] = eeprom->manufacturer[j], i++;
574 output[i] = 0x00, i++;
b8aa7b35
TJ
575 }
576
577 // Output product name
d9f0cce7 578 output[0x10] = i + 0x80; // calculate offset
b8aa7b35
TJ
579 output[i] = product_size*2 + 2, i++;
580 output[i] = 0x03, i++;
581 for (j = 0; j < product_size; j++) {
d9f0cce7
TJ
582 output[i] = eeprom->product[j], i++;
583 output[i] = 0x00, i++;
b8aa7b35 584 }
d9f0cce7 585
b8aa7b35 586 // Output serial
d9f0cce7 587 output[0x12] = i + 0x80; // calculate offset
b8aa7b35
TJ
588 output[i] = serial_size*2 + 2, i++;
589 output[i] = 0x03, i++;
590 for (j = 0; j < serial_size; j++) {
d9f0cce7
TJ
591 output[i] = eeprom->serial[j], i++;
592 output[i] = 0x00, i++;
b8aa7b35
TJ
593 }
594
595 // calculate checksum
596 checksum = 0xAAAA;
d9f0cce7 597
b8aa7b35 598 for (i = 0; i < 63; i++) {
d9f0cce7
TJ
599 value = output[i*2];
600 value += output[(i*2)+1] << 8;
b8aa7b35 601
d9f0cce7
TJ
602 checksum = value^checksum;
603 checksum = (checksum << 1) | (checksum >> 15);
b8aa7b35
TJ
604 }
605
606 output[0x7E] = checksum;
d9f0cce7 607 output[0x7F] = checksum >> 8;
b8aa7b35 608
8ed61121 609 return size_check;
b8aa7b35
TJ
610}
611
612
be5d7eec 613int ftdi_read_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) {
a3da1d95
GE
614 int i;
615
616 for (i = 0; i < 64; i++) {
617 if (usb_control_msg(ftdi->usb_dev, 0xC0, 0x90, 0, i, eeprom+(i*2), 2, ftdi->usb_timeout) != 2) {
d9f0cce7
TJ
618 ftdi->error_str = "Reading eeprom failed";
619 return -1;
a3da1d95
GE
620 }
621 }
622
623 return 0;
624}
625
626
be5d7eec 627int ftdi_write_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) {
a3da1d95
GE
628 unsigned short usb_val;
629 int i;
630
631 for (i = 0; i < 64; i++) {
d9f0cce7
TJ
632 usb_val = eeprom[i*2];
633 usb_val += eeprom[(i*2)+1] << 8;
634 if (usb_control_msg(ftdi->usb_dev, 0x40, 0x91, usb_val, i, NULL, 0, ftdi->usb_timeout) != 0) {
635 ftdi->error_str = "Unable to write eeprom";
636 return -1;
637 }
a3da1d95
GE
638 }
639
640 return 0;
641}
642
643
644int ftdi_erase_eeprom(struct ftdi_context *ftdi) {
645 if (usb_control_msg(ftdi->usb_dev, 0x40, 0x92, 0, 0, NULL, 0, ftdi->usb_timeout) != 0) {
646 ftdi->error_str = "Unable to erase eeprom";
647 return -1;
648 }
649
650 return 0;
651}