gateware

A collection of little open source FPGA hobby projects
git clone http://frotz.net/git/gateware.git
Log | Files | Refs | README

ftdi.c (5741B)


      1 // Copyright 2015 Brian Swetland <swetland@frotz.net>
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #include "ftdi.h"
     20 
     21 #include <libusb-1.0/libusb.h>
     22 
     23 // FTDI MPSSE Device Info
     24 static struct {
     25 	u16 vid;
     26 	u16 pid;
     27 	u8 ep_in;
     28 	u8 ep_out;
     29 	const char *name;
     30 } devinfo[] = {
     31 	{ 0x0403, 0x6010, 0x81, 0x02, "ftdi" },
     32 	{ 0x0403, 0x6014, 0x81, 0x02, "ftdi" },
     33 	{ 0x0000, 0x0000, 0},
     34 };
     35 
     36 #define FTDI_GPIO_READ_LO		0x81
     37 #define FTDI_GPIO_READ_HI		0x83
     38 #define FTDI_GPIO_WRITE_LO		0x80 // Val Dir  (1=Out 0=In)
     39 #define FTDI_GPIO_WRITE_HI		0x82 // Val Dir  (1=Out 0=In)
     40 
     41 #define FTDI_LOOPBACK_OFF		0x85
     42 #define FTDI_CLOCK_DIV_1		0x8A
     43 #define FTDI_CLOCK_DIV_5		0x8B
     44 #define FTDI_DIVISOR_SET		0x86
     45 
     46 // TN = TX on Negative Clock Edge
     47 // TP = TX on Positive CLock Edge
     48 // byte transfers followed by LenLo LenHi (len-1) then data
     49 #define FTDI_MSB_TX_BYTES_TP		0x10
     50 #define FTDI_MSB_TX_BYTES_TN		0x11 //
     51 #define FTDI_MSB_IO_BYTES_TN_RP		0x31 //
     52 #define FTDI_MSB_IO_BYTES_TP_RN		0x34
     53 
     54 #define FTDI_LSB_TX_BYTES_TP		0x18
     55 #define FTDI_LSB_TX_BYTES_TN		0x19
     56 #define FTDI_LSB_IO_BYTES_TN_RP		0x39
     57 #define FTDI_LSB_IO_BYTES_TP_RN		0x3C
     58 
     59 struct FTDI {
     60 	struct libusb_device_handle *udev;
     61 	u8 ep_in;
     62 	u8 ep_out;
     63 	u32 read_count;
     64 	u32 read_size;
     65 	u8 *read_ptr;
     66 	u8 read_buffer[512];
     67 };
     68 
     69 #define FTDI_REQTYPE_OUT	(LIBUSB_REQUEST_TYPE_VENDOR \
     70 	| LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT)
     71 #define FTDI_CTL_RESET		0x00
     72 #define FTDI_CTL_SET_BITMODE	0x0B
     73 #define FTDI_CTL_SET_EVENT_CH	0x06
     74 #define FTDI_CTL_SET_ERROR_CH	0x07
     75 
     76 #define FTDI_IFC_A 1
     77 #define FTDI_IFC_B 2
     78 
     79 static int ftdi_reset(FTDI *d) {
     80 	struct libusb_device_handle *udev = d->udev;
     81 	if (libusb_control_transfer(udev, FTDI_REQTYPE_OUT, FTDI_CTL_RESET,
     82 		0, FTDI_IFC_A, NULL, 0, 10000) < 0) {
     83 		fprintf(stderr, "ftdi: reset failed\n");
     84 		return -1;
     85 	}
     86 	return 0;
     87 }
     88 
     89 static int ftdi_mpsse_enable(FTDI *d) {
     90 	struct libusb_device_handle *udev = d->udev;
     91 	if (libusb_control_transfer(udev, FTDI_REQTYPE_OUT, FTDI_CTL_SET_BITMODE,
     92 		0x0000, FTDI_IFC_A, NULL, 0, 10000) < 0) {
     93 		fprintf(stderr, "ftdi: set bitmode failed\n");
     94 		return -1;
     95 	}
     96 	if (libusb_control_transfer(udev, FTDI_REQTYPE_OUT, FTDI_CTL_SET_BITMODE,
     97 		0x020b, FTDI_IFC_A, NULL, 0, 10000) < 0) {
     98 		fprintf(stderr, "ftdi: set bitmode failed\n");
     99 		return -1;
    100 	}
    101 	if (libusb_control_transfer(udev, FTDI_REQTYPE_OUT, FTDI_CTL_SET_EVENT_CH,
    102 		0, FTDI_IFC_A, NULL, 0, 10000) < 0) {
    103 		fprintf(stderr, "ftdi: disable event character failed\n");
    104 		return -1;
    105 	}
    106 	return 0;	
    107 	if (libusb_control_transfer(udev, FTDI_REQTYPE_OUT, FTDI_CTL_SET_ERROR_CH,
    108 		0, FTDI_IFC_A, NULL, 0, 10000) < 0) {
    109 		fprintf(stderr, "ftdi: disable error character failed\n");
    110 		return -1;
    111 	}
    112 	return 0;	
    113 }
    114 
    115 static int ftdi_init(FTDI *d) {
    116 	struct libusb_device_handle *udev;
    117 	int n;
    118 
    119 	if (libusb_init(NULL) < 0) {
    120 		fprintf(stderr, "ftdi_open: failed to init libusb\n");
    121 		return -1;
    122 	}
    123 	for (n = 0; devinfo[n].name; n++) {
    124 		udev = libusb_open_device_with_vid_pid(NULL,
    125 			devinfo[n].vid, devinfo[n].pid);
    126 		if (udev == 0)
    127 	       		continue;
    128 		libusb_detach_kernel_driver(udev, 0);
    129 		if (libusb_claim_interface(udev, 0) < 0) {
    130 			//TODO: close
    131 			continue;
    132 		}
    133 		d->udev = udev;
    134 		d->read_ptr = d->read_buffer;
    135 		d->read_size = 512;
    136 		d->read_count = 0;
    137 		d->ep_in = devinfo[n].ep_in;
    138 		d->ep_out = devinfo[n].ep_out;
    139 		return 0;
    140 	}
    141 	fprintf(stderr, "ftdi_open: failed to find usb device\n");
    142 	return -1;
    143 }
    144 
    145 static int usb_bulk(struct libusb_device_handle *udev,
    146 	unsigned char ep, void *data, int len, unsigned timeout) {
    147 	int r, xfer;
    148 	r = libusb_bulk_transfer(udev, ep, data, len, &xfer, timeout);
    149 	if (r < 0) {
    150 		fprintf(stderr,"bulk: error: %d\n", r);
    151 		return r;
    152 	}
    153 	return xfer;
    154 }
    155 
    156 /* TODO: handle smaller packet size for lowspeed version of the part */
    157 /* TODO: multi-packet reads */
    158 /* TODO: asynch/background reads */
    159 int ftdi_read(FTDI *d, unsigned char *buffer, int count, int timeout) {
    160 	int xfer;
    161 	while (count > 0) {
    162 		if (d->read_count >= count) {
    163 			memcpy(buffer, d->read_ptr, count);
    164 			d->read_count -= count;
    165 			d->read_ptr += count;
    166 			return 0;
    167 		}
    168 		if (d->read_count > 0) {
    169 			memcpy(buffer, d->read_ptr, d->read_count);
    170 			count -= d->read_count;
    171 			buffer += d->read_count;
    172 			d->read_count = 0;
    173 		}
    174 		xfer = usb_bulk(d->udev, d->ep_in, d->read_buffer, d->read_size, 1000);
    175 		if (xfer < 0)
    176 			return -1;
    177 		if (xfer < 2)
    178 			return -1;
    179 		/* discard header */
    180 		d->read_ptr = d->read_buffer + 2;
    181 		d->read_count = xfer - 2;
    182 	}
    183 	return 0;
    184 }
    185 
    186 
    187 FTDI *ftdi_open(void) {
    188 	FTDI *d;
    189 	if ((d = malloc(sizeof(FTDI))) == NULL) {
    190 		return NULL;
    191 	}
    192 	if (ftdi_init(d))
    193 		goto fail0;
    194 	if (ftdi_reset(d))
    195 		goto fail1;
    196 	if (ftdi_mpsse_enable(d))
    197 		goto fail1;
    198 	return d;
    199 fail1:
    200 	libusb_close(d->udev);
    201 fail0:
    202 	// close?
    203 	free(d);
    204 	return NULL;
    205 }
    206 
    207 int ftdi_send(FTDI *d, void *data, int len, int timeout_ms) {
    208 	return usb_bulk(d->udev, d->ep_out, data, len, timeout_ms);
    209 }
    210 
    211 int ftdi_gpio_set_lo(FTDI *d, u8 val, u8 out) {
    212 	u8 cmd[3] = { FTDI_GPIO_WRITE_LO, val, out };
    213 	return ftdi_send(d, cmd, 3, 1000);
    214 }
    215 
    216 int ftdi_gpio_get_lo(FTDI *d) {
    217 	u8 cmd[1] = { FTDI_GPIO_READ_LO };
    218 	if (ftdi_send(d, cmd, 1, 1000) < 0)
    219 		return -1;
    220 	if (ftdi_read(d, cmd, 1, 1000) < 0)
    221 		return -1;
    222 	return cmd[0];
    223 }
    224