xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/FTDI.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
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 #include "FTDI.h"
9 #include "FTDIRegs.h"
10 
11 FTDIDevice::FTDIDevice(usb_device device, uint16 vendorID, uint16 productID,
12 	const char *description)
13 	:	SerialDevice(device, vendorID, productID, description),
14 		fHeaderLength(0),
15 		fStatusMSR(0),
16 		fStatusLSR(0)
17 {
18 }
19 
20 
21 status_t
22 FTDIDevice::AddDevice(const usb_configuration_info *config)
23 {
24 	TRACE_FUNCALLS("> FTDIDevice::AddDevice(%08x, %08x)\n", this, config);
25 	status_t status = ENODEV;
26 	if (config->interface_count > 0) {
27 		int32 pipesSet = 0;
28 		usb_interface_info *interface = config->interface[0].active;
29 		for (size_t i = 0; i < interface->endpoint_count; i++) {
30 			usb_endpoint_info *endpoint = &interface->endpoint[i];
31 			if (endpoint->descr->attributes == USB_EP_ATTR_BULK) {
32 				if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
33 					SetReadPipe(endpoint->handle);
34 					if (++pipesSet >= 3)
35 						break;
36 				} else {
37 					if (endpoint->descr->endpoint_address) {
38 						SetControlPipe(endpoint->handle);
39 						SetWritePipe(endpoint->handle);
40 						pipesSet += 2;
41 						if (pipesSet >= 3)
42 							break;
43 					}
44 				}
45 			}
46 		}
47 
48 		if (pipesSet >= 3) {
49 			if (ProductID() == PRODUCT_FTDI_8U100AX)
50 				fHeaderLength = 1;
51 			else
52 				fHeaderLength = 0;
53 
54 			status = B_OK;
55 		}
56 	}
57 
58 	TRACE_FUNCRET("< FTDIDevice::AddDevice() returns: 0x%08x\n", status);
59 	return status;
60 }
61 
62 
63 status_t
64 FTDIDevice::ResetDevice()
65 {
66 	TRACE_FUNCALLS("> FTDIDevice::ResetDevice(0x%08x)\n", this);
67 
68 	size_t length = 0;
69 	status_t status = gUSBModule->send_request(Device(),
70 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
71 		FTDI_SIO_RESET, FTDI_SIO_RESET_SIO,
72 		FTDI_PIT_DEFAULT, 0, NULL, &length);
73 
74 	TRACE_FUNCRET("< FTDIDevice::ResetDevice() returns:%08x\n", status);
75 	return status;
76 }
77 
78 
79 status_t
80 FTDIDevice::SetLineCoding(usb_serial_line_coding *lineCoding)
81 {
82 	TRACE_FUNCALLS("> FTDIDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n",
83 		this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity,
84 		lineCoding->databits);
85 
86 	int32 rate = 0;
87 	if (ProductID() == PRODUCT_FTDI_8U100AX) {
88 		switch (lineCoding->speed) {
89 			case 300: rate = ftdi_sio_b300; break;
90 			case 600: rate = ftdi_sio_b600; break;
91 			case 1200: rate = ftdi_sio_b1200; break;
92 			case 2400: rate = ftdi_sio_b2400; break;
93 			case 4800: rate = ftdi_sio_b4800; break;
94 			case 9600: rate = ftdi_sio_b9600; break;
95 			case 19200: rate = ftdi_sio_b19200; break;
96 			case 38400: rate = ftdi_sio_b38400; break;
97 			case 57600: rate = ftdi_sio_b57600; break;
98 			case 115200: rate = ftdi_sio_b115200; break;
99 			default:
100 				rate = ftdi_sio_b19200;
101 				TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is "
102 					"not supported by this hardware. Defaulted to %d\n",
103 					lineCoding->speed, rate);
104 			break;
105 		}
106 	} else {
107 		switch (lineCoding->speed) {
108 			case 300: rate = ftdi_8u232am_b300; break;
109 			case 600: rate = ftdi_8u232am_b600; break;
110 			case 1200: rate = ftdi_8u232am_b1200; break;
111 			case 2400: rate = ftdi_8u232am_b2400; break;
112 			case 4800: rate = ftdi_8u232am_b4800; break;
113 			case 9600: rate = ftdi_8u232am_b9600; break;
114 			case 19200: rate = ftdi_8u232am_b19200; break;
115 			case 38400: rate = ftdi_8u232am_b38400; break;
116 			case 57600: rate = ftdi_8u232am_b57600; break;
117 			case 115200: rate = ftdi_8u232am_b115200; break;
118 			case 230400: rate = ftdi_8u232am_b230400; break;
119 			case 460800: rate = ftdi_8u232am_b460800; break;
120 			case 921600: rate = ftdi_8u232am_b921600; break;
121 			default:
122 				rate = ftdi_sio_b19200;
123 				TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is "
124 					"not supported by this hardware. Defaulted to %d\n",
125 					lineCoding->speed, rate);
126 				break;
127 		}
128 	}
129 
130 	size_t length = 0;
131 	status_t status = gUSBModule->send_request(Device(),
132 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
133 		FTDI_SIO_SET_BAUD_RATE, rate,
134 		FTDI_PIT_DEFAULT, 0, NULL, &length);
135 	if (status != B_OK)
136 		TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): datarate set request failed: 0x%08x\n", status);
137 
138 	int32 data = 0;
139 	switch (lineCoding->stopbits) {
140 		case LC_STOP_BIT_2: data = FTDI_SIO_SET_DATA_STOP_BITS_2; break;
141 		case LC_STOP_BIT_1: data = FTDI_SIO_SET_DATA_STOP_BITS_1; break;
142 		default:
143 			TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong stopbits param: %d\n",
144 				lineCoding->stopbits);
145 			break;
146 	}
147 
148 	switch (lineCoding->parity) {
149 		case LC_PARITY_NONE: data |= FTDI_SIO_SET_DATA_PARITY_NONE; break;
150 		case LC_PARITY_EVEN: data |= FTDI_SIO_SET_DATA_PARITY_EVEN; break;
151 		case LC_PARITY_ODD:	data |= FTDI_SIO_SET_DATA_PARITY_ODD; break;
152 		default:
153 			TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong parity param: %d\n",
154 				lineCoding->parity);
155 			break;
156 	}
157 
158 	switch (lineCoding->databits) {
159 		case 8: data |= FTDI_SIO_SET_DATA_BITS(8); break;
160 		case 7: data |= FTDI_SIO_SET_DATA_BITS(7); break;
161 		default:
162 			TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong databits param: %d\n",
163 				lineCoding->databits);
164 			break;
165 	}
166 
167 	length = 0;
168 	status = gUSBModule->send_request(Device(),
169 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
170 		FTDI_SIO_SET_DATA, data,
171 		FTDI_PIT_DEFAULT, 0, NULL, &length);
172 	if (status != B_OK)
173 		TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): data set request failed: %08x\n", status);
174 
175 	TRACE_FUNCRET("< FTDIDevice::SetLineCoding() returns: 0x%08x\n", status);
176 	return status;
177 }
178 
179 
180 status_t
181 FTDIDevice::SetControlLineState(uint16 state)
182 {
183 	TRACE_FUNCALLS("> FTDIDevice::SetControlLineState(0x%08x, 0x%04x)\n", this, state);
184 
185 	int32 control;
186 	control = (state & CLS_LINE_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
187 	control |= (state & CLS_LINE_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
188 
189 	size_t length = 0;
190 	status_t status = gUSBModule->send_request(Device(),
191 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
192 		FTDI_SIO_MODEM_CTRL, control,
193 		FTDI_PIT_DEFAULT, 0, NULL, &length);
194 
195 	if (status != B_OK)
196 		TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): control set request failed: 0x%08x\n", status);
197 
198 	TRACE_FUNCRET("< FTDIDevice::SetControlLineState() returns: 0x%08x\n", status);
199 	return status;
200 }
201 
202 
203 void
204 FTDIDevice::OnRead(char **buffer, size_t *numBytes)
205 {
206 	fStatusMSR = FTDI_GET_MSR(*buffer);
207 	fStatusLSR = FTDI_GET_LSR(*buffer);
208 	TRACE("FTDIDevice::OnRead(): MSR: 0x%02x LSR: 0x%02x\n", fStatusMSR, fStatusLSR);
209 	*buffer += 2;
210 	*numBytes -= 2;
211 }
212 
213 
214 void
215 FTDIDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
216 {
217 	char *writeBuffer = WriteBuffer();
218 	if (fHeaderLength > 0) {
219 		if (*numBytes >= WriteBufferSize() - fHeaderLength)
220 			*numBytes = *packetBytes = WriteBufferSize() - fHeaderLength;
221 
222 		*writeBuffer = FTDI_OUT_TAG(*numBytes, FTDI_PIT_DEFAULT);
223 	}
224 
225 	memcpy(writeBuffer + fHeaderLength, buffer, *packetBytes);
226 	*packetBytes += fHeaderLength;
227 }
228