xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/FTDI.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
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 		switch (lineCoding->speed) {
115 			case 300: rate = ftdi_8u232am_b300; break;
116 			case 600: rate = ftdi_8u232am_b600; break;
117 			case 1200: rate = ftdi_8u232am_b1200; break;
118 			case 2400: rate = ftdi_8u232am_b2400; break;
119 			case 4800: rate = ftdi_8u232am_b4800; break;
120 			case 9600: rate = ftdi_8u232am_b9600; break;
121 			case 19200: rate = ftdi_8u232am_b19200; break;
122 			case 38400: rate = ftdi_8u232am_b38400; break;
123 			case 57600: rate = ftdi_8u232am_b57600; break;
124 			case 115200: rate = ftdi_8u232am_b115200; break;
125 			case 230400: rate = ftdi_8u232am_b230400; break;
126 			case 460800: rate = ftdi_8u232am_b460800; break;
127 			case 921600: rate = ftdi_8u232am_b921600; break;
128 			default:
129 				rate = ftdi_sio_b19200;
130 				TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is "
131 					"not supported by this hardware. Defaulted to %d\n",
132 					lineCoding->speed, rate);
133 				break;
134 		}
135 	}
136 
137 	size_t length = 0;
138 	status_t status = gUSBModule->send_request(Device(),
139 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
140 		FTDI_SIO_SET_BAUD_RATE, rate,
141 		FTDI_PIT_DEFAULT, 0, NULL, &length);
142 	if (status != B_OK)
143 		TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): datarate set request failed: 0x%08x\n", status);
144 
145 	int32 data = 0;
146 	switch (lineCoding->stopbits) {
147 		case USB_CDC_LINE_CODING_1_STOPBIT: data = FTDI_SIO_SET_DATA_STOP_BITS_2; break;
148 		case USB_CDC_LINE_CODING_2_STOPBITS: data = FTDI_SIO_SET_DATA_STOP_BITS_1; break;
149 		default:
150 			TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong stopbits param: %d\n",
151 				lineCoding->stopbits);
152 			break;
153 	}
154 
155 	switch (lineCoding->parity) {
156 		case USB_CDC_LINE_CODING_NO_PARITY: data |= FTDI_SIO_SET_DATA_PARITY_NONE; break;
157 		case USB_CDC_LINE_CODING_EVEN_PARITY: data |= FTDI_SIO_SET_DATA_PARITY_EVEN; break;
158 		case USB_CDC_LINE_CODING_ODD_PARITY:	data |= FTDI_SIO_SET_DATA_PARITY_ODD; break;
159 		default:
160 			TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong parity param: %d\n",
161 				lineCoding->parity);
162 			break;
163 	}
164 
165 	switch (lineCoding->databits) {
166 		case 8: data |= FTDI_SIO_SET_DATA_BITS(8); break;
167 		case 7: data |= FTDI_SIO_SET_DATA_BITS(7); break;
168 		default:
169 			TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong databits param: %d\n",
170 				lineCoding->databits);
171 			break;
172 	}
173 
174 	length = 0;
175 	status = gUSBModule->send_request(Device(),
176 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
177 		FTDI_SIO_SET_DATA, data,
178 		FTDI_PIT_DEFAULT, 0, NULL, &length);
179 	if (status != B_OK)
180 		TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): data set request failed: %08x\n", status);
181 
182 	TRACE_FUNCRET("< FTDIDevice::SetLineCoding() returns: 0x%08x\n", status);
183 	return status;
184 }
185 
186 
187 status_t
188 FTDIDevice::SetControlLineState(uint16 state)
189 {
190 	TRACE_FUNCALLS("> FTDIDevice::SetControlLineState(0x%08x, 0x%04x)\n", this, state);
191 
192 	int32 control;
193 	control = (state & USB_CDC_CONTROL_SIGNAL_STATE_RTS) ? FTDI_SIO_SET_RTS_HIGH
194 		: FTDI_SIO_SET_RTS_LOW;
195 
196 	size_t length = 0;
197 	status_t status = gUSBModule->send_request(Device(),
198 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
199 		FTDI_SIO_MODEM_CTRL, control,
200 		FTDI_PIT_DEFAULT, 0, NULL, &length);
201 
202 	if (status != B_OK)
203 		TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): control set request failed: 0x%08x\n", status);
204 
205 	control = (state & USB_CDC_CONTROL_SIGNAL_STATE_DTR) ? FTDI_SIO_SET_DTR_HIGH
206 		: FTDI_SIO_SET_DTR_LOW;
207 
208 	status = gUSBModule->send_request(Device(),
209 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
210 		FTDI_SIO_MODEM_CTRL, control,
211 		FTDI_PIT_DEFAULT, 0, NULL, &length);
212 
213 	if (status != B_OK)
214 		TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): control set request failed: 0x%08x\n", status);
215 
216 	TRACE_FUNCRET("< FTDIDevice::SetControlLineState() returns: 0x%08x\n", status);
217 	return status;
218 }
219 
220 
221 void
222 FTDIDevice::OnRead(char **buffer, size_t *numBytes)
223 {
224 	fStatusMSR = FTDI_GET_MSR(*buffer);
225 	fStatusLSR = FTDI_GET_LSR(*buffer);
226 	TRACE("FTDIDevice::OnRead(): MSR: 0x%02x LSR: 0x%02x\n", fStatusMSR, fStatusLSR);
227 	*buffer += 2;
228 	*numBytes -= 2;
229 }
230 
231 
232 void
233 FTDIDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
234 {
235 	if (*numBytes > FTDI_BUFFER_SIZE)
236 		*numBytes = *packetBytes = FTDI_BUFFER_SIZE;
237 
238 	char *writeBuffer = WriteBuffer();
239 	if (fHeaderLength > 0) {
240 		if (*numBytes > WriteBufferSize() - fHeaderLength)
241 			*numBytes = *packetBytes = WriteBufferSize() - fHeaderLength;
242 
243 		*writeBuffer = FTDI_OUT_TAG(*numBytes, FTDI_PIT_DEFAULT);
244 	}
245 
246 	memcpy(writeBuffer + fHeaderLength, buffer, *packetBytes);
247 	*packetBytes += fHeaderLength;
248 }
249