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
17FTDIDevice::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
27status_t
28FTDIDevice::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
69status_t
70FTDIDevice::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
85status_t
86FTDIDevice::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
187status_t
188FTDIDevice::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
221void
222FTDIDevice::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
232void
233FTDIDevice::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