1 /* 2 * Copyright 2022, Gerasim Troeglazov <3dEyes@gmail.com> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "WinChipHead.h" 7 8 WCHDevice::WCHDevice(usb_device device, uint16 vendorID, uint16 productID, 9 const char *description) 10 : SerialDevice(device, vendorID, productID, description), 11 fChipVersion(0), 12 fStatusMCR(0), 13 fStatusLCR(CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX | CH34X_LCR_CS8), 14 fDataRate(CH34X_SIO_9600) 15 { 16 } 17 18 19 // Called for each configuration of the device. Return B_OK if the given 20 // configuration sounds like it is the usb serial one. 21 status_t 22 WCHDevice::AddDevice(const usb_configuration_info *config) 23 { 24 TRACE_FUNCALLS("> WCHDevice::AddDevice(%08x, %08x)\n", this, config); 25 26 status_t status = ENODEV; 27 if (config->interface_count > 0) { 28 int32 pipesSet = 0; 29 usb_interface_info *interface = config->interface[0].active; 30 for (size_t i = 0; i < interface->endpoint_count; i++) { 31 usb_endpoint_info *endpoint = &interface->endpoint[i]; 32 if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 33 if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 34 SetReadPipe(endpoint->handle); 35 if (++pipesSet >= 3) 36 break; 37 } else { 38 if (endpoint->descr->endpoint_address) { 39 SetControlPipe(endpoint->handle); 40 SetWritePipe(endpoint->handle); 41 pipesSet += 2; 42 if (pipesSet >= 3) 43 break; 44 } 45 } 46 } 47 } 48 49 if (pipesSet >= 3) { 50 status = B_OK; 51 } 52 } 53 54 TRACE_FUNCRET("< WCHDevice::AddDevice() returns: 0x%08x\n", status); 55 56 return status; 57 } 58 59 60 status_t 61 WCHDevice::ResetDevice() 62 { 63 TRACE_FUNCALLS("> WCHDevice::ResetDevice(0x%08x)\n", this); 64 size_t length = 0; 65 66 uint8 inputBuffer[CH34X_INPUT_BUF_SIZE]; 67 status_t status = gUSBModule->send_request(Device(), 68 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, 69 CH34X_REQ_READ_VERSION, 0, 0, sizeof(inputBuffer), inputBuffer, &length); 70 71 if (status == B_OK) { 72 fChipVersion = inputBuffer[0]; 73 TRACE_ALWAYS("= WCHDevice::ResetDevice(): Chip version: 0x%02x\n", fChipVersion); 74 } else { 75 TRACE_ALWAYS("= WCHDevice::ResetDevice(): Can't get chip version: 0x%08x\n", 76 status); 77 return status; 78 } 79 80 status = gUSBModule->send_request(Device(), 81 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 82 CH34X_REQ_SERIAL_INIT, 0, 0, 0, NULL, &length); 83 84 if (status != B_OK) { 85 TRACE_ALWAYS("= WCHDevice::ResetDevice(): init failed\n"); 86 return status; 87 } 88 89 status = WriteConfig(fDataRate, fStatusLCR, fStatusMCR); 90 91 TRACE_FUNCRET("< WCHDevice::ResetDevice() returns:%08x\n", status); 92 return status; 93 } 94 95 status_t 96 WCHDevice::SetLineCoding(usb_cdc_line_coding *lineCoding) 97 { 98 TRACE_FUNCALLS("> WCHDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n", 99 this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity, 100 lineCoding->databits); 101 102 fStatusLCR = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; 103 104 switch (lineCoding->stopbits) { 105 case USB_CDC_LINE_CODING_1_STOPBIT: 106 break; 107 case USB_CDC_LINE_CODING_2_STOPBITS: 108 fStatusLCR |= CH34X_LCR_STOP_BITS_2; 109 break; 110 default: 111 TRACE_ALWAYS("= WCHDevice::SetLineCoding(): Wrong stopbits param: %d\n", 112 lineCoding->stopbits); 113 break; 114 } 115 116 switch (lineCoding->parity) { 117 case USB_CDC_LINE_CODING_NO_PARITY: 118 break; 119 case USB_CDC_LINE_CODING_EVEN_PARITY: 120 fStatusLCR |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN; 121 break; 122 case USB_CDC_LINE_CODING_ODD_PARITY: 123 fStatusLCR |= CH34X_LCR_ENABLE_PAR; 124 break; 125 default: 126 TRACE_ALWAYS("= WCHDevice::SetLineCoding(): Wrong parity param: %d\n", 127 lineCoding->parity); 128 break; 129 } 130 131 switch (lineCoding->databits) { 132 case 5: 133 fStatusLCR |= CH34X_LCR_CS5; 134 break; 135 case 6: 136 fStatusLCR |= CH34X_LCR_CS6; 137 break; 138 case 7: 139 fStatusLCR |= CH34X_LCR_CS7; 140 break; 141 case 8: 142 fStatusLCR |= CH34X_LCR_CS8; 143 break; 144 default: 145 fStatusLCR |= CH34X_LCR_CS8; 146 TRACE_ALWAYS("= WCHDevice::SetLineCoding(): Wrong databits param: %d\n", 147 lineCoding->databits); 148 break; 149 } 150 151 switch (lineCoding->speed) { 152 case 600: fDataRate = CH34X_SIO_600; break; 153 case 1200: fDataRate = CH34X_SIO_1200; break; 154 case 1800: fDataRate = CH34X_SIO_1800; break; 155 case 2400: fDataRate = CH34X_SIO_2400; break; 156 case 4800: fDataRate = CH34X_SIO_4800; break; 157 case 9600: fDataRate = CH34X_SIO_9600; break; 158 case 19200: fDataRate = CH34X_SIO_19200; break; 159 case 31250: fDataRate = CH34X_SIO_31250; break; 160 case 38400: fDataRate = CH34X_SIO_38400; break; 161 case 57600: fDataRate = CH34X_SIO_57600; break; 162 case 115200: fDataRate = CH34X_SIO_115200; break; 163 case 230400: fDataRate = CH34X_SIO_230400; break; 164 default: 165 fDataRate = CH34X_SIO_9600; 166 TRACE_ALWAYS("= WCHDevice::SetLineCoding(): Datarate: %d is not " 167 "supported by this hardware. Defaulted to %d\n", 168 lineCoding->speed, CH34X_DEFAULT_BAUD_RATE); 169 break; 170 } 171 172 status_t status = WriteConfig(fDataRate, fStatusLCR, fStatusMCR); 173 174 if (status != B_OK) 175 TRACE_ALWAYS("= WCHDevice::SetLineCoding(): WriteConfig failed\n"); 176 177 TRACE_FUNCRET("< WCHDevice::SetLineCoding() returns: 0x%08x\n", status); 178 179 return status; 180 } 181 182 183 status_t 184 WCHDevice::SetControlLineState(uint16 state) 185 { 186 TRACE_FUNCALLS("> WCHDevice::SetControlLineState(0x%08x, 0x%04x)\n", 187 this, state); 188 189 fStatusMCR = 0; 190 191 if (state & USB_CDC_CONTROL_SIGNAL_STATE_RTS) 192 fStatusMCR |= CH34X_BIT_RTS; 193 194 if (state & USB_CDC_CONTROL_SIGNAL_STATE_DTR) 195 fStatusMCR |= CH34X_BIT_DTR; 196 197 size_t length = 0; 198 status_t status = 0; 199 200 if (fChipVersion < CH34X_VER_20) { 201 status = gUSBModule->send_request(Device(), 202 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 203 CH34X_REQ_WRITE_REG, CH34X_REG_STAT1 | (CH34X_REG_STAT1 << 8), 204 ~fStatusMCR | (~fStatusMCR << 8), 0, NULL, &length); 205 } else { 206 status = gUSBModule->send_request(Device(), 207 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 208 CH34X_REQ_MODEM_CTRL, ~fStatusMCR, 0, 0, NULL, &length); 209 } 210 211 TRACE_FUNCRET("< WCHDevice::SetControlLineState() returns: 0x%08x\n", 212 status); 213 214 return status; 215 } 216 217 status_t 218 WCHDevice::WriteConfig(uint16 dataRate, uint8 lcr, uint8 mcr) 219 { 220 size_t length = 0; 221 status_t status = gUSBModule->send_request(Device(), 222 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 223 CH34X_REQ_WRITE_REG, CH34X_REG_BPS_PRE | (CH34X_REG_BPS_DIV << 8), 224 dataRate | CH34X_BPS_PRE_IMM, 0, NULL, &length); 225 226 if (status != B_OK) { 227 TRACE_ALWAYS("= WCHDevice::WriteConfig(): datarate request failed: 0x%08x\n", 228 status); 229 return status; 230 } 231 232 status = gUSBModule->send_request(Device(), 233 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 234 CH34X_REQ_WRITE_REG, CH34X_REG_LCR | (CH34X_REG_LCR2 << 8), 235 lcr, 0, NULL, &length); 236 237 if (status != B_OK) { 238 TRACE_ALWAYS("= WCHDevice::WriteConfig(): LCR request failed: 0x%08x\n", 239 status); 240 return status; 241 } 242 243 status = gUSBModule->send_request(Device(), 244 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 245 CH34X_REQ_MODEM_CTRL, ~mcr, 0, 0, NULL, &length); 246 247 if (status != B_OK) 248 TRACE_ALWAYS("= WCHDevice::WriteConfig(): handshake failed: 0x%08x\n", status); 249 250 return status; 251 } 252