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", this, state); 189 190 int32 control; 191 control = (state & USB_CDC_CONTROL_SIGNAL_STATE_RTS) ? FTDI_SIO_SET_RTS_HIGH 192 : FTDI_SIO_SET_RTS_LOW; 193 194 size_t length = 0; 195 status_t status = gUSBModule->send_request(Device(), 196 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 197 FTDI_SIO_MODEM_CTRL, control, 198 FTDI_PIT_DEFAULT, 0, NULL, &length); 199 200 if (status != B_OK) 201 TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): control set request failed: 0x%08x\n", status); 202 203 control = (state & USB_CDC_CONTROL_SIGNAL_STATE_DTR) ? FTDI_SIO_SET_DTR_HIGH 204 : FTDI_SIO_SET_DTR_LOW; 205 206 status = gUSBModule->send_request(Device(), 207 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 208 FTDI_SIO_MODEM_CTRL, control, 209 FTDI_PIT_DEFAULT, 0, NULL, &length); 210 211 if (status != B_OK) 212 TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): control set request failed: 0x%08x\n", status); 213 214 TRACE_FUNCRET("< FTDIDevice::SetControlLineState() returns: 0x%08x\n", status); 215 return status; 216 } 217 218 219 void 220 FTDIDevice::OnRead(char **buffer, size_t *numBytes) 221 { 222 fStatusMSR = FTDI_GET_MSR(*buffer); 223 fStatusLSR = FTDI_GET_LSR(*buffer); 224 TRACE("FTDIDevice::OnRead(): MSR: 0x%02x LSR: 0x%02x\n", fStatusMSR, fStatusLSR); 225 *buffer += 2; 226 *numBytes -= 2; 227 } 228 229 230 void 231 FTDIDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 232 { 233 if (*numBytes > FTDI_BUFFER_SIZE) 234 *numBytes = *packetBytes = FTDI_BUFFER_SIZE; 235 236 char *writeBuffer = WriteBuffer(); 237 if (fHeaderLength > 0) { 238 if (*numBytes > WriteBufferSize() - fHeaderLength) 239 *numBytes = *packetBytes = WriteBufferSize() - fHeaderLength; 240 241 *writeBuffer = FTDI_OUT_TAG(*numBytes, FTDI_PIT_DEFAULT); 242 } 243 244 memcpy(writeBuffer + fHeaderLength, buffer, *packetBytes); 245 *packetBytes += fHeaderLength; 246 } 247