xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/Silicon.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
1 /*
2  * Copyright 2011, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Alexander von Gluck IV, kallisti5@unixzen.com
7  */
8 
9 
10 #include "Silicon.h"
11 
12 
13 static const int kBaudrateGeneratorFrequency = 0x384000;
14 
15 
16 SiliconDevice::SiliconDevice(usb_device device, uint16 vendorID, uint16 productID,
17 	const char *description)
18 	:	SerialDevice(device, vendorID, productID, description)
19 {
20 }
21 
22 
23 // Called for each configuration of the device. Return B_OK if the given
24 // configuration sounds like it is the usb serial one.
25 status_t
26 SiliconDevice::AddDevice(const usb_configuration_info *config)
27 {
28 	status_t status = ENODEV;
29 	if (config->interface_count > 0) {
30 		int32 pipesSet = 0;
31 		usb_interface_info *interface = config->interface[0].active;
32 		for (size_t i = 0; i < interface->endpoint_count; i++) {
33 			usb_endpoint_info *endpoint = &interface->endpoint[i];
34 			if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) {
35 				if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) {
36 					SetReadPipe(endpoint->handle);
37 					if (++pipesSet >= 3)
38 						break;
39 				} else {
40 					if (endpoint->descr->endpoint_address) {
41 						SetControlPipe(endpoint->handle);
42 						SetWritePipe(endpoint->handle);
43 						pipesSet += 2;
44 						if (pipesSet >= 3)
45 							break;
46 					}
47 				}
48 			}
49 		}
50 
51 		if (pipesSet >= 3) {
52 			status = B_OK;
53 		}
54 	}
55 	return status;
56 }
57 
58 
59 // Called on opening the device - Good time to enable the UART ?
60 status_t
61 SiliconDevice::ResetDevice()
62 {
63 	uint16_t enableUart = 1;
64 	return WriteConfig(ENABLE_UART, &enableUart, 2);
65 }
66 
67 
68 status_t
69 SiliconDevice::SetLineCoding(usb_cdc_line_coding *lineCoding)
70 {
71 	uint16_t divider = kBaudrateGeneratorFrequency / lineCoding->speed ;
72 	status_t result = WriteConfig(SET_BAUDRATE_DIVIDER, &divider, 2);
73 
74 	if (result != B_OK) return result;
75 
76 	uint16_t data = 0;
77 
78 	switch (lineCoding->stopbits) {
79 		case USB_CDC_LINE_CODING_1_STOPBIT: data = 0; break;
80 		case USB_CDC_LINE_CODING_2_STOPBITS: data = 2; break;
81 		default:
82 			TRACE_ALWAYS("= SiliconDevice::SetLineCoding(): Wrong stopbits param: %d\n",
83 				lineCoding->stopbits);
84 			break;
85 	}
86 
87 	switch (lineCoding->parity) {
88 		case USB_CDC_LINE_CODING_NO_PARITY: data |= 0 << 4; break;
89 		case USB_CDC_LINE_CODING_EVEN_PARITY: data |= 2 << 4; break;
90 		case USB_CDC_LINE_CODING_ODD_PARITY:	data |= 1 << 4; break;
91 		default:
92 			TRACE_ALWAYS("= SiliconDevice::SetLineCoding(): Wrong parity param: %d\n",
93 				lineCoding->parity);
94 			break;
95 	}
96 
97 	data |= lineCoding->databits << 8;
98 
99 	return WriteConfig(SET_LINE_FORMAT, &data, 2);
100 }
101 
102 
103 status_t
104 SiliconDevice::SetControlLineState(uint16 state)
105 {
106 	uint16_t control = 0;
107 	control |= 0x0300; // We are updating DTR and RTS
108 	control |= (state & USB_CDC_CONTROL_SIGNAL_STATE_RTS) ? 2 : 0;
109 	control |= (state & USB_CDC_CONTROL_SIGNAL_STATE_DTR) ? 1 : 0;
110 
111 	return WriteConfig(SET_STATUS, &control, 2);
112 }
113 
114 
115 status_t SiliconDevice::WriteConfig(CP210XRequest request, uint16_t* data,
116 	size_t size)
117 {
118 	size_t replyLength = 0;
119 	status_t result;
120 	// Small requests (16 bits and less) use the "value" field for their data.
121 	// Bigger ones use the actual buffer.
122 	if (size <= 2) {
123 		result = gUSBModule->send_request(Device(),
124 			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, request, data[0], 0, 0,
125 			NULL, &replyLength);
126 	} else {
127 		result = gUSBModule->send_request(Device(),
128 			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, request, 0x0000, 0,
129 			size, data, &replyLength);
130 	}
131 
132 	if (result != B_OK) {
133 		TRACE_ALWAYS("= SiliconDevice request failed: 0x%08x (%s)\n",
134 			result, strerror(result));
135 	}
136 
137 	return result;
138 }
139