1 /* 2 * Copyright (c) 2007-2008 by Michael Lotz 3 * Heavily based on the original usb_serial driver which is: 4 * 5 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li> 6 * Distributed under the terms of the MIT License. 7 * 8 * Authors: 9 * Alexander von Gluck IV, kallisti5@unixzen.com 10 */ 11 12 13 #include "FTDI.h" 14 #include "FTDIRegs.h" 15 16 17 FTDIDevice::FTDIDevice(usb_device device, uint16 vendorID, uint16 productID, 18 const char *description) 19 : SerialDevice(device, vendorID, productID, description), 20 fHeaderLength(0), 21 fStatusMSR(0), 22 fStatusLSR(0) 23 { 24 } 25 26 27 status_t 28 FTDIDevice::AddDevice(const usb_configuration_info *config) 29 { 30 TRACE_FUNCALLS("> FTDIDevice::AddDevice(%08x, %08x)\n", this, config); 31 status_t status = ENODEV; 32 if (config->interface_count > 0) { 33 int32 pipesSet = 0; 34 usb_interface_info *interface = config->interface[0].active; 35 for (size_t i = 0; i < interface->endpoint_count; i++) { 36 usb_endpoint_info *endpoint = &interface->endpoint[i]; 37 if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 38 if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 39 SetReadPipe(endpoint->handle); 40 if (++pipesSet >= 3) 41 break; 42 } else { 43 if (endpoint->descr->endpoint_address) { 44 SetControlPipe(endpoint->handle); 45 SetWritePipe(endpoint->handle); 46 pipesSet += 2; 47 if (pipesSet >= 3) 48 break; 49 } 50 } 51 } 52 } 53 54 if (pipesSet >= 3) { 55 if (ProductID() == 0x8372) // AU100AX 56 fHeaderLength = 1; 57 else 58 fHeaderLength = 0; 59 60 status = B_OK; 61 } 62 } 63 64 TRACE_FUNCRET("< FTDIDevice::AddDevice() returns: 0x%08x\n", status); 65 return status; 66 } 67 68 69 status_t 70 FTDIDevice::ResetDevice() 71 { 72 TRACE_FUNCALLS("> FTDIDevice::ResetDevice(0x%08x)\n", this); 73 74 size_t length = 0; 75 status_t status = gUSBModule->send_request(Device(), 76 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 77 FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, 78 FTDI_PIT_DEFAULT, 0, NULL, &length); 79 80 TRACE_FUNCRET("< FTDIDevice::ResetDevice() returns:%08x\n", status); 81 return status; 82 } 83 84 85 status_t 86 FTDIDevice::SetLineCoding(usb_cdc_line_coding *lineCoding) 87 { 88 TRACE_FUNCALLS("> FTDIDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n", 89 this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity, 90 lineCoding->databits); 91 92 int32 rate = 0; 93 if (ProductID() == 0x8372) { 94 // AU100AX 95 switch (lineCoding->speed) { 96 case 300: rate = ftdi_sio_b300; break; 97 case 600: rate = ftdi_sio_b600; break; 98 case 1200: rate = ftdi_sio_b1200; break; 99 case 2400: rate = ftdi_sio_b2400; break; 100 case 4800: rate = ftdi_sio_b4800; break; 101 case 9600: rate = ftdi_sio_b9600; break; 102 case 19200: rate = ftdi_sio_b19200; break; 103 case 38400: rate = ftdi_sio_b38400; break; 104 case 57600: rate = ftdi_sio_b57600; break; 105 case 115200: rate = ftdi_sio_b115200; break; 106 default: 107 rate = ftdi_sio_b19200; 108 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is " 109 "not supported by this hardware. Defaulted to %d\n", 110 lineCoding->speed, rate); 111 break; 112 } 113 } else { 114 /* Compute baudrate register value as documented in AN232B-05 from FTDI. 115 Bits 13-0 are the integer divider, and bits 16-14 are the fractional 116 divider setting. 3Mbaud and 2Mbaud are special values, and at such 117 high speeds the use of the fractional divider is not possible. */ 118 if (lineCoding->speed == 3000000) 119 rate = 0; 120 else if (lineCoding->speed == 2000000) 121 rate = 1; 122 else { 123 if (lineCoding->speed > 1500000) { 124 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is " 125 "not supported by this hardware. Defaulted to %d\n", 126 lineCoding->speed, 19200); 127 lineCoding->speed = 19200; 128 } 129 rate = 3000000 * 8 / lineCoding->speed; 130 int frac = ftdi_8u232am_frac[rate & 0x7]; 131 rate = (rate >> 3) | frac; 132 } 133 } 134 135 size_t length = 0; 136 status_t status = gUSBModule->send_request(Device(), 137 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 138 FTDI_SIO_SET_BAUD_RATE, rate, 139 FTDI_PIT_DEFAULT, 0, NULL, &length); 140 if (status != B_OK) 141 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): datarate set request failed: 0x%08x\n", status); 142 143 int32 data = 0; 144 switch (lineCoding->stopbits) { 145 case USB_CDC_LINE_CODING_1_STOPBIT: data = FTDI_SIO_SET_DATA_STOP_BITS_2; break; 146 case USB_CDC_LINE_CODING_2_STOPBITS: data = FTDI_SIO_SET_DATA_STOP_BITS_1; break; 147 default: 148 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong stopbits param: %d\n", 149 lineCoding->stopbits); 150 break; 151 } 152 153 switch (lineCoding->parity) { 154 case USB_CDC_LINE_CODING_NO_PARITY: data |= FTDI_SIO_SET_DATA_PARITY_NONE; break; 155 case USB_CDC_LINE_CODING_EVEN_PARITY: data |= FTDI_SIO_SET_DATA_PARITY_EVEN; break; 156 case USB_CDC_LINE_CODING_ODD_PARITY: data |= FTDI_SIO_SET_DATA_PARITY_ODD; break; 157 default: 158 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong parity param: %d\n", 159 lineCoding->parity); 160 break; 161 } 162 163 switch (lineCoding->databits) { 164 case 8: data |= FTDI_SIO_SET_DATA_BITS(8); break; 165 case 7: data |= FTDI_SIO_SET_DATA_BITS(7); break; 166 default: 167 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong databits param: %d\n", 168 lineCoding->databits); 169 break; 170 } 171 172 length = 0; 173 status = gUSBModule->send_request(Device(), 174 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 175 FTDI_SIO_SET_DATA, data, 176 FTDI_PIT_DEFAULT, 0, NULL, &length); 177 if (status != B_OK) 178 TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): data set request failed: %08x\n", status); 179 180 TRACE_FUNCRET("< FTDIDevice::SetLineCoding() returns: 0x%08x\n", status); 181 return status; 182 } 183 184 185 status_t 186 FTDIDevice::SetControlLineState(uint16 state) 187 { 188 TRACE_FUNCALLS("> FTDIDevice::SetControlLineState(0x%08x, 0x%04x)\n", 189 this, state); 190 191 int32 control; 192 control = (state & USB_CDC_CONTROL_SIGNAL_STATE_RTS) ? FTDI_SIO_SET_RTS_HIGH 193 : FTDI_SIO_SET_RTS_LOW; 194 195 size_t length = 0; 196 status_t status = gUSBModule->send_request(Device(), 197 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 198 FTDI_SIO_MODEM_CTRL, control, 199 FTDI_PIT_DEFAULT, 0, NULL, &length); 200 201 if (status != B_OK) { 202 TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): " 203 "control set request failed: 0x%08x\n", status); 204 } 205 206 control = (state & USB_CDC_CONTROL_SIGNAL_STATE_DTR) ? FTDI_SIO_SET_DTR_HIGH 207 : FTDI_SIO_SET_DTR_LOW; 208 209 status = gUSBModule->send_request(Device(), 210 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 211 FTDI_SIO_MODEM_CTRL, control, 212 FTDI_PIT_DEFAULT, 0, NULL, &length); 213 214 if (status != B_OK) { 215 TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): " 216 "control set request failed: 0x%08x\n", status); 217 } 218 219 TRACE_FUNCRET("< FTDIDevice::SetControlLineState() returns: 0x%08x\n", 220 status); 221 return status; 222 } 223 224 225 status_t 226 FTDIDevice::SetHardwareFlowControl(bool enable) 227 { 228 TRACE_FUNCALLS("> FTDIDevice::SetHardwareFlowControl(0x%08x, %d)\n", 229 this, enable); 230 231 uint32 control = enable ? FTDI_SIO_RTS_CTS_HS : FTDI_SIO_DISABLE_FLOW_CTRL; 232 233 size_t length = 0; 234 status_t status = gUSBModule->send_request(Device(), 235 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 236 FTDI_SIO_SET_FLOW_CTRL, 0, 237 FTDI_PIT_DEFAULT | (control << 8), 0, NULL, &length); 238 239 if (status != B_OK) 240 TRACE_ALWAYS("= FTDIDevice::SetHardwareFlowControl(): " 241 "request failed: 0x%08x\n", status); 242 243 TRACE_FUNCRET("< FTDIDevice::SetHardwareFlowControl() returns: 0x%08x\n", 244 status); 245 return status; 246 } 247 248 249 void 250 FTDIDevice::OnRead(char **buffer, size_t *numBytes) 251 { 252 /* The input consists of 64-byte packets, in which the first two bytes 253 * give the status (16C550 like) of the UART. A single buffer may have 254 * several of these packets in it. 255 */ 256 257 size_t i = 0; 258 size_t j = 0; 259 260 while (i < *numBytes) { 261 if ((i % 64) == 0) { 262 fStatusMSR = FTDI_GET_MSR(*buffer + i); 263 fStatusLSR = FTDI_GET_LSR(*buffer + i); 264 TRACE("FTDIDevice::OnRead(): MSR: 0x%02x LSR: 0x%02x\n", 265 fStatusMSR, fStatusLSR); 266 267 // Skip over the buffer header 268 i += 2; 269 } else { 270 // Group normal bytes towards the start of the buffer 271 (*buffer)[j++] = (*buffer)[i++]; 272 } 273 } 274 275 // Tell the caller about the number of "real" bytes remaining in the buffer 276 *numBytes = j; 277 } 278 279 280 void 281 FTDIDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 282 { 283 if (*numBytes > FTDI_BUFFER_SIZE) 284 *numBytes = *packetBytes = FTDI_BUFFER_SIZE; 285 286 char *writeBuffer = WriteBuffer(); 287 if (fHeaderLength > 0) { 288 if (*numBytes > WriteBufferSize() - fHeaderLength) 289 *numBytes = *packetBytes = WriteBufferSize() - fHeaderLength; 290 291 *writeBuffer = FTDI_OUT_TAG(*numBytes, FTDI_PIT_DEFAULT); 292 } 293 294 memcpy(writeBuffer + fHeaderLength, buffer, *packetBytes); 295 *packetBytes += fHeaderLength; 296 } 297