1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddk/binding.h> 6#include <ddk/debug.h> 7#include <ddk/device.h> 8#include <ddk/driver.h> 9#include <ddk/protocol/serial-impl.h> 10#include <ddk/protocol/usb.h> 11#include <ddk/usb/usb.h> 12#include <zircon/listnode.h> 13#include <zircon/hw/usb.h> 14 15#include <inttypes.h> 16#include <fcntl.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20#include <threads.h> 21#include <unistd.h> 22 23#include "ftdi.h" 24 25#define FTDI_STATUS_SIZE 2 26#define FTDI_RX_HEADER_SIZE 4 27 28#define READ_REQ_COUNT 8 29#define WRITE_REQ_COUNT 4 30#define INTR_REQ_COUNT 4 31#define USB_BUF_SIZE 2048 32#define INTR_REQ_SIZE 4 33 34#define FIFOSIZE 256 35#define FIFOMASK (FIFOSIZE - 1) 36 37typedef struct { 38 zx_device_t* usb_device; 39 zx_device_t* zxdev; 40 usb_protocol_t usb; 41 42 uint16_t ftditype; 43 uint32_t baudrate; 44 45 serial_port_info_t serial_port_info; 46 serial_impl_protocol_t serial; 47 48 serial_notify_cb notify_cb; 49 void* notify_cb_cookie; 50 bool enabled; 51 uint32_t state; 52 // pool of free USB requests 53 list_node_t free_read_reqs; 54 list_node_t free_write_reqs; 55 // list of received packets not yet read by upper layer 56 list_node_t completed_reads; 57 size_t read_offset; 58 mtx_t mutex; 59} ftdi_t; 60 61 62static uint32_t ftdi_check_state(ftdi_t* ftdi) { 63 uint32_t state = 0; 64 65 state |= list_is_empty(&ftdi->free_write_reqs) ? 0 : SERIAL_STATE_WRITABLE; 66 67 state |= list_is_empty(&ftdi->completed_reads) ? 0 : SERIAL_STATE_READABLE; 68 69 if (state != ftdi->state) { 70 ftdi->state = state; 71 if (ftdi->notify_cb) { 72 ftdi->notify_cb(state, ftdi->notify_cb_cookie); 73 } 74 } 75 return state; 76} 77 78static void ftdi_read_complete(usb_request_t* request, void* cookie) { 79 ftdi_t* ftdi = (ftdi_t*)cookie; 80 81 if (request->response.status == ZX_ERR_IO_NOT_PRESENT) { 82 zxlogf(INFO,"FTDI: remote closed\n"); 83 usb_req_release(&ftdi->usb, request); 84 return; 85 } 86 87 mtx_lock(&ftdi->mutex); 88 if ((request->response.status == ZX_OK) && (request->response.actual > 2)) { 89 list_add_tail(&ftdi->completed_reads, &request->node); 90 ftdi_check_state(ftdi); 91 } else { 92 usb_request_queue(&ftdi->usb, request); 93 } 94 mtx_unlock(&ftdi->mutex); 95} 96 97static void ftdi_write_complete(usb_request_t* request, void* cookie) { 98 ftdi_t* ftdi = (ftdi_t*)cookie; 99 100 if (request->response.status == ZX_ERR_IO_NOT_PRESENT) { 101 usb_req_release(&ftdi->usb, request); 102 return; 103 } 104 mtx_lock(&ftdi->mutex); 105 list_add_tail(&ftdi->free_write_reqs, &request->node); 106 ftdi_check_state(ftdi); 107 mtx_unlock(&ftdi->mutex); 108} 109 110static zx_status_t ftdi_calc_dividers(uint32_t* baudrate, uint32_t clock, uint32_t divisor, 111 uint16_t* integer_div, uint16_t* fraction_div) { 112 113 static const uint8_t frac_lookup[8] = {0, 3, 2, 4, 1, 5, 6, 7}; 114 115 uint32_t base_clock = clock/divisor; 116 117 // integer dividers of 1 and 0 are special cases. 0=base_clock and 1 = 2/3 of base clock 118 if (*baudrate >= base_clock) { // return with max baud rate achievable 119 *fraction_div = 0; 120 *integer_div = 0; 121 *baudrate = base_clock; 122 } 123 else if (*baudrate >= (base_clock* 2 )/3) { 124 *integer_div = 1; 125 *fraction_div = 0; 126 *baudrate = (base_clock * 2)/3; 127 } else { 128 // create a 28.4 fractional integer 129 uint32_t ratio = (base_clock * 16) / *baudrate; 130 ratio++; //round up if needed 131 ratio = ratio & 0xfffffffe; 132 133 *baudrate = (base_clock << 4) / ratio; 134 *integer_div = ratio >> 4; 135 *fraction_div = frac_lookup[ (ratio >> 1) & 0x07 ]; 136 } 137 return ZX_OK; 138} 139 140static zx_status_t ftdi_write(void *ctx, const void* buf, size_t length, size_t* actual) { 141 ftdi_t* ftdi = ctx; 142 usb_request_t* req = NULL; 143 zx_status_t status = ZX_OK; 144 145 mtx_lock(&ftdi->mutex); 146 147 req = list_remove_head_type(&ftdi->free_write_reqs, usb_request_t, node); 148 if (!req) { 149 status = ZX_ERR_SHOULD_WAIT; 150 *actual = 0; 151 goto out; 152 } 153 154 *actual = usb_req_copy_to(&ftdi->usb, req, buf, length, 0); 155 req->header.length = length; 156 157 usb_request_queue(&ftdi->usb,req); 158 ftdi_check_state(ftdi); 159 160out: 161 mtx_unlock(&ftdi->mutex); 162 return status; 163} 164 165 166static zx_status_t ftdi_read(void* ctx, void* data, size_t len, size_t* actual) { 167 ftdi_t* ftdi = ctx; 168 size_t bytes_copied = 0; 169 size_t offset = ftdi->read_offset; 170 uint8_t* buffer = (uint8_t*)data; 171 172 mtx_lock(&ftdi->mutex); 173 174 usb_request_t* req = list_peek_head_type(&ftdi->completed_reads, 175 usb_request_t, node); 176 while ((req) && (bytes_copied < len)) { 177 178 size_t to_copy = req->response.actual - offset - FTDI_STATUS_SIZE; 179 180 if ( (to_copy + bytes_copied) > len) { 181 to_copy = len - bytes_copied; 182 } 183 184 usb_req_copy_from(&ftdi->usb, req, &buffer[bytes_copied], 185 to_copy, offset + FTDI_STATUS_SIZE); 186 187 bytes_copied = bytes_copied + to_copy; 188 189 if ((to_copy + offset + FTDI_STATUS_SIZE) < req->response.actual) { 190 offset = offset + to_copy; 191 goto out; 192 } else { 193 list_remove_head(&ftdi->completed_reads); 194 // requeue the read request 195 usb_request_queue(&ftdi->usb, req); 196 offset = 0; 197 } 198 199 req = list_peek_head_type(&ftdi->completed_reads, usb_request_t, node); 200 } 201 ftdi_check_state(ftdi); 202 203out: 204 ftdi->read_offset = offset; 205 mtx_unlock(&ftdi->mutex); 206 *actual = bytes_copied; 207 return *actual? ZX_OK : ZX_ERR_SHOULD_WAIT; 208} 209 210 211static zx_status_t ftdi_set_baudrate(ftdi_t* ftdi, uint32_t baudrate){ 212 uint16_t whole,fraction,value,index; 213 zx_status_t status; 214 215 if (ftdi == NULL) { 216 return ZX_ERR_INVALID_ARGS; 217 } 218 219 switch(ftdi->ftditype) { 220 case FTDI_TYPE_R: 221 case FTDI_TYPE_2232C: 222 case FTDI_TYPE_BM: 223 ftdi_calc_dividers(&baudrate,FTDI_C_CLK,16,&whole,&fraction); 224 ftdi->baudrate = baudrate; 225 break; 226 default: 227 return ZX_ERR_INVALID_ARGS; 228 } 229 value = (whole & 0x3fff) | (fraction << 14); 230 index = fraction >> 2; 231 status = usb_control(&ftdi->usb, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 232 FTDI_SIO_SET_BAUDRATE, value, index, NULL, 0, 233 ZX_TIME_INFINITE,NULL); 234 if (status == ZX_OK) { 235 ftdi->baudrate = baudrate; 236 } 237 return status; 238} 239 240static zx_status_t ftdi_reset(ftdi_t* ftdi) { 241 242 if (ftdi == NULL || ftdi->usb_device == NULL) { 243 return ZX_ERR_INVALID_ARGS; 244 } 245 246 return usb_control( 247 &ftdi->usb, 248 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 249 FTDI_SIO_RESET_REQUEST, 250 FTDI_SIO_RESET, //value 251 0, //index 252 NULL, 0, //data,length 253 ZX_TIME_INFINITE, 254 NULL); 255} 256 257 258static zx_status_t ftdi_serial_config(void* ctx, uint32_t baud_rate, uint32_t flags) { 259 ftdi_t* ftdi = ctx; 260 261 if (baud_rate != ftdi->baudrate) { 262 return ftdi_set_baudrate(ftdi, baud_rate); 263 } 264 265 return ZX_OK; 266} 267 268 269static zx_status_t ftdi_serial_get_info(void* ctx, serial_port_info_t* info) { 270 ftdi_t* ftdi = ctx; 271 memcpy(info, &ftdi->serial_port_info, sizeof(*info)); 272 return ZX_OK; 273} 274 275static zx_status_t ftdi_serial_enable(void* ctx, bool enable) { 276 ftdi_t* ftdi = ctx; 277 ftdi->enabled = enable; 278 return ZX_OK; 279} 280 281static zx_status_t ftdi_set_notify_callback(void* ctx, serial_notify_cb cb, void* cookie) { 282 ftdi_t* ftdi = ctx; 283 284 if (ftdi->enabled) { 285 return ZX_ERR_BAD_STATE; 286 } 287 288 ftdi->notify_cb = cb; 289 ftdi->notify_cb_cookie = cookie; 290 291 mtx_lock(&ftdi->mutex); 292 ftdi_check_state(ftdi); 293 mtx_unlock(&ftdi->mutex); 294 295 return ZX_OK; 296} 297 298static serial_impl_ops_t ftdi_serial_ops = { 299 .get_info = ftdi_serial_get_info, 300 .config = ftdi_serial_config, 301 .enable = ftdi_serial_enable, 302 303 .read = ftdi_read, 304 .write = ftdi_write, 305 .set_notify_callback = ftdi_set_notify_callback, 306}; 307 308 309static void ftdi_free(ftdi_t* ftdi) { 310 usb_request_t* req; 311 while ((req = list_remove_head_type(&ftdi->free_read_reqs, usb_request_t, node)) != NULL) { 312 usb_req_release(&ftdi->usb, req); 313 } 314 while ((req = list_remove_head_type(&ftdi->free_write_reqs, usb_request_t, node)) != NULL) { 315 usb_req_release(&ftdi->usb, req); 316 } 317 while ((req = list_remove_head_type(&ftdi->completed_reads, usb_request_t, node)) != NULL) { 318 usb_req_release(&ftdi->usb, req); 319 } 320 321 free(ftdi); 322} 323 324static void ftdi_uart_release(void* ctx) { 325 zxlogf(INFO,"releasing ftdi uart driver\n"); 326 ftdi_t* ftdi = ctx; 327 ftdi_free(ftdi); 328} 329 330static void ftdi_unbind(void* ctx) { 331 ftdi_t* ftdi = ctx; 332 device_remove(ftdi->usb_device); 333} 334 335static zx_protocol_device_t ftdi_device_proto = { 336 .version = DEVICE_OPS_VERSION, 337 .unbind = ftdi_unbind, 338 .release = ftdi_uart_release, 339}; 340 341static zx_status_t ftdi_bind(void* ctx, zx_device_t* device) { 342 343 usb_protocol_t usb; 344 zx_status_t status = device_get_protocol(device, ZX_PROTOCOL_USB, &usb); 345 if (status != ZX_OK) { 346 return status; 347 } 348 349 // find our endpoints 350 usb_desc_iter_t iter; 351 status = usb_desc_iter_init(&usb, &iter); 352 353 if (status != ZX_OK) { 354 return status; 355 } 356 357 usb_desc_iter_next_interface(&iter, true); 358 359 uint8_t bulk_in_addr = 0; 360 uint8_t bulk_out_addr = 0; 361 362 usb_endpoint_descriptor_t* endp = usb_desc_iter_next_endpoint(&iter); 363 //int idx = 0; 364 while (endp) { 365 if (usb_ep_direction(endp) == USB_ENDPOINT_OUT) { 366 if (usb_ep_type(endp) == USB_ENDPOINT_BULK) { 367 bulk_out_addr = endp->bEndpointAddress; 368 } 369 } else { 370 if (usb_ep_type(endp) == USB_ENDPOINT_BULK) { 371 bulk_in_addr = endp->bEndpointAddress; 372 } 373 } 374 endp = usb_desc_iter_next_endpoint(&iter); 375 } 376 377 usb_desc_iter_release(&iter); 378 379 if (!bulk_in_addr || !bulk_out_addr ) { 380 zxlogf(ERROR,"FTDI: could not find all endpoints\n"); 381 return ZX_ERR_NOT_SUPPORTED; 382 } 383 384 ftdi_t* ftdi = calloc(1, sizeof(ftdi_t)); 385 if (!ftdi) { 386 zxlogf(ERROR,"FTDI: Not enough memory\n"); 387 return ZX_ERR_NO_MEMORY; 388 } 389 390 ftdi->ftditype = FTDI_TYPE_R; 391 392 list_initialize(&ftdi->free_read_reqs); 393 list_initialize(&ftdi->free_write_reqs); 394 list_initialize(&ftdi->completed_reads); 395 396 ftdi->usb_device = device; 397 398 memcpy(&ftdi->usb, &usb, sizeof(ftdi->usb)); 399 400 mtx_init(&ftdi->mutex, mtx_plain); 401 402 for (int i = 0; i < READ_REQ_COUNT; i++) { 403 usb_request_t* req; 404 status = usb_req_alloc(&ftdi->usb, &req, USB_BUF_SIZE, bulk_in_addr); 405 if (status != ZX_OK) { 406 goto fail; 407 } 408 req->complete_cb = ftdi_read_complete; 409 req->cookie = ftdi; 410 list_add_head(&ftdi->free_read_reqs, &req->node); 411 } 412 for (int i = 0; i < WRITE_REQ_COUNT; i++) { 413 usb_request_t* req; 414 status = usb_req_alloc(&ftdi->usb, &req, USB_BUF_SIZE, bulk_out_addr); 415 if (status != ZX_OK) { 416 goto fail; 417 } 418 req->complete_cb = ftdi_write_complete; 419 req->cookie = ftdi; 420 list_add_head(&ftdi->free_write_reqs, &req->node); 421 } 422 423 if (ftdi_reset(ftdi) < 0) { 424 zxlogf(ERROR,"FTDI reset failed\n"); 425 goto fail; 426 } 427 428 status = ftdi_set_baudrate(ftdi, 115200); 429 if (status != ZX_OK) { 430 zxlogf(ERROR,"FTDI: set baudrate failed\n"); 431 goto fail; 432 } 433 434 ftdi->serial_port_info.serial_class = SERIAL_CLASS_GENERIC; 435 436 device_add_args_t args = { 437 .version = DEVICE_ADD_ARGS_VERSION, 438 .name = "ftdi-uart", 439 .ctx = ftdi, 440 .ops = &ftdi_device_proto, 441 .proto_id = ZX_PROTOCOL_SERIAL_IMPL, 442 .proto_ops = &ftdi_serial_ops, 443 }; 444 445 status = device_add(ftdi->usb_device, &args, &ftdi->zxdev); 446 if (status != ZX_OK) { 447 zxlogf(ERROR, "ftdi_uart: device_add failed\n"); 448 goto fail; 449 } 450 451 //Queue the read requests 452 usb_request_t* req; 453 usb_request_t* prev; 454 list_for_every_entry_safe (&ftdi->free_read_reqs, req, prev, usb_request_t, node) { 455 list_delete(&req->node); 456 usb_request_queue(&ftdi->usb, req); 457 } 458 459 zxlogf(INFO,"ftdi bind successful\n"); 460 return status; 461 462fail: 463 zxlogf(ERROR,"ftdi_bind failed: %d\n", status); 464 ftdi_free(ftdi); 465 return status; 466} 467 468static zx_driver_ops_t _ftdi_driver_ops = { 469 .version = DRIVER_OPS_VERSION, 470 .bind = ftdi_bind, 471}; 472 473ZIRCON_DRIVER_BEGIN(ftdi, _ftdi_driver_ops, "zircon", "0.1", 3) 474 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_USB), 475 BI_MATCH_IF(EQ, BIND_USB_VID, FTDI_VID), 476 BI_MATCH_IF(EQ, BIND_USB_PID, FTDI_232R_PID), 477ZIRCON_DRIVER_END(ftdi) 478