| | 1 | /*************************************************************************** |
| | 2 | ftdi.c - description |
| | 3 | ------------------- |
| | 4 | begin : Fri Apr 4 2003 |
| | 5 | copyright : (C) 2003-2020 by Intra2net AG and the libftdi developers |
| | 6 | email : opensource@intra2net.com |
| | 7 | SPDX-License-Identifier: LGPL-2.1-only |
| | 8 | ***************************************************************************/ |
| | 9 | |
| | 10 | /*************************************************************************** |
| | 11 | * * |
| | 12 | * This program is free software; you can redistribute it and/or modify * |
| | 13 | * it under the terms of the GNU Lesser General Public License * |
| | 14 | * version 2.1 as published by the Free Software Foundation; * |
| | 15 | * * |
| | 16 | ***************************************************************************/ |
| | 17 | |
| | 18 | /** |
| | 19 | \mainpage libftdi API documentation |
| | 20 | |
| | 21 | Library to talk to FTDI chips. You find the latest versions of libftdi at |
| | 22 | https://www.intra2net.com/en/developer/libftdi/ |
| | 23 | |
| | 24 | The library is easy to use. Have a look at this short example: |
| | 25 | \include simple.c |
| | 26 | |
| | 27 | More examples can be found in the "examples" directory. |
| | 28 | */ |
| | 29 | /** \addtogroup libftdi */ |
| | 30 | /* @{ */ |
| | 31 | |
| | 32 | #include <libusb.h> |
| | 33 | #include <string.h> |
| | 34 | #include <errno.h> |
| | 35 | #include <stdio.h> |
| | 36 | #include <stdlib.h> |
| | 37 | |
| | 38 | #include "ftdi_i.h" |
| | 39 | /* Prevent deprecated messages when building library */ |
| | 40 | #define _FTDI_DISABLE_DEPRECATED |
| | 41 | #include "ftdi.h" |
| | 42 | #include "ftdi_version_i.h" |
| | 43 | |
| | 44 | #define ftdi_error_return(code, str) do { \ |
| | 45 | if ( ftdi ) \ |
| | 46 | ftdi->error_str = str; \ |
| | 47 | else \ |
| | 48 | fprintf(stderr, str); \ |
| | 49 | return code; \ |
| | 50 | } while(0); |
| | 51 | |
| | 52 | #define ftdi_error_return_free_device_list(code, str, devs) do { \ |
| | 53 | libusb_free_device_list(devs,1); \ |
| | 54 | ftdi->error_str = str; \ |
| | 55 | return code; \ |
| | 56 | } while(0); |
| | 57 | |
| | 58 | |
| | 59 | /** |
| | 60 | Internal function to close usb device pointer. |
| | 61 | Sets ftdi->usb_dev to NULL. |
| | 62 | \internal |
| | 63 | |
| | 64 | \param ftdi pointer to ftdi_context |
| | 65 | |
| | 66 | \retval none |
| | 67 | */ |
| | 68 | static void ftdi_usb_close_internal (struct ftdi_context *ftdi) |
| | 69 | { |
| | 70 | if (ftdi && ftdi->usb_dev) |
| | 71 | { |
| | 72 | libusb_close (ftdi->usb_dev); |
| | 73 | ftdi->usb_dev = NULL; |
| | 74 | if(ftdi->eeprom) |
| | 75 | ftdi->eeprom->initialized_for_connected_device = 0; |
| | 76 | } |
| | 77 | } |
| | 78 | |
| | 79 | /** |
| | 80 | Initializes a ftdi_context. |
| | 81 | |
| | 82 | \param ftdi pointer to ftdi_context |
| | 83 | |
| | 84 | \retval 0: all fine |
| | 85 | \retval -1: couldn't allocate read buffer |
| | 86 | \retval -2: couldn't allocate struct buffer |
| | 87 | \retval -3: libusb_init() failed |
| | 88 | |
| | 89 | \remark This should be called before all functions |
| | 90 | */ |
| | 91 | int ftdi_init(struct ftdi_context *ftdi) |
| | 92 | { |
| | 93 | struct ftdi_eeprom* eeprom; |
| | 94 | ftdi->usb_ctx = NULL; |
| | 95 | ftdi->usb_dev = NULL; |
| | 96 | ftdi->usb_read_timeout = 5000; |
| | 97 | ftdi->usb_write_timeout = 5000; |
| | 98 | |
| | 99 | ftdi->type = TYPE_BM; /* chip type */ |
| | 100 | ftdi->baudrate = -1; |
| | 101 | ftdi->bitbang_enabled = 0; /* 0: normal mode 1: any of the bitbang modes enabled */ |
| | 102 | |
| | 103 | ftdi->readbuffer = NULL; |
| | 104 | ftdi->readbuffer_offset = 0; |
| | 105 | ftdi->readbuffer_remaining = 0; |
| | 106 | ftdi->writebuffer_chunksize = 4096; |
| | 107 | ftdi->max_packet_size = 0; |
| | 108 | ftdi->error_str = NULL; |
| | 109 | ftdi->module_detach_mode = AUTO_DETACH_SIO_MODULE; |
| | 110 | |
| | 111 | if (libusb_init(&ftdi->usb_ctx) < 0) |
| | 112 | ftdi_error_return(-3, "libusb_init() failed"); |
| | 113 | |
| | 114 | ftdi_set_interface(ftdi, INTERFACE_ANY); |
| | 115 | ftdi->bitbang_mode = 1; /* when bitbang is enabled this holds the number of the mode */ |
| | 116 | |
| | 117 | eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom)); |
| | 118 | if (eeprom == 0) |
| | 119 | ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom"); |
| | 120 | memset(eeprom, 0, sizeof(struct ftdi_eeprom)); |
| | 121 | ftdi->eeprom = eeprom; |
| | 122 | |
| | 123 | /* All fine. Now allocate the readbuffer */ |
| | 124 | return ftdi_read_data_set_chunksize(ftdi, 4096); |
| | 125 | } |
| | 126 | |
| | 127 | /** |
| | 128 | Allocate and initialize a new ftdi_context |
| | 129 | |
| | 130 | \return a pointer to a new ftdi_context, or NULL on failure |
| | 131 | */ |
| | 132 | struct ftdi_context *ftdi_new(void) |
| | 133 | { |
| | 134 | struct ftdi_context * ftdi = (struct ftdi_context *)malloc(sizeof(struct ftdi_context)); |
| | 135 | |
| | 136 | if (ftdi == NULL) |
| | 137 | { |
| | 138 | return NULL; |
| | 139 | } |
| | 140 | |
| | 141 | if (ftdi_init(ftdi) != 0) |
| | 142 | { |
| | 143 | free(ftdi); |
| | 144 | return NULL; |
| | 145 | } |
| | 146 | |
| | 147 | return ftdi; |
| | 148 | } |
| | 149 | |
| | 150 | /** |
| | 151 | Open selected channels on a chip, otherwise use first channel. |
| | 152 | |
| | 153 | \param ftdi pointer to ftdi_context |
| | 154 | \param interface Interface to use for FT2232C/2232H/4232H chips. |
| | 155 | |
| | 156 | \retval 0: all fine |
| | 157 | \retval -1: unknown interface |
| | 158 | \retval -2: USB device unavailable |
| | 159 | \retval -3: Device already open, interface can't be set in that state |
| | 160 | */ |
| | 161 | int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface) |
| | 162 | { |
| | 163 | if (ftdi == NULL) |
| | 164 | ftdi_error_return(-2, "USB device unavailable"); |
| | 165 | |
| | 166 | if (ftdi->usb_dev != NULL) |
| | 167 | { |
| | 168 | int check_interface = interface; |
| | 169 | if (check_interface == INTERFACE_ANY) |
| | 170 | check_interface = INTERFACE_A; |
| | 171 | |
| | 172 | if (ftdi->index != check_interface) |
| | 173 | ftdi_error_return(-3, "Interface can not be changed on an already open device"); |
| | 174 | } |
| | 175 | |
| | 176 | switch (interface) |
| | 177 | { |
| | 178 | case INTERFACE_ANY: |
| | 179 | case INTERFACE_A: |
| | 180 | ftdi->interface = 0; |
| | 181 | ftdi->index = INTERFACE_A; |
| | 182 | ftdi->in_ep = 0x02; |
| | 183 | ftdi->out_ep = 0x81; |
| | 184 | break; |
| | 185 | case INTERFACE_B: |
| | 186 | ftdi->interface = 1; |
| | 187 | ftdi->index = INTERFACE_B; |
| | 188 | ftdi->in_ep = 0x04; |
| | 189 | ftdi->out_ep = 0x83; |
| | 190 | break; |
| | 191 | case INTERFACE_C: |
| | 192 | ftdi->interface = 2; |
| | 193 | ftdi->index = INTERFACE_C; |
| | 194 | ftdi->in_ep = 0x06; |
| | 195 | ftdi->out_ep = 0x85; |
| | 196 | break; |
| | 197 | case INTERFACE_D: |
| | 198 | ftdi->interface = 3; |
| | 199 | ftdi->index = INTERFACE_D; |
| | 200 | ftdi->in_ep = 0x08; |
| | 201 | ftdi->out_ep = 0x87; |
| | 202 | break; |
| | 203 | default: |
| | 204 | ftdi_error_return(-1, "Unknown interface"); |
| | 205 | } |
| | 206 | return 0; |
| | 207 | } |
| | 208 | |
| | 209 | /** |
| | 210 | Deinitializes a ftdi_context. |
| | 211 | |
| | 212 | \param ftdi pointer to ftdi_context |
| | 213 | */ |
| | 214 | void ftdi_deinit(struct ftdi_context *ftdi) |
| | 215 | { |
| | 216 | if (ftdi == NULL) |
| | 217 | return; |
| | 218 | |
| | 219 | ftdi_usb_close_internal (ftdi); |
| | 220 | |
| | 221 | if (ftdi->readbuffer != NULL) |
| | 222 | { |
| | 223 | free(ftdi->readbuffer); |
| | 224 | ftdi->readbuffer = NULL; |
| | 225 | } |
| | 226 | |
| | 227 | if (ftdi->eeprom != NULL) |
| | 228 | { |
| | 229 | if (ftdi->eeprom->manufacturer != 0) |
| | 230 | { |
| | 231 | free(ftdi->eeprom->manufacturer); |
| | 232 | ftdi->eeprom->manufacturer = 0; |
| | 233 | } |
| | 234 | if (ftdi->eeprom->product != 0) |
| | 235 | { |
| | 236 | free(ftdi->eeprom->product); |
| | 237 | ftdi->eeprom->product = 0; |
| | 238 | } |
| | 239 | if (ftdi->eeprom->serial != 0) |
| | 240 | { |
| | 241 | free(ftdi->eeprom->serial); |
| | 242 | ftdi->eeprom->serial = 0; |
| | 243 | } |
| | 244 | free(ftdi->eeprom); |
| | 245 | ftdi->eeprom = NULL; |
| | 246 | } |
| | 247 | |
| | 248 | if (ftdi->usb_ctx) |
| | 249 | { |
| | 250 | libusb_exit(ftdi->usb_ctx); |
| | 251 | ftdi->usb_ctx = NULL; |
| | 252 | } |
| | 253 | } |
| | 254 | |
| | 255 | /** |
| | 256 | Deinitialize and free an ftdi_context. |
| | 257 | |
| | 258 | \param ftdi pointer to ftdi_context |
| | 259 | */ |
| | 260 | void ftdi_free(struct ftdi_context *ftdi) |
| | 261 | { |
| | 262 | ftdi_deinit(ftdi); |
| | 263 | free(ftdi); |
| | 264 | } |
| | 265 | |
| | 266 | /** |
| | 267 | Use an already open libusb device. |
| | 268 | |
| | 269 | \param ftdi pointer to ftdi_context |
| | 270 | \param usb libusb libusb_device_handle to use |
| | 271 | */ |
| | 272 | void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb) |
| | 273 | { |
| | 274 | if (ftdi == NULL) |
| | 275 | return; |
| | 276 | |
| | 277 | ftdi->usb_dev = usb; |
| | 278 | } |
| | 279 | |
| | 280 | /** |
| | 281 | * @brief Get libftdi library version |
| | 282 | * |
| | 283 | * @return ftdi_version_info Library version information |
| | 284 | **/ |
| | 285 | struct ftdi_version_info ftdi_get_library_version(void) |
| | 286 | { |
| | 287 | struct ftdi_version_info ver; |
| | 288 | |
| | 289 | ver.major = FTDI_MAJOR_VERSION; |
| | 290 | ver.minor = FTDI_MINOR_VERSION; |
| | 291 | ver.micro = FTDI_MICRO_VERSION; |
| | 292 | ver.version_str = FTDI_VERSION_STRING; |
| | 293 | ver.snapshot_str = FTDI_SNAPSHOT_VERSION; |
| | 294 | |
| | 295 | return ver; |
| | 296 | } |
| | 297 | |
| | 298 | /** |
| | 299 | Finds all ftdi devices with given VID:PID on the usb bus. Creates a new |
| | 300 | ftdi_device_list which needs to be deallocated by ftdi_list_free() after |
| | 301 | use. With VID:PID 0:0, search for the default devices |
| | 302 | (0x403:0x6001, 0x403:0x6010, 0x403:0x6011, 0x403:0x6014, 0x403:0x6015) |
| | 303 | |
| | 304 | \param ftdi pointer to ftdi_context |
| | 305 | \param devlist Pointer where to store list of found devices |
| | 306 | \param vendor Vendor ID to search for |
| | 307 | \param product Product ID to search for |
| | 308 | |
| | 309 | \retval >0: number of devices found |
| | 310 | \retval -3: out of memory |
| | 311 | \retval -5: libusb_get_device_list() failed |
| | 312 | \retval -6: libusb_get_device_descriptor() failed |
| | 313 | */ |
| | 314 | int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devlist, int vendor, int product) |
| | 315 | { |
| | 316 | struct ftdi_device_list **curdev; |
| | 317 | libusb_device *dev; |
| | 318 | libusb_device **devs; |
| | 319 | int count = 0; |
| | 320 | int i = 0; |
| | 321 | |
| | 322 | if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) |
| | 323 | ftdi_error_return(-5, "libusb_get_device_list() failed"); |
| | 324 | |
| | 325 | curdev = devlist; |
| | 326 | *curdev = NULL; |
| | 327 | |
| | 328 | while ((dev = devs[i++]) != NULL) |
| | 329 | { |
| | 330 | struct libusb_device_descriptor desc; |
| | 331 | |
| | 332 | if (libusb_get_device_descriptor(dev, &desc) < 0) |
| | 333 | ftdi_error_return_free_device_list(-6, "libusb_get_device_descriptor() failed", devs); |
| | 334 | |
| | 335 | if (((vendor || product) && |
| | 336 | desc.idVendor == vendor && desc.idProduct == product) || |
| | 337 | (!(vendor || product) && |
| | 338 | (desc.idVendor == 0x403) && (desc.idProduct == 0x6001 || desc.idProduct == 0x6010 |
| | 339 | || desc.idProduct == 0x6011 || desc.idProduct == 0x6014 |
| | 340 | || desc.idProduct == 0x6015))) |
| | 341 | { |
| | 342 | *curdev = (struct ftdi_device_list*)malloc(sizeof(struct ftdi_device_list)); |
| | 343 | if (!*curdev) |
| | 344 | ftdi_error_return_free_device_list(-3, "out of memory", devs); |
| | 345 | |
| | 346 | (*curdev)->next = NULL; |
| | 347 | (*curdev)->dev = dev; |
| | 348 | libusb_ref_device(dev); |
| | 349 | curdev = &(*curdev)->next; |
| | 350 | count++; |
| | 351 | } |
| | 352 | } |
| | 353 | libusb_free_device_list(devs,1); |
| | 354 | return count; |
| | 355 | } |
| | 356 | |
| | 357 | /** |
| | 358 | Frees a usb device list. |
| | 359 | |
| | 360 | \param devlist USB device list created by ftdi_usb_find_all() |
| | 361 | */ |
| | 362 | void ftdi_list_free(struct ftdi_device_list **devlist) |
| | 363 | { |
| | 364 | struct ftdi_device_list *curdev, *next; |
| | 365 | |
| | 366 | for (curdev = *devlist; curdev != NULL;) |
| | 367 | { |
| | 368 | next = curdev->next; |
| | 369 | libusb_unref_device(curdev->dev); |
| | 370 | free(curdev); |
| | 371 | curdev = next; |
| | 372 | } |
| | 373 | |
| | 374 | *devlist = NULL; |
| | 375 | } |
| | 376 | |
| | 377 | /** |
| | 378 | Frees a usb device list. |
| | 379 | |
| | 380 | \param devlist USB device list created by ftdi_usb_find_all() |
| | 381 | */ |
| | 382 | void ftdi_list_free2(struct ftdi_device_list *devlist) |
| | 383 | { |
| | 384 | ftdi_list_free(&devlist); |
| | 385 | } |
| | 386 | |
| | 387 | /** |
| | 388 | Return device ID strings from the usb device. |
| | 389 | |
| | 390 | The parameters manufacturer, description and serial may be NULL |
| | 391 | or pointer to buffers to store the fetched strings. |
| | 392 | |
| | 393 | \note Use this function only in combination with ftdi_usb_find_all() |
| | 394 | as it closes the internal "usb_dev" after use. |
| | 395 | |
| | 396 | \param ftdi pointer to ftdi_context |
| | 397 | \param dev libusb usb_dev to use |
| | 398 | \param manufacturer Store manufacturer string here if not NULL |
| | 399 | \param mnf_len Buffer size of manufacturer string |
| | 400 | \param description Store product description string here if not NULL |
| | 401 | \param desc_len Buffer size of product description string |
| | 402 | \param serial Store serial string here if not NULL |
| | 403 | \param serial_len Buffer size of serial string |
| | 404 | |
| | 405 | \retval 0: all fine |
| | 406 | \retval -1: wrong arguments |
| | 407 | \retval -4: unable to open device |
| | 408 | \retval -7: get product manufacturer failed |
| | 409 | \retval -8: get product description failed |
| | 410 | \retval -9: get serial number failed |
| | 411 | \retval -11: libusb_get_device_descriptor() failed |
| | 412 | */ |
| | 413 | int ftdi_usb_get_strings(struct ftdi_context *ftdi, |
| | 414 | struct libusb_device *dev, |
| | 415 | char *manufacturer, int mnf_len, |
| | 416 | char *description, int desc_len, |
| | 417 | char *serial, int serial_len) |
| | 418 | { |
| | 419 | int ret; |
| | 420 | |
| | 421 | if ((ftdi==NULL) || (dev==NULL)) |
| | 422 | return -1; |
| | 423 | |
| | 424 | if (ftdi->usb_dev == NULL && libusb_open(dev, &ftdi->usb_dev) < 0) |
| | 425 | ftdi_error_return(-4, "libusb_open() failed"); |
| | 426 | |
| | 427 | // ftdi->usb_dev will not be NULL when entering ftdi_usb_get_strings2(), so |
| | 428 | // it won't be closed either. This allows us to close it whether we actually |
| | 429 | // called libusb_open() up above or not. This matches the expected behavior |
| | 430 | // (and note) for ftdi_usb_get_strings(). |
| | 431 | ret = ftdi_usb_get_strings2(ftdi, dev, |
| | 432 | manufacturer, mnf_len, |
| | 433 | description, desc_len, |
| | 434 | serial, serial_len); |
| | 435 | |
| | 436 | // only close it if it was successful, as all other return codes close |
| | 437 | // before returning already. |
| | 438 | if (ret == 0) |
| | 439 | ftdi_usb_close_internal(ftdi); |
| | 440 | |
| | 441 | return ret; |
| | 442 | } |
| | 443 | |
| | 444 | /** |
| | 445 | Return device ID strings from the usb device. |
| | 446 | |
| | 447 | The parameters manufacturer, description and serial may be NULL |
| | 448 | or pointer to buffers to store the fetched strings. |
| | 449 | |
| | 450 | \note The old function ftdi_usb_get_strings() always closes the device. |
| | 451 | This version only closes the device if it was opened by it. |
| | 452 | |
| | 453 | \param ftdi pointer to ftdi_context |
| | 454 | \param dev libusb usb_dev to use |
| | 455 | \param manufacturer Store manufacturer string here if not NULL |
| | 456 | \param mnf_len Buffer size of manufacturer string |
| | 457 | \param description Store product description string here if not NULL |
| | 458 | \param desc_len Buffer size of product description string |
| | 459 | \param serial Store serial string here if not NULL |
| | 460 | \param serial_len Buffer size of serial string |
| | 461 | |
| | 462 | \retval 0: all fine |
| | 463 | \retval -1: wrong arguments |
| | 464 | \retval -4: unable to open device |
| | 465 | \retval -7: get product manufacturer failed |
| | 466 | \retval -8: get product description failed |
| | 467 | \retval -9: get serial number failed |
| | 468 | \retval -11: libusb_get_device_descriptor() failed |
| | 469 | */ |
| | 470 | int ftdi_usb_get_strings2(struct ftdi_context *ftdi, struct libusb_device *dev, |
| | 471 | char *manufacturer, int mnf_len, |
| | 472 | char *description, int desc_len, |
| | 473 | char *serial, int serial_len) |
| | 474 | { |
| | 475 | struct libusb_device_descriptor desc; |
| | 476 | char need_open; |
| | 477 | |
| | 478 | if ((ftdi==NULL) || (dev==NULL)) |
| | 479 | return -1; |
| | 480 | |
| | 481 | need_open = (ftdi->usb_dev == NULL); |
| | 482 | if (need_open && libusb_open(dev, &ftdi->usb_dev) < 0) |
| | 483 | ftdi_error_return(-4, "libusb_open() failed"); |
| | 484 | |
| | 485 | if (libusb_get_device_descriptor(dev, &desc) < 0) |
| | 486 | ftdi_error_return(-11, "libusb_get_device_descriptor() failed"); |
| | 487 | |
| | 488 | if (manufacturer != NULL && mnf_len > 0) |
| | 489 | { |
| | 490 | if (desc.iManufacturer == 0) |
| | 491 | { |
| | 492 | manufacturer[0] = '\0'; |
| | 493 | } |
| | 494 | else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iManufacturer, (unsigned char *)manufacturer, mnf_len) < 0) |
| | 495 | { |
| | 496 | ftdi_usb_close_internal (ftdi); |
| | 497 | ftdi_error_return(-7, "libusb_get_string_descriptor_ascii() failed"); |
| | 498 | } |
| | 499 | } |
| | 500 | |
| | 501 | if (description != NULL && desc_len > 0) |
| | 502 | { |
| | 503 | if (desc.iProduct == 0) |
| | 504 | { |
| | 505 | description[0] = '\0'; |
| | 506 | } |
| | 507 | else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)description, desc_len) < 0) |
| | 508 | { |
| | 509 | ftdi_usb_close_internal (ftdi); |
| | 510 | ftdi_error_return(-8, "libusb_get_string_descriptor_ascii() failed"); |
| | 511 | } |
| | 512 | } |
| | 513 | |
| | 514 | if (serial != NULL && serial_len > 0) |
| | 515 | { |
| | 516 | if (desc.iSerialNumber == 0) |
| | 517 | { |
| | 518 | serial[0] = '\0'; |
| | 519 | } |
| | 520 | else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)serial, serial_len) < 0) |
| | 521 | { |
| | 522 | ftdi_usb_close_internal (ftdi); |
| | 523 | ftdi_error_return(-9, "libusb_get_string_descriptor_ascii() failed"); |
| | 524 | } |
| | 525 | } |
| | 526 | |
| | 527 | if (need_open) |
| | 528 | ftdi_usb_close_internal (ftdi); |
| | 529 | |
| | 530 | return 0; |
| | 531 | } |
| | 532 | |
| | 533 | /** |
| | 534 | * Internal function to determine the maximum packet size. |
| | 535 | * \param ftdi pointer to ftdi_context |
| | 536 | * \param dev libusb usb_dev to use |
| | 537 | * \retval Maximum packet size for this device |
| | 538 | */ |
| | 539 | static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, libusb_device *dev) |
| | 540 | { |
| | 541 | struct libusb_device_descriptor desc; |
| | 542 | struct libusb_config_descriptor *config0; |
| | 543 | unsigned int packet_size; |
| | 544 | |
| | 545 | // Sanity check |
| | 546 | if (ftdi == NULL || dev == NULL) |
| | 547 | return 64; |
| | 548 | |
| | 549 | // Determine maximum packet size. Init with default value. |
| | 550 | // New hi-speed devices from FTDI use a packet size of 512 bytes |
| | 551 | // but could be connected to a normal speed USB hub -> 64 bytes packet size. |
| | 552 | if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H) |
| | 553 | packet_size = 512; |
| | 554 | else |
| | 555 | packet_size = 64; |
| | 556 | |
| | 557 | if (libusb_get_device_descriptor(dev, &desc) < 0) |
| | 558 | return packet_size; |
| | 559 | |
| | 560 | if (libusb_get_config_descriptor(dev, 0, &config0) < 0) |
| | 561 | return packet_size; |
| | 562 | |
| | 563 | if (desc.bNumConfigurations > 0) |
| | 564 | { |
| | 565 | if (ftdi->interface < config0->bNumInterfaces) |
| | 566 | { |
| | 567 | struct libusb_interface interface = config0->interface[ftdi->interface]; |
| | 568 | if (interface.num_altsetting > 0) |
| | 569 | { |
| | 570 | struct libusb_interface_descriptor descriptor = interface.altsetting[0]; |
| | 571 | if (descriptor.bNumEndpoints > 0) |
| | 572 | { |
| | 573 | packet_size = descriptor.endpoint[0].wMaxPacketSize; |
| | 574 | } |
| | 575 | } |
| | 576 | } |
| | 577 | } |
| | 578 | |
| | 579 | libusb_free_config_descriptor (config0); |
| | 580 | return packet_size; |
| | 581 | } |
| | 582 | |
| | 583 | /** |
| | 584 | Opens a ftdi device given by an usb_device. |
| | 585 | |
| | 586 | \param ftdi pointer to ftdi_context |
| | 587 | \param dev libusb usb_dev to use |
| | 588 | |
| | 589 | \retval 0: all fine |
| | 590 | \retval -3: unable to config device |
| | 591 | \retval -4: unable to open device |
| | 592 | \retval -5: unable to claim device |
| | 593 | \retval -6: reset failed |
| | 594 | \retval -7: set baudrate failed |
| | 595 | \retval -8: ftdi context invalid |
| | 596 | \retval -9: libusb_get_device_descriptor() failed |
| | 597 | \retval -10: libusb_get_config_descriptor() failed |
| | 598 | \retval -11: libusb_detach_kernel_driver() failed |
| | 599 | \retval -12: libusb_get_configuration() failed |
| | 600 | */ |
| | 601 | int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) |
| | 602 | { |
| | 603 | struct libusb_device_descriptor desc; |
| | 604 | struct libusb_config_descriptor *config0; |
| | 605 | int cfg, cfg0, detach_errno = 0; |
| | 606 | |
| | 607 | if (ftdi == NULL) |
| | 608 | ftdi_error_return(-8, "ftdi context invalid"); |
| | 609 | |
| | 610 | if (libusb_open(dev, &ftdi->usb_dev) < 0) |
| | 611 | ftdi_error_return(-4, "libusb_open() failed"); |
| | 612 | |
| | 613 | if (libusb_get_device_descriptor(dev, &desc) < 0) |
| | 614 | ftdi_error_return(-9, "libusb_get_device_descriptor() failed"); |
| | 615 | |
| | 616 | if (libusb_get_config_descriptor(dev, 0, &config0) < 0) |
| | 617 | ftdi_error_return(-10, "libusb_get_config_descriptor() failed"); |
| | 618 | cfg0 = config0->bConfigurationValue; |
| | 619 | libusb_free_config_descriptor (config0); |
| | 620 | |
| | 621 | // Try to detach ftdi_sio kernel module. |
| | 622 | // |
| | 623 | // The return code is kept in a separate variable and only parsed |
| | 624 | // if usb_set_configuration() or usb_claim_interface() fails as the |
| | 625 | // detach operation might be denied and everything still works fine. |
| | 626 | // Likely scenario is a static ftdi_sio kernel module. |
| | 627 | if (ftdi->module_detach_mode == AUTO_DETACH_SIO_MODULE) |
| | 628 | { |
| | 629 | if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0) |
| | 630 | detach_errno = errno; |
| | 631 | } |
| | 632 | else if (ftdi->module_detach_mode == AUTO_DETACH_REATACH_SIO_MODULE) |
| | 633 | { |
| | 634 | if (libusb_set_auto_detach_kernel_driver(ftdi->usb_dev, 1) != LIBUSB_SUCCESS) |
| | 635 | detach_errno = errno; |
| | 636 | } |
| | 637 | |
| | 638 | if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0) |
| | 639 | ftdi_error_return(-12, "libusb_get_configuration () failed"); |
| | 640 | // set configuration (needed especially for windows) |
| | 641 | // tolerate EBUSY: one device with one configuration, but two interfaces |
| | 642 | // and libftdi sessions to both interfaces (e.g. FT2232) |
| | 643 | if (desc.bNumConfigurations > 0 && cfg != cfg0) |
| | 644 | { |
| | 645 | if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0) |
| | 646 | { |
| | 647 | ftdi_usb_close_internal (ftdi); |
| | 648 | if (detach_errno == EPERM) |
| | 649 | { |
| | 650 | ftdi_error_return(-8, "inappropriate permissions on device!"); |
| | 651 | } |
| | 652 | else |
| | 653 | { |
| | 654 | ftdi_error_return(-3, "unable to set usb configuration. Make sure the default FTDI driver is not in use"); |
| | 655 | } |
| | 656 | } |
| | 657 | } |
| | 658 | |
| | 659 | if (libusb_claim_interface(ftdi->usb_dev, ftdi->interface) < 0) |
| | 660 | { |
| | 661 | ftdi_usb_close_internal (ftdi); |
| | 662 | if (detach_errno == EPERM) |
| | 663 | { |
| | 664 | ftdi_error_return(-8, "inappropriate permissions on device!"); |
| | 665 | } |
| | 666 | else |
| | 667 | { |
| | 668 | ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI driver is not in use"); |
| | 669 | } |
| | 670 | } |
| | 671 | |
| | 672 | if (ftdi_usb_reset (ftdi) != 0) |
| | 673 | { |
| | 674 | ftdi_usb_close_internal (ftdi); |
| | 675 | ftdi_error_return(-6, "ftdi_usb_reset failed"); |
| | 676 | } |
| | 677 | |
| | 678 | // Try to guess chip type |
| | 679 | // Bug in the BM type chips: bcdDevice is 0x200 for serial == 0 |
| | 680 | if (desc.bcdDevice == 0x400 || (desc.bcdDevice == 0x200 |
| | 681 | && desc.iSerialNumber == 0)) |
| | 682 | ftdi->type = TYPE_BM; |
| | 683 | else if (desc.bcdDevice == 0x200) |
| | 684 | ftdi->type = TYPE_AM; |
| | 685 | else if (desc.bcdDevice == 0x500) |
| | 686 | ftdi->type = TYPE_2232C; |
| | 687 | else if (desc.bcdDevice == 0x600) |
| | 688 | ftdi->type = TYPE_R; |
| | 689 | else if (desc.bcdDevice == 0x700) |
| | 690 | ftdi->type = TYPE_2232H; |
| | 691 | else if (desc.bcdDevice == 0x800) |
| | 692 | ftdi->type = TYPE_4232H; |
| | 693 | else if (desc.bcdDevice == 0x900) |
| | 694 | ftdi->type = TYPE_232H; |
| | 695 | else if (desc.bcdDevice == 0x1000) |
| | 696 | ftdi->type = TYPE_230X; |
| | 697 | |
| | 698 | // Determine maximum packet size |
| | 699 | ftdi->max_packet_size = _ftdi_determine_max_packet_size(ftdi, dev); |
| | 700 | |
| | 701 | if (ftdi_set_baudrate (ftdi, 9600) != 0) |
| | 702 | { |
| | 703 | ftdi_usb_close_internal (ftdi); |
| | 704 | ftdi_error_return(-7, "set baudrate failed"); |
| | 705 | } |
| | 706 | |
| | 707 | ftdi_error_return(0, "all fine"); |
| | 708 | } |
| | 709 | |
| | 710 | /** |
| | 711 | Opens the first device with a given vendor and product ids. |
| | 712 | |
| | 713 | \param ftdi pointer to ftdi_context |
| | 714 | \param vendor Vendor ID |
| | 715 | \param product Product ID |
| | 716 | |
| | 717 | \retval same as ftdi_usb_open_desc() |
| | 718 | */ |
| | 719 | int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product) |
| | 720 | { |
| | 721 | return ftdi_usb_open_desc(ftdi, vendor, product, NULL, NULL); |
| | 722 | } |
| | 723 | |
| | 724 | /** |
| | 725 | Opens the first device with a given, vendor id, product id, |
| | 726 | description and serial. |
| | 727 | |
| | 728 | \param ftdi pointer to ftdi_context |
| | 729 | \param vendor Vendor ID |
| | 730 | \param product Product ID |
| | 731 | \param description Description to search for. Use NULL if not needed. |
| | 732 | \param serial Serial to search for. Use NULL if not needed. |
| | 733 | |
| | 734 | \retval 0: all fine |
| | 735 | \retval -3: usb device not found |
| | 736 | \retval -4: unable to open device |
| | 737 | \retval -5: unable to claim device |
| | 738 | \retval -6: reset failed |
| | 739 | \retval -7: set baudrate failed |
| | 740 | \retval -8: get product description failed |
| | 741 | \retval -9: get serial number failed |
| | 742 | \retval -12: libusb_get_device_list() failed |
| | 743 | \retval -13: libusb_get_device_descriptor() failed |
| | 744 | */ |
| | 745 | int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product, |
| | 746 | const char* description, const char* serial) |
| | 747 | { |
| | 748 | return ftdi_usb_open_desc_index(ftdi,vendor,product,description,serial,0); |
| | 749 | } |
| | 750 | |
| | 751 | /** |
| | 752 | Opens the index-th device with a given, vendor id, product id, |
| | 753 | description and serial. |
| | 754 | |
| | 755 | \param ftdi pointer to ftdi_context |
| | 756 | \param vendor Vendor ID |
| | 757 | \param product Product ID |
| | 758 | \param description Description to search for. Use NULL if not needed. |
| | 759 | \param serial Serial to search for. Use NULL if not needed. |
| | 760 | \param index Number of matching device to open if there are more than one, starts with 0. |
| | 761 | |
| | 762 | \retval 0: all fine |
| | 763 | \retval -1: usb_find_busses() failed |
| | 764 | \retval -2: usb_find_devices() failed |
| | 765 | \retval -3: usb device not found |
| | 766 | \retval -4: unable to open device |
| | 767 | \retval -5: unable to claim device |
| | 768 | \retval -6: reset failed |
| | 769 | \retval -7: set baudrate failed |
| | 770 | \retval -8: get product description failed |
| | 771 | \retval -9: get serial number failed |
| | 772 | \retval -10: unable to close device |
| | 773 | \retval -11: ftdi context invalid |
| | 774 | \retval -12: libusb_get_device_list() failed |
| | 775 | */ |
| | 776 | int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, |
| | 777 | const char* description, const char* serial, unsigned int index) |
| | 778 | { |
| | 779 | libusb_device *dev; |
| | 780 | libusb_device **devs; |
| | 781 | char string[256]; |
| | 782 | int i = 0; |
| | 783 | |
| | 784 | if (ftdi == NULL) |
| | 785 | ftdi_error_return(-11, "ftdi context invalid"); |
| | 786 | |
| | 787 | if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) |
| | 788 | ftdi_error_return(-12, "libusb_get_device_list() failed"); |
| | 789 | |
| | 790 | while ((dev = devs[i++]) != NULL) |
| | 791 | { |
| | 792 | struct libusb_device_descriptor desc; |
| | 793 | int res; |
| | 794 | |
| | 795 | if (libusb_get_device_descriptor(dev, &desc) < 0) |
| | 796 | ftdi_error_return_free_device_list(-13, "libusb_get_device_descriptor() failed", devs); |
| | 797 | |
| | 798 | if (desc.idVendor == vendor && desc.idProduct == product) |
| | 799 | { |
| | 800 | if (libusb_open(dev, &ftdi->usb_dev) < 0) |
| | 801 | ftdi_error_return_free_device_list(-4, "usb_open() failed", devs); |
| | 802 | |
| | 803 | if (description != NULL) |
| | 804 | { |
| | 805 | if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)string, sizeof(string)) < 0) |
| | 806 | { |
| | 807 | ftdi_usb_close_internal (ftdi); |
| | 808 | ftdi_error_return_free_device_list(-8, "unable to fetch product description", devs); |
| | 809 | } |
| | 810 | if (strncmp(string, description, sizeof(string)) != 0) |
| | 811 | { |
| | 812 | ftdi_usb_close_internal (ftdi); |
| | 813 | continue; |
| | 814 | } |
| | 815 | } |
| | 816 | if (serial != NULL) |
| | 817 | { |
| | 818 | if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)string, sizeof(string)) < 0) |
| | 819 | { |
| | 820 | ftdi_usb_close_internal (ftdi); |
| | 821 | ftdi_error_return_free_device_list(-9, "unable to fetch serial number", devs); |
| | 822 | } |
| | 823 | if (strncmp(string, serial, sizeof(string)) != 0) |
| | 824 | { |
| | 825 | ftdi_usb_close_internal (ftdi); |
| | 826 | continue; |
| | 827 | } |
| | 828 | } |
| | 829 | |
| | 830 | ftdi_usb_close_internal (ftdi); |
| | 831 | |
| | 832 | if (index > 0) |
| | 833 | { |
| | 834 | index--; |
| | 835 | continue; |
| | 836 | } |
| | 837 | |
| | 838 | res = ftdi_usb_open_dev(ftdi, dev); |
| | 839 | libusb_free_device_list(devs,1); |
| | 840 | return res; |
| | 841 | } |
| | 842 | } |
| | 843 | |
| | 844 | // device not found |
| | 845 | ftdi_error_return_free_device_list(-3, "device not found", devs); |
| | 846 | } |
| | 847 | |
| | 848 | /** |
| | 849 | Opens the device at a given USB bus and device address. |
| | 850 | |
| | 851 | \param ftdi pointer to ftdi_context |
| | 852 | \param bus Bus number |
| | 853 | \param addr Device address |
| | 854 | |
| | 855 | \retval 0: all fine |
| | 856 | \retval -1: usb_find_busses() failed |
| | 857 | \retval -2: usb_find_devices() failed |
| | 858 | \retval -3: usb device not found |
| | 859 | \retval -4: unable to open device |
| | 860 | \retval -5: unable to claim device |
| | 861 | \retval -6: reset failed |
| | 862 | \retval -7: set baudrate failed |
| | 863 | \retval -8: get product description failed |
| | 864 | \retval -9: get serial number failed |
| | 865 | \retval -10: unable to close device |
| | 866 | \retval -11: ftdi context invalid |
| | 867 | \retval -12: libusb_get_device_list() failed |
| | 868 | */ |
| | 869 | int ftdi_usb_open_bus_addr(struct ftdi_context *ftdi, uint8_t bus, uint8_t addr) |
| | 870 | { |
| | 871 | libusb_device *dev; |
| | 872 | libusb_device **devs; |
| | 873 | int i = 0; |
| | 874 | |
| | 875 | if (ftdi == NULL) |
| | 876 | ftdi_error_return(-11, "ftdi context invalid"); |
| | 877 | |
| | 878 | if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) |
| | 879 | ftdi_error_return(-12, "libusb_get_device_list() failed"); |
| | 880 | |
| | 881 | while ((dev = devs[i++]) != NULL) |
| | 882 | { |
| | 883 | if (libusb_get_bus_number(dev) == bus && libusb_get_device_address(dev) == addr) |
| | 884 | { |
| | 885 | int res; |
| | 886 | res = ftdi_usb_open_dev(ftdi, dev); |
| | 887 | libusb_free_device_list(devs,1); |
| | 888 | return res; |
| | 889 | } |
| | 890 | } |
| | 891 | |
| | 892 | // device not found |
| | 893 | ftdi_error_return_free_device_list(-3, "device not found", devs); |
| | 894 | } |
| | 895 | |
| | 896 | /** |
| | 897 | Opens the ftdi-device described by a description-string. |
| | 898 | Intended to be used for parsing a device-description given as commandline argument. |
| | 899 | |
| | 900 | \param ftdi pointer to ftdi_context |
| | 901 | \param description NULL-terminated description-string, using this format: |
| | 902 | \li <tt>d:\<devicenode></tt> path of bus and device-node (e.g. "003/001") within usb device tree (usually at /proc/bus/usb/) |
| | 903 | \li <tt>i:\<vendor>:\<product></tt> first device with given vendor and product id, ids can be decimal, octal (preceded by "0") or hex (preceded by "0x") |
| | 904 | \li <tt>i:\<vendor>:\<product>:\<index></tt> as above with index being the number of the device (starting with 0) if there are more than one |
| | 905 | \li <tt>s:\<vendor>:\<product>:\<serial></tt> first device with given vendor id, product id and serial string |
| | 906 | |
| | 907 | \note The description format may be extended in later versions. |
| | 908 | |
| | 909 | \retval 0: all fine |
| | 910 | \retval -2: libusb_get_device_list() failed |
| | 911 | \retval -3: usb device not found |
| | 912 | \retval -4: unable to open device |
| | 913 | \retval -5: unable to claim device |
| | 914 | \retval -6: reset failed |
| | 915 | \retval -7: set baudrate failed |
| | 916 | \retval -8: get product description failed |
| | 917 | \retval -9: get serial number failed |
| | 918 | \retval -10: unable to close device |
| | 919 | \retval -11: illegal description format |
| | 920 | \retval -12: ftdi context invalid |
| | 921 | */ |
| | 922 | int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description) |
| | 923 | { |
| | 924 | if (ftdi == NULL) |
| | 925 | ftdi_error_return(-12, "ftdi context invalid"); |
| | 926 | |
| | 927 | if (description[0] == 0 || description[1] != ':') |
| | 928 | ftdi_error_return(-11, "illegal description format"); |
| | 929 | |
| | 930 | if (description[0] == 'd') |
| | 931 | { |
| | 932 | libusb_device *dev; |
| | 933 | libusb_device **devs; |
| | 934 | unsigned int bus_number, device_address; |
| | 935 | int i = 0; |
| | 936 | |
| | 937 | if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) |
| | 938 | ftdi_error_return(-2, "libusb_get_device_list() failed"); |
| | 939 | |
| | 940 | /* XXX: This doesn't handle symlinks/odd paths/etc... */ |
| | 941 | if (sscanf (description + 2, "%u/%u", &bus_number, &device_address) != 2) |
| | 942 | ftdi_error_return_free_device_list(-11, "illegal description format", devs); |
| | 943 | |
| | 944 | while ((dev = devs[i++]) != NULL) |
| | 945 | { |
| | 946 | int ret; |
| | 947 | if (bus_number == libusb_get_bus_number (dev) |
| | 948 | && device_address == libusb_get_device_address (dev)) |
| | 949 | { |
| | 950 | ret = ftdi_usb_open_dev(ftdi, dev); |
| | 951 | libusb_free_device_list(devs,1); |
| | 952 | return ret; |
| | 953 | } |
| | 954 | } |
| | 955 | |
| | 956 | // device not found |
| | 957 | ftdi_error_return_free_device_list(-3, "device not found", devs); |
| | 958 | } |
| | 959 | else if (description[0] == 'i' || description[0] == 's') |
| | 960 | { |
| | 961 | unsigned int vendor; |
| | 962 | unsigned int product; |
| | 963 | unsigned int index=0; |
| | 964 | const char *serial=NULL; |
| | 965 | const char *startp, *endp; |
| | 966 | |
| | 967 | errno=0; |
| | 968 | startp=description+2; |
| | 969 | vendor=strtoul((char*)startp,(char**)&endp,0); |
| | 970 | if (*endp != ':' || endp == startp || errno != 0) |
| | 971 | ftdi_error_return(-11, "illegal description format"); |
| | 972 | |
| | 973 | startp=endp+1; |
| | 974 | product=strtoul((char*)startp,(char**)&endp,0); |
| | 975 | if (endp == startp || errno != 0) |
| | 976 | ftdi_error_return(-11, "illegal description format"); |
| | 977 | |
| | 978 | if (description[0] == 'i' && *endp != 0) |
| | 979 | { |
| | 980 | /* optional index field in i-mode */ |
| | 981 | if (*endp != ':') |
| | 982 | ftdi_error_return(-11, "illegal description format"); |
| | 983 | |
| | 984 | startp=endp+1; |
| | 985 | index=strtoul((char*)startp,(char**)&endp,0); |
| | 986 | if (*endp != 0 || endp == startp || errno != 0) |
| | 987 | ftdi_error_return(-11, "illegal description format"); |
| | 988 | } |
| | 989 | if (description[0] == 's') |
| | 990 | { |
| | 991 | if (*endp != ':') |
| | 992 | ftdi_error_return(-11, "illegal description format"); |
| | 993 | |
| | 994 | /* rest of the description is the serial */ |
| | 995 | serial=endp+1; |
| | 996 | } |
| | 997 | |
| | 998 | return ftdi_usb_open_desc_index(ftdi, vendor, product, NULL, serial, index); |
| | 999 | } |
| | 1000 | else |
| | 1001 | { |
| | 1002 | ftdi_error_return(-11, "illegal description format"); |
| | 1003 | } |
| | 1004 | } |
| | 1005 | |
| | 1006 | /** |
| | 1007 | Resets the ftdi device. |
| | 1008 | |
| | 1009 | \param ftdi pointer to ftdi_context |
| | 1010 | |
| | 1011 | \retval 0: all fine |
| | 1012 | \retval -1: FTDI reset failed |
| | 1013 | \retval -2: USB device unavailable |
| | 1014 | */ |
| | 1015 | int ftdi_usb_reset(struct ftdi_context *ftdi) |
| | 1016 | { |
| | 1017 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1018 | ftdi_error_return(-2, "USB device unavailable"); |
| | 1019 | |
| | 1020 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1021 | SIO_RESET_REQUEST, SIO_RESET_SIO, |
| | 1022 | ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1023 | ftdi_error_return(-1,"FTDI reset failed"); |
| | 1024 | |
| | 1025 | // Invalidate data in the readbuffer |
| | 1026 | ftdi->readbuffer_offset = 0; |
| | 1027 | ftdi->readbuffer_remaining = 0; |
| | 1028 | |
| | 1029 | return 0; |
| | 1030 | } |
| | 1031 | |
| | 1032 | /** |
| | 1033 | Clears the read buffer on the chip and the internal read buffer. |
| | 1034 | This is the correct behavior for an RX flush. |
| | 1035 | |
| | 1036 | \param ftdi pointer to ftdi_context |
| | 1037 | |
| | 1038 | \retval 0: all fine |
| | 1039 | \retval -1: read buffer purge failed |
| | 1040 | \retval -2: USB device unavailable |
| | 1041 | */ |
| | 1042 | int ftdi_tciflush(struct ftdi_context *ftdi) |
| | 1043 | { |
| | 1044 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1045 | ftdi_error_return(-2, "USB device unavailable"); |
| | 1046 | |
| | 1047 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1048 | SIO_RESET_REQUEST, SIO_TCIFLUSH, |
| | 1049 | ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1050 | ftdi_error_return(-1, "FTDI purge of RX buffer failed"); |
| | 1051 | |
| | 1052 | // Invalidate data in the readbuffer |
| | 1053 | ftdi->readbuffer_offset = 0; |
| | 1054 | ftdi->readbuffer_remaining = 0; |
| | 1055 | |
| | 1056 | return 0; |
| | 1057 | } |
| | 1058 | |
| | 1059 | |
| | 1060 | /** |
| | 1061 | Clears the write buffer on the chip and the internal read buffer. |
| | 1062 | This is incorrect behavior for an RX flush. |
| | 1063 | |
| | 1064 | \param ftdi pointer to ftdi_context |
| | 1065 | |
| | 1066 | \retval 0: all fine |
| | 1067 | \retval -1: write buffer purge failed |
| | 1068 | \retval -2: USB device unavailable |
| | 1069 | |
| | 1070 | \deprecated Use \ref ftdi_tciflush(struct ftdi_context *ftdi) |
| | 1071 | */ |
| | 1072 | int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi) |
| | 1073 | { |
| | 1074 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1075 | ftdi_error_return(-2, "USB device unavailable"); |
| | 1076 | |
| | 1077 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1078 | SIO_RESET_REQUEST, SIO_RESET_PURGE_RX, |
| | 1079 | ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1080 | ftdi_error_return(-1, "FTDI purge of RX buffer failed"); |
| | 1081 | |
| | 1082 | // Invalidate data in the readbuffer |
| | 1083 | ftdi->readbuffer_offset = 0; |
| | 1084 | ftdi->readbuffer_remaining = 0; |
| | 1085 | |
| | 1086 | return 0; |
| | 1087 | } |
| | 1088 | |
| | 1089 | /** |
| | 1090 | Clears the write buffer on the chip. |
| | 1091 | This is correct behavior for a TX flush. |
| | 1092 | |
| | 1093 | \param ftdi pointer to ftdi_context |
| | 1094 | |
| | 1095 | \retval 0: all fine |
| | 1096 | \retval -1: write buffer purge failed |
| | 1097 | \retval -2: USB device unavailable |
| | 1098 | */ |
| | 1099 | int ftdi_tcoflush(struct ftdi_context *ftdi) |
| | 1100 | { |
| | 1101 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1102 | ftdi_error_return(-2, "USB device unavailable"); |
| | 1103 | |
| | 1104 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1105 | SIO_RESET_REQUEST, SIO_TCOFLUSH, |
| | 1106 | ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1107 | ftdi_error_return(-1, "FTDI purge of TX buffer failed"); |
| | 1108 | |
| | 1109 | return 0; |
| | 1110 | } |
| | 1111 | |
| | 1112 | |
| | 1113 | /** |
| | 1114 | Clears the read buffer on the chip. |
| | 1115 | This is incorrect behavior for a TX flush. |
| | 1116 | |
| | 1117 | \param ftdi pointer to ftdi_context |
| | 1118 | |
| | 1119 | \retval 0: all fine |
| | 1120 | \retval -1: read buffer purge failed |
| | 1121 | \retval -2: USB device unavailable |
| | 1122 | |
| | 1123 | \deprecated Use \ref ftdi_tcoflush(struct ftdi_context *ftdi) |
| | 1124 | */ |
| | 1125 | int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi) |
| | 1126 | { |
| | 1127 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1128 | ftdi_error_return(-2, "USB device unavailable"); |
| | 1129 | |
| | 1130 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1131 | SIO_RESET_REQUEST, SIO_RESET_PURGE_TX, |
| | 1132 | ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1133 | ftdi_error_return(-1, "FTDI purge of TX buffer failed"); |
| | 1134 | |
| | 1135 | return 0; |
| | 1136 | } |
| | 1137 | |
| | 1138 | /** |
| | 1139 | Clears the RX and TX FIFOs on the chip and the internal read buffer. |
| | 1140 | This is correct behavior for both RX and TX flush. |
| | 1141 | |
| | 1142 | \param ftdi pointer to ftdi_context |
| | 1143 | |
| | 1144 | \retval 0: all fine |
| | 1145 | \retval -1: read buffer purge failed |
| | 1146 | \retval -2: write buffer purge failed |
| | 1147 | \retval -3: USB device unavailable |
| | 1148 | */ |
| | 1149 | int ftdi_tcioflush(struct ftdi_context *ftdi) |
| | 1150 | { |
| | 1151 | int result; |
| | 1152 | |
| | 1153 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1154 | ftdi_error_return(-3, "USB device unavailable"); |
| | 1155 | |
| | 1156 | result = ftdi_tcoflush(ftdi); |
| | 1157 | if (result < 0) |
| | 1158 | return -1; |
| | 1159 | |
| | 1160 | result = ftdi_tciflush(ftdi); |
| | 1161 | if (result < 0) |
| | 1162 | return -2; |
| | 1163 | |
| | 1164 | return 0; |
| | 1165 | } |
| | 1166 | |
| | 1167 | /** |
| | 1168 | Clears the buffers on the chip and the internal read buffer. |
| | 1169 | While coded incorrectly, the result is satisfactory. |
| | 1170 | |
| | 1171 | \param ftdi pointer to ftdi_context |
| | 1172 | |
| | 1173 | \retval 0: all fine |
| | 1174 | \retval -1: read buffer purge failed |
| | 1175 | \retval -2: write buffer purge failed |
| | 1176 | \retval -3: USB device unavailable |
| | 1177 | |
| | 1178 | \deprecated Use \ref ftdi_tcioflush(struct ftdi_context *ftdi) |
| | 1179 | */ |
| | 1180 | int ftdi_usb_purge_buffers(struct ftdi_context *ftdi) |
| | 1181 | { |
| | 1182 | int result; |
| | 1183 | |
| | 1184 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1185 | ftdi_error_return(-3, "USB device unavailable"); |
| | 1186 | |
| | 1187 | result = ftdi_usb_purge_rx_buffer(ftdi); |
| | 1188 | if (result < 0) |
| | 1189 | return -1; |
| | 1190 | |
| | 1191 | result = ftdi_usb_purge_tx_buffer(ftdi); |
| | 1192 | if (result < 0) |
| | 1193 | return -2; |
| | 1194 | |
| | 1195 | return 0; |
| | 1196 | } |
| | 1197 | |
| | 1198 | |
| | 1199 | |
| | 1200 | /** |
| | 1201 | Closes the ftdi device. Call ftdi_deinit() if you're cleaning up. |
| | 1202 | |
| | 1203 | \param ftdi pointer to ftdi_context |
| | 1204 | |
| | 1205 | \retval 0: all fine |
| | 1206 | \retval -1: usb_release failed |
| | 1207 | \retval -3: ftdi context invalid |
| | 1208 | */ |
| | 1209 | int ftdi_usb_close(struct ftdi_context *ftdi) |
| | 1210 | { |
| | 1211 | int rtn = 0; |
| | 1212 | |
| | 1213 | if (ftdi == NULL) |
| | 1214 | ftdi_error_return(-3, "ftdi context invalid"); |
| | 1215 | |
| | 1216 | if (ftdi->usb_dev != NULL) |
| | 1217 | if (libusb_release_interface(ftdi->usb_dev, ftdi->interface) < 0) |
| | 1218 | rtn = -1; |
| | 1219 | |
| | 1220 | ftdi_usb_close_internal (ftdi); |
| | 1221 | |
| | 1222 | return rtn; |
| | 1223 | } |
| | 1224 | |
| | 1225 | /* ftdi_to_clkbits_AM For the AM device, convert a requested baudrate |
| | 1226 | to encoded divisor and the achievable baudrate |
| | 1227 | Function is only used internally |
| | 1228 | \internal |
| | 1229 | |
| | 1230 | See AN120 |
| | 1231 | clk/1 -> 0 |
| | 1232 | clk/1.5 -> 1 |
| | 1233 | clk/2 -> 2 |
| | 1234 | From /2, 0.125/ 0.25 and 0.5 steps may be taken |
| | 1235 | The fractional part has frac_code encoding |
| | 1236 | */ |
| | 1237 | static int ftdi_to_clkbits_AM(int baudrate, unsigned long *encoded_divisor) |
| | 1238 | |
| | 1239 | { |
| | 1240 | static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7}; |
| | 1241 | static const char am_adjust_up[8] = {0, 0, 0, 1, 0, 3, 2, 1}; |
| | 1242 | static const char am_adjust_dn[8] = {0, 0, 0, 1, 0, 1, 2, 3}; |
| | 1243 | int divisor, best_divisor, best_baud, best_baud_diff; |
| | 1244 | int i; |
| | 1245 | divisor = 24000000 / baudrate; |
| | 1246 | |
| | 1247 | // Round down to supported fraction (AM only) |
| | 1248 | divisor -= am_adjust_dn[divisor & 7]; |
| | 1249 | |
| | 1250 | // Try this divisor and the one above it (because division rounds down) |
| | 1251 | best_divisor = 0; |
| | 1252 | best_baud = 0; |
| | 1253 | best_baud_diff = 0; |
| | 1254 | for (i = 0; i < 2; i++) |
| | 1255 | { |
| | 1256 | int try_divisor = divisor + i; |
| | 1257 | int baud_estimate; |
| | 1258 | int baud_diff; |
| | 1259 | |
| | 1260 | // Round up to supported divisor value |
| | 1261 | if (try_divisor <= 8) |
| | 1262 | { |
| | 1263 | // Round up to minimum supported divisor |
| | 1264 | try_divisor = 8; |
| | 1265 | } |
| | 1266 | else if (divisor < 16) |
| | 1267 | { |
| | 1268 | // AM doesn't support divisors 9 through 15 inclusive |
| | 1269 | try_divisor = 16; |
| | 1270 | } |
| | 1271 | else |
| | 1272 | { |
| | 1273 | // Round up to supported fraction (AM only) |
| | 1274 | try_divisor += am_adjust_up[try_divisor & 7]; |
| | 1275 | if (try_divisor > 0x1FFF8) |
| | 1276 | { |
| | 1277 | // Round down to maximum supported divisor value (for AM) |
| | 1278 | try_divisor = 0x1FFF8; |
| | 1279 | } |
| | 1280 | } |
| | 1281 | // Get estimated baud rate (to nearest integer) |
| | 1282 | baud_estimate = (24000000 + (try_divisor / 2)) / try_divisor; |
| | 1283 | // Get absolute difference from requested baud rate |
| | 1284 | if (baud_estimate < baudrate) |
| | 1285 | { |
| | 1286 | baud_diff = baudrate - baud_estimate; |
| | 1287 | } |
| | 1288 | else |
| | 1289 | { |
| | 1290 | baud_diff = baud_estimate - baudrate; |
| | 1291 | } |
| | 1292 | if (i == 0 || baud_diff < best_baud_diff) |
| | 1293 | { |
| | 1294 | // Closest to requested baud rate so far |
| | 1295 | best_divisor = try_divisor; |
| | 1296 | best_baud = baud_estimate; |
| | 1297 | best_baud_diff = baud_diff; |
| | 1298 | if (baud_diff == 0) |
| | 1299 | { |
| | 1300 | // Spot on! No point trying |
| | 1301 | break; |
| | 1302 | } |
| | 1303 | } |
| | 1304 | } |
| | 1305 | // Encode the best divisor value |
| | 1306 | *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 7] << 14); |
| | 1307 | // Deal with special cases for encoded value |
| | 1308 | if (*encoded_divisor == 1) |
| | 1309 | { |
| | 1310 | *encoded_divisor = 0; // 3000000 baud |
| | 1311 | } |
| | 1312 | else if (*encoded_divisor == 0x4001) |
| | 1313 | { |
| | 1314 | *encoded_divisor = 1; // 2000000 baud (BM only) |
| | 1315 | } |
| | 1316 | return best_baud; |
| | 1317 | } |
| | 1318 | |
| | 1319 | /* ftdi_to_clkbits Convert a requested baudrate for a given system clock and predivisor |
| | 1320 | to encoded divisor and the achievable baudrate |
| | 1321 | Function is only used internally |
| | 1322 | \internal |
| | 1323 | |
| | 1324 | See AN120 |
| | 1325 | clk/1 -> 0 |
| | 1326 | clk/1.5 -> 1 |
| | 1327 | clk/2 -> 2 |
| | 1328 | From /2, 0.125 steps may be taken. |
| | 1329 | The fractional part has frac_code encoding |
| | 1330 | |
| | 1331 | value[13:0] of value is the divisor |
| | 1332 | index[9] mean 12 MHz Base(120 MHz/10) rate versus 3 MHz (48 MHz/16) else |
| | 1333 | |
| | 1334 | H Type have all features above with |
| | 1335 | {index[8],value[15:14]} is the encoded subdivisor |
| | 1336 | |
| | 1337 | FT232R, FT2232 and FT232BM have no option for 12 MHz and with |
| | 1338 | {index[0],value[15:14]} is the encoded subdivisor |
| | 1339 | |
| | 1340 | AM Type chips have only four fractional subdivisors at value[15:14] |
| | 1341 | for subdivisors 0, 0.5, 0.25, 0.125 |
| | 1342 | */ |
| | 1343 | static int ftdi_to_clkbits(int baudrate, int clk, int clk_div, unsigned long *encoded_divisor) |
| | 1344 | { |
| | 1345 | static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7}; |
| | 1346 | int best_baud = 0; |
| | 1347 | int divisor, best_divisor; |
| | 1348 | if (baudrate >= clk/clk_div) |
| | 1349 | { |
| | 1350 | *encoded_divisor = 0; |
| | 1351 | best_baud = clk/clk_div; |
| | 1352 | } |
| | 1353 | else if (baudrate >= clk/(clk_div + clk_div/2)) |
| | 1354 | { |
| | 1355 | *encoded_divisor = 1; |
| | 1356 | best_baud = clk/(clk_div + clk_div/2); |
| | 1357 | } |
| | 1358 | else if (baudrate >= clk/(2*clk_div)) |
| | 1359 | { |
| | 1360 | *encoded_divisor = 2; |
| | 1361 | best_baud = clk/(2*clk_div); |
| | 1362 | } |
| | 1363 | else |
| | 1364 | { |
| | 1365 | /* We divide by 16 to have 3 fractional bits and one bit for rounding */ |
| | 1366 | divisor = clk*16/clk_div / baudrate; |
| | 1367 | if (divisor & 1) /* Decide if to round up or down*/ |
| | 1368 | best_divisor = divisor /2 +1; |
| | 1369 | else |
| | 1370 | best_divisor = divisor/2; |
| | 1371 | if(best_divisor > 0x20000) |
| | 1372 | best_divisor = 0x1ffff; |
| | 1373 | best_baud = clk*16/clk_div/best_divisor; |
| | 1374 | if (best_baud & 1) /* Decide if to round up or down*/ |
| | 1375 | best_baud = best_baud /2 +1; |
| | 1376 | else |
| | 1377 | best_baud = best_baud /2; |
| | 1378 | *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 0x7] << 14); |
| | 1379 | } |
| | 1380 | return best_baud; |
| | 1381 | } |
| | 1382 | /** |
| | 1383 | ftdi_convert_baudrate returns nearest supported baud rate to that requested. |
| | 1384 | Function is only used internally |
| | 1385 | \internal |
| | 1386 | */ |
| | 1387 | static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, |
| | 1388 | unsigned short *value, unsigned short *index) |
| | 1389 | { |
| | 1390 | int best_baud; |
| | 1391 | unsigned long encoded_divisor; |
| | 1392 | |
| | 1393 | if (baudrate <= 0) |
| | 1394 | { |
| | 1395 | // Return error |
| | 1396 | return -1; |
| | 1397 | } |
| | 1398 | |
| | 1399 | #define H_CLK 120000000 |
| | 1400 | #define C_CLK 48000000 |
| | 1401 | if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_232H)) |
| | 1402 | { |
| | 1403 | if(baudrate*10 > H_CLK /0x3fff) |
| | 1404 | { |
| | 1405 | /* On H Devices, use 12 000 000 Baudrate when possible |
| | 1406 | We have a 14 bit divisor, a 1 bit divisor switch (10 or 16) |
| | 1407 | three fractional bits and a 120 MHz clock |
| | 1408 | Assume AN_120 "Sub-integer divisors between 0 and 2 are not allowed" holds for |
| | 1409 | DIV/10 CLK too, so /1, /1.5 and /2 can be handled the same*/ |
| | 1410 | best_baud = ftdi_to_clkbits(baudrate, H_CLK, 10, &encoded_divisor); |
| | 1411 | encoded_divisor |= 0x20000; /* switch on CLK/10*/ |
| | 1412 | } |
| | 1413 | else |
| | 1414 | best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor); |
| | 1415 | } |
| | 1416 | else if ((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C) || (ftdi->type == TYPE_R) || (ftdi->type == TYPE_230X)) |
| | 1417 | { |
| | 1418 | best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor); |
| | 1419 | } |
| | 1420 | else |
| | 1421 | { |
| | 1422 | best_baud = ftdi_to_clkbits_AM(baudrate, &encoded_divisor); |
| | 1423 | } |
| | 1424 | // Split into "value" and "index" values |
| | 1425 | *value = (unsigned short)(encoded_divisor & 0xFFFF); |
| | 1426 | if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H) |
| | 1427 | { |
| | 1428 | *index = (unsigned short)(encoded_divisor >> 8); |
| | 1429 | *index &= 0xFF00; |
| | 1430 | *index |= ftdi->index; |
| | 1431 | } |
| | 1432 | else |
| | 1433 | *index = (unsigned short)(encoded_divisor >> 16); |
| | 1434 | |
| | 1435 | // Return the nearest baud rate |
| | 1436 | return best_baud; |
| | 1437 | } |
| | 1438 | |
| | 1439 | /** |
| | 1440 | * @brief Wrapper function to export ftdi_convert_baudrate() to the unit test |
| | 1441 | * Do not use, it's only for the unit test framework |
| | 1442 | **/ |
| | 1443 | int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, |
| | 1444 | unsigned short *value, unsigned short *index) |
| | 1445 | { |
| | 1446 | return ftdi_convert_baudrate(baudrate, ftdi, value, index); |
| | 1447 | } |
| | 1448 | |
| | 1449 | /** |
| | 1450 | Sets the chip baud rate |
| | 1451 | |
| | 1452 | \param ftdi pointer to ftdi_context |
| | 1453 | \param baudrate baud rate to set |
| | 1454 | |
| | 1455 | \retval 0: all fine |
| | 1456 | \retval -1: invalid baudrate |
| | 1457 | \retval -2: setting baudrate failed |
| | 1458 | \retval -3: USB device unavailable |
| | 1459 | */ |
| | 1460 | int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate) |
| | 1461 | { |
| | 1462 | unsigned short value, index; |
| | 1463 | int actual_baudrate; |
| | 1464 | |
| | 1465 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1466 | ftdi_error_return(-3, "USB device unavailable"); |
| | 1467 | |
| | 1468 | if (ftdi->bitbang_enabled) |
| | 1469 | { |
| | 1470 | baudrate = baudrate*4; |
| | 1471 | } |
| | 1472 | |
| | 1473 | actual_baudrate = ftdi_convert_baudrate(baudrate, ftdi, &value, &index); |
| | 1474 | if (actual_baudrate <= 0) |
| | 1475 | ftdi_error_return (-1, "Silly baudrate <= 0."); |
| | 1476 | |
| | 1477 | // Check within tolerance (about 5%) |
| | 1478 | if ((actual_baudrate * 2 < baudrate /* Catch overflows */ ) |
| | 1479 | || ((actual_baudrate < baudrate) |
| | 1480 | ? (actual_baudrate * 21 < baudrate * 20) |
| | 1481 | : (baudrate * 21 < actual_baudrate * 20))) |
| | 1482 | ftdi_error_return (-1, "Unsupported baudrate. Note: bitbang baudrates are automatically multiplied by 4"); |
| | 1483 | |
| | 1484 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1485 | SIO_SET_BAUDRATE_REQUEST, value, |
| | 1486 | index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1487 | ftdi_error_return (-2, "Setting new baudrate failed"); |
| | 1488 | |
| | 1489 | ftdi->baudrate = baudrate; |
| | 1490 | return 0; |
| | 1491 | } |
| | 1492 | |
| | 1493 | /** |
| | 1494 | Set (RS232) line characteristics. |
| | 1495 | The break type can only be set via ftdi_set_line_property2() |
| | 1496 | and defaults to "off". |
| | 1497 | |
| | 1498 | \param ftdi pointer to ftdi_context |
| | 1499 | \param bits Number of bits |
| | 1500 | \param sbit Number of stop bits |
| | 1501 | \param parity Parity mode |
| | 1502 | |
| | 1503 | \retval 0: all fine |
| | 1504 | \retval -1: Setting line property failed |
| | 1505 | */ |
| | 1506 | int ftdi_set_line_property(struct ftdi_context *ftdi, enum ftdi_bits_type bits, |
| | 1507 | enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity) |
| | 1508 | { |
| | 1509 | return ftdi_set_line_property2(ftdi, bits, sbit, parity, BREAK_OFF); |
| | 1510 | } |
| | 1511 | |
| | 1512 | /** |
| | 1513 | Set (RS232) line characteristics |
| | 1514 | |
| | 1515 | \param ftdi pointer to ftdi_context |
| | 1516 | \param bits Number of bits |
| | 1517 | \param sbit Number of stop bits |
| | 1518 | \param parity Parity mode |
| | 1519 | \param break_type Break type |
| | 1520 | |
| | 1521 | \retval 0: all fine |
| | 1522 | \retval -1: Setting line property failed |
| | 1523 | \retval -2: USB device unavailable |
| | 1524 | */ |
| | 1525 | int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits, |
| | 1526 | enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, |
| | 1527 | enum ftdi_break_type break_type) |
| | 1528 | { |
| | 1529 | unsigned short value = bits; |
| | 1530 | |
| | 1531 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1532 | ftdi_error_return(-2, "USB device unavailable"); |
| | 1533 | |
| | 1534 | switch (parity) |
| | 1535 | { |
| | 1536 | case NONE: |
| | 1537 | value |= (0x00 << 8); |
| | 1538 | break; |
| | 1539 | case ODD: |
| | 1540 | value |= (0x01 << 8); |
| | 1541 | break; |
| | 1542 | case EVEN: |
| | 1543 | value |= (0x02 << 8); |
| | 1544 | break; |
| | 1545 | case MARK: |
| | 1546 | value |= (0x03 << 8); |
| | 1547 | break; |
| | 1548 | case SPACE: |
| | 1549 | value |= (0x04 << 8); |
| | 1550 | break; |
| | 1551 | } |
| | 1552 | |
| | 1553 | switch (sbit) |
| | 1554 | { |
| | 1555 | case STOP_BIT_1: |
| | 1556 | value |= (0x00 << 11); |
| | 1557 | break; |
| | 1558 | case STOP_BIT_15: |
| | 1559 | value |= (0x01 << 11); |
| | 1560 | break; |
| | 1561 | case STOP_BIT_2: |
| | 1562 | value |= (0x02 << 11); |
| | 1563 | break; |
| | 1564 | } |
| | 1565 | |
| | 1566 | switch (break_type) |
| | 1567 | { |
| | 1568 | case BREAK_OFF: |
| | 1569 | value |= (0x00 << 14); |
| | 1570 | break; |
| | 1571 | case BREAK_ON: |
| | 1572 | value |= (0x01 << 14); |
| | 1573 | break; |
| | 1574 | } |
| | 1575 | |
| | 1576 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 1577 | SIO_SET_DATA_REQUEST, value, |
| | 1578 | ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 1579 | ftdi_error_return (-1, "Setting new line property failed"); |
| | 1580 | |
| | 1581 | return 0; |
| | 1582 | } |
| | 1583 | |
| | 1584 | /** |
| | 1585 | Writes data in chunks (see ftdi_write_data_set_chunksize()) to the chip |
| | 1586 | |
| | 1587 | \param ftdi pointer to ftdi_context |
| | 1588 | \param buf Buffer with the data |
| | 1589 | \param size Size of the buffer |
| | 1590 | |
| | 1591 | \retval -666: USB device unavailable |
| | 1592 | \retval <0: error code from usb_bulk_write() |
| | 1593 | \retval >0: number of bytes written |
| | 1594 | */ |
| | 1595 | int ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int size) |
| | 1596 | { |
| | 1597 | int offset = 0; |
| | 1598 | int actual_length; |
| | 1599 | |
| | 1600 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1601 | ftdi_error_return(-666, "USB device unavailable"); |
| | 1602 | |
| | 1603 | while (offset < size) |
| | 1604 | { |
| | 1605 | int write_size = ftdi->writebuffer_chunksize; |
| | 1606 | |
| | 1607 | if (offset+write_size > size) |
| | 1608 | write_size = size-offset; |
| | 1609 | |
| | 1610 | if (libusb_bulk_transfer(ftdi->usb_dev, ftdi->in_ep, (unsigned char *)buf+offset, write_size, &actual_length, ftdi->usb_write_timeout) < 0) |
| | 1611 | ftdi_error_return(-1, "usb bulk write failed"); |
| | 1612 | |
| | 1613 | offset += actual_length; |
| | 1614 | } |
| | 1615 | |
| | 1616 | return offset; |
| | 1617 | } |
| | 1618 | |
| | 1619 | static void LIBUSB_CALL ftdi_read_data_cb(struct libusb_transfer *transfer) |
| | 1620 | { |
| | 1621 | struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data; |
| | 1622 | struct ftdi_context *ftdi = tc->ftdi; |
| | 1623 | int packet_size, actual_length, num_of_chunks, chunk_remains, i, ret; |
| | 1624 | |
| | 1625 | packet_size = ftdi->max_packet_size; |
| | 1626 | |
| | 1627 | actual_length = transfer->actual_length; |
| | 1628 | |
| | 1629 | if (actual_length > 2) |
| | 1630 | { |
| | 1631 | // skip FTDI status bytes. |
| | 1632 | // Maybe stored in the future to enable modem use |
| | 1633 | num_of_chunks = actual_length / packet_size; |
| | 1634 | chunk_remains = actual_length % packet_size; |
| | 1635 | //printf("actual_length = %X, num_of_chunks = %X, chunk_remains = %X, readbuffer_offset = %X\n", actual_length, num_of_chunks, chunk_remains, ftdi->readbuffer_offset); |
| | 1636 | |
| | 1637 | ftdi->readbuffer_offset += 2; |
| | 1638 | actual_length -= 2; |
| | 1639 | |
| | 1640 | if (actual_length > packet_size - 2) |
| | 1641 | { |
| | 1642 | for (i = 1; i < num_of_chunks; i++) |
| | 1643 | memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i, |
| | 1644 | ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i, |
| | 1645 | packet_size - 2); |
| | 1646 | if (chunk_remains > 2) |
| | 1647 | { |
| | 1648 | memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i, |
| | 1649 | ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i, |
| | 1650 | chunk_remains-2); |
| | 1651 | actual_length -= 2*num_of_chunks; |
| | 1652 | } |
| | 1653 | else |
| | 1654 | actual_length -= 2*(num_of_chunks-1)+chunk_remains; |
| | 1655 | } |
| | 1656 | |
| | 1657 | if (actual_length > 0) |
| | 1658 | { |
| | 1659 | // data still fits in buf? |
| | 1660 | if (tc->offset + actual_length <= tc->size) |
| | 1661 | { |
| | 1662 | memcpy (tc->buf + tc->offset, ftdi->readbuffer + ftdi->readbuffer_offset, actual_length); |
| | 1663 | //printf("buf[0] = %X, buf[1] = %X\n", buf[0], buf[1]); |
| | 1664 | tc->offset += actual_length; |
| | 1665 | |
| | 1666 | ftdi->readbuffer_offset = 0; |
| | 1667 | ftdi->readbuffer_remaining = 0; |
| | 1668 | |
| | 1669 | /* Did we read exactly the right amount of bytes? */ |
| | 1670 | if (tc->offset == tc->size) |
| | 1671 | { |
| | 1672 | //printf("read_data exact rem %d offset %d\n", |
| | 1673 | //ftdi->readbuffer_remaining, offset); |
| | 1674 | tc->completed = 1; |
| | 1675 | return; |
| | 1676 | } |
| | 1677 | } |
| | 1678 | else |
| | 1679 | { |
| | 1680 | // only copy part of the data or size <= readbuffer_chunksize |
| | 1681 | int part_size = tc->size - tc->offset; |
| | 1682 | memcpy (tc->buf + tc->offset, ftdi->readbuffer + ftdi->readbuffer_offset, part_size); |
| | 1683 | tc->offset += part_size; |
| | 1684 | |
| | 1685 | ftdi->readbuffer_offset += part_size; |
| | 1686 | ftdi->readbuffer_remaining = actual_length - part_size; |
| | 1687 | |
| | 1688 | /* printf("Returning part: %d - size: %d - offset: %d - actual_length: %d - remaining: %d\n", |
| | 1689 | part_size, size, offset, actual_length, ftdi->readbuffer_remaining); */ |
| | 1690 | tc->completed = 1; |
| | 1691 | return; |
| | 1692 | } |
| | 1693 | } |
| | 1694 | } |
| | 1695 | |
| | 1696 | if (transfer->status == LIBUSB_TRANSFER_CANCELLED) |
| | 1697 | tc->completed = LIBUSB_TRANSFER_CANCELLED; |
| | 1698 | else |
| | 1699 | { |
| | 1700 | ret = libusb_submit_transfer (transfer); |
| | 1701 | if (ret < 0) |
| | 1702 | tc->completed = 1; |
| | 1703 | } |
| | 1704 | } |
| | 1705 | |
| | 1706 | |
| | 1707 | static void LIBUSB_CALL ftdi_write_data_cb(struct libusb_transfer *transfer) |
| | 1708 | { |
| | 1709 | struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data; |
| | 1710 | struct ftdi_context *ftdi = tc->ftdi; |
| | 1711 | |
| | 1712 | tc->offset += transfer->actual_length; |
| | 1713 | |
| | 1714 | if (tc->offset == tc->size) |
| | 1715 | { |
| | 1716 | tc->completed = 1; |
| | 1717 | } |
| | 1718 | else |
| | 1719 | { |
| | 1720 | int write_size = ftdi->writebuffer_chunksize; |
| | 1721 | int ret; |
| | 1722 | |
| | 1723 | if (tc->offset + write_size > tc->size) |
| | 1724 | write_size = tc->size - tc->offset; |
| | 1725 | |
| | 1726 | transfer->length = write_size; |
| | 1727 | transfer->buffer = tc->buf + tc->offset; |
| | 1728 | |
| | 1729 | if (transfer->status == LIBUSB_TRANSFER_CANCELLED) |
| | 1730 | tc->completed = LIBUSB_TRANSFER_CANCELLED; |
| | 1731 | else |
| | 1732 | { |
| | 1733 | ret = libusb_submit_transfer (transfer); |
| | 1734 | if (ret < 0) |
| | 1735 | tc->completed = 1; |
| | 1736 | } |
| | 1737 | } |
| | 1738 | } |
| | 1739 | |
| | 1740 | |
| | 1741 | /** |
| | 1742 | Writes data to the chip. Does not wait for completion of the transfer |
| | 1743 | nor does it make sure that the transfer was successful. |
| | 1744 | |
| | 1745 | Use libusb 1.0 asynchronous API. |
| | 1746 | |
| | 1747 | \param ftdi pointer to ftdi_context |
| | 1748 | \param buf Buffer with the data |
| | 1749 | \param size Size of the buffer |
| | 1750 | |
| | 1751 | \retval NULL: Some error happens when submit transfer |
| | 1752 | \retval !NULL: Pointer to a ftdi_transfer_control |
| | 1753 | */ |
| | 1754 | |
| | 1755 | struct ftdi_transfer_control *ftdi_write_data_submit(struct ftdi_context *ftdi, unsigned char *buf, int size) |
| | 1756 | { |
| | 1757 | struct ftdi_transfer_control *tc; |
| | 1758 | struct libusb_transfer *transfer; |
| | 1759 | int write_size, ret; |
| | 1760 | |
| | 1761 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1762 | return NULL; |
| | 1763 | |
| | 1764 | tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc)); |
| | 1765 | if (!tc) |
| | 1766 | return NULL; |
| | 1767 | |
| | 1768 | transfer = libusb_alloc_transfer(0); |
| | 1769 | if (!transfer) |
| | 1770 | { |
| | 1771 | free(tc); |
| | 1772 | return NULL; |
| | 1773 | } |
| | 1774 | |
| | 1775 | tc->ftdi = ftdi; |
| | 1776 | tc->completed = 0; |
| | 1777 | tc->buf = buf; |
| | 1778 | tc->size = size; |
| | 1779 | tc->offset = 0; |
| | 1780 | |
| | 1781 | if (size < (int)ftdi->writebuffer_chunksize) |
| | 1782 | write_size = size; |
| | 1783 | else |
| | 1784 | write_size = ftdi->writebuffer_chunksize; |
| | 1785 | |
| | 1786 | libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->in_ep, buf, |
| | 1787 | write_size, ftdi_write_data_cb, tc, |
| | 1788 | ftdi->usb_write_timeout); |
| | 1789 | transfer->type = LIBUSB_TRANSFER_TYPE_BULK; |
| | 1790 | |
| | 1791 | ret = libusb_submit_transfer(transfer); |
| | 1792 | if (ret < 0) |
| | 1793 | { |
| | 1794 | libusb_free_transfer(transfer); |
| | 1795 | free(tc); |
| | 1796 | return NULL; |
| | 1797 | } |
| | 1798 | tc->transfer = transfer; |
| | 1799 | |
| | 1800 | return tc; |
| | 1801 | } |
| | 1802 | |
| | 1803 | /** |
| | 1804 | Reads data from the chip. Does not wait for completion of the transfer |
| | 1805 | nor does it make sure that the transfer was successful. |
| | 1806 | |
| | 1807 | Use libusb 1.0 asynchronous API. |
| | 1808 | |
| | 1809 | \param ftdi pointer to ftdi_context |
| | 1810 | \param buf Buffer with the data |
| | 1811 | \param size Size of the buffer |
| | 1812 | |
| | 1813 | \retval NULL: Some error happens when submit transfer |
| | 1814 | \retval !NULL: Pointer to a ftdi_transfer_control |
| | 1815 | */ |
| | 1816 | |
| | 1817 | struct ftdi_transfer_control *ftdi_read_data_submit(struct ftdi_context *ftdi, unsigned char *buf, int size) |
| | 1818 | { |
| | 1819 | struct ftdi_transfer_control *tc; |
| | 1820 | struct libusb_transfer *transfer; |
| | 1821 | int ret; |
| | 1822 | |
| | 1823 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 1824 | return NULL; |
| | 1825 | |
| | 1826 | tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc)); |
| | 1827 | if (!tc) |
| | 1828 | return NULL; |
| | 1829 | |
| | 1830 | tc->ftdi = ftdi; |
| | 1831 | tc->buf = buf; |
| | 1832 | tc->size = size; |
| | 1833 | |
| | 1834 | if (size <= (int)ftdi->readbuffer_remaining) |
| | 1835 | { |
| | 1836 | memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size); |
| | 1837 | |
| | 1838 | // Fix offsets |
| | 1839 | ftdi->readbuffer_remaining -= size; |
| | 1840 | ftdi->readbuffer_offset += size; |
| | 1841 | |
| | 1842 | /* printf("Returning bytes from buffer: %d - remaining: %d\n", size, ftdi->readbuffer_remaining); */ |
| | 1843 | |
| | 1844 | tc->completed = 1; |
| | 1845 | tc->offset = size; |
| | 1846 | tc->transfer = NULL; |
| | 1847 | return tc; |
| | 1848 | } |
| | 1849 | |
| | 1850 | tc->completed = 0; |
| | 1851 | if (ftdi->readbuffer_remaining != 0) |
| | 1852 | { |
| | 1853 | memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, ftdi->readbuffer_remaining); |
| | 1854 | |
| | 1855 | tc->offset = ftdi->readbuffer_remaining; |
| | 1856 | } |
| | 1857 | else |
| | 1858 | tc->offset = 0; |
| | 1859 | |
| | 1860 | transfer = libusb_alloc_transfer(0); |
| | 1861 | if (!transfer) |
| | 1862 | { |
| | 1863 | free (tc); |
| | 1864 | return NULL; |
| | 1865 | } |
| | 1866 | |
| | 1867 | ftdi->readbuffer_remaining = 0; |
| | 1868 | ftdi->readbuffer_offset = 0; |
| | 1869 | |
| | 1870 | libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep, ftdi->readbuffer, ftdi->readbuffer_chunksize, ftdi_read_data_cb, tc, ftdi->usb_read_timeout); |
| | 1871 | transfer->type = LIBUSB_TRANSFER_TYPE_BULK; |
| | 1872 | |
| | 1873 | ret = libusb_submit_transfer(transfer); |
| | 1874 | if (ret < 0) |
| | 1875 | { |
| | 1876 | libusb_free_transfer(transfer); |
| | 1877 | free (tc); |
| | 1878 | return NULL; |
| | 1879 | } |
| | 1880 | tc->transfer = transfer; |
| | 1881 | |
| | 1882 | return tc; |
| | 1883 | } |
| | 1884 | |
| | 1885 | /** |
| | 1886 | Wait for completion of the transfer. |
| | 1887 | |
| | 1888 | Use libusb 1.0 asynchronous API. |
| | 1889 | |
| | 1890 | \param tc pointer to ftdi_transfer_control |
| | 1891 | |
| | 1892 | \retval < 0: Some error happens |
| | 1893 | \retval >= 0: Data size transferred |
| | 1894 | */ |
| | 1895 | |
| | 1896 | int ftdi_transfer_data_done(struct ftdi_transfer_control *tc) |
| | 1897 | { |
| | 1898 | int ret; |
| | 1899 | struct timeval to = { 0, 0 }; |
| | 1900 | while (!tc->completed) |
| | 1901 | { |
| | 1902 | ret = libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, |
| | 1903 | &to, &tc->completed); |
| | 1904 | if (ret < 0) |
| | 1905 | { |
| | 1906 | if (ret == LIBUSB_ERROR_INTERRUPTED) |
| | 1907 | continue; |
| | 1908 | libusb_cancel_transfer(tc->transfer); |
| | 1909 | while (!tc->completed) |
| | 1910 | if (libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, |
| | 1911 | &to, &tc->completed) < 0) |
| | 1912 | break; |
| | 1913 | libusb_free_transfer(tc->transfer); |
| | 1914 | free (tc); |
| | 1915 | return ret; |
| | 1916 | } |
| | 1917 | } |
| | 1918 | |
| | 1919 | ret = tc->offset; |
| | 1920 | /** |
| | 1921 | * tc->transfer could be NULL if "(size <= ftdi->readbuffer_remaining)" |
| | 1922 | * at ftdi_read_data_submit(). Therefore, we need to check it here. |
| | 1923 | **/ |
| | 1924 | if (tc->transfer) |
| | 1925 | { |
| | 1926 | if (tc->transfer->status != LIBUSB_TRANSFER_COMPLETED) |
| | 1927 | ret = -1; |
| | 1928 | libusb_free_transfer(tc->transfer); |
| | 1929 | } |
| | 1930 | free(tc); |
| | 1931 | return ret; |
| | 1932 | } |
| | 1933 | |
| | 1934 | /** |
| | 1935 | Cancel transfer and wait for completion. |
| | 1936 | |
| | 1937 | Use libusb 1.0 asynchronous API. |
| | 1938 | |
| | 1939 | \param tc pointer to ftdi_transfer_control |
| | 1940 | \param to pointer to timeout value or NULL for infinite |
| | 1941 | */ |
| | 1942 | |
| | 1943 | void ftdi_transfer_data_cancel(struct ftdi_transfer_control *tc, |
| | 1944 | struct timeval * to) |
| | 1945 | { |
| | 1946 | struct timeval tv = { 0, 0 }; |
| | 1947 | |
| | 1948 | if (!tc->completed && tc->transfer != NULL) |
| | 1949 | { |
| | 1950 | if (to == NULL) |
| | 1951 | to = &tv; |
| | 1952 | |
| | 1953 | libusb_cancel_transfer(tc->transfer); |
| | 1954 | while (!tc->completed) |
| | 1955 | { |
| | 1956 | if (libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, to, &tc->completed) < 0) |
| | 1957 | break; |
| | 1958 | } |
| | 1959 | } |
| | 1960 | |
| | 1961 | if (tc->transfer) |
| | 1962 | libusb_free_transfer(tc->transfer); |
| | 1963 | |
| | 1964 | free (tc); |
| | 1965 | } |
| | 1966 | |
| | 1967 | /** |
| | 1968 | Configure write buffer chunk size. |
| | 1969 | Default is 4096. |
| | 1970 | |
| | 1971 | \param ftdi pointer to ftdi_context |
| | 1972 | \param chunksize Chunk size |
| | 1973 | |
| | 1974 | \retval 0: all fine |
| | 1975 | \retval -1: ftdi context invalid |
| | 1976 | */ |
| | 1977 | int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) |
| | 1978 | { |
| | 1979 | if (ftdi == NULL) |
| | 1980 | ftdi_error_return(-1, "ftdi context invalid"); |
| | 1981 | |
| | 1982 | ftdi->writebuffer_chunksize = chunksize; |
| | 1983 | return 0; |
| | 1984 | } |
| | 1985 | |
| | 1986 | /** |
| | 1987 | Get write buffer chunk size. |
| | 1988 | |
| | 1989 | \param ftdi pointer to ftdi_context |
| | 1990 | \param chunksize Pointer to store chunk size in |
| | 1991 | |
| | 1992 | \retval 0: all fine |
| | 1993 | \retval -1: ftdi context invalid |
| | 1994 | */ |
| | 1995 | int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) |
| | 1996 | { |
| | 1997 | if (ftdi == NULL) |
| | 1998 | ftdi_error_return(-1, "ftdi context invalid"); |
| | 1999 | |
| | 2000 | *chunksize = ftdi->writebuffer_chunksize; |
| | 2001 | return 0; |
| | 2002 | } |
| | 2003 | |
| | 2004 | /** |
| | 2005 | Reads data in chunks (see ftdi_read_data_set_chunksize()) from the chip. |
| | 2006 | |
| | 2007 | Automatically strips the two modem status bytes transferred during every read. |
| | 2008 | |
| | 2009 | \param ftdi pointer to ftdi_context |
| | 2010 | \param buf Buffer to store data in |
| | 2011 | \param size Size of the buffer |
| | 2012 | |
| | 2013 | \retval -666: USB device unavailable |
| | 2014 | \retval <0: error code from libusb_bulk_transfer() |
| | 2015 | \retval 0: no data was available |
| | 2016 | \retval >0: number of bytes read |
| | 2017 | |
| | 2018 | */ |
| | 2019 | int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size) |
| | 2020 | { |
| | 2021 | int offset = 0, ret, i, num_of_chunks, chunk_remains; |
| | 2022 | int packet_size; |
| | 2023 | int actual_length = 1; |
| | 2024 | |
| | 2025 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2026 | ftdi_error_return(-666, "USB device unavailable"); |
| | 2027 | |
| | 2028 | // Packet size sanity check (avoid division by zero) |
| | 2029 | packet_size = ftdi->max_packet_size; |
| | 2030 | if (packet_size == 0) |
| | 2031 | ftdi_error_return(-1, "max_packet_size is bogus (zero)"); |
| | 2032 | |
| | 2033 | // everything we want is still in the readbuffer? |
| | 2034 | if (size <= (int)ftdi->readbuffer_remaining) |
| | 2035 | { |
| | 2036 | memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size); |
| | 2037 | |
| | 2038 | // Fix offsets |
| | 2039 | ftdi->readbuffer_remaining -= size; |
| | 2040 | ftdi->readbuffer_offset += size; |
| | 2041 | |
| | 2042 | /* printf("Returning bytes from buffer: %d - remaining: %d\n", size, ftdi->readbuffer_remaining); */ |
| | 2043 | |
| | 2044 | return size; |
| | 2045 | } |
| | 2046 | // something still in the readbuffer, but not enough to satisfy 'size'? |
| | 2047 | if (ftdi->readbuffer_remaining != 0) |
| | 2048 | { |
| | 2049 | memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, ftdi->readbuffer_remaining); |
| | 2050 | |
| | 2051 | // Fix offset |
| | 2052 | offset += ftdi->readbuffer_remaining; |
| | 2053 | } |
| | 2054 | // do the actual USB read |
| | 2055 | while (offset < size && actual_length > 0) |
| | 2056 | { |
| | 2057 | ftdi->readbuffer_remaining = 0; |
| | 2058 | ftdi->readbuffer_offset = 0; |
| | 2059 | /* returns how much received */ |
| | 2060 | ret = libusb_bulk_transfer (ftdi->usb_dev, ftdi->out_ep, ftdi->readbuffer, ftdi->readbuffer_chunksize, &actual_length, ftdi->usb_read_timeout); |
| | 2061 | if (ret < 0) |
| | 2062 | ftdi_error_return(ret, "usb bulk read failed"); |
| | 2063 | |
| | 2064 | if (actual_length > 2) |
| | 2065 | { |
| | 2066 | // skip FTDI status bytes. |
| | 2067 | // Maybe stored in the future to enable modem use |
| | 2068 | num_of_chunks = actual_length / packet_size; |
| | 2069 | chunk_remains = actual_length % packet_size; |
| | 2070 | //printf("actual_length = %X, num_of_chunks = %X, chunk_remains = %X, readbuffer_offset = %X\n", actual_length, num_of_chunks, chunk_remains, ftdi->readbuffer_offset); |
| | 2071 | |
| | 2072 | ftdi->readbuffer_offset += 2; |
| | 2073 | actual_length -= 2; |
| | 2074 | |
| | 2075 | if (actual_length > packet_size - 2) |
| | 2076 | { |
| | 2077 | for (i = 1; i < num_of_chunks; i++) |
| | 2078 | memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i, |
| | 2079 | ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i, |
| | 2080 | packet_size - 2); |
| | 2081 | if (chunk_remains > 2) |
| | 2082 | { |
| | 2083 | memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i, |
| | 2084 | ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i, |
| | 2085 | chunk_remains-2); |
| | 2086 | actual_length -= 2*num_of_chunks; |
| | 2087 | } |
| | 2088 | else |
| | 2089 | actual_length -= 2*(num_of_chunks-1)+chunk_remains; |
| | 2090 | } |
| | 2091 | } |
| | 2092 | else if (actual_length <= 2) |
| | 2093 | { |
| | 2094 | // no more data to read? |
| | 2095 | return offset; |
| | 2096 | } |
| | 2097 | if (actual_length > 0) |
| | 2098 | { |
| | 2099 | // data still fits in buf? |
| | 2100 | if (offset+actual_length <= size) |
| | 2101 | { |
| | 2102 | memcpy (buf+offset, ftdi->readbuffer+ftdi->readbuffer_offset, actual_length); |
| | 2103 | //printf("buf[0] = %X, buf[1] = %X\n", buf[0], buf[1]); |
| | 2104 | offset += actual_length; |
| | 2105 | |
| | 2106 | /* Did we read exactly the right amount of bytes? */ |
| | 2107 | if (offset == size) |
| | 2108 | //printf("read_data exact rem %d offset %d\n", |
| | 2109 | //ftdi->readbuffer_remaining, offset); |
| | 2110 | return offset; |
| | 2111 | } |
| | 2112 | else |
| | 2113 | { |
| | 2114 | // only copy part of the data or size <= readbuffer_chunksize |
| | 2115 | int part_size = size-offset; |
| | 2116 | memcpy (buf+offset, ftdi->readbuffer+ftdi->readbuffer_offset, part_size); |
| | 2117 | |
| | 2118 | ftdi->readbuffer_offset += part_size; |
| | 2119 | ftdi->readbuffer_remaining = actual_length-part_size; |
| | 2120 | offset += part_size; |
| | 2121 | |
| | 2122 | /* printf("Returning part: %d - size: %d - offset: %d - actual_length: %d - remaining: %d\n", |
| | 2123 | part_size, size, offset, actual_length, ftdi->readbuffer_remaining); */ |
| | 2124 | |
| | 2125 | return offset; |
| | 2126 | } |
| | 2127 | } |
| | 2128 | } |
| | 2129 | // never reached |
| | 2130 | return -127; |
| | 2131 | } |
| | 2132 | |
| | 2133 | /** |
| | 2134 | Configure read buffer chunk size. |
| | 2135 | Default is 4096. |
| | 2136 | |
| | 2137 | Automatically reallocates the buffer. |
| | 2138 | |
| | 2139 | \param ftdi pointer to ftdi_context |
| | 2140 | \param chunksize Chunk size |
| | 2141 | |
| | 2142 | \retval 0: all fine |
| | 2143 | \retval -1: ftdi context invalid |
| | 2144 | */ |
| | 2145 | int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) |
| | 2146 | { |
| | 2147 | unsigned char *new_buf; |
| | 2148 | |
| | 2149 | if (ftdi == NULL) |
| | 2150 | ftdi_error_return(-1, "ftdi context invalid"); |
| | 2151 | |
| | 2152 | // Invalidate all remaining data |
| | 2153 | ftdi->readbuffer_offset = 0; |
| | 2154 | ftdi->readbuffer_remaining = 0; |
| | 2155 | #ifdef __linux__ |
| | 2156 | /* We can't set readbuffer_chunksize larger than MAX_BULK_BUFFER_LENGTH, |
| | 2157 | which is defined in libusb-1.0. Otherwise, each USB read request will |
| | 2158 | be divided into multiple URBs. This will cause issues on Linux kernel |
| | 2159 | older than 2.6.32. */ |
| | 2160 | if (chunksize > 16384) |
| | 2161 | chunksize = 16384; |
| | 2162 | #endif |
| | 2163 | |
| | 2164 | if ((new_buf = (unsigned char *)realloc(ftdi->readbuffer, chunksize)) == NULL) |
| | 2165 | ftdi_error_return(-1, "out of memory for readbuffer"); |
| | 2166 | |
| | 2167 | ftdi->readbuffer = new_buf; |
| | 2168 | ftdi->readbuffer_chunksize = chunksize; |
| | 2169 | |
| | 2170 | return 0; |
| | 2171 | } |
| | 2172 | |
| | 2173 | /** |
| | 2174 | Get read buffer chunk size. |
| | 2175 | |
| | 2176 | \param ftdi pointer to ftdi_context |
| | 2177 | \param chunksize Pointer to store chunk size in |
| | 2178 | |
| | 2179 | \retval 0: all fine |
| | 2180 | \retval -1: FTDI context invalid |
| | 2181 | */ |
| | 2182 | int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) |
| | 2183 | { |
| | 2184 | if (ftdi == NULL) |
| | 2185 | ftdi_error_return(-1, "FTDI context invalid"); |
| | 2186 | |
| | 2187 | *chunksize = ftdi->readbuffer_chunksize; |
| | 2188 | return 0; |
| | 2189 | } |
| | 2190 | |
| | 2191 | /** |
| | 2192 | Enable/disable bitbang modes. |
| | 2193 | |
| | 2194 | \param ftdi pointer to ftdi_context |
| | 2195 | \param bitmask Bitmask to configure lines. |
| | 2196 | HIGH/ON value configures a line as output. |
| | 2197 | \param mode Bitbang mode: use the values defined in \ref ftdi_mpsse_mode |
| | 2198 | |
| | 2199 | \retval 0: all fine |
| | 2200 | \retval -1: can't enable bitbang mode |
| | 2201 | \retval -2: USB device unavailable |
| | 2202 | */ |
| | 2203 | int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode) |
| | 2204 | { |
| | 2205 | unsigned short usb_val; |
| | 2206 | |
| | 2207 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2208 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2209 | |
| | 2210 | usb_val = bitmask; // low byte: bitmask |
| | 2211 | usb_val |= (mode << 8); |
| | 2212 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2213 | ftdi_error_return(-1, "unable to configure bitbang mode. Perhaps not a BM/2232C type chip?"); |
| | 2214 | |
| | 2215 | ftdi->bitbang_mode = mode; |
| | 2216 | ftdi->bitbang_enabled = (mode == BITMODE_RESET) ? 0 : 1; |
| | 2217 | return 0; |
| | 2218 | } |
| | 2219 | |
| | 2220 | /** |
| | 2221 | Set module detach mode. |
| | 2222 | |
| | 2223 | \param ftdi pointer to ftdi_context |
| | 2224 | \param mode detach mode to use. |
| | 2225 | |
| | 2226 | \retval 0: all fine |
| | 2227 | \retval -1: can't enable bitbang mode |
| | 2228 | */ |
| | 2229 | int ftdi_set_module_detach_mode(struct ftdi_context *ftdi, enum ftdi_module_detach_mode mode) |
| | 2230 | { |
| | 2231 | if (ftdi == NULL) |
| | 2232 | ftdi_error_return(-1, "FTDI context invalid"); |
| | 2233 | |
| | 2234 | ftdi->module_detach_mode = mode; |
| | 2235 | return 0; |
| | 2236 | } |
| | 2237 | |
| | 2238 | /** |
| | 2239 | Disable bitbang mode. |
| | 2240 | |
| | 2241 | \param ftdi pointer to ftdi_context |
| | 2242 | |
| | 2243 | \retval 0: all fine |
| | 2244 | \retval -1: can't disable bitbang mode |
| | 2245 | \retval -2: USB device unavailable |
| | 2246 | */ |
| | 2247 | int ftdi_disable_bitbang(struct ftdi_context *ftdi) |
| | 2248 | { |
| | 2249 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2250 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2251 | |
| | 2252 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, 0, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2253 | ftdi_error_return(-1, "unable to leave bitbang mode. Perhaps not a BM type chip?"); |
| | 2254 | |
| | 2255 | ftdi->bitbang_enabled = 0; |
| | 2256 | return 0; |
| | 2257 | } |
| | 2258 | |
| | 2259 | |
| | 2260 | /** |
| | 2261 | Directly read pin state, circumventing the read buffer. Useful for bitbang mode. |
| | 2262 | |
| | 2263 | \param ftdi pointer to ftdi_context |
| | 2264 | \param pins Pointer to store pins into |
| | 2265 | |
| | 2266 | \retval 0: all fine |
| | 2267 | \retval -1: read pins failed |
| | 2268 | \retval -2: USB device unavailable |
| | 2269 | */ |
| | 2270 | int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins) |
| | 2271 | { |
| | 2272 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2273 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2274 | |
| | 2275 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_PINS_REQUEST, 0, ftdi->index, (unsigned char *)pins, 1, ftdi->usb_read_timeout) != 1) |
| | 2276 | ftdi_error_return(-1, "read pins failed"); |
| | 2277 | |
| | 2278 | return 0; |
| | 2279 | } |
| | 2280 | |
| | 2281 | /** |
| | 2282 | Set latency timer |
| | 2283 | |
| | 2284 | The FTDI chip keeps data in the internal buffer for a specific |
| | 2285 | amount of time if the buffer is not full yet to decrease |
| | 2286 | load on the usb bus. |
| | 2287 | |
| | 2288 | \param ftdi pointer to ftdi_context |
| | 2289 | \param latency Value between 1 and 255 |
| | 2290 | |
| | 2291 | \retval 0: all fine |
| | 2292 | \retval -1: latency out of range |
| | 2293 | \retval -2: unable to set latency timer |
| | 2294 | \retval -3: USB device unavailable |
| | 2295 | */ |
| | 2296 | int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency) |
| | 2297 | { |
| | 2298 | unsigned short usb_val; |
| | 2299 | |
| | 2300 | if (latency < 1) |
| | 2301 | ftdi_error_return(-1, "latency out of range. Only valid for 1-255"); |
| | 2302 | |
| | 2303 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2304 | ftdi_error_return(-3, "USB device unavailable"); |
| | 2305 | |
| | 2306 | usb_val = latency; |
| | 2307 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_LATENCY_TIMER_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2308 | ftdi_error_return(-2, "unable to set latency timer"); |
| | 2309 | |
| | 2310 | return 0; |
| | 2311 | } |
| | 2312 | |
| | 2313 | /** |
| | 2314 | Get latency timer |
| | 2315 | |
| | 2316 | \param ftdi pointer to ftdi_context |
| | 2317 | \param latency Pointer to store latency value in |
| | 2318 | |
| | 2319 | \retval 0: all fine |
| | 2320 | \retval -1: unable to get latency timer |
| | 2321 | \retval -2: USB device unavailable |
| | 2322 | */ |
| | 2323 | int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency) |
| | 2324 | { |
| | 2325 | unsigned short usb_val; |
| | 2326 | |
| | 2327 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2328 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2329 | |
| | 2330 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_GET_LATENCY_TIMER_REQUEST, 0, ftdi->index, (unsigned char *)&usb_val, 1, ftdi->usb_read_timeout) != 1) |
| | 2331 | ftdi_error_return(-1, "reading latency timer failed"); |
| | 2332 | |
| | 2333 | *latency = (unsigned char)usb_val; |
| | 2334 | return 0; |
| | 2335 | } |
| | 2336 | |
| | 2337 | /** |
| | 2338 | Poll modem status information |
| | 2339 | |
| | 2340 | This function allows the retrieve the two status bytes of the device. |
| | 2341 | The device sends these bytes also as a header for each read access |
| | 2342 | where they are discarded by ftdi_read_data(). The chip generates |
| | 2343 | the two stripped status bytes in the absence of data every 40 ms. |
| | 2344 | |
| | 2345 | Layout of the first byte: |
| | 2346 | - B0..B3 - must be 0 |
| | 2347 | - B4 Clear to send (CTS) |
| | 2348 | 0 = inactive |
| | 2349 | 1 = active |
| | 2350 | - B5 Data set ready (DTS) |
| | 2351 | 0 = inactive |
| | 2352 | 1 = active |
| | 2353 | - B6 Ring indicator (RI) |
| | 2354 | 0 = inactive |
| | 2355 | 1 = active |
| | 2356 | - B7 Receive line signal detect (RLSD) |
| | 2357 | 0 = inactive |
| | 2358 | 1 = active |
| | 2359 | |
| | 2360 | Layout of the second byte: |
| | 2361 | - B0 Data ready (DR) |
| | 2362 | - B1 Overrun error (OE) |
| | 2363 | - B2 Parity error (PE) |
| | 2364 | - B3 Framing error (FE) |
| | 2365 | - B4 Break interrupt (BI) |
| | 2366 | - B5 Transmitter holding register (THRE) |
| | 2367 | - B6 Transmitter empty (TEMT) |
| | 2368 | - B7 Error in RCVR FIFO |
| | 2369 | |
| | 2370 | \param ftdi pointer to ftdi_context |
| | 2371 | \param status Pointer to store status information in. Must be two bytes. |
| | 2372 | |
| | 2373 | \retval 0: all fine |
| | 2374 | \retval -1: unable to retrieve status information |
| | 2375 | \retval -2: USB device unavailable |
| | 2376 | */ |
| | 2377 | int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status) |
| | 2378 | { |
| | 2379 | char usb_val[2]; |
| | 2380 | |
| | 2381 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2382 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2383 | |
| | 2384 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_POLL_MODEM_STATUS_REQUEST, 0, ftdi->index, (unsigned char *)usb_val, 2, ftdi->usb_read_timeout) != 2) |
| | 2385 | ftdi_error_return(-1, "getting modem status failed"); |
| | 2386 | |
| | 2387 | *status = (usb_val[1] << 8) | (usb_val[0] & 0xFF); |
| | 2388 | |
| | 2389 | return 0; |
| | 2390 | } |
| | 2391 | |
| | 2392 | /** |
| | 2393 | Set flowcontrol for ftdi chip |
| | 2394 | |
| | 2395 | Note: Do not use this function to enable XON/XOFF mode, use ftdi_setflowctrl_xonxoff() instead. |
| | 2396 | |
| | 2397 | \param ftdi pointer to ftdi_context |
| | 2398 | \param flowctrl flow control to use. should be |
| | 2399 | SIO_DISABLE_FLOW_CTRL, SIO_RTS_CTS_HS, SIO_DTR_DSR_HS |
| | 2400 | |
| | 2401 | \retval 0: all fine |
| | 2402 | \retval -1: set flow control failed |
| | 2403 | \retval -2: USB device unavailable |
| | 2404 | */ |
| | 2405 | int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl) |
| | 2406 | { |
| | 2407 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2408 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2409 | |
| | 2410 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 2411 | SIO_SET_FLOW_CTRL_REQUEST, 0, (flowctrl | ftdi->index), |
| | 2412 | NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2413 | ftdi_error_return(-1, "set flow control failed"); |
| | 2414 | |
| | 2415 | return 0; |
| | 2416 | } |
| | 2417 | |
| | 2418 | /** |
| | 2419 | Set XON/XOFF flowcontrol for ftdi chip |
| | 2420 | |
| | 2421 | \param ftdi pointer to ftdi_context |
| | 2422 | \param xon character code used to resume transmission |
| | 2423 | \param xoff character code used to pause transmission |
| | 2424 | |
| | 2425 | \retval 0: all fine |
| | 2426 | \retval -1: set flow control failed |
| | 2427 | \retval -2: USB device unavailable |
| | 2428 | */ |
| | 2429 | int ftdi_setflowctrl_xonxoff(struct ftdi_context *ftdi, unsigned char xon, unsigned char xoff) |
| | 2430 | { |
| | 2431 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2432 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2433 | |
| | 2434 | uint16_t xonxoff = xon | (xoff << 8); |
| | 2435 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 2436 | SIO_SET_FLOW_CTRL_REQUEST, xonxoff, (SIO_XON_XOFF_HS | ftdi->index), |
| | 2437 | NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2438 | ftdi_error_return(-1, "set flow control failed"); |
| | 2439 | |
| | 2440 | return 0; |
| | 2441 | } |
| | 2442 | |
| | 2443 | /** |
| | 2444 | Set dtr line |
| | 2445 | |
| | 2446 | \param ftdi pointer to ftdi_context |
| | 2447 | \param state state to set line to (1 or 0) |
| | 2448 | |
| | 2449 | \retval 0: all fine |
| | 2450 | \retval -1: set dtr failed |
| | 2451 | \retval -2: USB device unavailable |
| | 2452 | */ |
| | 2453 | int ftdi_setdtr(struct ftdi_context *ftdi, int state) |
| | 2454 | { |
| | 2455 | unsigned short usb_val; |
| | 2456 | |
| | 2457 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2458 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2459 | |
| | 2460 | if (state) |
| | 2461 | usb_val = SIO_SET_DTR_HIGH; |
| | 2462 | else |
| | 2463 | usb_val = SIO_SET_DTR_LOW; |
| | 2464 | |
| | 2465 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 2466 | SIO_SET_MODEM_CTRL_REQUEST, usb_val, ftdi->index, |
| | 2467 | NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2468 | ftdi_error_return(-1, "set dtr failed"); |
| | 2469 | |
| | 2470 | return 0; |
| | 2471 | } |
| | 2472 | |
| | 2473 | /** |
| | 2474 | Set rts line |
| | 2475 | |
| | 2476 | \param ftdi pointer to ftdi_context |
| | 2477 | \param state state to set line to (1 or 0) |
| | 2478 | |
| | 2479 | \retval 0: all fine |
| | 2480 | \retval -1: set rts failed |
| | 2481 | \retval -2: USB device unavailable |
| | 2482 | */ |
| | 2483 | int ftdi_setrts(struct ftdi_context *ftdi, int state) |
| | 2484 | { |
| | 2485 | unsigned short usb_val; |
| | 2486 | |
| | 2487 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2488 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2489 | |
| | 2490 | if (state) |
| | 2491 | usb_val = SIO_SET_RTS_HIGH; |
| | 2492 | else |
| | 2493 | usb_val = SIO_SET_RTS_LOW; |
| | 2494 | |
| | 2495 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 2496 | SIO_SET_MODEM_CTRL_REQUEST, usb_val, ftdi->index, |
| | 2497 | NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2498 | ftdi_error_return(-1, "set of rts failed"); |
| | 2499 | |
| | 2500 | return 0; |
| | 2501 | } |
| | 2502 | |
| | 2503 | /** |
| | 2504 | Set dtr and rts line in one pass |
| | 2505 | |
| | 2506 | \param ftdi pointer to ftdi_context |
| | 2507 | \param dtr DTR state to set line to (1 or 0) |
| | 2508 | \param rts RTS state to set line to (1 or 0) |
| | 2509 | |
| | 2510 | \retval 0: all fine |
| | 2511 | \retval -1: set dtr/rts failed |
| | 2512 | \retval -2: USB device unavailable |
| | 2513 | */ |
| | 2514 | int ftdi_setdtr_rts(struct ftdi_context *ftdi, int dtr, int rts) |
| | 2515 | { |
| | 2516 | unsigned short usb_val; |
| | 2517 | |
| | 2518 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2519 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2520 | |
| | 2521 | if (dtr) |
| | 2522 | usb_val = SIO_SET_DTR_HIGH; |
| | 2523 | else |
| | 2524 | usb_val = SIO_SET_DTR_LOW; |
| | 2525 | |
| | 2526 | if (rts) |
| | 2527 | usb_val |= SIO_SET_RTS_HIGH; |
| | 2528 | else |
| | 2529 | usb_val |= SIO_SET_RTS_LOW; |
| | 2530 | |
| | 2531 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 2532 | SIO_SET_MODEM_CTRL_REQUEST, usb_val, ftdi->index, |
| | 2533 | NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2534 | ftdi_error_return(-1, "set of rts/dtr failed"); |
| | 2535 | |
| | 2536 | return 0; |
| | 2537 | } |
| | 2538 | |
| | 2539 | /** |
| | 2540 | Set the special event character |
| | 2541 | |
| | 2542 | \param ftdi pointer to ftdi_context |
| | 2543 | \param eventch Event character |
| | 2544 | \param enable 0 to disable the event character, non-zero otherwise |
| | 2545 | |
| | 2546 | \retval 0: all fine |
| | 2547 | \retval -1: unable to set event character |
| | 2548 | \retval -2: USB device unavailable |
| | 2549 | */ |
| | 2550 | int ftdi_set_event_char(struct ftdi_context *ftdi, |
| | 2551 | unsigned char eventch, unsigned char enable) |
| | 2552 | { |
| | 2553 | unsigned short usb_val; |
| | 2554 | |
| | 2555 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2556 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2557 | |
| | 2558 | usb_val = eventch; |
| | 2559 | if (enable) |
| | 2560 | usb_val |= 1 << 8; |
| | 2561 | |
| | 2562 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_EVENT_CHAR_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2563 | ftdi_error_return(-1, "setting event character failed"); |
| | 2564 | |
| | 2565 | return 0; |
| | 2566 | } |
| | 2567 | |
| | 2568 | /** |
| | 2569 | Set error character |
| | 2570 | |
| | 2571 | \param ftdi pointer to ftdi_context |
| | 2572 | \param errorch Error character |
| | 2573 | \param enable 0 to disable the error character, non-zero otherwise |
| | 2574 | |
| | 2575 | \retval 0: all fine |
| | 2576 | \retval -1: unable to set error character |
| | 2577 | \retval -2: USB device unavailable |
| | 2578 | */ |
| | 2579 | int ftdi_set_error_char(struct ftdi_context *ftdi, |
| | 2580 | unsigned char errorch, unsigned char enable) |
| | 2581 | { |
| | 2582 | unsigned short usb_val; |
| | 2583 | |
| | 2584 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 2585 | ftdi_error_return(-2, "USB device unavailable"); |
| | 2586 | |
| | 2587 | usb_val = errorch; |
| | 2588 | if (enable) |
| | 2589 | usb_val |= 1 << 8; |
| | 2590 | |
| | 2591 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_ERROR_CHAR_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 2592 | ftdi_error_return(-1, "setting error character failed"); |
| | 2593 | |
| | 2594 | return 0; |
| | 2595 | } |
| | 2596 | |
| | 2597 | /** |
| | 2598 | Init eeprom with default values for the connected device |
| | 2599 | \param ftdi pointer to ftdi_context |
| | 2600 | \param manufacturer String to use as Manufacturer |
| | 2601 | \param product String to use as Product description |
| | 2602 | \param serial String to use as Serial number description |
| | 2603 | |
| | 2604 | \retval 0: all fine |
| | 2605 | \retval -1: No struct ftdi_context |
| | 2606 | \retval -2: No struct ftdi_eeprom |
| | 2607 | \retval -3: No connected device or device not yet opened |
| | 2608 | */ |
| | 2609 | int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, const char * manufacturer, |
| | 2610 | const char * product, const char * serial) |
| | 2611 | { |
| | 2612 | struct ftdi_eeprom *eeprom; |
| | 2613 | |
| | 2614 | if (ftdi == NULL) |
| | 2615 | ftdi_error_return(-1, "No struct ftdi_context"); |
| | 2616 | |
| | 2617 | if (ftdi->eeprom == NULL) |
| | 2618 | ftdi_error_return(-2,"No struct ftdi_eeprom"); |
| | 2619 | |
| | 2620 | eeprom = ftdi->eeprom; |
| | 2621 | memset(eeprom, 0, sizeof(struct ftdi_eeprom)); |
| | 2622 | |
| | 2623 | if (ftdi->usb_dev == NULL) |
| | 2624 | ftdi_error_return(-3, "No connected device or device not yet opened"); |
| | 2625 | |
| | 2626 | eeprom->vendor_id = 0x0403; |
| | 2627 | eeprom->use_serial = (serial != NULL); |
| | 2628 | if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM) || |
| | 2629 | (ftdi->type == TYPE_R)) |
| | 2630 | eeprom->product_id = 0x6001; |
| | 2631 | else if (ftdi->type == TYPE_4232H) |
| | 2632 | eeprom->product_id = 0x6011; |
| | 2633 | else if (ftdi->type == TYPE_232H) |
| | 2634 | eeprom->product_id = 0x6014; |
| | 2635 | else if (ftdi->type == TYPE_230X) |
| | 2636 | eeprom->product_id = 0x6015; |
| | 2637 | else |
| | 2638 | eeprom->product_id = 0x6010; |
| | 2639 | |
| | 2640 | if (ftdi->type == TYPE_AM) |
| | 2641 | eeprom->usb_version = 0x0101; |
| | 2642 | else |
| | 2643 | eeprom->usb_version = 0x0200; |
| | 2644 | eeprom->max_power = 100; |
| | 2645 | |
| | 2646 | if (eeprom->manufacturer) |
| | 2647 | free (eeprom->manufacturer); |
| | 2648 | eeprom->manufacturer = NULL; |
| | 2649 | if (manufacturer) |
| | 2650 | { |
| | 2651 | eeprom->manufacturer = (char *)malloc(strlen(manufacturer)+1); |
| | 2652 | if (eeprom->manufacturer) |
| | 2653 | strcpy(eeprom->manufacturer, manufacturer); |
| | 2654 | } |
| | 2655 | |
| | 2656 | if (eeprom->product) |
| | 2657 | free (eeprom->product); |
| | 2658 | eeprom->product = NULL; |
| | 2659 | if(product) |
| | 2660 | { |
| | 2661 | eeprom->product = (char *)malloc(strlen(product)+1); |
| | 2662 | if (eeprom->product) |
| | 2663 | strcpy(eeprom->product, product); |
| | 2664 | } |
| | 2665 | else |
| | 2666 | { |
| | 2667 | const char* default_product; |
| | 2668 | switch(ftdi->type) |
| | 2669 | { |
| | 2670 | case TYPE_AM: default_product = "AM"; break; |
| | 2671 | case TYPE_BM: default_product = "BM"; break; |
| | 2672 | case TYPE_2232C: default_product = "Dual RS232"; break; |
| | 2673 | case TYPE_R: default_product = "FT232R USB UART"; break; |
| | 2674 | case TYPE_2232H: default_product = "Dual RS232-HS"; break; |
| | 2675 | case TYPE_4232H: default_product = "FT4232H"; break; |
| | 2676 | case TYPE_232H: default_product = "Single-RS232-HS"; break; |
| | 2677 | case TYPE_230X: default_product = "FT230X Basic UART"; break; |
| | 2678 | default: |
| | 2679 | ftdi_error_return(-3, "Unknown chip type"); |
| | 2680 | } |
| | 2681 | eeprom->product = (char *)malloc(strlen(default_product) +1); |
| | 2682 | if (eeprom->product) |
| | 2683 | strcpy(eeprom->product, default_product); |
| | 2684 | } |
| | 2685 | |
| | 2686 | if (eeprom->serial) |
| | 2687 | free (eeprom->serial); |
| | 2688 | eeprom->serial = NULL; |
| | 2689 | if (serial) |
| | 2690 | { |
| | 2691 | eeprom->serial = (char *)malloc(strlen(serial)+1); |
| | 2692 | if (eeprom->serial) |
| | 2693 | strcpy(eeprom->serial, serial); |
| | 2694 | } |
| | 2695 | |
| | 2696 | if (ftdi->type == TYPE_R) |
| | 2697 | { |
| | 2698 | eeprom->max_power = 90; |
| | 2699 | eeprom->size = 0x80; |
| | 2700 | eeprom->cbus_function[0] = CBUS_TXLED; |
| | 2701 | eeprom->cbus_function[1] = CBUS_RXLED; |
| | 2702 | eeprom->cbus_function[2] = CBUS_TXDEN; |
| | 2703 | eeprom->cbus_function[3] = CBUS_PWREN; |
| | 2704 | eeprom->cbus_function[4] = CBUS_SLEEP; |
| | 2705 | } |
| | 2706 | else if (ftdi->type == TYPE_230X) |
| | 2707 | { |
| | 2708 | eeprom->max_power = 90; |
| | 2709 | eeprom->size = 0x100; |
| | 2710 | eeprom->cbus_function[0] = CBUSX_TXDEN; |
| | 2711 | eeprom->cbus_function[1] = CBUSX_RXLED; |
| | 2712 | eeprom->cbus_function[2] = CBUSX_TXLED; |
| | 2713 | eeprom->cbus_function[3] = CBUSX_SLEEP; |
| | 2714 | } |
| | 2715 | else |
| | 2716 | { |
| | 2717 | if(ftdi->type == TYPE_232H) |
| | 2718 | { |
| | 2719 | int i; |
| | 2720 | for (i=0; i<10; i++) |
| | 2721 | eeprom->cbus_function[i] = CBUSH_TRISTATE; |
| | 2722 | } |
| | 2723 | eeprom->size = -1; |
| | 2724 | } |
| | 2725 | switch (ftdi->type) |
| | 2726 | { |
| | 2727 | case TYPE_AM: |
| | 2728 | eeprom->release_number = 0x0200; |
| | 2729 | break; |
| | 2730 | case TYPE_BM: |
| | 2731 | eeprom->release_number = 0x0400; |
| | 2732 | break; |
| | 2733 | case TYPE_2232C: |
| | 2734 | eeprom->release_number = 0x0500; |
| | 2735 | break; |
| | 2736 | case TYPE_R: |
| | 2737 | eeprom->release_number = 0x0600; |
| | 2738 | break; |
| | 2739 | case TYPE_2232H: |
| | 2740 | eeprom->release_number = 0x0700; |
| | 2741 | break; |
| | 2742 | case TYPE_4232H: |
| | 2743 | eeprom->release_number = 0x0800; |
| | 2744 | break; |
| | 2745 | case TYPE_232H: |
| | 2746 | eeprom->release_number = 0x0900; |
| | 2747 | break; |
| | 2748 | case TYPE_230X: |
| | 2749 | eeprom->release_number = 0x1000; |
| | 2750 | break; |
| | 2751 | default: |
| | 2752 | eeprom->release_number = 0x00; |
| | 2753 | } |
| | 2754 | return 0; |
| | 2755 | } |
| | 2756 | |
| | 2757 | int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, const char * manufacturer, |
| | 2758 | const char * product, const char * serial) |
| | 2759 | { |
| | 2760 | struct ftdi_eeprom *eeprom; |
| | 2761 | |
| | 2762 | if (ftdi == NULL) |
| | 2763 | ftdi_error_return(-1, "No struct ftdi_context"); |
| | 2764 | |
| | 2765 | if (ftdi->eeprom == NULL) |
| | 2766 | ftdi_error_return(-2,"No struct ftdi_eeprom"); |
| | 2767 | |
| | 2768 | eeprom = ftdi->eeprom; |
| | 2769 | |
| | 2770 | if (ftdi->usb_dev == NULL) |
| | 2771 | ftdi_error_return(-3, "No connected device or device not yet opened"); |
| | 2772 | |
| | 2773 | if (manufacturer) |
| | 2774 | { |
| | 2775 | if (eeprom->manufacturer) |
| | 2776 | free (eeprom->manufacturer); |
| | 2777 | eeprom->manufacturer = (char *)malloc(strlen(manufacturer)+1); |
| | 2778 | if (eeprom->manufacturer) |
| | 2779 | strcpy(eeprom->manufacturer, manufacturer); |
| | 2780 | } |
| | 2781 | |
| | 2782 | if(product) |
| | 2783 | { |
| | 2784 | if (eeprom->product) |
| | 2785 | free (eeprom->product); |
| | 2786 | eeprom->product = (char *)malloc(strlen(product)+1); |
| | 2787 | if (eeprom->product) |
| | 2788 | strcpy(eeprom->product, product); |
| | 2789 | } |
| | 2790 | |
| | 2791 | if (serial) |
| | 2792 | { |
| | 2793 | if (eeprom->serial) |
| | 2794 | free (eeprom->serial); |
| | 2795 | eeprom->serial = (char *)malloc(strlen(serial)+1); |
| | 2796 | if (eeprom->serial) |
| | 2797 | { |
| | 2798 | strcpy(eeprom->serial, serial); |
| | 2799 | eeprom->use_serial = 1; |
| | 2800 | } |
| | 2801 | } |
| | 2802 | return 0; |
| | 2803 | } |
| | 2804 | |
| | 2805 | /** |
| | 2806 | Return device ID strings from the eeprom. Device needs to be connected. |
| | 2807 | |
| | 2808 | The parameters manufacturer, description and serial may be NULL |
| | 2809 | or pointer to buffers to store the fetched strings. |
| | 2810 | |
| | 2811 | \param ftdi pointer to ftdi_context |
| | 2812 | \param manufacturer Store manufacturer string here if not NULL |
| | 2813 | \param mnf_len Buffer size of manufacturer string |
| | 2814 | \param product Store product description string here if not NULL |
| | 2815 | \param prod_len Buffer size of product description string |
| | 2816 | \param serial Store serial string here if not NULL |
| | 2817 | \param serial_len Buffer size of serial string |
| | 2818 | |
| | 2819 | \retval 0: all fine |
| | 2820 | \retval -1: ftdi context invalid |
| | 2821 | \retval -2: ftdi eeprom buffer invalid |
| | 2822 | */ |
| | 2823 | int ftdi_eeprom_get_strings(struct ftdi_context *ftdi, |
| | 2824 | char *manufacturer, int mnf_len, |
| | 2825 | char *product, int prod_len, |
| | 2826 | char *serial, int serial_len) |
| | 2827 | { |
| | 2828 | struct ftdi_eeprom *eeprom; |
| | 2829 | |
| | 2830 | if (ftdi == NULL) |
| | 2831 | ftdi_error_return(-1, "No struct ftdi_context"); |
| | 2832 | if (ftdi->eeprom == NULL) |
| | 2833 | ftdi_error_return(-2, "No struct ftdi_eeprom"); |
| | 2834 | |
| | 2835 | eeprom = ftdi->eeprom; |
| | 2836 | |
| | 2837 | if (manufacturer) |
| | 2838 | { |
| | 2839 | strncpy(manufacturer, eeprom->manufacturer, mnf_len); |
| | 2840 | if (mnf_len > 0) |
| | 2841 | manufacturer[mnf_len - 1] = '\0'; |
| | 2842 | } |
| | 2843 | |
| | 2844 | if (product) |
| | 2845 | { |
| | 2846 | strncpy(product, eeprom->product, prod_len); |
| | 2847 | if (prod_len > 0) |
| | 2848 | product[prod_len - 1] = '\0'; |
| | 2849 | } |
| | 2850 | |
| | 2851 | if (serial) |
| | 2852 | { |
| | 2853 | strncpy(serial, eeprom->serial, serial_len); |
| | 2854 | if (serial_len > 0) |
| | 2855 | serial[serial_len - 1] = '\0'; |
| | 2856 | } |
| | 2857 | |
| | 2858 | return 0; |
| | 2859 | } |
| | 2860 | |
| | 2861 | /*FTD2XX doesn't check for values not fitting in the ACBUS Signal options*/ |
| | 2862 | void set_ft232h_cbus(struct ftdi_eeprom *eeprom, unsigned char * output) |
| | 2863 | { |
| | 2864 | int i; |
| | 2865 | for(i=0; i<5; i++) |
| | 2866 | { |
| | 2867 | int mode_low, mode_high; |
| | 2868 | if (eeprom->cbus_function[2*i]> CBUSH_CLK7_5) |
| | 2869 | mode_low = CBUSH_TRISTATE; |
| | 2870 | else |
| | 2871 | mode_low = eeprom->cbus_function[2*i]; |
| | 2872 | if (eeprom->cbus_function[2*i+1]> CBUSH_CLK7_5) |
| | 2873 | mode_high = CBUSH_TRISTATE; |
| | 2874 | else |
| | 2875 | mode_high = eeprom->cbus_function[2*i+1]; |
| | 2876 | |
| | 2877 | output[0x18+i] = (mode_high <<4) | mode_low; |
| | 2878 | } |
| | 2879 | } |
| | 2880 | /* Return the bits for the encoded EEPROM Structure of a requested Mode |
| | 2881 | * |
| | 2882 | */ |
| | 2883 | static unsigned char type2bit(unsigned char type, enum ftdi_chip_type chip) |
| | 2884 | { |
| | 2885 | switch (chip) |
| | 2886 | { |
| | 2887 | case TYPE_2232H: |
| | 2888 | case TYPE_2232C: |
| | 2889 | { |
| | 2890 | switch (type) |
| | 2891 | { |
| | 2892 | case CHANNEL_IS_UART: return 0; |
| | 2893 | case CHANNEL_IS_FIFO: return 0x01; |
| | 2894 | case CHANNEL_IS_OPTO: return 0x02; |
| | 2895 | case CHANNEL_IS_CPU : return 0x04; |
| | 2896 | default: return 0; |
| | 2897 | } |
| | 2898 | } |
| | 2899 | case TYPE_232H: |
| | 2900 | { |
| | 2901 | switch (type) |
| | 2902 | { |
| | 2903 | case CHANNEL_IS_UART : return 0; |
| | 2904 | case CHANNEL_IS_FIFO : return 0x01; |
| | 2905 | case CHANNEL_IS_OPTO : return 0x02; |
| | 2906 | case CHANNEL_IS_CPU : return 0x04; |
| | 2907 | case CHANNEL_IS_FT1284 : return 0x08; |
| | 2908 | default: return 0; |
| | 2909 | } |
| | 2910 | } |
| | 2911 | case TYPE_R: |
| | 2912 | { |
| | 2913 | switch (type) |
| | 2914 | { |
| | 2915 | case CHANNEL_IS_UART : return 0; |
| | 2916 | case CHANNEL_IS_FIFO : return 0x01; |
| | 2917 | default: return 0; |
| | 2918 | } |
| | 2919 | } |
| | 2920 | case TYPE_230X: /* FT230X is only UART */ |
| | 2921 | case TYPE_AM: |
| | 2922 | case TYPE_BM: |
| | 2923 | case TYPE_4232H: |
| | 2924 | default: return 0; |
| | 2925 | } |
| | 2926 | /* fallback */ |
| | 2927 | return 0; |
| | 2928 | } |
| | 2929 | |
| | 2930 | /** |
| | 2931 | Build binary buffer from ftdi_eeprom structure. |
| | 2932 | Output is suitable for ftdi_write_eeprom(). |
| | 2933 | |
| | 2934 | \param ftdi pointer to ftdi_context |
| | 2935 | |
| | 2936 | \retval >=0: size of eeprom user area in bytes |
| | 2937 | \retval -1: eeprom size (128 bytes) exceeded by custom strings |
| | 2938 | \retval -2: Invalid eeprom or ftdi pointer |
| | 2939 | \retval -3: Invalid cbus function setting (FIXME: Not in the code?) |
| | 2940 | \retval -4: Chip doesn't support invert (FIXME: Not in the code?) |
| | 2941 | \retval -5: Chip doesn't support high current drive (FIXME: Not in the code?) |
| | 2942 | \retval -6: No connected EEPROM or EEPROM Type unknown |
| | 2943 | */ |
| | 2944 | int ftdi_eeprom_build(struct ftdi_context *ftdi) |
| | 2945 | { |
| | 2946 | unsigned char i, j, eeprom_size_mask; |
| | 2947 | unsigned short checksum, value; |
| | 2948 | unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; |
| | 2949 | int user_area_size, free_start, free_end; |
| | 2950 | struct ftdi_eeprom *eeprom; |
| | 2951 | unsigned char * output; |
| | 2952 | |
| | 2953 | if (ftdi == NULL) |
| | 2954 | ftdi_error_return(-2,"No context"); |
| | 2955 | if (ftdi->eeprom == NULL) |
| | 2956 | ftdi_error_return(-2,"No eeprom structure"); |
| | 2957 | |
| | 2958 | eeprom= ftdi->eeprom; |
| | 2959 | output = eeprom->buf; |
| | 2960 | |
| | 2961 | if (eeprom->chip == -1) |
| | 2962 | ftdi_error_return(-6,"No connected EEPROM or EEPROM type unknown"); |
| | 2963 | |
| | 2964 | if (eeprom->size == -1) |
| | 2965 | { |
| | 2966 | if ((eeprom->chip == 0x56) || (eeprom->chip == 0x66)) |
| | 2967 | eeprom->size = 0x100; |
| | 2968 | else |
| | 2969 | eeprom->size = 0x80; |
| | 2970 | } |
| | 2971 | |
| | 2972 | if (eeprom->manufacturer != NULL) |
| | 2973 | manufacturer_size = strlen(eeprom->manufacturer); |
| | 2974 | if (eeprom->product != NULL) |
| | 2975 | product_size = strlen(eeprom->product); |
| | 2976 | if (eeprom->serial != NULL) |
| | 2977 | serial_size = strlen(eeprom->serial); |
| | 2978 | |
| | 2979 | // eeprom size check |
| | 2980 | switch (ftdi->type) |
| | 2981 | { |
| | 2982 | case TYPE_AM: |
| | 2983 | case TYPE_BM: |
| | 2984 | case TYPE_R: |
| | 2985 | user_area_size = 96; // base size for strings (total of 48 characters) |
| | 2986 | break; |
| | 2987 | case TYPE_2232C: |
| | 2988 | user_area_size = 90; // two extra config bytes and 4 bytes PnP stuff |
| | 2989 | break; |
| | 2990 | case TYPE_230X: |
| | 2991 | user_area_size = 88; // four extra config bytes + 4 bytes PnP stuff |
| | 2992 | break; |
| | 2993 | case TYPE_2232H: // six extra config bytes + 4 bytes PnP stuff |
| | 2994 | case TYPE_4232H: |
| | 2995 | user_area_size = 86; |
| | 2996 | break; |
| | 2997 | case TYPE_232H: |
| | 2998 | user_area_size = 80; |
| | 2999 | break; |
| | 3000 | default: |
| | 3001 | user_area_size = 0; |
| | 3002 | break; |
| | 3003 | } |
| | 3004 | user_area_size -= (manufacturer_size + product_size + serial_size) * 2; |
| | 3005 | |
| | 3006 | if (user_area_size < 0) |
| | 3007 | ftdi_error_return(-1,"eeprom size exceeded"); |
| | 3008 | |
| | 3009 | // empty eeprom |
| | 3010 | if (ftdi->type == TYPE_230X) |
| | 3011 | { |
| | 3012 | /* FT230X have a reserved section in the middle of the MTP, |
| | 3013 | which cannot be written to, but must be included in the checksum */ |
| | 3014 | memset(ftdi->eeprom->buf, 0, 0x80); |
| | 3015 | memset((ftdi->eeprom->buf + 0xa0), 0, (FTDI_MAX_EEPROM_SIZE - 0xa0)); |
| | 3016 | } |
| | 3017 | else |
| | 3018 | { |
| | 3019 | memset(ftdi->eeprom->buf, 0, FTDI_MAX_EEPROM_SIZE); |
| | 3020 | } |
| | 3021 | |
| | 3022 | // Bytes and Bits set for all Types |
| | 3023 | |
| | 3024 | // Addr 02: Vendor ID |
| | 3025 | output[0x02] = eeprom->vendor_id; |
| | 3026 | output[0x03] = eeprom->vendor_id >> 8; |
| | 3027 | |
| | 3028 | // Addr 04: Product ID |
| | 3029 | output[0x04] = eeprom->product_id; |
| | 3030 | output[0x05] = eeprom->product_id >> 8; |
| | 3031 | |
| | 3032 | // Addr 06: Device release number (0400h for BM features) |
| | 3033 | output[0x06] = eeprom->release_number; |
| | 3034 | output[0x07] = eeprom->release_number >> 8; |
| | 3035 | |
| | 3036 | // Addr 08: Config descriptor |
| | 3037 | // Bit 7: always 1 |
| | 3038 | // Bit 6: 1 if this device is self powered, 0 if bus powered |
| | 3039 | // Bit 5: 1 if this device uses remote wakeup |
| | 3040 | // Bit 4-0: reserved - 0 |
| | 3041 | j = 0x80; |
| | 3042 | if (eeprom->self_powered) |
| | 3043 | j |= 0x40; |
| | 3044 | if (eeprom->remote_wakeup) |
| | 3045 | j |= 0x20; |
| | 3046 | output[0x08] = j; |
| | 3047 | |
| | 3048 | // Addr 09: Max power consumption: max power = value * 2 mA |
| | 3049 | output[0x09] = eeprom->max_power / MAX_POWER_MILLIAMP_PER_UNIT; |
| | 3050 | |
| | 3051 | if ((ftdi->type != TYPE_AM) && (ftdi->type != TYPE_230X)) |
| | 3052 | { |
| | 3053 | // Addr 0A: Chip configuration |
| | 3054 | // Bit 7: 0 - reserved |
| | 3055 | // Bit 6: 0 - reserved |
| | 3056 | // Bit 5: 0 - reserved |
| | 3057 | // Bit 4: 1 - Change USB version |
| | 3058 | // Bit 3: 1 - Use the serial number string |
| | 3059 | // Bit 2: 1 - Enable suspend pull downs for lower power |
| | 3060 | // Bit 1: 1 - Out EndPoint is Isochronous |
| | 3061 | // Bit 0: 1 - In EndPoint is Isochronous |
| | 3062 | // |
| | 3063 | j = 0; |
| | 3064 | if (eeprom->in_is_isochronous) |
| | 3065 | j = j | 1; |
| | 3066 | if (eeprom->out_is_isochronous) |
| | 3067 | j = j | 2; |
| | 3068 | output[0x0A] = j; |
| | 3069 | } |
| | 3070 | |
| | 3071 | // Dynamic content |
| | 3072 | // Strings start at 0x94 (TYPE_AM, TYPE_BM) |
| | 3073 | // 0x96 (TYPE_2232C), 0x98 (TYPE_R) and 0x9a (TYPE_x232H) |
| | 3074 | // 0xa0 (TYPE_232H, TYPE_230X) |
| | 3075 | i = 0; |
| | 3076 | switch (ftdi->type) |
| | 3077 | { |
| | 3078 | case TYPE_2232H: |
| | 3079 | case TYPE_4232H: |
| | 3080 | i += 2; |
| | 3081 | /* Fall through*/ |
| | 3082 | case TYPE_R: |
| | 3083 | i += 2; |
| | 3084 | /* Fall through*/ |
| | 3085 | case TYPE_2232C: |
| | 3086 | i += 2; |
| | 3087 | /* Fall through*/ |
| | 3088 | case TYPE_AM: |
| | 3089 | case TYPE_BM: |
| | 3090 | i += 0x94; |
| | 3091 | break; |
| | 3092 | case TYPE_232H: |
| | 3093 | case TYPE_230X: |
| | 3094 | i = 0xa0; |
| | 3095 | break; |
| | 3096 | } |
| | 3097 | /* Wrap around 0x80 for 128 byte EEPROMS (Internal and 93x46) */ |
| | 3098 | eeprom_size_mask = eeprom->size -1; |
| | 3099 | free_end = i & eeprom_size_mask; |
| | 3100 | |
| | 3101 | // Addr 0E: Offset of the manufacturer string + 0x80, calculated later |
| | 3102 | // Addr 0F: Length of manufacturer string |
| | 3103 | // Output manufacturer |
| | 3104 | output[0x0E] = i; // calculate offset |
| | 3105 | output[i & eeprom_size_mask] = manufacturer_size*2 + 2, i++; |
| | 3106 | output[i & eeprom_size_mask] = 0x03, i++; // type: string |
| | 3107 | for (j = 0; j < manufacturer_size; j++) |
| | 3108 | { |
| | 3109 | output[i & eeprom_size_mask] = eeprom->manufacturer[j], i++; |
| | 3110 | output[i & eeprom_size_mask] = 0x00, i++; |
| | 3111 | } |
| | 3112 | output[0x0F] = manufacturer_size*2 + 2; |
| | 3113 | |
| | 3114 | // Addr 10: Offset of the product string + 0x80, calculated later |
| | 3115 | // Addr 11: Length of product string |
| | 3116 | output[0x10] = i | 0x80; // calculate offset |
| | 3117 | output[i & eeprom_size_mask] = product_size*2 + 2, i++; |
| | 3118 | output[i & eeprom_size_mask] = 0x03, i++; |
| | 3119 | for (j = 0; j < product_size; j++) |
| | 3120 | { |
| | 3121 | output[i & eeprom_size_mask] = eeprom->product[j], i++; |
| | 3122 | output[i & eeprom_size_mask] = 0x00, i++; |
| | 3123 | } |
| | 3124 | output[0x11] = product_size*2 + 2; |
| | 3125 | |
| | 3126 | if (eeprom->use_serial) { |
| | 3127 | // Addr 12: Offset of the serial string + 0x80, calculated later |
| | 3128 | // Addr 13: Length of serial string |
| | 3129 | output[0x12] = i | 0x80; // calculate offset |
| | 3130 | output[i & eeprom_size_mask] = serial_size*2 + 2, i++; |
| | 3131 | output[i & eeprom_size_mask] = 0x03, i++; |
| | 3132 | for (j = 0; j < serial_size; j++) |
| | 3133 | { |
| | 3134 | output[i & eeprom_size_mask] = eeprom->serial[j], i++; |
| | 3135 | output[i & eeprom_size_mask] = 0x00, i++; |
| | 3136 | } |
| | 3137 | output[0x13] = serial_size*2 + 2; |
| | 3138 | } |
| | 3139 | |
| | 3140 | // Legacy port name and PnP fields for FT2232 and newer chips |
| | 3141 | // It doesn't appear when written with FT_Prog for FT4232H chip. |
| | 3142 | if (ftdi->type > TYPE_BM && ftdi->type != TYPE_4232H) |
| | 3143 | { |
| | 3144 | output[i & eeprom_size_mask] = 0x02; /* as seen when written with FTD2XX */ |
| | 3145 | i++; |
| | 3146 | output[i & eeprom_size_mask] = 0x03; /* as seen when written with FTD2XX */ |
| | 3147 | i++; |
| | 3148 | output[i & eeprom_size_mask] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */ |
| | 3149 | i++; |
| | 3150 | output[i & eeprom_size_mask] = 0x00; |
| | 3151 | i++; |
| | 3152 | } |
| | 3153 | |
| | 3154 | if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */ |
| | 3155 | { |
| | 3156 | if (eeprom->use_serial) |
| | 3157 | output[0x0A] |= USE_SERIAL_NUM; |
| | 3158 | else |
| | 3159 | output[0x0A] &= ~USE_SERIAL_NUM; |
| | 3160 | } |
| | 3161 | |
| | 3162 | /* Bytes and Bits specific to (some) types |
| | 3163 | Write linear, as this allows easier fixing */ |
| | 3164 | switch (ftdi->type) |
| | 3165 | { |
| | 3166 | case TYPE_AM: |
| | 3167 | break; |
| | 3168 | case TYPE_BM: |
| | 3169 | output[0x0C] = eeprom->usb_version & 0xff; |
| | 3170 | output[0x0D] = (eeprom->usb_version>>8) & 0xff; |
| | 3171 | if (eeprom->use_usb_version) |
| | 3172 | output[0x0A] |= USE_USB_VERSION_BIT; |
| | 3173 | else |
| | 3174 | output[0x0A] &= ~USE_USB_VERSION_BIT; |
| | 3175 | |
| | 3176 | break; |
| | 3177 | case TYPE_2232C: |
| | 3178 | |
| | 3179 | output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232C); |
| | 3180 | if (eeprom->channel_a_driver) |
| | 3181 | output[0x00] |= DRIVER_VCP; |
| | 3182 | else |
| | 3183 | output[0x00] &= ~DRIVER_VCP; |
| | 3184 | |
| | 3185 | if (eeprom->high_current_a) |
| | 3186 | output[0x00] |= HIGH_CURRENT_DRIVE; |
| | 3187 | else |
| | 3188 | output[0x00] &= ~HIGH_CURRENT_DRIVE; |
| | 3189 | |
| | 3190 | output[0x01] = type2bit(eeprom->channel_b_type, TYPE_2232C); |
| | 3191 | if (eeprom->channel_b_driver) |
| | 3192 | output[0x01] |= DRIVER_VCP; |
| | 3193 | else |
| | 3194 | output[0x01] &= ~DRIVER_VCP; |
| | 3195 | |
| | 3196 | if (eeprom->high_current_b) |
| | 3197 | output[0x01] |= HIGH_CURRENT_DRIVE; |
| | 3198 | else |
| | 3199 | output[0x01] &= ~HIGH_CURRENT_DRIVE; |
| | 3200 | |
| | 3201 | if (eeprom->in_is_isochronous) |
| | 3202 | output[0x0A] |= 0x1; |
| | 3203 | else |
| | 3204 | output[0x0A] &= ~0x1; |
| | 3205 | if (eeprom->out_is_isochronous) |
| | 3206 | output[0x0A] |= 0x2; |
| | 3207 | else |
| | 3208 | output[0x0A] &= ~0x2; |
| | 3209 | if (eeprom->suspend_pull_downs) |
| | 3210 | output[0x0A] |= 0x4; |
| | 3211 | else |
| | 3212 | output[0x0A] &= ~0x4; |
| | 3213 | if (eeprom->use_usb_version) |
| | 3214 | output[0x0A] |= USE_USB_VERSION_BIT; |
| | 3215 | else |
| | 3216 | output[0x0A] &= ~USE_USB_VERSION_BIT; |
| | 3217 | |
| | 3218 | output[0x0C] = eeprom->usb_version & 0xff; |
| | 3219 | output[0x0D] = (eeprom->usb_version>>8) & 0xff; |
| | 3220 | output[0x14] = eeprom->chip; |
| | 3221 | break; |
| | 3222 | case TYPE_R: |
| | 3223 | output[0x00] = type2bit(eeprom->channel_a_type, TYPE_R); |
| | 3224 | if (eeprom->high_current) |
| | 3225 | output[0x00] |= HIGH_CURRENT_DRIVE_R; |
| | 3226 | |
| | 3227 | /* Field is inverted for TYPE_R: Bit 00.3 set to 1 is D2XX, VCP is 0 */ |
| | 3228 | if (eeprom->channel_a_driver) |
| | 3229 | output[0x00] &= ~DRIVER_VCP; |
| | 3230 | else |
| | 3231 | output[0x00] |= DRIVER_VCP; |
| | 3232 | |
| | 3233 | if (eeprom->external_oscillator) |
| | 3234 | output[0x00] |= 0x02; |
| | 3235 | output[0x01] = 0x40; /* Hard coded Endpoint Size */ |
| | 3236 | |
| | 3237 | if (eeprom->suspend_pull_downs) |
| | 3238 | output[0x0A] |= 0x4; |
| | 3239 | else |
| | 3240 | output[0x0A] &= ~0x4; |
| | 3241 | output[0x0B] = eeprom->invert; |
| | 3242 | output[0x0C] = eeprom->usb_version & 0xff; |
| | 3243 | output[0x0D] = (eeprom->usb_version>>8) & 0xff; |
| | 3244 | |
| | 3245 | if (eeprom->cbus_function[0] > CBUS_BB_RD) |
| | 3246 | output[0x14] = CBUS_TXLED; |
| | 3247 | else |
| | 3248 | output[0x14] = eeprom->cbus_function[0]; |
| | 3249 | |
| | 3250 | if (eeprom->cbus_function[1] > CBUS_BB_RD) |
| | 3251 | output[0x14] |= CBUS_RXLED<<4; |
| | 3252 | else |
| | 3253 | output[0x14] |= eeprom->cbus_function[1]<<4; |
| | 3254 | |
| | 3255 | if (eeprom->cbus_function[2] > CBUS_BB_RD) |
| | 3256 | output[0x15] = CBUS_TXDEN; |
| | 3257 | else |
| | 3258 | output[0x15] = eeprom->cbus_function[2]; |
| | 3259 | |
| | 3260 | if (eeprom->cbus_function[3] > CBUS_BB_RD) |
| | 3261 | output[0x15] |= CBUS_PWREN<<4; |
| | 3262 | else |
| | 3263 | output[0x15] |= eeprom->cbus_function[3]<<4; |
| | 3264 | |
| | 3265 | if (eeprom->cbus_function[4] > CBUS_CLK6) |
| | 3266 | output[0x16] = CBUS_SLEEP; |
| | 3267 | else |
| | 3268 | output[0x16] = eeprom->cbus_function[4]; |
| | 3269 | break; |
| | 3270 | case TYPE_2232H: |
| | 3271 | output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232H); |
| | 3272 | if (eeprom->channel_a_driver) |
| | 3273 | output[0x00] |= DRIVER_VCP; |
| | 3274 | else |
| | 3275 | output[0x00] &= ~DRIVER_VCP; |
| | 3276 | |
| | 3277 | output[0x01] = type2bit(eeprom->channel_b_type, TYPE_2232H); |
| | 3278 | if (eeprom->channel_b_driver) |
| | 3279 | output[0x01] |= DRIVER_VCP; |
| | 3280 | else |
| | 3281 | output[0x01] &= ~DRIVER_VCP; |
| | 3282 | |
| | 3283 | if (eeprom->suspend_dbus7) |
| | 3284 | output[0x01] |= SUSPEND_DBUS7_BIT; |
| | 3285 | else |
| | 3286 | output[0x01] &= ~SUSPEND_DBUS7_BIT; |
| | 3287 | |
| | 3288 | if (eeprom->suspend_pull_downs) |
| | 3289 | output[0x0A] |= 0x4; |
| | 3290 | else |
| | 3291 | output[0x0A] &= ~0x4; |
| | 3292 | |
| | 3293 | if (eeprom->group0_drive > DRIVE_16MA) |
| | 3294 | output[0x0c] |= DRIVE_16MA; |
| | 3295 | else |
| | 3296 | output[0x0c] |= eeprom->group0_drive; |
| | 3297 | if (eeprom->group0_schmitt) |
| | 3298 | output[0x0c] |= IS_SCHMITT; |
| | 3299 | if (eeprom->group0_slew) |
| | 3300 | output[0x0c] |= SLOW_SLEW; |
| | 3301 | |
| | 3302 | if (eeprom->group1_drive > DRIVE_16MA) |
| | 3303 | output[0x0c] |= DRIVE_16MA<<4; |
| | 3304 | else |
| | 3305 | output[0x0c] |= eeprom->group1_drive<<4; |
| | 3306 | if (eeprom->group1_schmitt) |
| | 3307 | output[0x0c] |= IS_SCHMITT<<4; |
| | 3308 | if (eeprom->group1_slew) |
| | 3309 | output[0x0c] |= SLOW_SLEW<<4; |
| | 3310 | |
| | 3311 | if (eeprom->group2_drive > DRIVE_16MA) |
| | 3312 | output[0x0d] |= DRIVE_16MA; |
| | 3313 | else |
| | 3314 | output[0x0d] |= eeprom->group2_drive; |
| | 3315 | if (eeprom->group2_schmitt) |
| | 3316 | output[0x0d] |= IS_SCHMITT; |
| | 3317 | if (eeprom->group2_slew) |
| | 3318 | output[0x0d] |= SLOW_SLEW; |
| | 3319 | |
| | 3320 | if (eeprom->group3_drive > DRIVE_16MA) |
| | 3321 | output[0x0d] |= DRIVE_16MA<<4; |
| | 3322 | else |
| | 3323 | output[0x0d] |= eeprom->group3_drive<<4; |
| | 3324 | if (eeprom->group3_schmitt) |
| | 3325 | output[0x0d] |= IS_SCHMITT<<4; |
| | 3326 | if (eeprom->group3_slew) |
| | 3327 | output[0x0d] |= SLOW_SLEW<<4; |
| | 3328 | |
| | 3329 | output[0x18] = eeprom->chip; |
| | 3330 | |
| | 3331 | break; |
| | 3332 | case TYPE_4232H: |
| | 3333 | if (eeprom->channel_a_driver) |
| | 3334 | output[0x00] |= DRIVER_VCP; |
| | 3335 | else |
| | 3336 | output[0x00] &= ~DRIVER_VCP; |
| | 3337 | if (eeprom->channel_b_driver) |
| | 3338 | output[0x01] |= DRIVER_VCP; |
| | 3339 | else |
| | 3340 | output[0x01] &= ~DRIVER_VCP; |
| | 3341 | if (eeprom->channel_c_driver) |
| | 3342 | output[0x00] |= (DRIVER_VCP << 4); |
| | 3343 | else |
| | 3344 | output[0x00] &= ~(DRIVER_VCP << 4); |
| | 3345 | if (eeprom->channel_d_driver) |
| | 3346 | output[0x01] |= (DRIVER_VCP << 4); |
| | 3347 | else |
| | 3348 | output[0x01] &= ~(DRIVER_VCP << 4); |
| | 3349 | |
| | 3350 | if (eeprom->suspend_pull_downs) |
| | 3351 | output[0x0a] |= 0x4; |
| | 3352 | else |
| | 3353 | output[0x0a] &= ~0x4; |
| | 3354 | |
| | 3355 | if (eeprom->channel_a_rs485enable) |
| | 3356 | output[0x0b] |= CHANNEL_IS_RS485 << 0; |
| | 3357 | else |
| | 3358 | output[0x0b] &= ~(CHANNEL_IS_RS485 << 0); |
| | 3359 | if (eeprom->channel_b_rs485enable) |
| | 3360 | output[0x0b] |= CHANNEL_IS_RS485 << 1; |
| | 3361 | else |
| | 3362 | output[0x0b] &= ~(CHANNEL_IS_RS485 << 1); |
| | 3363 | if (eeprom->channel_c_rs485enable) |
| | 3364 | output[0x0b] |= CHANNEL_IS_RS485 << 2; |
| | 3365 | else |
| | 3366 | output[0x0b] &= ~(CHANNEL_IS_RS485 << 2); |
| | 3367 | if (eeprom->channel_d_rs485enable) |
| | 3368 | output[0x0b] |= CHANNEL_IS_RS485 << 3; |
| | 3369 | else |
| | 3370 | output[0x0b] &= ~(CHANNEL_IS_RS485 << 3); |
| | 3371 | |
| | 3372 | if (eeprom->group0_drive > DRIVE_16MA) |
| | 3373 | output[0x0c] |= DRIVE_16MA; |
| | 3374 | else |
| | 3375 | output[0x0c] |= eeprom->group0_drive; |
| | 3376 | if (eeprom->group0_schmitt) |
| | 3377 | output[0x0c] |= IS_SCHMITT; |
| | 3378 | if (eeprom->group0_slew) |
| | 3379 | output[0x0c] |= SLOW_SLEW; |
| | 3380 | |
| | 3381 | if (eeprom->group1_drive > DRIVE_16MA) |
| | 3382 | output[0x0c] |= DRIVE_16MA<<4; |
| | 3383 | else |
| | 3384 | output[0x0c] |= eeprom->group1_drive<<4; |
| | 3385 | if (eeprom->group1_schmitt) |
| | 3386 | output[0x0c] |= IS_SCHMITT<<4; |
| | 3387 | if (eeprom->group1_slew) |
| | 3388 | output[0x0c] |= SLOW_SLEW<<4; |
| | 3389 | |
| | 3390 | if (eeprom->group2_drive > DRIVE_16MA) |
| | 3391 | output[0x0d] |= DRIVE_16MA; |
| | 3392 | else |
| | 3393 | output[0x0d] |= eeprom->group2_drive; |
| | 3394 | if (eeprom->group2_schmitt) |
| | 3395 | output[0x0d] |= IS_SCHMITT; |
| | 3396 | if (eeprom->group2_slew) |
| | 3397 | output[0x0d] |= SLOW_SLEW; |
| | 3398 | |
| | 3399 | if (eeprom->group3_drive > DRIVE_16MA) |
| | 3400 | output[0x0d] |= DRIVE_16MA<<4; |
| | 3401 | else |
| | 3402 | output[0x0d] |= eeprom->group3_drive<<4; |
| | 3403 | if (eeprom->group3_schmitt) |
| | 3404 | output[0x0d] |= IS_SCHMITT<<4; |
| | 3405 | if (eeprom->group3_slew) |
| | 3406 | output[0x0d] |= SLOW_SLEW<<4; |
| | 3407 | |
| | 3408 | output[0x18] = eeprom->chip; |
| | 3409 | |
| | 3410 | break; |
| | 3411 | case TYPE_232H: |
| | 3412 | output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H); |
| | 3413 | if (eeprom->channel_a_driver) |
| | 3414 | output[0x00] |= DRIVER_VCPH; |
| | 3415 | else |
| | 3416 | output[0x00] &= ~DRIVER_VCPH; |
| | 3417 | |
| | 3418 | if (eeprom->powersave) |
| | 3419 | output[0x01] |= POWER_SAVE_DISABLE_H; |
| | 3420 | else |
| | 3421 | output[0x01] &= ~POWER_SAVE_DISABLE_H; |
| | 3422 | |
| | 3423 | if (eeprom->suspend_pull_downs) |
| | 3424 | output[0x0a] |= 0x4; |
| | 3425 | else |
| | 3426 | output[0x0a] &= ~0x4; |
| | 3427 | |
| | 3428 | if (eeprom->clock_polarity) |
| | 3429 | output[0x01] |= FT1284_CLK_IDLE_STATE; |
| | 3430 | else |
| | 3431 | output[0x01] &= ~FT1284_CLK_IDLE_STATE; |
| | 3432 | if (eeprom->data_order) |
| | 3433 | output[0x01] |= FT1284_DATA_LSB; |
| | 3434 | else |
| | 3435 | output[0x01] &= ~FT1284_DATA_LSB; |
| | 3436 | if (eeprom->flow_control) |
| | 3437 | output[0x01] |= FT1284_FLOW_CONTROL; |
| | 3438 | else |
| | 3439 | output[0x01] &= ~FT1284_FLOW_CONTROL; |
| | 3440 | |
| | 3441 | if (eeprom->group0_drive > DRIVE_16MA) |
| | 3442 | output[0x0c] |= DRIVE_16MA; |
| | 3443 | else |
| | 3444 | output[0x0c] |= eeprom->group0_drive; |
| | 3445 | if (eeprom->group0_schmitt) |
| | 3446 | output[0x0c] |= IS_SCHMITT; |
| | 3447 | if (eeprom->group0_slew) |
| | 3448 | output[0x0c] |= SLOW_SLEW; |
| | 3449 | |
| | 3450 | if (eeprom->group1_drive > DRIVE_16MA) |
| | 3451 | output[0x0d] |= DRIVE_16MA; |
| | 3452 | else |
| | 3453 | output[0x0d] |= eeprom->group1_drive; |
| | 3454 | if (eeprom->group1_schmitt) |
| | 3455 | output[0x0d] |= IS_SCHMITT; |
| | 3456 | if (eeprom->group1_slew) |
| | 3457 | output[0x0d] |= SLOW_SLEW; |
| | 3458 | |
| | 3459 | set_ft232h_cbus(eeprom, output); |
| | 3460 | |
| | 3461 | output[0x1e] = eeprom->chip; |
| | 3462 | /* FIXME: Build FT232H specific EEPROM settings */ |
| | 3463 | break; |
| | 3464 | case TYPE_230X: |
| | 3465 | output[0x00] = 0x80; /* Actually, leave the default value */ |
| | 3466 | /*FIXME: Make DBUS & CBUS Control configurable*/ |
| | 3467 | output[0x0c] = 0; /* DBUS drive 4mA, CBUS drive 4mA like factory default */ |
| | 3468 | for (j = 0; j <= 6; j++) |
| | 3469 | { |
| | 3470 | output[0x1a + j] = eeprom->cbus_function[j]; |
| | 3471 | } |
| | 3472 | output[0x0b] = eeprom->invert; |
| | 3473 | break; |
| | 3474 | } |
| | 3475 | |
| | 3476 | /* First address without use */ |
| | 3477 | free_start = 0; |
| | 3478 | switch (ftdi->type) |
| | 3479 | { |
| | 3480 | case TYPE_230X: |
| | 3481 | free_start += 2; |
| | 3482 | /* Fall through*/ |
| | 3483 | case TYPE_232H: |
| | 3484 | free_start += 6; |
| | 3485 | /* Fall through*/ |
| | 3486 | case TYPE_2232H: |
| | 3487 | case TYPE_4232H: |
| | 3488 | free_start += 2; |
| | 3489 | /* Fall through*/ |
| | 3490 | case TYPE_R: |
| | 3491 | free_start += 2; |
| | 3492 | /* Fall through*/ |
| | 3493 | case TYPE_2232C: |
| | 3494 | free_start++; |
| | 3495 | /* Fall through*/ |
| | 3496 | case TYPE_AM: |
| | 3497 | case TYPE_BM: |
| | 3498 | free_start += 0x14; |
| | 3499 | } |
| | 3500 | |
| | 3501 | /* Arbitrary user data */ |
| | 3502 | if (eeprom->user_data && eeprom->user_data_size >= 0) |
| | 3503 | { |
| | 3504 | if (eeprom->user_data_addr < free_start) |
| | 3505 | fprintf(stderr,"Warning, user data starts inside the generated data!\n"); |
| | 3506 | if (eeprom->user_data_addr + eeprom->user_data_size >= free_end) |
| | 3507 | fprintf(stderr,"Warning, user data overlaps the strings area!\n"); |
| | 3508 | if (eeprom->user_data_addr + eeprom->user_data_size > eeprom->size) |
| | 3509 | ftdi_error_return(-1,"eeprom size exceeded"); |
| | 3510 | memcpy(output + eeprom->user_data_addr, eeprom->user_data, eeprom->user_data_size); |
| | 3511 | } |
| | 3512 | |
| | 3513 | // calculate checksum |
| | 3514 | checksum = 0xAAAA; |
| | 3515 | |
| | 3516 | for (i = 0; i < eeprom->size/2-1; i++) |
| | 3517 | { |
| | 3518 | if ((ftdi->type == TYPE_230X) && (i == 0x12)) |
| | 3519 | { |
| | 3520 | /* FT230X has a user section in the MTP which is not part of the checksum */ |
| | 3521 | i = 0x40; |
| | 3522 | } |
| | 3523 | if ((ftdi->type == TYPE_230X) && (i >= 0x40) && (i < 0x50)) { |
| | 3524 | uint16_t data = 0; |
| | 3525 | if (ftdi_read_eeprom_location(ftdi, i, &data)) { |
| | 3526 | fprintf(stderr, "Reading Factory Configuration Data failed\n"); |
| | 3527 | i = 0x50; |
| | 3528 | } |
| | 3529 | value = data; |
| | 3530 | output[i * 2] = data; |
| | 3531 | output[(i * 2) + 1] = data >> 8; |
| | 3532 | } |
| | 3533 | else { |
| | 3534 | value = output[i*2]; |
| | 3535 | value += output[(i*2)+1] << 8; |
| | 3536 | } |
| | 3537 | checksum = value^checksum; |
| | 3538 | checksum = (checksum << 1) | (checksum >> 15); |
| | 3539 | } |
| | 3540 | |
| | 3541 | output[eeprom->size-2] = checksum; |
| | 3542 | output[eeprom->size-1] = checksum >> 8; |
| | 3543 | |
| | 3544 | eeprom->initialized_for_connected_device = 1; |
| | 3545 | return user_area_size; |
| | 3546 | } |
| | 3547 | /* Decode the encoded EEPROM field for the FTDI Mode into a value for the abstracted |
| | 3548 | * EEPROM structure |
| | 3549 | * |
| | 3550 | * FTD2XX doesn't allow to set multiple bits in the interface mode bitfield, and so do we |
| | 3551 | */ |
| | 3552 | static unsigned char bit2type(unsigned char bits) |
| | 3553 | { |
| | 3554 | switch (bits) |
| | 3555 | { |
| | 3556 | case 0: return CHANNEL_IS_UART; |
| | 3557 | case 1: return CHANNEL_IS_FIFO; |
| | 3558 | case 2: return CHANNEL_IS_OPTO; |
| | 3559 | case 4: return CHANNEL_IS_CPU; |
| | 3560 | case 8: return CHANNEL_IS_FT1284; |
| | 3561 | default: |
| | 3562 | fprintf(stderr," Unexpected value %d for Hardware Interface type\n", |
| | 3563 | bits); |
| | 3564 | } |
| | 3565 | return 0; |
| | 3566 | } |
| | 3567 | /* Decode 230X / 232R type chips invert bits |
| | 3568 | * Prints directly to stdout. |
| | 3569 | */ |
| | 3570 | static void print_inverted_bits(int invert) |
| | 3571 | { |
| | 3572 | const char *r_bits[] = {"TXD","RXD","RTS","CTS","DTR","DSR","DCD","RI"}; |
| | 3573 | int i; |
| | 3574 | |
| | 3575 | fprintf(stdout,"Inverted bits:"); |
| | 3576 | for (i=0; i<8; i++) |
| | 3577 | if ((invert & (1<<i)) == (1<<i)) |
| | 3578 | fprintf(stdout," %s",r_bits[i]); |
| | 3579 | |
| | 3580 | fprintf(stdout,"\n"); |
| | 3581 | } |
| | 3582 | /** |
| | 3583 | Decode binary EEPROM image into an ftdi_eeprom structure. |
| | 3584 | |
| | 3585 | For FT-X devices use AN_201 FT-X MTP memory Configuration to decode. |
| | 3586 | |
| | 3587 | \param ftdi pointer to ftdi_context |
| | 3588 | \param verbose Decode EEPROM on stdout |
| | 3589 | |
| | 3590 | \retval 0: all fine |
| | 3591 | \retval -1: something went wrong |
| | 3592 | |
| | 3593 | FIXME: How to pass size? How to handle size field in ftdi_eeprom? |
| | 3594 | FIXME: Strings are malloc'ed here and should be freed somewhere |
| | 3595 | */ |
| | 3596 | int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) |
| | 3597 | { |
| | 3598 | int i, j; |
| | 3599 | unsigned short checksum, eeprom_checksum, value; |
| | 3600 | unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; |
| | 3601 | int eeprom_size; |
| | 3602 | struct ftdi_eeprom *eeprom; |
| | 3603 | unsigned char *buf = NULL; |
| | 3604 | |
| | 3605 | if (ftdi == NULL) |
| | 3606 | ftdi_error_return(-1,"No context"); |
| | 3607 | if (ftdi->eeprom == NULL) |
| | 3608 | ftdi_error_return(-1,"No eeprom structure"); |
| | 3609 | |
| | 3610 | eeprom = ftdi->eeprom; |
| | 3611 | eeprom_size = eeprom->size; |
| | 3612 | buf = ftdi->eeprom->buf; |
| | 3613 | |
| | 3614 | // Addr 02: Vendor ID |
| | 3615 | eeprom->vendor_id = buf[0x02] + (buf[0x03] << 8); |
| | 3616 | |
| | 3617 | // Addr 04: Product ID |
| | 3618 | eeprom->product_id = buf[0x04] + (buf[0x05] << 8); |
| | 3619 | |
| | 3620 | // Addr 06: Device release number |
| | 3621 | eeprom->release_number = buf[0x06] + (buf[0x07]<<8); |
| | 3622 | |
| | 3623 | // Addr 08: Config descriptor |
| | 3624 | // Bit 7: always 1 |
| | 3625 | // Bit 6: 1 if this device is self powered, 0 if bus powered |
| | 3626 | // Bit 5: 1 if this device uses remote wakeup |
| | 3627 | eeprom->self_powered = !!(buf[0x08] & 0x40); |
| | 3628 | eeprom->remote_wakeup = !!(buf[0x08] & 0x20); |
| | 3629 | |
| | 3630 | // Addr 09: Max power consumption: max power = value * 2 mA |
| | 3631 | eeprom->max_power = MAX_POWER_MILLIAMP_PER_UNIT * buf[0x09]; |
| | 3632 | |
| | 3633 | // Addr 0A: Chip configuration |
| | 3634 | // Bit 7: 0 - reserved |
| | 3635 | // Bit 6: 0 - reserved |
| | 3636 | // Bit 5: 0 - reserved |
| | 3637 | // Bit 4: 1 - Change USB version on BM and 2232C |
| | 3638 | // Bit 3: 1 - Use the serial number string |
| | 3639 | // Bit 2: 1 - Enable suspend pull downs for lower power |
| | 3640 | // Bit 1: 1 - Out EndPoint is Isochronous |
| | 3641 | // Bit 0: 1 - In EndPoint is Isochronous |
| | 3642 | // |
| | 3643 | eeprom->in_is_isochronous = !!(buf[0x0A]&0x01); |
| | 3644 | eeprom->out_is_isochronous = !!(buf[0x0A]&0x02); |
| | 3645 | eeprom->suspend_pull_downs = !!(buf[0x0A]&0x04); |
| | 3646 | eeprom->use_serial = !!(buf[0x0A] & USE_SERIAL_NUM); |
| | 3647 | eeprom->use_usb_version = !!(buf[0x0A] & USE_USB_VERSION_BIT); |
| | 3648 | |
| | 3649 | // Addr 0C: USB version low byte when 0x0A |
| | 3650 | // Addr 0D: USB version high byte when 0x0A |
| | 3651 | eeprom->usb_version = buf[0x0C] + (buf[0x0D] << 8); |
| | 3652 | |
| | 3653 | // Addr 0E: Offset of the manufacturer string + 0x80, calculated later |
| | 3654 | // Addr 0F: Length of manufacturer string |
| | 3655 | manufacturer_size = buf[0x0F]/2; |
| | 3656 | if (eeprom->manufacturer) |
| | 3657 | free(eeprom->manufacturer); |
| | 3658 | if (manufacturer_size > 0) |
| | 3659 | { |
| | 3660 | eeprom->manufacturer = (char *)malloc(manufacturer_size); |
| | 3661 | if (eeprom->manufacturer) |
| | 3662 | { |
| | 3663 | // Decode manufacturer |
| | 3664 | i = buf[0x0E] & (eeprom_size -1); // offset |
| | 3665 | for (j=0; j<manufacturer_size-1; j++) |
| | 3666 | { |
| | 3667 | eeprom->manufacturer[j] = buf[2*j+i+2]; |
| | 3668 | } |
| | 3669 | eeprom->manufacturer[j] = '\0'; |
| | 3670 | } |
| | 3671 | } |
| | 3672 | else eeprom->manufacturer = NULL; |
| | 3673 | |
| | 3674 | // Addr 10: Offset of the product string + 0x80, calculated later |
| | 3675 | // Addr 11: Length of product string |
| | 3676 | if (eeprom->product) |
| | 3677 | free(eeprom->product); |
| | 3678 | product_size = buf[0x11]/2; |
| | 3679 | if (product_size > 0) |
| | 3680 | { |
| | 3681 | eeprom->product = (char *)malloc(product_size); |
| | 3682 | if (eeprom->product) |
| | 3683 | { |
| | 3684 | // Decode product name |
| | 3685 | i = buf[0x10] & (eeprom_size -1); // offset |
| | 3686 | for (j=0; j<product_size-1; j++) |
| | 3687 | { |
| | 3688 | eeprom->product[j] = buf[2*j+i+2]; |
| | 3689 | } |
| | 3690 | eeprom->product[j] = '\0'; |
| | 3691 | } |
| | 3692 | } |
| | 3693 | else eeprom->product = NULL; |
| | 3694 | |
| | 3695 | // Addr 12: Offset of the serial string + 0x80, calculated later |
| | 3696 | // Addr 13: Length of serial string |
| | 3697 | if (eeprom->serial) |
| | 3698 | free(eeprom->serial); |
| | 3699 | serial_size = buf[0x13]/2; |
| | 3700 | if (serial_size > 0) |
| | 3701 | { |
| | 3702 | eeprom->serial = (char *)malloc(serial_size); |
| | 3703 | if (eeprom->serial) |
| | 3704 | { |
| | 3705 | // Decode serial |
| | 3706 | i = buf[0x12] & (eeprom_size -1); // offset |
| | 3707 | for (j=0; j<serial_size-1; j++) |
| | 3708 | { |
| | 3709 | eeprom->serial[j] = buf[2*j+i+2]; |
| | 3710 | } |
| | 3711 | eeprom->serial[j] = '\0'; |
| | 3712 | } |
| | 3713 | } |
| | 3714 | else eeprom->serial = NULL; |
| | 3715 | |
| | 3716 | // verify checksum |
| | 3717 | checksum = 0xAAAA; |
| | 3718 | |
| | 3719 | for (i = 0; i < eeprom_size/2-1; i++) |
| | 3720 | { |
| | 3721 | if ((ftdi->type == TYPE_230X) && (i == 0x12)) |
| | 3722 | { |
| | 3723 | /* FT230X has a user section in the MTP which is not part of the checksum */ |
| | 3724 | i = 0x40; |
| | 3725 | } |
| | 3726 | value = buf[i*2]; |
| | 3727 | value += buf[(i*2)+1] << 8; |
| | 3728 | |
| | 3729 | checksum = value^checksum; |
| | 3730 | checksum = (checksum << 1) | (checksum >> 15); |
| | 3731 | } |
| | 3732 | |
| | 3733 | eeprom_checksum = buf[eeprom_size-2] + (buf[eeprom_size-1] << 8); |
| | 3734 | |
| | 3735 | if (eeprom_checksum != checksum) |
| | 3736 | { |
| | 3737 | fprintf(stderr, "Checksum Error: %04x %04x\n", checksum, eeprom_checksum); |
| | 3738 | ftdi_error_return(-1,"EEPROM checksum error"); |
| | 3739 | } |
| | 3740 | |
| | 3741 | eeprom->channel_a_type = 0; |
| | 3742 | if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM)) |
| | 3743 | { |
| | 3744 | eeprom->chip = -1; |
| | 3745 | } |
| | 3746 | else if (ftdi->type == TYPE_2232C) |
| | 3747 | { |
| | 3748 | eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); |
| | 3749 | eeprom->channel_a_driver = !!(buf[0x00] & DRIVER_VCP); |
| | 3750 | eeprom->high_current_a = !!(buf[0x00] & HIGH_CURRENT_DRIVE); |
| | 3751 | eeprom->channel_b_type = buf[0x01] & 0x7; |
| | 3752 | eeprom->channel_b_driver = !!(buf[0x01] & DRIVER_VCP); |
| | 3753 | eeprom->high_current_b = !!(buf[0x01] & HIGH_CURRENT_DRIVE); |
| | 3754 | eeprom->chip = buf[0x14]; |
| | 3755 | } |
| | 3756 | else if (ftdi->type == TYPE_R) |
| | 3757 | { |
| | 3758 | /* TYPE_R flags D2XX, not VCP as all others */ |
| | 3759 | eeprom->channel_a_driver = !(buf[0x00] & DRIVER_VCP); /* note: inverted flag, use a single NOT */ |
| | 3760 | eeprom->high_current = !!(buf[0x00] & HIGH_CURRENT_DRIVE_R); |
| | 3761 | eeprom->external_oscillator = !!(buf[0x00] & 0x02); |
| | 3762 | if ( (buf[0x01]&0x40) != 0x40) |
| | 3763 | fprintf(stderr, |
| | 3764 | "TYPE_R EEPROM byte[0x01] Bit 6 unexpected Endpoint size." |
| | 3765 | " If this happened with the\n" |
| | 3766 | " EEPROM programmed by FTDI tools, please report " |
| | 3767 | "to libftdi@developer.intra2net.com\n"); |
| | 3768 | |
| | 3769 | eeprom->chip = buf[0x16]; |
| | 3770 | // Addr 0B: Invert data lines |
| | 3771 | // Works only on FT232R, not FT245R, but no way to distinguish |
| | 3772 | eeprom->invert = buf[0x0B]; /* note: not a bitflag */ |
| | 3773 | // Addr 14: CBUS function: CBUS0, CBUS1 |
| | 3774 | // Addr 15: CBUS function: CBUS2, CBUS3 |
| | 3775 | // Addr 16: CBUS function: CBUS5 |
| | 3776 | eeprom->cbus_function[0] = buf[0x14] & 0x0f; |
| | 3777 | eeprom->cbus_function[1] = (buf[0x14] >> 4) & 0x0f; |
| | 3778 | eeprom->cbus_function[2] = buf[0x15] & 0x0f; |
| | 3779 | eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f; |
| | 3780 | eeprom->cbus_function[4] = buf[0x16] & 0x0f; |
| | 3781 | } |
| | 3782 | else if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) |
| | 3783 | { |
| | 3784 | eeprom->channel_a_driver = !!(buf[0x00] & DRIVER_VCP); |
| | 3785 | eeprom->channel_b_driver = !!(buf[0x01] & DRIVER_VCP); |
| | 3786 | |
| | 3787 | if (ftdi->type == TYPE_2232H) |
| | 3788 | { |
| | 3789 | eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); |
| | 3790 | eeprom->channel_b_type = bit2type(buf[0x01] & 0x7); |
| | 3791 | eeprom->suspend_dbus7 = !!(buf[0x01] & SUSPEND_DBUS7_BIT); |
| | 3792 | } |
| | 3793 | else |
| | 3794 | { |
| | 3795 | eeprom->channel_c_driver = !!((buf[0x00] >> 4) & DRIVER_VCP); |
| | 3796 | eeprom->channel_d_driver = !!((buf[0x01] >> 4) & DRIVER_VCP); |
| | 3797 | eeprom->channel_a_rs485enable = !!(buf[0x0b] & (CHANNEL_IS_RS485 << 0)); |
| | 3798 | eeprom->channel_b_rs485enable = !!(buf[0x0b] & (CHANNEL_IS_RS485 << 1)); |
| | 3799 | eeprom->channel_c_rs485enable = !!(buf[0x0b] & (CHANNEL_IS_RS485 << 2)); |
| | 3800 | eeprom->channel_d_rs485enable = !!(buf[0x0b] & (CHANNEL_IS_RS485 << 3)); |
| | 3801 | } |
| | 3802 | |
| | 3803 | eeprom->chip = buf[0x18]; |
| | 3804 | eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; /* not a bitflag */ |
| | 3805 | eeprom->group0_schmitt = !!(buf[0x0c] & IS_SCHMITT); |
| | 3806 | eeprom->group0_slew = !!(buf[0x0c] & SLOW_SLEW); |
| | 3807 | eeprom->group1_drive = (buf[0x0c] >> 4) & DRIVE_16MA; /* not a bitflag */ |
| | 3808 | eeprom->group1_schmitt = !!((buf[0x0c] >> 4) & IS_SCHMITT); |
| | 3809 | eeprom->group1_slew = !!((buf[0x0c] >> 4) & SLOW_SLEW); |
| | 3810 | eeprom->group2_drive = buf[0x0d] & DRIVE_16MA; /* not a bitflag */ |
| | 3811 | eeprom->group2_schmitt = !!(buf[0x0d] & IS_SCHMITT); |
| | 3812 | eeprom->group2_slew = !!(buf[0x0d] & SLOW_SLEW); |
| | 3813 | eeprom->group3_drive = (buf[0x0d] >> 4) & DRIVE_16MA; /* not a bitflag */ |
| | 3814 | eeprom->group3_schmitt = !!((buf[0x0d] >> 4) & IS_SCHMITT); |
| | 3815 | eeprom->group3_slew = !!((buf[0x0d] >> 4) & SLOW_SLEW); |
| | 3816 | } |
| | 3817 | else if (ftdi->type == TYPE_232H) |
| | 3818 | { |
| | 3819 | eeprom->channel_a_type = buf[0x00] & 0xf; |
| | 3820 | eeprom->channel_a_driver = !!(buf[0x00] & DRIVER_VCPH); |
| | 3821 | eeprom->clock_polarity = !!(buf[0x01] & FT1284_CLK_IDLE_STATE); |
| | 3822 | eeprom->data_order = !!(buf[0x01] & FT1284_DATA_LSB); |
| | 3823 | eeprom->flow_control = !!(buf[0x01] & FT1284_FLOW_CONTROL); |
| | 3824 | eeprom->powersave = !!(buf[0x01] & POWER_SAVE_DISABLE_H); |
| | 3825 | eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; /* not a bitflag */ |
| | 3826 | eeprom->group0_schmitt = !!(buf[0x0c] & IS_SCHMITT); |
| | 3827 | eeprom->group0_slew = !!(buf[0x0c] & SLOW_SLEW); |
| | 3828 | eeprom->group1_drive = buf[0x0d] & DRIVE_16MA; /* not a bitflag */ |
| | 3829 | eeprom->group1_schmitt = !!(buf[0x0d] & IS_SCHMITT); |
| | 3830 | eeprom->group1_slew = !!(buf[0x0d] & SLOW_SLEW); |
| | 3831 | |
| | 3832 | for(i=0; i<5; i++) |
| | 3833 | { |
| | 3834 | eeprom->cbus_function[2*i ] = buf[0x18+i] & 0x0f; |
| | 3835 | eeprom->cbus_function[2*i+1] = (buf[0x18+i] >> 4) & 0x0f; |
| | 3836 | } |
| | 3837 | eeprom->chip = buf[0x1e]; |
| | 3838 | /*FIXME: Decipher more values*/ |
| | 3839 | } |
| | 3840 | else if (ftdi->type == TYPE_230X) |
| | 3841 | { |
| | 3842 | for(i=0; i<4; i++) |
| | 3843 | { |
| | 3844 | eeprom->cbus_function[i] = buf[0x1a + i] & 0xFF; |
| | 3845 | } |
| | 3846 | eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; /* not a bitflag */ |
| | 3847 | eeprom->group0_schmitt = !!(buf[0x0c] & IS_SCHMITT); |
| | 3848 | eeprom->group0_slew = !!(buf[0x0c] & SLOW_SLEW); |
| | 3849 | eeprom->group1_drive = (buf[0x0c] >> 4) & DRIVE_16MA; /* not a bitflag */ |
| | 3850 | eeprom->group1_schmitt = !!((buf[0x0c] >> 4) & IS_SCHMITT); |
| | 3851 | eeprom->group1_slew = !!((buf[0x0c] >> 4) & SLOW_SLEW); |
| | 3852 | |
| | 3853 | eeprom->invert = buf[0xb]; /* not a bitflag */ |
| | 3854 | } |
| | 3855 | |
| | 3856 | if (verbose) |
| | 3857 | { |
| | 3858 | const char *channel_mode[] = {"UART", "FIFO", "CPU", "OPTO", "FT1284"}; |
| | 3859 | fprintf(stdout, "VID: 0x%04x\n",eeprom->vendor_id); |
| | 3860 | fprintf(stdout, "PID: 0x%04x\n",eeprom->product_id); |
| | 3861 | fprintf(stdout, "Release: 0x%04x\n",eeprom->release_number); |
| | 3862 | |
| | 3863 | if (eeprom->self_powered) |
| | 3864 | fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n"); |
| | 3865 | else |
| | 3866 | fprintf(stdout, "Bus Powered: %3d mA%s", eeprom->max_power, |
| | 3867 | (eeprom->remote_wakeup)?" USB Remote Wake Up\n":"\n"); |
| | 3868 | if (eeprom->manufacturer) |
| | 3869 | fprintf(stdout, "Manufacturer: %s\n",eeprom->manufacturer); |
| | 3870 | if (eeprom->product) |
| | 3871 | fprintf(stdout, "Product: %s\n",eeprom->product); |
| | 3872 | if (eeprom->serial) |
| | 3873 | fprintf(stdout, "Serial: %s\n",eeprom->serial); |
| | 3874 | fprintf(stdout, "Checksum : %04x\n", checksum); |
| | 3875 | if (ftdi->type == TYPE_R) { |
| | 3876 | fprintf(stdout, "Internal EEPROM\n"); |
| | 3877 | fprintf(stdout,"Oscillator: %s\n", eeprom->external_oscillator?"External":"Internal"); |
| | 3878 | } |
| | 3879 | else if (eeprom->chip >= 0x46) |
| | 3880 | fprintf(stdout, "Attached EEPROM: 93x%02x\n", eeprom->chip); |
| | 3881 | if (eeprom->suspend_dbus7) |
| | 3882 | fprintf(stdout, "Suspend on DBUS7\n"); |
| | 3883 | if (eeprom->suspend_pull_downs) |
| | 3884 | fprintf(stdout, "Pull IO pins low during suspend\n"); |
| | 3885 | if(eeprom->powersave) |
| | 3886 | { |
| | 3887 | if(ftdi->type >= TYPE_232H) |
| | 3888 | fprintf(stdout,"Enter low power state on ACBUS7\n"); |
| | 3889 | } |
| | 3890 | if (eeprom->remote_wakeup) |
| | 3891 | fprintf(stdout, "Enable Remote Wake Up\n"); |
| | 3892 | fprintf(stdout, "PNP: %d\n",(eeprom->is_not_pnp)?0:1); |
| | 3893 | if (ftdi->type >= TYPE_2232C) |
| | 3894 | fprintf(stdout,"Channel A has Mode %s%s%s\n", |
| | 3895 | channel_mode[eeprom->channel_a_type], |
| | 3896 | (eeprom->channel_a_driver)?" VCP":"", |
| | 3897 | (eeprom->high_current_a)?" High Current IO":""); |
| | 3898 | if (ftdi->type == TYPE_232H) |
| | 3899 | { |
| | 3900 | fprintf(stdout,"FT1284 Mode Clock is idle %s, %s first, %sFlow Control\n", |
| | 3901 | (eeprom->clock_polarity)?"HIGH":"LOW", |
| | 3902 | (eeprom->data_order)?"LSB":"MSB", |
| | 3903 | (eeprom->flow_control)?"":"No "); |
| | 3904 | } |
| | 3905 | if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_2232C)) |
| | 3906 | fprintf(stdout,"Channel B has Mode %s%s%s\n", |
| | 3907 | channel_mode[eeprom->channel_b_type], |
| | 3908 | (eeprom->channel_b_driver)?" VCP":"", |
| | 3909 | (eeprom->high_current_b)?" High Current IO":""); |
| | 3910 | if (ftdi->type == TYPE_4232H) |
| | 3911 | { |
| | 3912 | fprintf(stdout,"Channel C has Mode UART%s\n", |
| | 3913 | (eeprom->channel_c_driver)?" VCP":""); |
| | 3914 | fprintf(stdout,"Channel D has Mode UART%s\n", |
| | 3915 | (eeprom->channel_d_driver)?" VCP":""); |
| | 3916 | } |
| | 3917 | if (((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C)) && |
| | 3918 | eeprom->use_usb_version) |
| | 3919 | fprintf(stdout,"Use explicit USB Version %04x\n",eeprom->usb_version); |
| | 3920 | |
| | 3921 | if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) |
| | 3922 | { |
| | 3923 | fprintf(stdout,"%s has %d mA drive%s%s\n", |
| | 3924 | (ftdi->type == TYPE_2232H)?"AL":"A", |
| | 3925 | (eeprom->group0_drive+1) *4, |
| | 3926 | (eeprom->group0_schmitt)?" Schmitt Input":"", |
| | 3927 | (eeprom->group0_slew)?" Slow Slew":""); |
| | 3928 | fprintf(stdout,"%s has %d mA drive%s%s\n", |
| | 3929 | (ftdi->type == TYPE_2232H)?"AH":"B", |
| | 3930 | (eeprom->group1_drive+1) *4, |
| | 3931 | (eeprom->group1_schmitt)?" Schmitt Input":"", |
| | 3932 | (eeprom->group1_slew)?" Slow Slew":""); |
| | 3933 | fprintf(stdout,"%s has %d mA drive%s%s\n", |
| | 3934 | (ftdi->type == TYPE_2232H)?"BL":"C", |
| | 3935 | (eeprom->group2_drive+1) *4, |
| | 3936 | (eeprom->group2_schmitt)?" Schmitt Input":"", |
| | 3937 | (eeprom->group2_slew)?" Slow Slew":""); |
| | 3938 | fprintf(stdout,"%s has %d mA drive%s%s\n", |
| | 3939 | (ftdi->type == TYPE_2232H)?"BH":"D", |
| | 3940 | (eeprom->group3_drive+1) *4, |
| | 3941 | (eeprom->group3_schmitt)?" Schmitt Input":"", |
| | 3942 | (eeprom->group3_slew)?" Slow Slew":""); |
| | 3943 | } |
| | 3944 | else if (ftdi->type == TYPE_232H) |
| | 3945 | { |
| | 3946 | const char *cbush_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN", |
| | 3947 | "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN", |
| | 3948 | "CLK30","CLK15","CLK7_5" |
| | 3949 | }; |
| | 3950 | fprintf(stdout,"ACBUS has %d mA drive%s%s\n", |
| | 3951 | (eeprom->group0_drive+1) *4, |
| | 3952 | (eeprom->group0_schmitt)?" Schmitt Input":"", |
| | 3953 | (eeprom->group0_slew)?" Slow Slew":""); |
| | 3954 | fprintf(stdout,"ADBUS has %d mA drive%s%s\n", |
| | 3955 | (eeprom->group1_drive+1) *4, |
| | 3956 | (eeprom->group1_schmitt)?" Schmitt Input":"", |
| | 3957 | (eeprom->group1_slew)?" Slow Slew":""); |
| | 3958 | for (i=0; i<10; i++) |
| | 3959 | { |
| | 3960 | if (eeprom->cbus_function[i]<= CBUSH_CLK7_5 ) |
| | 3961 | fprintf(stdout,"C%d Function: %s\n", i, |
| | 3962 | cbush_mux[eeprom->cbus_function[i]]); |
| | 3963 | } |
| | 3964 | } |
| | 3965 | else if (ftdi->type == TYPE_230X) |
| | 3966 | { |
| | 3967 | const char *cbusx_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN", |
| | 3968 | "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN", |
| | 3969 | "CLK24","CLK12","CLK6","BAT_DETECT","BAT_DETECT#", |
| | 3970 | "I2C_TXE#", "I2C_RXF#", "VBUS_SENSE", "BB_WR#", |
| | 3971 | "BBRD#", "TIME_STAMP", "AWAKE#", |
| | 3972 | }; |
| | 3973 | fprintf(stdout,"DBUS has %d mA drive%s%s\n", |
| | 3974 | (eeprom->group0_drive+1) *4, |
| | 3975 | (eeprom->group0_schmitt)?" Schmitt Input":"", |
| | 3976 | (eeprom->group0_slew)?" Slow Slew":""); |
| | 3977 | fprintf(stdout,"CBUS has %d mA drive%s%s\n", |
| | 3978 | (eeprom->group1_drive+1) *4, |
| | 3979 | (eeprom->group1_schmitt)?" Schmitt Input":"", |
| | 3980 | (eeprom->group1_slew)?" Slow Slew":""); |
| | 3981 | for (i=0; i<4; i++) |
| | 3982 | { |
| | 3983 | if (eeprom->cbus_function[i]<= CBUSX_AWAKE) |
| | 3984 | fprintf(stdout,"CBUS%d Function: %s\n", i, cbusx_mux[eeprom->cbus_function[i]]); |
| | 3985 | } |
| | 3986 | |
| | 3987 | if (eeprom->invert) |
| | 3988 | print_inverted_bits(eeprom->invert); |
| | 3989 | } |
| | 3990 | |
| | 3991 | if (ftdi->type == TYPE_R) |
| | 3992 | { |
| | 3993 | const char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED", |
| | 3994 | "SLEEP","CLK48","CLK24","CLK12","CLK6", |
| | 3995 | "IOMODE","BB_WR","BB_RD" |
| | 3996 | }; |
| | 3997 | const char *cbus_BB[] = {"RXF","TXE","RD", "WR"}; |
| | 3998 | |
| | 3999 | if (eeprom->invert) |
| | 4000 | print_inverted_bits(eeprom->invert); |
| | 4001 | |
| | 4002 | for (i=0; i<5; i++) |
| | 4003 | { |
| | 4004 | if (eeprom->cbus_function[i]<=CBUS_BB_RD) |
| | 4005 | fprintf(stdout,"C%d Function: %s\n", i, |
| | 4006 | cbus_mux[eeprom->cbus_function[i]]); |
| | 4007 | else |
| | 4008 | { |
| | 4009 | if (i < 4) |
| | 4010 | /* Running MPROG show that C0..3 have fixed function Synchronous |
| | 4011 | Bit Bang mode */ |
| | 4012 | fprintf(stdout,"C%d BB Function: %s\n", i, |
| | 4013 | cbus_BB[i]); |
| | 4014 | else |
| | 4015 | fprintf(stdout, "Unknown CBUS mode. Might be special mode?\n"); |
| | 4016 | } |
| | 4017 | } |
| | 4018 | } |
| | 4019 | } |
| | 4020 | return 0; |
| | 4021 | } |
| | 4022 | |
| | 4023 | /** |
| | 4024 | Get a value from the decoded EEPROM structure |
| | 4025 | |
| | 4026 | \param ftdi pointer to ftdi_context |
| | 4027 | \param value_name Enum of the value to query |
| | 4028 | \param value Pointer to store read value |
| | 4029 | |
| | 4030 | \retval 0: all fine |
| | 4031 | \retval -1: Value doesn't exist |
| | 4032 | */ |
| | 4033 | int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int* value) |
| | 4034 | { |
| | 4035 | switch (value_name) |
| | 4036 | { |
| | 4037 | case VENDOR_ID: |
| | 4038 | *value = ftdi->eeprom->vendor_id; |
| | 4039 | break; |
| | 4040 | case PRODUCT_ID: |
| | 4041 | *value = ftdi->eeprom->product_id; |
| | 4042 | break; |
| | 4043 | case RELEASE_NUMBER: |
| | 4044 | *value = ftdi->eeprom->release_number; |
| | 4045 | break; |
| | 4046 | case SELF_POWERED: |
| | 4047 | *value = ftdi->eeprom->self_powered; |
| | 4048 | break; |
| | 4049 | case REMOTE_WAKEUP: |
| | 4050 | *value = ftdi->eeprom->remote_wakeup; |
| | 4051 | break; |
| | 4052 | case IS_NOT_PNP: |
| | 4053 | *value = ftdi->eeprom->is_not_pnp; |
| | 4054 | break; |
| | 4055 | case SUSPEND_DBUS7: |
| | 4056 | *value = ftdi->eeprom->suspend_dbus7; |
| | 4057 | break; |
| | 4058 | case IN_IS_ISOCHRONOUS: |
| | 4059 | *value = ftdi->eeprom->in_is_isochronous; |
| | 4060 | break; |
| | 4061 | case OUT_IS_ISOCHRONOUS: |
| | 4062 | *value = ftdi->eeprom->out_is_isochronous; |
| | 4063 | break; |
| | 4064 | case SUSPEND_PULL_DOWNS: |
| | 4065 | *value = ftdi->eeprom->suspend_pull_downs; |
| | 4066 | break; |
| | 4067 | case USE_SERIAL: |
| | 4068 | *value = ftdi->eeprom->use_serial; |
| | 4069 | break; |
| | 4070 | case USB_VERSION: |
| | 4071 | *value = ftdi->eeprom->usb_version; |
| | 4072 | break; |
| | 4073 | case USE_USB_VERSION: |
| | 4074 | *value = ftdi->eeprom->use_usb_version; |
| | 4075 | break; |
| | 4076 | case MAX_POWER: |
| | 4077 | *value = ftdi->eeprom->max_power; |
| | 4078 | break; |
| | 4079 | case CHANNEL_A_TYPE: |
| | 4080 | *value = ftdi->eeprom->channel_a_type; |
| | 4081 | break; |
| | 4082 | case CHANNEL_B_TYPE: |
| | 4083 | *value = ftdi->eeprom->channel_b_type; |
| | 4084 | break; |
| | 4085 | case CHANNEL_A_DRIVER: |
| | 4086 | *value = ftdi->eeprom->channel_a_driver; |
| | 4087 | break; |
| | 4088 | case CHANNEL_B_DRIVER: |
| | 4089 | *value = ftdi->eeprom->channel_b_driver; |
| | 4090 | break; |
| | 4091 | case CHANNEL_C_DRIVER: |
| | 4092 | *value = ftdi->eeprom->channel_c_driver; |
| | 4093 | break; |
| | 4094 | case CHANNEL_D_DRIVER: |
| | 4095 | *value = ftdi->eeprom->channel_d_driver; |
| | 4096 | break; |
| | 4097 | case CHANNEL_A_RS485: |
| | 4098 | *value = ftdi->eeprom->channel_a_rs485enable; |
| | 4099 | break; |
| | 4100 | case CHANNEL_B_RS485: |
| | 4101 | *value = ftdi->eeprom->channel_b_rs485enable; |
| | 4102 | break; |
| | 4103 | case CHANNEL_C_RS485: |
| | 4104 | *value = ftdi->eeprom->channel_c_rs485enable; |
| | 4105 | break; |
| | 4106 | case CHANNEL_D_RS485: |
| | 4107 | *value = ftdi->eeprom->channel_d_rs485enable; |
| | 4108 | break; |
| | 4109 | case CBUS_FUNCTION_0: |
| | 4110 | *value = ftdi->eeprom->cbus_function[0]; |
| | 4111 | break; |
| | 4112 | case CBUS_FUNCTION_1: |
| | 4113 | *value = ftdi->eeprom->cbus_function[1]; |
| | 4114 | break; |
| | 4115 | case CBUS_FUNCTION_2: |
| | 4116 | *value = ftdi->eeprom->cbus_function[2]; |
| | 4117 | break; |
| | 4118 | case CBUS_FUNCTION_3: |
| | 4119 | *value = ftdi->eeprom->cbus_function[3]; |
| | 4120 | break; |
| | 4121 | case CBUS_FUNCTION_4: |
| | 4122 | *value = ftdi->eeprom->cbus_function[4]; |
| | 4123 | break; |
| | 4124 | case CBUS_FUNCTION_5: |
| | 4125 | *value = ftdi->eeprom->cbus_function[5]; |
| | 4126 | break; |
| | 4127 | case CBUS_FUNCTION_6: |
| | 4128 | *value = ftdi->eeprom->cbus_function[6]; |
| | 4129 | break; |
| | 4130 | case CBUS_FUNCTION_7: |
| | 4131 | *value = ftdi->eeprom->cbus_function[7]; |
| | 4132 | break; |
| | 4133 | case CBUS_FUNCTION_8: |
| | 4134 | *value = ftdi->eeprom->cbus_function[8]; |
| | 4135 | break; |
| | 4136 | case CBUS_FUNCTION_9: |
| | 4137 | *value = ftdi->eeprom->cbus_function[9]; |
| | 4138 | break; |
| | 4139 | case HIGH_CURRENT: |
| | 4140 | *value = ftdi->eeprom->high_current; |
| | 4141 | break; |
| | 4142 | case HIGH_CURRENT_A: |
| | 4143 | *value = ftdi->eeprom->high_current_a; |
| | 4144 | break; |
| | 4145 | case HIGH_CURRENT_B: |
| | 4146 | *value = ftdi->eeprom->high_current_b; |
| | 4147 | break; |
| | 4148 | case INVERT: |
| | 4149 | *value = ftdi->eeprom->invert; |
| | 4150 | break; |
| | 4151 | case GROUP0_DRIVE: |
| | 4152 | *value = ftdi->eeprom->group0_drive; |
| | 4153 | break; |
| | 4154 | case GROUP0_SCHMITT: |
| | 4155 | *value = ftdi->eeprom->group0_schmitt; |
| | 4156 | break; |
| | 4157 | case GROUP0_SLEW: |
| | 4158 | *value = ftdi->eeprom->group0_slew; |
| | 4159 | break; |
| | 4160 | case GROUP1_DRIVE: |
| | 4161 | *value = ftdi->eeprom->group1_drive; |
| | 4162 | break; |
| | 4163 | case GROUP1_SCHMITT: |
| | 4164 | *value = ftdi->eeprom->group1_schmitt; |
| | 4165 | break; |
| | 4166 | case GROUP1_SLEW: |
| | 4167 | *value = ftdi->eeprom->group1_slew; |
| | 4168 | break; |
| | 4169 | case GROUP2_DRIVE: |
| | 4170 | *value = ftdi->eeprom->group2_drive; |
| | 4171 | break; |
| | 4172 | case GROUP2_SCHMITT: |
| | 4173 | *value = ftdi->eeprom->group2_schmitt; |
| | 4174 | break; |
| | 4175 | case GROUP2_SLEW: |
| | 4176 | *value = ftdi->eeprom->group2_slew; |
| | 4177 | break; |
| | 4178 | case GROUP3_DRIVE: |
| | 4179 | *value = ftdi->eeprom->group3_drive; |
| | 4180 | break; |
| | 4181 | case GROUP3_SCHMITT: |
| | 4182 | *value = ftdi->eeprom->group3_schmitt; |
| | 4183 | break; |
| | 4184 | case GROUP3_SLEW: |
| | 4185 | *value = ftdi->eeprom->group3_slew; |
| | 4186 | break; |
| | 4187 | case POWER_SAVE: |
| | 4188 | *value = ftdi->eeprom->powersave; |
| | 4189 | break; |
| | 4190 | case CLOCK_POLARITY: |
| | 4191 | *value = ftdi->eeprom->clock_polarity; |
| | 4192 | break; |
| | 4193 | case DATA_ORDER: |
| | 4194 | *value = ftdi->eeprom->data_order; |
| | 4195 | break; |
| | 4196 | case FLOW_CONTROL: |
| | 4197 | *value = ftdi->eeprom->flow_control; |
| | 4198 | break; |
| | 4199 | case CHIP_TYPE: |
| | 4200 | *value = ftdi->eeprom->chip; |
| | 4201 | break; |
| | 4202 | case CHIP_SIZE: |
| | 4203 | *value = ftdi->eeprom->size; |
| | 4204 | break; |
| | 4205 | case EXTERNAL_OSCILLATOR: |
| | 4206 | *value = ftdi->eeprom->external_oscillator; |
| | 4207 | break; |
| | 4208 | case USER_DATA_ADDR: |
| | 4209 | *value = ftdi->eeprom->user_data_addr; |
| | 4210 | break; |
| | 4211 | default: |
| | 4212 | ftdi_error_return(-1, "Request for unknown EEPROM value"); |
| | 4213 | } |
| | 4214 | return 0; |
| | 4215 | } |
| | 4216 | |
| | 4217 | /** |
| | 4218 | Set a value in the decoded EEPROM Structure |
| | 4219 | No parameter checking is performed |
| | 4220 | |
| | 4221 | \param ftdi pointer to ftdi_context |
| | 4222 | \param value_name Enum of the value to set |
| | 4223 | \param value to set |
| | 4224 | |
| | 4225 | \retval 0: all fine |
| | 4226 | \retval -1: Value doesn't exist |
| | 4227 | \retval -2: Value not user settable |
| | 4228 | */ |
| | 4229 | int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int value) |
| | 4230 | { |
| | 4231 | switch (value_name) |
| | 4232 | { |
| | 4233 | case VENDOR_ID: |
| | 4234 | ftdi->eeprom->vendor_id = value; |
| | 4235 | break; |
| | 4236 | case PRODUCT_ID: |
| | 4237 | ftdi->eeprom->product_id = value; |
| | 4238 | break; |
| | 4239 | case RELEASE_NUMBER: |
| | 4240 | ftdi->eeprom->release_number = value; |
| | 4241 | break; |
| | 4242 | case SELF_POWERED: |
| | 4243 | ftdi->eeprom->self_powered = value; |
| | 4244 | break; |
| | 4245 | case REMOTE_WAKEUP: |
| | 4246 | ftdi->eeprom->remote_wakeup = value; |
| | 4247 | break; |
| | 4248 | case IS_NOT_PNP: |
| | 4249 | ftdi->eeprom->is_not_pnp = value; |
| | 4250 | break; |
| | 4251 | case SUSPEND_DBUS7: |
| | 4252 | ftdi->eeprom->suspend_dbus7 = value; |
| | 4253 | break; |
| | 4254 | case IN_IS_ISOCHRONOUS: |
| | 4255 | ftdi->eeprom->in_is_isochronous = value; |
| | 4256 | break; |
| | 4257 | case OUT_IS_ISOCHRONOUS: |
| | 4258 | ftdi->eeprom->out_is_isochronous = value; |
| | 4259 | break; |
| | 4260 | case SUSPEND_PULL_DOWNS: |
| | 4261 | ftdi->eeprom->suspend_pull_downs = value; |
| | 4262 | break; |
| | 4263 | case USE_SERIAL: |
| | 4264 | ftdi->eeprom->use_serial = value; |
| | 4265 | break; |
| | 4266 | case USB_VERSION: |
| | 4267 | ftdi->eeprom->usb_version = value; |
| | 4268 | break; |
| | 4269 | case USE_USB_VERSION: |
| | 4270 | ftdi->eeprom->use_usb_version = value; |
| | 4271 | break; |
| | 4272 | case MAX_POWER: |
| | 4273 | ftdi->eeprom->max_power = value; |
| | 4274 | break; |
| | 4275 | case CHANNEL_A_TYPE: |
| | 4276 | ftdi->eeprom->channel_a_type = value; |
| | 4277 | break; |
| | 4278 | case CHANNEL_B_TYPE: |
| | 4279 | ftdi->eeprom->channel_b_type = value; |
| | 4280 | break; |
| | 4281 | case CHANNEL_A_DRIVER: |
| | 4282 | ftdi->eeprom->channel_a_driver = value; |
| | 4283 | break; |
| | 4284 | case CHANNEL_B_DRIVER: |
| | 4285 | ftdi->eeprom->channel_b_driver = value; |
| | 4286 | break; |
| | 4287 | case CHANNEL_C_DRIVER: |
| | 4288 | ftdi->eeprom->channel_c_driver = value; |
| | 4289 | break; |
| | 4290 | case CHANNEL_D_DRIVER: |
| | 4291 | ftdi->eeprom->channel_d_driver = value; |
| | 4292 | break; |
| | 4293 | case CHANNEL_A_RS485: |
| | 4294 | ftdi->eeprom->channel_a_rs485enable = value; |
| | 4295 | break; |
| | 4296 | case CHANNEL_B_RS485: |
| | 4297 | ftdi->eeprom->channel_b_rs485enable = value; |
| | 4298 | break; |
| | 4299 | case CHANNEL_C_RS485: |
| | 4300 | ftdi->eeprom->channel_c_rs485enable = value; |
| | 4301 | break; |
| | 4302 | case CHANNEL_D_RS485: |
| | 4303 | ftdi->eeprom->channel_d_rs485enable = value; |
| | 4304 | break; |
| | 4305 | case CBUS_FUNCTION_0: |
| | 4306 | ftdi->eeprom->cbus_function[0] = value; |
| | 4307 | break; |
| | 4308 | case CBUS_FUNCTION_1: |
| | 4309 | ftdi->eeprom->cbus_function[1] = value; |
| | 4310 | break; |
| | 4311 | case CBUS_FUNCTION_2: |
| | 4312 | ftdi->eeprom->cbus_function[2] = value; |
| | 4313 | break; |
| | 4314 | case CBUS_FUNCTION_3: |
| | 4315 | ftdi->eeprom->cbus_function[3] = value; |
| | 4316 | break; |
| | 4317 | case CBUS_FUNCTION_4: |
| | 4318 | ftdi->eeprom->cbus_function[4] = value; |
| | 4319 | break; |
| | 4320 | case CBUS_FUNCTION_5: |
| | 4321 | ftdi->eeprom->cbus_function[5] = value; |
| | 4322 | break; |
| | 4323 | case CBUS_FUNCTION_6: |
| | 4324 | ftdi->eeprom->cbus_function[6] = value; |
| | 4325 | break; |
| | 4326 | case CBUS_FUNCTION_7: |
| | 4327 | ftdi->eeprom->cbus_function[7] = value; |
| | 4328 | break; |
| | 4329 | case CBUS_FUNCTION_8: |
| | 4330 | ftdi->eeprom->cbus_function[8] = value; |
| | 4331 | break; |
| | 4332 | case CBUS_FUNCTION_9: |
| | 4333 | ftdi->eeprom->cbus_function[9] = value; |
| | 4334 | break; |
| | 4335 | case HIGH_CURRENT: |
| | 4336 | ftdi->eeprom->high_current = value; |
| | 4337 | break; |
| | 4338 | case HIGH_CURRENT_A: |
| | 4339 | ftdi->eeprom->high_current_a = value; |
| | 4340 | break; |
| | 4341 | case HIGH_CURRENT_B: |
| | 4342 | ftdi->eeprom->high_current_b = value; |
| | 4343 | break; |
| | 4344 | case INVERT: |
| | 4345 | ftdi->eeprom->invert = value; |
| | 4346 | break; |
| | 4347 | case GROUP0_DRIVE: |
| | 4348 | ftdi->eeprom->group0_drive = value; |
| | 4349 | break; |
| | 4350 | case GROUP0_SCHMITT: |
| | 4351 | ftdi->eeprom->group0_schmitt = value; |
| | 4352 | break; |
| | 4353 | case GROUP0_SLEW: |
| | 4354 | ftdi->eeprom->group0_slew = value; |
| | 4355 | break; |
| | 4356 | case GROUP1_DRIVE: |
| | 4357 | ftdi->eeprom->group1_drive = value; |
| | 4358 | break; |
| | 4359 | case GROUP1_SCHMITT: |
| | 4360 | ftdi->eeprom->group1_schmitt = value; |
| | 4361 | break; |
| | 4362 | case GROUP1_SLEW: |
| | 4363 | ftdi->eeprom->group1_slew = value; |
| | 4364 | break; |
| | 4365 | case GROUP2_DRIVE: |
| | 4366 | ftdi->eeprom->group2_drive = value; |
| | 4367 | break; |
| | 4368 | case GROUP2_SCHMITT: |
| | 4369 | ftdi->eeprom->group2_schmitt = value; |
| | 4370 | break; |
| | 4371 | case GROUP2_SLEW: |
| | 4372 | ftdi->eeprom->group2_slew = value; |
| | 4373 | break; |
| | 4374 | case GROUP3_DRIVE: |
| | 4375 | ftdi->eeprom->group3_drive = value; |
| | 4376 | break; |
| | 4377 | case GROUP3_SCHMITT: |
| | 4378 | ftdi->eeprom->group3_schmitt = value; |
| | 4379 | break; |
| | 4380 | case GROUP3_SLEW: |
| | 4381 | ftdi->eeprom->group3_slew = value; |
| | 4382 | break; |
| | 4383 | case CHIP_TYPE: |
| | 4384 | ftdi->eeprom->chip = value; |
| | 4385 | break; |
| | 4386 | case POWER_SAVE: |
| | 4387 | ftdi->eeprom->powersave = value; |
| | 4388 | break; |
| | 4389 | case CLOCK_POLARITY: |
| | 4390 | ftdi->eeprom->clock_polarity = value; |
| | 4391 | break; |
| | 4392 | case DATA_ORDER: |
| | 4393 | ftdi->eeprom->data_order = value; |
| | 4394 | break; |
| | 4395 | case FLOW_CONTROL: |
| | 4396 | ftdi->eeprom->flow_control = value; |
| | 4397 | break; |
| | 4398 | case CHIP_SIZE: |
| | 4399 | ftdi_error_return(-2, "EEPROM Value can't be changed"); |
| | 4400 | break; |
| | 4401 | case EXTERNAL_OSCILLATOR: |
| | 4402 | ftdi->eeprom->external_oscillator = value; |
| | 4403 | break; |
| | 4404 | case USER_DATA_ADDR: |
| | 4405 | ftdi->eeprom->user_data_addr = value; |
| | 4406 | break; |
| | 4407 | |
| | 4408 | default : |
| | 4409 | ftdi_error_return(-1, "Request to unknown EEPROM value"); |
| | 4410 | } |
| | 4411 | ftdi->eeprom->initialized_for_connected_device = 0; |
| | 4412 | return 0; |
| | 4413 | } |
| | 4414 | |
| | 4415 | /** Get the read-only buffer to the binary EEPROM content |
| | 4416 | |
| | 4417 | \param ftdi pointer to ftdi_context |
| | 4418 | \param buf buffer to receive EEPROM content |
| | 4419 | \param size Size of receiving buffer |
| | 4420 | |
| | 4421 | \retval 0: All fine |
| | 4422 | \retval -1: struct ftdi_contxt or ftdi_eeprom missing |
| | 4423 | \retval -2: Not enough room to store eeprom |
| | 4424 | */ |
| | 4425 | int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size) |
| | 4426 | { |
| | 4427 | if (!ftdi || !(ftdi->eeprom)) |
| | 4428 | ftdi_error_return(-1, "No appropriate structure"); |
| | 4429 | |
| | 4430 | if (!buf || size < ftdi->eeprom->size) |
| | 4431 | ftdi_error_return(-1, "Not enough room to store eeprom"); |
| | 4432 | |
| | 4433 | // Only copy up to FTDI_MAX_EEPROM_SIZE bytes |
| | 4434 | if (size > FTDI_MAX_EEPROM_SIZE) |
| | 4435 | size = FTDI_MAX_EEPROM_SIZE; |
| | 4436 | |
| | 4437 | memcpy(buf, ftdi->eeprom->buf, size); |
| | 4438 | |
| | 4439 | return 0; |
| | 4440 | } |
| | 4441 | |
| | 4442 | /** Set the EEPROM content from the user-supplied prefilled buffer |
| | 4443 | |
| | 4444 | \param ftdi pointer to ftdi_context |
| | 4445 | \param buf buffer to read EEPROM content |
| | 4446 | \param size Size of buffer |
| | 4447 | |
| | 4448 | \retval 0: All fine |
| | 4449 | \retval -1: struct ftdi_context or ftdi_eeprom or buf missing |
| | 4450 | */ |
| | 4451 | int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size) |
| | 4452 | { |
| | 4453 | if (!ftdi || !(ftdi->eeprom) || !buf) |
| | 4454 | ftdi_error_return(-1, "No appropriate structure"); |
| | 4455 | |
| | 4456 | // Only copy up to FTDI_MAX_EEPROM_SIZE bytes |
| | 4457 | if (size > FTDI_MAX_EEPROM_SIZE) |
| | 4458 | size = FTDI_MAX_EEPROM_SIZE; |
| | 4459 | |
| | 4460 | memcpy(ftdi->eeprom->buf, buf, size); |
| | 4461 | |
| | 4462 | return 0; |
| | 4463 | } |
| | 4464 | |
| | 4465 | /** Set the EEPROM user data content from the user-supplied prefilled buffer |
| | 4466 | |
| | 4467 | \param ftdi pointer to ftdi_context |
| | 4468 | \param buf buffer to read EEPROM user data content |
| | 4469 | \param size Size of buffer |
| | 4470 | |
| | 4471 | \retval 0: All fine |
| | 4472 | \retval -1: struct ftdi_context or ftdi_eeprom or buf missing |
| | 4473 | */ |
| | 4474 | int ftdi_set_eeprom_user_data(struct ftdi_context *ftdi, const char * buf, int size) |
| | 4475 | { |
| | 4476 | if (!ftdi || !(ftdi->eeprom) || !buf) |
| | 4477 | ftdi_error_return(-1, "No appropriate structure"); |
| | 4478 | |
| | 4479 | ftdi->eeprom->user_data_size = size; |
| | 4480 | ftdi->eeprom->user_data = buf; |
| | 4481 | return 0; |
| | 4482 | } |
| | 4483 | |
| | 4484 | /** |
| | 4485 | Read eeprom location |
| | 4486 | |
| | 4487 | \param ftdi pointer to ftdi_context |
| | 4488 | \param eeprom_addr Address of eeprom location to be read |
| | 4489 | \param eeprom_val Pointer to store read eeprom location |
| | 4490 | |
| | 4491 | \retval 0: all fine |
| | 4492 | \retval -1: read failed |
| | 4493 | \retval -2: USB device unavailable |
| | 4494 | */ |
| | 4495 | int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val) |
| | 4496 | { |
| | 4497 | unsigned char buf[2]; |
| | 4498 | |
| | 4499 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 4500 | ftdi_error_return(-2, "USB device unavailable"); |
| | 4501 | |
| | 4502 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, eeprom_addr, buf, 2, ftdi->usb_read_timeout) != 2) |
| | 4503 | ftdi_error_return(-1, "reading eeprom failed"); |
| | 4504 | |
| | 4505 | *eeprom_val = (0xff & buf[0]) | (buf[1] << 8); |
| | 4506 | |
| | 4507 | return 0; |
| | 4508 | } |
| | 4509 | |
| | 4510 | /** |
| | 4511 | Read eeprom |
| | 4512 | |
| | 4513 | \param ftdi pointer to ftdi_context |
| | 4514 | |
| | 4515 | \retval 0: all fine |
| | 4516 | \retval -1: read failed |
| | 4517 | \retval -2: USB device unavailable |
| | 4518 | */ |
| | 4519 | int ftdi_read_eeprom(struct ftdi_context *ftdi) |
| | 4520 | { |
| | 4521 | int i; |
| | 4522 | unsigned char *buf; |
| | 4523 | |
| | 4524 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 4525 | ftdi_error_return(-2, "USB device unavailable"); |
| | 4526 | buf = ftdi->eeprom->buf; |
| | 4527 | |
| | 4528 | for (i = 0; i < FTDI_MAX_EEPROM_SIZE/2; i++) |
| | 4529 | { |
| | 4530 | if (libusb_control_transfer( |
| | 4531 | ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE,SIO_READ_EEPROM_REQUEST, 0, i, |
| | 4532 | buf+(i*2), 2, ftdi->usb_read_timeout) != 2) |
| | 4533 | ftdi_error_return(-1, "reading eeprom failed"); |
| | 4534 | } |
| | 4535 | |
| | 4536 | if (ftdi->type == TYPE_R) |
| | 4537 | ftdi->eeprom->size = 0x80; |
| | 4538 | /* Guesses size of eeprom by comparing halves |
| | 4539 | - will not work with blank eeprom */ |
| | 4540 | else if (strrchr((const char *)buf, 0xff) == ((const char *)buf +FTDI_MAX_EEPROM_SIZE -1)) |
| | 4541 | ftdi->eeprom->size = -1; |
| | 4542 | else if (memcmp(buf,&buf[0x80],0x80) == 0) |
| | 4543 | ftdi->eeprom->size = 0x80; |
| | 4544 | else if (memcmp(buf,&buf[0x40],0x40) == 0) |
| | 4545 | ftdi->eeprom->size = 0x40; |
| | 4546 | else |
| | 4547 | ftdi->eeprom->size = 0x100; |
| | 4548 | return 0; |
| | 4549 | } |
| | 4550 | |
| | 4551 | /* |
| | 4552 | ftdi_read_chipid_shift does the bitshift operation needed for the FTDIChip-ID |
| | 4553 | Function is only used internally |
| | 4554 | \internal |
| | 4555 | */ |
| | 4556 | static unsigned char ftdi_read_chipid_shift(unsigned char value) |
| | 4557 | { |
| | 4558 | return ((value & 1) << 1) | |
| | 4559 | ((value & 2) << 5) | |
| | 4560 | ((value & 4) >> 2) | |
| | 4561 | ((value & 8) << 4) | |
| | 4562 | ((value & 16) >> 1) | |
| | 4563 | ((value & 32) >> 1) | |
| | 4564 | ((value & 64) >> 4) | |
| | 4565 | ((value & 128) >> 2); |
| | 4566 | } |
| | 4567 | |
| | 4568 | /** |
| | 4569 | Read the FTDIChip-ID from R-type devices |
| | 4570 | |
| | 4571 | \param ftdi pointer to ftdi_context |
| | 4572 | \param chipid Pointer to store FTDIChip-ID |
| | 4573 | |
| | 4574 | \retval 0: all fine |
| | 4575 | \retval -1: read failed |
| | 4576 | \retval -2: USB device unavailable |
| | 4577 | */ |
| | 4578 | int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid) |
| | 4579 | { |
| | 4580 | unsigned int a = 0, b = 0; |
| | 4581 | |
| | 4582 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 4583 | ftdi_error_return(-2, "USB device unavailable"); |
| | 4584 | |
| | 4585 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, 0x43, (unsigned char *)&a, 2, ftdi->usb_read_timeout) == 2) |
| | 4586 | { |
| | 4587 | a = a << 8 | a >> 8; |
| | 4588 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, 0x44, (unsigned char *)&b, 2, ftdi->usb_read_timeout) == 2) |
| | 4589 | { |
| | 4590 | b = b << 8 | b >> 8; |
| | 4591 | a = (a << 16) | (b & 0xFFFF); |
| | 4592 | a = ftdi_read_chipid_shift(a) | ftdi_read_chipid_shift(a>>8)<<8 |
| | 4593 | | ftdi_read_chipid_shift(a>>16)<<16 | ftdi_read_chipid_shift(a>>24)<<24; |
| | 4594 | *chipid = a ^ 0xa5f0f7d1; |
| | 4595 | return 0; |
| | 4596 | } |
| | 4597 | } |
| | 4598 | |
| | 4599 | ftdi_error_return(-1, "read of FTDIChip-ID failed"); |
| | 4600 | } |
| | 4601 | |
| | 4602 | /** |
| | 4603 | Write eeprom location |
| | 4604 | |
| | 4605 | \param ftdi pointer to ftdi_context |
| | 4606 | \param eeprom_addr Address of eeprom location to be written |
| | 4607 | \param eeprom_val Value to be written |
| | 4608 | |
| | 4609 | \retval 0: all fine |
| | 4610 | \retval -1: write failed |
| | 4611 | \retval -2: USB device unavailable |
| | 4612 | \retval -3: Invalid access to checksum protected area below 0x80 |
| | 4613 | \retval -4: Device can't access unprotected area |
| | 4614 | \retval -5: Reading chip type failed |
| | 4615 | */ |
| | 4616 | int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, |
| | 4617 | unsigned short eeprom_val) |
| | 4618 | { |
| | 4619 | int chip_type_location; |
| | 4620 | unsigned short chip_type; |
| | 4621 | |
| | 4622 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 4623 | ftdi_error_return(-2, "USB device unavailable"); |
| | 4624 | |
| | 4625 | if (eeprom_addr <0x80) |
| | 4626 | ftdi_error_return(-2, "Invalid access to checksum protected area below 0x80"); |
| | 4627 | |
| | 4628 | |
| | 4629 | switch (ftdi->type) |
| | 4630 | { |
| | 4631 | case TYPE_BM: |
| | 4632 | case TYPE_2232C: |
| | 4633 | chip_type_location = 0x14; |
| | 4634 | break; |
| | 4635 | case TYPE_2232H: |
| | 4636 | case TYPE_4232H: |
| | 4637 | chip_type_location = 0x18; |
| | 4638 | break; |
| | 4639 | case TYPE_232H: |
| | 4640 | chip_type_location = 0x1e; |
| | 4641 | break; |
| | 4642 | case TYPE_AM: |
| | 4643 | case TYPE_R: |
| | 4644 | case TYPE_230X: |
| | 4645 | default: |
| | 4646 | ftdi_error_return(-4, "Device can't access unprotected area"); |
| | 4647 | } |
| | 4648 | |
| | 4649 | if (ftdi_read_eeprom_location( ftdi, chip_type_location>>1, &chip_type)) |
| | 4650 | ftdi_error_return(-5, "Reading failed"); |
| | 4651 | fprintf(stderr," loc 0x%04x val 0x%04x\n", chip_type_location,chip_type); |
| | 4652 | if ((chip_type & 0xff) != 0x66) |
| | 4653 | { |
| | 4654 | ftdi_error_return(-6, "EEPROM is not of 93x66"); |
| | 4655 | } |
| | 4656 | |
| | 4657 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 4658 | SIO_WRITE_EEPROM_REQUEST, eeprom_val, eeprom_addr, |
| | 4659 | NULL, 0, ftdi->usb_write_timeout) != 0) |
| | 4660 | ftdi_error_return(-1, "unable to write eeprom"); |
| | 4661 | |
| | 4662 | return 0; |
| | 4663 | } |
| | 4664 | |
| | 4665 | /** |
| | 4666 | Write eeprom |
| | 4667 | |
| | 4668 | \param ftdi pointer to ftdi_context |
| | 4669 | |
| | 4670 | \retval 0: all fine |
| | 4671 | \retval -1: read failed |
| | 4672 | \retval -2: USB device unavailable |
| | 4673 | \retval -3: EEPROM not initialized for the connected device; |
| | 4674 | */ |
| | 4675 | int ftdi_write_eeprom(struct ftdi_context *ftdi) |
| | 4676 | { |
| | 4677 | unsigned short usb_val, status; |
| | 4678 | int i, ret; |
| | 4679 | unsigned char *eeprom; |
| | 4680 | |
| | 4681 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 4682 | ftdi_error_return(-2, "USB device unavailable"); |
| | 4683 | |
| | 4684 | if(ftdi->eeprom->initialized_for_connected_device == 0) |
| | 4685 | ftdi_error_return(-3, "EEPROM not initialized for the connected device"); |
| | 4686 | |
| | 4687 | eeprom = ftdi->eeprom->buf; |
| | 4688 | |
| | 4689 | /* These commands were traced while running MProg */ |
| | 4690 | if ((ret = ftdi_usb_reset(ftdi)) != 0) |
| | 4691 | return ret; |
| | 4692 | if ((ret = ftdi_poll_modem_status(ftdi, &status)) != 0) |
| | 4693 | return ret; |
| | 4694 | if ((ret = ftdi_set_latency_timer(ftdi, 0x77)) != 0) |
| | 4695 | return ret; |
| | 4696 | |
| | 4697 | for (i = 0; i < ftdi->eeprom->size/2; i++) |
| | 4698 | { |
| | 4699 | /* Do not try to write to reserved area */ |
| | 4700 | if ((ftdi->type == TYPE_230X) && (i == 0x40)) |
| | 4701 | { |
| | 4702 | i = 0x50; |
| | 4703 | } |
| | 4704 | usb_val = eeprom[i*2]; |
| | 4705 | usb_val += eeprom[(i*2)+1] << 8; |
| | 4706 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 4707 | SIO_WRITE_EEPROM_REQUEST, usb_val, i, |
| | 4708 | NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 4709 | ftdi_error_return(-1, "unable to write eeprom"); |
| | 4710 | } |
| | 4711 | |
| | 4712 | return 0; |
| | 4713 | } |
| | 4714 | |
| | 4715 | /** |
| | 4716 | Erase eeprom |
| | 4717 | |
| | 4718 | This is not supported on FT232R/FT245R according to the MProg manual from FTDI. |
| | 4719 | |
| | 4720 | \param ftdi pointer to ftdi_context |
| | 4721 | |
| | 4722 | \retval 0: all fine |
| | 4723 | \retval -1: erase failed |
| | 4724 | \retval -2: USB device unavailable |
| | 4725 | \retval -3: Writing magic failed |
| | 4726 | \retval -4: Read EEPROM failed |
| | 4727 | \retval -5: Unexpected EEPROM value |
| | 4728 | */ |
| | 4729 | #define MAGIC 0x55aa |
| | 4730 | int ftdi_erase_eeprom(struct ftdi_context *ftdi) |
| | 4731 | { |
| | 4732 | unsigned short eeprom_value; |
| | 4733 | if (ftdi == NULL || ftdi->usb_dev == NULL) |
| | 4734 | ftdi_error_return(-2, "USB device unavailable"); |
| | 4735 | |
| | 4736 | if ((ftdi->type == TYPE_R) || (ftdi->type == TYPE_230X)) |
| | 4737 | { |
| | 4738 | ftdi->eeprom->chip = 0; |
| | 4739 | return 0; |
| | 4740 | } |
| | 4741 | |
| | 4742 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_ERASE_EEPROM_REQUEST, |
| | 4743 | 0, 0, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 4744 | ftdi_error_return(-1, "unable to erase eeprom"); |
| | 4745 | |
| | 4746 | |
| | 4747 | /* detect chip type by writing 0x55AA as magic at word position 0xc0 |
| | 4748 | Chip is 93x46 if magic is read at word position 0x00, as wraparound happens around 0x40 |
| | 4749 | Chip is 93x56 if magic is read at word position 0x40, as wraparound happens around 0x80 |
| | 4750 | Chip is 93x66 if magic is only read at word position 0xc0*/ |
| | 4751 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, |
| | 4752 | SIO_WRITE_EEPROM_REQUEST, MAGIC, 0xc0, |
| | 4753 | NULL, 0, ftdi->usb_write_timeout) != 0) |
| | 4754 | ftdi_error_return(-3, "Writing magic failed"); |
| | 4755 | if (ftdi_read_eeprom_location( ftdi, 0x00, &eeprom_value)) |
| | 4756 | ftdi_error_return(-4, "Reading failed"); |
| | 4757 | if (eeprom_value == MAGIC) |
| | 4758 | { |
| | 4759 | ftdi->eeprom->chip = 0x46; |
| | 4760 | } |
| | 4761 | else |
| | 4762 | { |
| | 4763 | if (ftdi_read_eeprom_location( ftdi, 0x40, &eeprom_value)) |
| | 4764 | ftdi_error_return(-4, "Reading failed"); |
| | 4765 | if (eeprom_value == MAGIC) |
| | 4766 | ftdi->eeprom->chip = 0x56; |
| | 4767 | else |
| | 4768 | { |
| | 4769 | if (ftdi_read_eeprom_location( ftdi, 0xc0, &eeprom_value)) |
| | 4770 | ftdi_error_return(-4, "Reading failed"); |
| | 4771 | if (eeprom_value == MAGIC) |
| | 4772 | ftdi->eeprom->chip = 0x66; |
| | 4773 | else |
| | 4774 | { |
| | 4775 | ftdi->eeprom->chip = -1; |
| | 4776 | } |
| | 4777 | } |
| | 4778 | } |
| | 4779 | if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_ERASE_EEPROM_REQUEST, |
| | 4780 | 0, 0, NULL, 0, ftdi->usb_write_timeout) < 0) |
| | 4781 | ftdi_error_return(-1, "unable to erase eeprom"); |
| | 4782 | return 0; |
| | 4783 | } |
| | 4784 | |
| | 4785 | /** |
| | 4786 | Get string representation for last error code |
| | 4787 | |
| | 4788 | \param ftdi pointer to ftdi_context |
| | 4789 | |
| | 4790 | \retval Pointer to error string |
| | 4791 | */ |
| | 4792 | const char *ftdi_get_error_string (struct ftdi_context *ftdi) |
| | 4793 | { |
| | 4794 | if (ftdi == NULL) |
| | 4795 | return ""; |
| | 4796 | |
| | 4797 | return ftdi->error_str; |
| | 4798 | } |
| | 4799 | |
| | 4800 | /* @} end of doxygen libftdi group */ |