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