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