Пример #1
0
int nifalcon_open(falcon_device* dev, unsigned int device_index)
{
	unsigned int count, i, status;
	struct ftdi_device_list *dev_list, *current;
	if(!dev->is_initialized) nifalcon_error_return(NIFALCON_DEVICE_NOT_VALID_ERROR, "tried to open an uninitialized device");
	if(dev->is_open) nifalcon_close(dev);

	count = ftdi_usb_find_all(&(dev->falcon), &dev_list, NIFALCON_VENDOR_ID, NIFALCON_PRODUCT_ID);
	if(count <= 0 || device_index > count)
	{
		ftdi_list_free(&dev_list);
		if(count == 0) nifalcon_error_return(NIFALCON_DEVICE_NOT_FOUND_ERROR, "no devices connected to system");
		nifalcon_error_return(NIFALCON_DEVICE_INDEX_OUT_OF_RANGE_ERROR, "device index out of range");
	}
	for(i = 0, current = dev_list; current != NULL && i < device_index; current = dev_list->next, ++i);
	if((dev->falcon_status_code = ftdi_usb_open_dev(&(dev->falcon), current->dev)) < 0) return dev->falcon_status_code;
	ftdi_list_free(&dev_list);
	//VERY IMPORTANT
	//If we do not reset latency to 1ms, then we either have to fill the FTDI butter (64bytes) or wait 16ms
	//to get any data back. This is what was causing massive slowness in pre-1.0 releases
	if((dev->falcon_status_code = ftdi_set_latency_timer(&(dev->falcon), 1)) < 0) return dev->falcon_status_code;

	//Shift to full speed
	if((dev->falcon_status_code = ftdi_set_baudrate(&(dev->falcon), 1456312)) < 0) return dev->falcon_status_code;

	dev->is_open = 1;
	return 0;
}
Пример #2
0
int ftdi_device_open(ftdi_device_t* dev, ftdi_interface_t interface) {
  error_clear(&dev->error);
  
  if (ftdi_set_interface(dev->libftdi_context, interface))
    error_set(&dev->error, FTDI_ERROR_INVALID_INTERFACE);
  else if (ftdi_usb_open_dev(dev->libftdi_context, dev->libusb_device))
    error_setf(&dev->error, FTDI_ERROR_OPEN, "%03:%03", dev->bus,
      dev->address);
    
  return error_get(&dev->error);
}
Пример #3
0
	bool FalconCommLibFTDI::open(uint8_t device_index)
	{
		LOG_INFO("Opening device " << device_index);
		if(!m_isInitialized)
		{
			LOG_ERROR("Device not initialized");
			m_errorCode = FALCON_COMM_NOT_INITIALIZED;
			return false;
		}
		unsigned int count, i, status;
		struct ftdi_device_list *dev_list, *current;
		if(m_isCommOpen) close();

		count = ftdi_usb_find_all((m_falconDevice), &dev_list, FALCON_VENDOR_ID, FALCON_PRODUCT_ID);
		if(count <= 0 || device_index > count)
		{
			ftdi_list_free(&dev_list);
			if(count == 0)
			{
				LOG_ERROR("No devices found");
				m_errorCode = FALCON_COMM_DEVICE_NOT_FOUND_ERROR;
				return false;
			}
			else if(device_index > count)
			{
				LOG_ERROR("Device index " << device_index << " out of range");
				m_errorCode = FALCON_COMM_DEVICE_INDEX_OUT_OF_RANGE_ERROR;
				return false;
			}
		}
		for(i = 0, current = dev_list; current != NULL && i < device_index; current = current->next, ++i);
		if(current==NULL)
		{
			LOG_ERROR("No devices found");
			m_errorCode = FALCON_COMM_DEVICE_NOT_FOUND_ERROR;
			return false;
		}
		if((m_deviceErrorCode = ftdi_usb_open_dev((m_falconDevice), current->dev)) < 0)
		{
			LOG_ERROR("Device error " << m_deviceErrorCode);
			m_errorCode = FALCON_COMM_DEVICE_ERROR;
			ftdi_list_free(&dev_list);
			return false;
		}
		ftdi_list_free(&dev_list);
		m_isCommOpen = true;
		//Purge buffers
		if((m_deviceErrorCode = ftdi_usb_purge_buffers((m_falconDevice))) < 0) return false;
		setNormalMode();
		return true;
	}
