blob: ebf4089e8f3b136902b65912f658ae88285a2cd5 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "ftdi_common.h"
// return number of interfaces, -1 for error
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
int fcom_num_interfaces(struct ftdi_context *fc) {
if (fc->usb_dev == NULL) {
// no ftdi_usb_open so haven't contacted device yet ... fail
return -1;
}
switch (fc->type) {
case(TYPE_AM):
case(TYPE_R):
case(TYPE_BM):
#ifdef TYPE_230X
case(TYPE_230X):
#endif
return 1;
break;
case(TYPE_2232C):
case(TYPE_2232H):
return 2;
break;
case(TYPE_4232H):
return 4;
break;
default:
assert(((void)"internal error", 0));
break;
}
return -1;
}
#pragma GCC diagnostic pop
int fcom_cfg(struct ftdi_context *fc, int interface,
enum ftdi_mpsse_mode mode, int direction) {
unsigned char latency;
if (fcom_num_interfaces(fc) > 1) {
prn_dbg("setting interface to %d\n", interface);
if (ftdi_set_interface(fc, interface)) {
ERROR_FTDI("setting interface", fc);
return FCOM_ERR_SET_INTERFACE;
}
}
CHECK_FTDI(ftdi_set_latency_timer(fc, FCOM_USB_LATENCY_TIMER),
"Set latency timer", fc);
CHECK_FTDI(ftdi_get_latency_timer(fc, &latency),
"Get latency timer", fc);
if (latency != FCOM_USB_LATENCY_TIMER)
prn_error("Latency timer = %d but tried to set to %d",
latency, FCOM_USB_LATENCY_TIMER);
CHECK_FTDI(ftdi_set_bitmode(fc, 0, BITMODE_RESET),
"Resetting", fc);
CHECK_FTDI(ftdi_set_bitmode(fc, direction, mode),
"setting mode", fc);
CHECK_FTDI(ftdi_usb_purge_buffers(fc), "Purge buffers", fc);
return FCOM_ERR_NONE;
}
#define USG_DEFAULT(...) \
printf(" DEFAULT="); \
printf(__VA_ARGS__)
static void usage(struct ftdi_common_args *fargs) {
puts("Common ftdi args ::");
puts(" -v <num> : vendor id of device to connect to");
USG_DEFAULT("0x%02x\n", fargs->vendor_id);
puts(" -p <num> : product id of device to connect to");
USG_DEFAULT("0x%02x\n", fargs->product_id);
puts(" -d <num> : "
"device serialname (use if >1 FTDI device with same vid:pid )");
USG_DEFAULT("%d\n", fargs->dev_id);
puts(" -i <interface> : interface id for FTDI port");
USG_DEFAULT("%d\n", fargs->interface);
puts(" -g <dir>:<val> : initial gpio configuration");
puts(" -h : this message");
puts("\nWhere:");
puts(" <interface> : a|b|c|d|1|2|3|4. Note '0' means 'Any' which is device dependent");
puts(" <hz> : number in hertz");
puts(" <dir> : mask for gpio direction. 1=output, 0=input");
puts(" <val> : mask for gpio value. 1=high, 0=low");
puts("\n");
}
int fcom_args(struct ftdi_common_args *fargs, int argc, char **argv) {
int c;
char *ptr;
int args_consumed = 0;
// TODO(tbroch) add uart bits,sbits,parity arg parsing
while ((c = getopt(argc, argv, "v:p:i:d:s:g:h")) != -1) {
switch (c) {
case 'v':
fargs->vendor_id = strtoul(optarg, NULL, 0);
args_consumed += 2;
break;
case 'p':
fargs->product_id = strtoul(optarg, NULL, 0);
args_consumed += 2;
break;
case 'i':
switch(optarg[0]) {
case '0':
fargs->interface = INTERFACE_ANY;
break;
case '1':
case 'a':
case 'A':
fargs->interface = INTERFACE_A;
break;
case '2':
case 'b':
case 'B':
fargs->interface = INTERFACE_B;
break;
case '3':
case 'c':
case 'C':
fargs->interface = INTERFACE_C;
break;
case '4':
case 'd':
case 'D':
fargs->interface = INTERFACE_D;
break;
default:
prn_fatal("Unknown interface value %c. Should be [a|b|c|d]\n", c);
break;
}
args_consumed += 2;
break;
case 'd':
fargs->serialname = malloc(strlen(optarg)+1);
strcpy(fargs->serialname, optarg);
case 'g':
fargs->direction = strtoul(optarg, &ptr, 0);
if (ptr[0] != ':') {
prn_fatal("Poorly formatted direction in -g <dir>:<val> string\n");
break;
}
ptr++;
fargs->value = strtoul(ptr, &ptr, 0);
if (ptr[0] != '\0') {
prn_fatal("Poorly formatted value in -g <dir>:<val> string\n");
break;
}
args_consumed += 2;
break;
case 'h':
usage(fargs);
return -1;
default:
// remaining args parsed by caller
break;
}
}
return args_consumed;
}
int fcom_lookup_serial(struct ftdi_context *fc, char *name) {
// TODO(tbroch) implement lookup of serial from eeprom
long fc_dump = (long)fc; /* Silence compiler warning. */
long name_dump = (long)name; /* Silence compiler warning. */
if (fc_dump > name_dump) /* Silence compiler warning. */
prn_fatal("not implemented\n");
else
prn_fatal("not implemented\n");
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
int fcom_is_mpsse(struct ftdi_context *fc,
struct ftdi_common_args *fargs) {
switch(fc->type) {
case(TYPE_2232C):
return (fargs->interface <= 1);
break;
case(TYPE_2232H):
case(TYPE_4232H):
return (fargs->interface <= 2);
break;
case(TYPE_AM):
case(TYPE_R):
case(TYPE_BM):
#ifdef TYPE_230X
case(TYPE_230X):
#endif
default:
return 0;
break;
}
}
#pragma GCC diagnostic pop
struct ftdi_itype *fcom_lookup_interface(struct ftdi_itype *interfaces,
unsigned int cnt,
unsigned int interface_num,
enum ftdi_interface_type itype) {
if (interface_num > cnt) {
return NULL;
}
if ((itype != ANY) && (interfaces[interface_num-1].type != itype)) {
return NULL;
}
return &interfaces[interface_num-1];
}
static unsigned debug_enabled(void) __attribute__((pure));
static unsigned debug_enabled(void)
{
return getenv("SERVOD_DEBUG") != NULL;
}
static void _prn_time(void)
{
struct timeval tv;
struct timezone tz;
struct tm *tm;
gettimeofday(&tv, &tz);
tm=localtime(&tv.tv_sec);
fprintf(stderr, "(%02d:%02d:%02d.%u)", tm->tm_hour, tm->tm_min,
tm->tm_sec, (unsigned int)tv.tv_usec);
}
static void _prn_common(const char *type,
const char *fmt,
va_list ap) __attribute__((format(printf, 2, 0)));
static void _prn_common(const char *type,
const char *fmt,
va_list ap)
{
fprintf(stderr, "%s :: ", type);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
void prn_fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_prn_common("-F-", fmt, ap);
va_end(ap);
exit(-1);
}
void prn_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_prn_common("-E-", fmt, ap);
va_end(ap);
}
void prn_warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_prn_common("-W-", fmt, ap);
va_end(ap);
}
void prn_info(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_prn_time();
_prn_common("-I-", fmt, ap);
va_end(ap);
}
void prn_perror(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
prn_error("%s (%d): ", strerror(errno), errno);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
void prn_dbg(const char *fmt, ...)
{
if (debug_enabled()) {
va_list ap;
va_start(ap, fmt);
_prn_time();
_prn_common("-D-", fmt, ap);
va_end(ap);
}
}
static void _prn_ftdi_common(const char *type,
int rv,
struct ftdi_context *context,
const char *fmt,
va_list ap) __attribute__((format(printf, 4, 0)));
static void _prn_ftdi_common(const char *type,
int rv,
struct ftdi_context *context,
const char *fmt,
va_list ap)
{
fprintf(stderr, "%s:", type);
vfprintf(stderr, fmt, ap);
fprintf(stderr, " : %d (%s)\n", rv, ftdi_get_error_string(context));
va_end(ap);
}
void prn_ftdi_error(int rv, struct ftdi_context *context, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_prn_ftdi_common("ERROR", rv, context, fmt, ap);
va_end(ap);
}
void prn_ftdi_warn(int rv, struct ftdi_context *context, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_prn_ftdi_common("WARN", rv, context, fmt, ap);
va_end(ap);
}