Пример #4
0
ReturnCode reader_connect(struct reader *reader,
			  int beep) {
  ReturnCode rc;

  if(reader->ftdic == NULL || reader->dev == NULL) {
    printf("reader entry null\n");
    return RC_NULL_ERROR;
  }

  if(ftdi_usb_open_dev(reader->ftdic, reader->dev) < 0){
    printf("ftdi usb open dev failed\n");
    return RC_IO_ERROR;
  }

  if((rc = reader_reset(reader)) != RC_SUCCESS){
    printf("reset failed\n");
    ftdi_usb_close(reader->ftdic);
    return rc;
  }

  if((rc = reader_purge(reader)) != RC_SUCCESS){
    printf("purge failed\n");
    ftdi_usb_close(reader->ftdic);
    return rc;
  }

  if(ftdi_set_baudrate(reader->ftdic, RFID1_BAUDRATE) < 0){
    printf("setbaudrate failed\n");
    ftdi_usb_close(reader->ftdic);
    return RC_IO_ERROR;
  }

  usleep(10000);


  if((rc = reader_ping(reader)) != RC_SUCCESS){
    ftdi_usb_close(reader->ftdic);
    return rc;
  }

  reader->connected = 1;

  if(beep) {
    reader_pass_beep(reader);
  }


  return RC_SUCCESS;
}
Пример #5
0
int Context::get_strings_and_reopen()
{
    // Get device strings (closes device)
    int ret=get_strings();
    if (ret < 0)
    {
        d->open = 0;
        return ret;
    }

    // Reattach device
    ret = ftdi_usb_open_dev(d->ftdi, d->dev);
    d->open = (ret >= 0);

    return ret;
}
Пример #6
0
/*
 * Open an FTDI device. The device is selected with regard to the given restrictions;
 * any of those may be NULL and index is counted in the subset selected by the
 * description and/or serial if given.
 *
 * Returns: true if successfully opened, false otherwise.
 */
bool FtdiDevice::open( const char* description, const char* serial, int index )
{
	hasFtdiError_ = false;
	
	if ( isOpen() ) {
		hasFtdiError_ = false;
		return false;
	}
	
	context_ = ftdi_new();
	if ( context_ == 0 ) {
		hasFtdiError_ = true;
		return false;
	}
	
	bool success = false;
	vec_deviceInfo* devs = const_cast<vec_deviceInfo*>( getDeviceList( context_ ) );
	
	vec_deviceInfo::iterator it;
	
	if ( devs != 0 ) {
		for ( it = devs->begin(); it != devs->end(); ++it ) {
			const deviceInfo& di = *it;
			
			if ( description != 0 || serial != 0 ) {
				if ( di.usbInfo == 0 )
					break;
				
				if ( description != 0 && std::strncmp( di.usbInfo->description, description,
																							std::strlen( description ) ) != 0 )
					continue;
				
				if ( serial != 0 && std::strncmp( di.usbInfo->serial, serial,
																				 std::strlen( serial ) ) != 0 )
					continue;
			}
			
			if ( index-- != 0 )
				continue;
			
			//If control gets here, we have found a suitable device.
			if ( ftdi_usb_open_dev( context_, di.ftdiDevice ) < 0 ) {
				//do not free context since that would also free the error message
				hasFtdiError_ = true;
			}
			usbInfo_ = new usbInformation( *( di.usbInfo ) );
			success = true;
		}
	} else {
		hasFtdiError_ = ( devs == 0 );
	}
	
	if ( ! success && ! hasFtdiError_ ) {
		delete context_; context_ = 0;
	}
	
	if ( success ) {
		purgeBuffers();
		reset();
	}
	
	return success;
}
Пример #7
0
int main(int argc, char **argv)
{
    struct ftdi_context *ftdi;
    unsigned char buf[1024];
    int f = 0, i;
    int vid = 0x403;
    int pid = 0;
    int baudrate = 115200;
    int interface = INTERFACE_ANY;
    int do_write = 0;
    unsigned int pattern = 0xffff;
    int retval = EXIT_FAILURE;

    while ((i = getopt(argc, argv, "i:v:p:b:w::")) != -1)
    {
        switch (i)
        {
            case 'i': // 0=ANY, 1=A, 2=B, 3=C, 4=D
                interface = strtoul(optarg, NULL, 0);
                break;
            case 'v':
                vid = strtoul(optarg, NULL, 0);
                break;
            case 'p':
                pid = strtoul(optarg, NULL, 0);
                break;
            case 'b':
                baudrate = strtoul(optarg, NULL, 0);
                break;
            case 'w':
                do_write = 1;
                if (optarg)
                    pattern = strtoul(optarg, NULL, 0);
                if (pattern > 0xff)
                {
                    fprintf(stderr, "Please provide a 8 bit pattern\n");
                    exit(-1);
                }
                break;
            default:
                fprintf(stderr, "usage: %s [-i interface] [-v vid] [-p pid] [-b baudrate] [-w [pattern]]\n", *argv);
                exit(-1);
        }
    }

    // Init
    if ((ftdi = ftdi_new()) == 0)
    {
        fprintf(stderr, "ftdi_new failed\n");
        return EXIT_FAILURE;
    }

    if (!vid && !pid && (interface == INTERFACE_ANY))
    {
        ftdi_set_interface(ftdi, INTERFACE_ANY);
        struct ftdi_device_list *devlist;
        int res;
        if ((res = ftdi_usb_find_all(ftdi, &devlist, 0, 0)) < 0)
        {
            fprintf(stderr, "No FTDI with default VID/PID found\n");
            goto do_deinit;
        }
        if (res == 1)
        {
            f = ftdi_usb_open_dev(ftdi,  devlist[0].dev);
            if (f<0)
            {
                fprintf(stderr, "Unable to open device %d: (%s)",
                        i, ftdi_get_error_string(ftdi));
            }
        }
        ftdi_list_free(&devlist);
        if (res > 1)
        {
            fprintf(stderr, "%d Devices found, please select Device with VID/PID\n", res);
            /* TODO: List Devices*/
            goto do_deinit;
        }
        if (res == 0)
        {
            fprintf(stderr, "No Devices found with default VID/PID\n");
            goto do_deinit;
        }
    }
    else
    {
        // Select interface
        ftdi_set_interface(ftdi, interface);
        
        // Open device
        f = ftdi_usb_open(ftdi, vid, pid);
    }
    if (f < 0)
    {
        fprintf(stderr, "unable to open ftdi device: %d (%s)\n", f, ftdi_get_error_string(ftdi));
        exit(-1);
    }

    // Set baudrate
    f = ftdi_set_baudrate(ftdi, baudrate);
    if (f < 0)
    {
        fprintf(stderr, "unable to set baudrate: %d (%s)\n", f, ftdi_get_error_string(ftdi));
        exit(-1);
    }
    
    /* Set line parameters
     *
     * TODO: Make these parameters settable from the command line
     *
     * Parameters are choosen that sending a continous stream of 0x55 
     * should give a square wave
     *
     */
    f = ftdi_set_line_property(ftdi, 8, STOP_BIT_1, NONE);
    if (f < 0)
    {
        fprintf(stderr, "unable to set line parameters: %d (%s)\n", f, ftdi_get_error_string(ftdi));
        exit(-1);
    }
    
    if (do_write)
        for(i=0; i<1024; i++)
            buf[i] = pattern;

    signal(SIGINT, sigintHandler);
    while (!exitRequested)
    {
        if (do_write)
            f = ftdi_write_data(ftdi, buf, 
                                (baudrate/512 >sizeof(buf))?sizeof(buf):
                                (baudrate/512)?baudrate/512:1);
        else
            f = ftdi_read_data(ftdi, buf, sizeof(buf));
        if (f<0)
            sleep(1);
        else if(f> 0 && !do_write)
        {
            fprintf(stderr, "read %d bytes\n", f);
            fwrite(buf, f, 1, stdout);
            fflush(stderr);
            fflush(stdout);
        }
    }
    signal(SIGINT, SIG_DFL);
    retval =  EXIT_SUCCESS;
            
    ftdi_usb_close(ftdi);
    do_deinit:
    ftdi_free(ftdi);

    return retval;
}
Пример #8
0
int spi_begin(uint8_t bus, uint8_t port)
{
	int ret;

	ftdi = ftdi_new();
	if (ftdi == 0) {
		fprintf(stderr, "ftdi_new failed\n");
		return -1;
	}

	if (bus > 0) {
		struct ftdi_device_list *list = NULL;
		struct ftdi_device_list *p;

		ret = ftdi_usb_find_all(ftdi, &list, 0, 0);
		if (ret < 0) {
			fprintf(stderr, "unable to list devices: %d (%s)\n",
					ret, ftdi_get_error_string(ftdi));
			ftdi_free(ftdi);
			return -2;
		}

		p = list;
		while (p) {
			if (bus == libusb_get_bus_number(p->dev) &&
				port == libusb_get_port_number(p->dev)) {
				ret = ftdi_usb_open_dev(ftdi, p->dev);
				break;
			}
			p = p->next;
		}

		ftdi_list_free(&list);

		if (!p) {
			fprintf(stderr, "dev on bus %i and port %i not found\n",
								bus, port);
			ftdi_free(ftdi);
			return -3;
		}
	} else
		ret = ftdi_usb_open(ftdi, 0x0403, 0x6001);

	if (ret < 0 && ret != -5) {
		fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret,
						ftdi_get_error_string(ftdi));
		ftdi_free(ftdi);
		return -4;
	}

	ret = ftdi_set_bitmode(ftdi, PINS_OUT, BITMODE_SYNCBB);
	if (ret != 0) {
		fprintf(stderr, "unable to set bitmode: %d (%s)\n", ret,
						ftdi_get_error_string(ftdi));
		ftdi_free(ftdi);
		return -5;
	}

	ret = ftdi_set_baudrate(ftdi, 57600);
	if (ret != 0) {
		fprintf(stderr, "unable to set baudrate: %d (%s)\n", ret,
						ftdi_get_error_string(ftdi));
		ftdi_disable_bitbang(ftdi);
		ftdi_free(ftdi);
		return -6;
	}

	digitalWrite(PIN_PROG, LOW);
	digitalWrite(PIN_FSCK, LOW);
	digitalWrite(PIN_FCSN, HIGH);
	digitalWrite(PIN_FMOSI, LOW);
	digitalWrite(PIN_RESET, HIGH);

	prog_begin();

	return 0;
}
int main(int argc, char *argv[])
{
    int ret, i;
    struct ftdi_device_list *devlist, *curdev;
    struct ftdi_context ftdic;
    struct ftdi_eeprom  eeprom;

    for (i = 0; i < CBUS_NUM; i++)
    {
        apcCBUS[i] = NULL;
    }

    {
        static struct option long_options[] =
        {

            {"help",                    no_argument,        NULL, 'h'},
            {"verbosity",               required_argument,  NULL, 'V'},

            {"vid",                     required_argument,  NULL, 'v'},
            {"pid",                     required_argument,  NULL, 'p'},

            {"manufacturer",            required_argument,  NULL, 'm'},
            {"description",             required_argument,  NULL, 'd'},

            {"serial",                  required_argument,  NULL, 's'},
            {"autoserial",              required_argument,  NULL, 'a'},

            {"C0",                      required_argument,  NULL, '0'},
            {"C1",                      required_argument,  NULL, '1'},
            {"C2",                      required_argument,  NULL, '2'},
            {"C3",                      required_argument,  NULL, '3'},
            {"C4",                      required_argument,  NULL, '4'},

            { NULL, 0, NULL, 0}
        };
        signed char opt;
        int option_index;

        while ((opt = getopt_long(argc, argv, "hV:v:p:m:d:s:a:0:1:2:3:4:", long_options, &option_index)) != -1)
        {
            switch (opt)
            {
            case 'h':
                print_usage_exit(argv);
                break;

            case 'V':
                if (iMyStrtoul(&u32Verbosity, optarg, "verbosity", 2))
                {
                    return EXIT_FAILURE;
                }
                break;

            case 'v':
                if (iMyStrtoul(&u32VID, optarg, "vendor id", 0xFFFF))
                {
                    return EXIT_FAILURE;
                }
                break;

            case 'p':
                if (iMyStrtoul(&u32PID, optarg, "product id", 0xFFFF))
                {
                    return EXIT_FAILURE;
                }
                break;

            case 'm':
                pcManufacturer = optarg;
                break;

            case 'd':
                pcDescription = optarg;
                break;

            case 's':
                pcSerial = optarg;
                break;

            case 'a':
                pcAutoSerial = optarg;
                break;

            case '0':
                apcCBUS[0] = optarg;
                break;

            case '1':
                apcCBUS[1] = optarg;
                break;

            case '2':
                apcCBUS[2] = optarg;
                break;

            case '3':
                apcCBUS[3] = optarg;
                break;

            case '4':
                apcCBUS[4] = optarg;
                break;

            default: /* '?' */
                print_usage_exit(argv);
            }
        }
    }

    printf("FTProg FTDI Programmer version %s\n\r", Version);

    /* Handle serial numbers */
    if (pcSerial && pcAutoSerial)
    {
        fprintf(stderr, "Please specify only one of serial number and autoserial\n\r");
        return EXIT_FAILURE;
    }

    if (pcSerial)
    {
        if (strlen(pcSerial) != 8)
        {
            fprintf(stderr, "Serial number must be 8 character string\n\r");
            return EXIT_FAILURE;
        }
    }

    if (pcAutoSerial)
    {
        int fd;
        if (strlen(pcAutoSerial) != 2)
        {
            fprintf(stderr, "Serial number prefix must be 2 character string\n\r");
            return EXIT_FAILURE;
        }

        pcSerial = malloc(sizeof(char) * 9);
        if (!pcSerial)
        {
            fprintf(stderr, "Memory error\n");
            return EXIT_FAILURE;
        }
        pcSerial[0] = pcAutoSerial[0];
        pcSerial[1] = pcAutoSerial[1];

        if ((fd = open("/dev/urandom", O_RDONLY)) < 0)
        {
            fprintf(stderr, "Could not open /dev/urandom (%s)\n\r", strerror(errno));
            return EXIT_FAILURE;
        }
        for (i = 2; i < 8; i++)
        {
            uint32_t j;
            read(fd, &j, 1);
            pcSerial[i] = "0123456789ABCDEF"[j % 16];
        }
        close(fd);

        pcSerial[8] = '\0';
        if (u32Verbosity > 0)
        {
            printf("Autogenerated serial number: '%s'\n", pcSerial);
        }
    }


    for (i = 0; i < CBUS_NUM; i++)
    {
        if (apcCBUS[i])
        {
            int j, iFound = 0;
            for (j = 0; j < (sizeof(asCBUSModeLookup)/sizeof(tsCBUSModeLookup)); j++)
            {
                if (strcmp(apcCBUS[i], asCBUSModeLookup[j].pcDescription) == 0)
                {
                    iFound = 1;
                    apsCBUS_Function[i] = &asCBUSModeLookup[j];
                }
            }
            if (!iFound)
            {
                fprintf(stderr, "Invalid C%d '%s'\n\r", i, apcCBUS[i]);
                return EXIT_FAILURE;
            }
        }
    }

    if (ftdi_init(&ftdic) < 0)
    {
        fprintf(stderr, "ftdi_init failed\n");
        return EXIT_FAILURE;
    }

    if ((ret = ftdi_usb_find_all(&ftdic, &devlist, u32VID, u32PID)) < 0)
    {
        fprintf(stderr, "ftdi_usb_find_all failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
        return EXIT_FAILURE;
    }

    printf("Number of FTDI devices found: %d\n", ret);

    for (i=0, curdev = devlist; curdev != NULL; i++, curdev = curdev->next)
    {
        printf(" Updating device: %d\n\r", i);

        if ((ret = ftdi_usb_open_dev(&ftdic, curdev->dev)) < 0)
        {
            fprintf(stderr, "ftdi_usb_open_dev failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
            return EXIT_FAILURE;
        }

        // Read out FTDIChip-ID of R type chips
        if (ftdic.type == TYPE_R)
        {
            unsigned char *pcEepromBuffer = NULL;
            unsigned int chipid;

            if ((ret = ftdi_read_chipid(&ftdic, &chipid)) < 0)
            {
                fprintf(stderr, "ftdi_read_chipid failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
                return EXIT_FAILURE;
            }

            printf("  FTDI chipid: %X\n", chipid);

            /* EEPROM is 160 bytes */
            ftdi_eeprom_setsize(&ftdic, &eeprom, 160);

            printf("  EEPROM size: %d bytes\n", ftdic.eeprom_size);
            pcEepromBuffer = malloc(ftdic.eeprom_size);
            if (!pcEepromBuffer)
            {
                fprintf(stderr, "Memory error!");
                return EXIT_FAILURE;
            }
            else
            {

                int i;
                if ((ret = ftdi_read_eeprom(&ftdic, pcEepromBuffer)) < 0)
                {
                    fprintf(stderr, "ftdi_read_eeprom failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
                    return EXIT_FAILURE;
                }
                if ((ret = ftdi_eeprom_decode(&eeprom, pcEepromBuffer, ftdic.eeprom_size)) < 0)
                {
                    if (ret != -1)
                    {
                        /* Avoid errors due to hard coded size causing checksum to fail. */
                        fprintf(stderr, "Error decoding eeprom buffer: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
                        return EXIT_FAILURE;
                    }
                }

                if (u32Verbosity > 0)
                {
                    printf("    Current Vendor: %d, %s\n", eeprom.vendor_id, eeprom.manufacturer);
                    printf("    Current Product: %d, %s\n", eeprom.product_id, eeprom.product);
                    printf("    Current Serial: %s\n", eeprom.serial);

                    if (u32Verbosity >= 2)
                    {
                        printf("      Current EEPROM Contents\n\r");
                        for (i = 0; i < ftdic.eeprom_size; i+=2)
                        {
                            if ((i % 16) == 0)
                            {
                                printf("        %04x:", i/2);
                            }
                            printf(" 0x%02x%02x", pcEepromBuffer[i],pcEepromBuffer[i+1]);
                            if ((i % 16) == 14)
                            {
                                printf("\n\r");
                            }
                        }
                    }
                }

                if (pcManufacturer)
                {
                    printf("  Setting manufacturer: '%s'\n\r", pcManufacturer);
                    free(eeprom.manufacturer);
                    eeprom.manufacturer     = pcManufacturer;
                }

                if (pcDescription)
                {
                    printf("  Setting description: '%s'\n\r", pcDescription);
                    free(eeprom.product);
                    eeprom.product          = pcDescription;
                }

                if (pcSerial)
                {
                    printf("  Setting serial number: '%s'\n\r", pcSerial);
                    free(eeprom.serial);
                    eeprom.serial           = pcSerial;
                }

                for (i = 0; i < CBUS_NUM; i++)
                {
                    if (apcCBUS[i])
                    {
                        /* Argument given */
                        printf("  Setting C%d: '%s' (%d)\n\r", i,
                               apsCBUS_Function[i]->pcDescription,
                               apsCBUS_Function[i]->iCBUSMode);

                        eeprom.cbus_function[i] = apsCBUS_Function[i]->iCBUSMode;
                    }
                }

                /* EEPROM is 160 bytes */
                ftdi_eeprom_setsize(&ftdic, &eeprom, 160);

                if ((ret = ftdi_eeprom_build(&eeprom, pcEepromBuffer)) < 0)
                {
                    fprintf(stderr, "ftdi_eeprom_build failed: %d (%s)\n\r", ret, ftdi_get_error_string(&ftdic));
                    return -1;
                }

                if ((ret = ftdi_write_eeprom(&ftdic, pcEepromBuffer)) < 0)
                {
                    fprintf(stderr, "ftdi_write_eeprom failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
                    return -1;
                }
                printf("  Wrote new EEPROM data successfully\n\r");
            }
        }

        if ((ret = ftdi_usb_close(&ftdic)) < 0)
        {
            fprintf(stderr, "ftdi_usb_close failed: %d (%s)\n\r", ret, ftdi_get_error_string(&ftdic));
            return EXIT_FAILURE;
        }
    }

    ftdi_list_free(&devlist);
    ftdi_deinit(&ftdic);
    return EXIT_SUCCESS;
}
Пример #10
0
int
main(int argc, char *argv[]) {
  int c;
  static struct option long_options[] = {
    {"manufacturer", 1, 0, 'm'},
    {"product",      1, 0, 'p'},
    {"serial",       1, 0, 's'},
    {"verbose",      0, 0, 'v'},
    {"help",         0, 0, 'h'},
    {NULL, 0, NULL, 0}
  };
  char orig_manufacturer[128];
  char* manufacturer = NULL;
  char orig_product[128];
  char* product = NULL;
  char orig_serial[128];
  char* serial = NULL;
  int bus = -1;
  int device = -1;
  struct ftdi_context ftdi;
  int ires = 0;

  while ((c = getopt_long(argc, argv, "m:p:s:vh", long_options, &optind)) != -1) {
    switch (c) {
      case 'm':
	manufacturer = optarg;
	break;
      case 'p':
	product = optarg;
	break;
      case 's':
	serial = optarg;
	break;
      case 'v':
	verbose_mode = true;
	break;
      case 'h':
	print_help(argc, argv);
	return EXIT_SUCCESS;
	break;
    }
  }

  if (optind + 1 != argc) {
    print_help(argc, argv);
    return EXIT_FAILURE;
  } else {
    if (!parse_device_identifier(&bus, &device, argv[optind])) {
      fprintf(stderr, "Unable to parse `%s'\n", argv[optind]);
      return EXIT_FAILURE;
    }
    print_verbose("Using device %03d:%03d\n", bus, device);
  }

  libusb_init(NULL);
  libusb_device** usb_devices;
  ssize_t n_devices = libusb_get_device_list(NULL, &usb_devices);
  if (n_devices < 0) {
    fprintf(stderr, "ERROR: Unable to list USB devices [%zd]: %s\n", n_devices, libusb_strerror((enum libusb_error) n_devices));
    return EXIT_FAILURE;
  }

  libusb_device* usb_device = NULL;
  for (int i = 0 ; i < n_devices ; i++) {
    if (libusb_get_bus_number(usb_devices[i]) == bus &&
	libusb_get_device_address(usb_devices[i]) == device) {
      usb_device = usb_devices[i];
      break;
    }
  }
  if (usb_device == NULL) {
    fprintf(stderr, "ERROR: Unable to find USB device at %03d:%03d\n", bus, device);
    return EXIT_FAILURE;
  }

  if ((ires = ftdi_init(&ftdi)) != 0) {
    fprintf(stderr, "ERROR: Unable to initialize libftdi (%d)\n", ires);
    return EXIT_FAILURE;
  }

  if ((ires = ftdi_usb_open_dev(&ftdi, usb_device)) != 0) {
    fprintf(stderr, "ERROR: Unable to open device (%d)\n", ires);
    fprintf(stderr, "       Perhaps you don't have sufficient permissions (i.e., you aren't root)?\n");
    return EXIT_FAILURE;
  }

  {
    struct libusb_device_descriptor desc;

    if ((ires = libusb_get_device_descriptor(libusb_get_device (ftdi.usb_dev), &desc)) < 0) {
      fprintf(stderr, "ERROR: Unable to retrieve device descriptor (%d): %s\n", ires, libusb_strerror((enum libusb_error) ires));
      return EXIT_FAILURE;
    }

    if ((ires = libusb_get_string_descriptor_ascii(ftdi.usb_dev, desc.iManufacturer, (unsigned char*) orig_manufacturer, sizeof(orig_manufacturer))) < 0) {
      fprintf(stderr, "ERROR: Unable to retrieve manufacturer (%d): %s\n", ires, libusb_strerror((enum libusb_error) ires));
      return EXIT_FAILURE;
    }
    print_verbose("Old manufacturer: %s\n", orig_manufacturer);
    if (manufacturer == NULL)
      manufacturer = orig_manufacturer;

    if ((ires = libusb_get_string_descriptor_ascii(ftdi.usb_dev, desc.iProduct, (unsigned char*) orig_product, sizeof(orig_product))) < 0) {
      fprintf(stderr, "ERROR: Unable to retrieve product (%d): %s\n", ires, libusb_strerror((enum libusb_error) ires));
      return EXIT_FAILURE;
    }
    print_verbose("Old product:      %s\n", orig_product);
    if (product == NULL)
      product = orig_product;

    if ((ires = libusb_get_string_descriptor_ascii(ftdi.usb_dev, desc.iSerialNumber, (unsigned char*) orig_serial, sizeof(orig_serial))) < 0) {
      fprintf(stderr, "ERROR: Unable to retrieve serial (%d): %s\n", ires, libusb_strerror((enum libusb_error) ires));
      return EXIT_FAILURE;
    }
    print_verbose("Old serial:       %s\n", orig_serial);
    if (serial == NULL)
      serial = orig_serial;
  }

  print_verbose("New manufacturer: %s\n", manufacturer);
  print_verbose("New product:      %s\n", product);
  print_verbose("New serial:       %s\n", serial);

  if ((ires = ftdi_eeprom_initdefaults (&ftdi, manufacturer, product, serial)) < 0) {
    fprintf(stderr, "Unable to set EEPROM defaults: %d\n", ires);
    return EXIT_FAILURE;
  }

  if ((ires = ftdi_eeprom_build (&ftdi)) < 0) {
    fprintf(stderr, "Unable to build EEPROM: %d\n", ires);
    return EXIT_FAILURE;
  }

  if ((ires = ftdi_write_eeprom (&ftdi)) < 0) {
    fprintf(stderr, "Unable to write EEPROM: %d\n", ires);
    return EXIT_FAILURE;
  }

  ftdi_deinit(&ftdi);

  return EXIT_SUCCESS;
}