xref: /haiku/src/add-ons/kernel/busses/usb/ehci_rh.cpp (revision 4466b89c65970de4c7236ac87faa2bee4589f413)
1 /*
2  * Copyright 2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include "ehci.h"
10 
11 #define USB_MODULE_NAME "ehci roothub"
12 
13 static usb_device_descriptor sEHCIRootHubDevice =
14 {
15 	18,								// Descriptor length
16 	USB_DESCRIPTOR_DEVICE,			// Descriptor type
17 	0x200,							// USB 2.0
18 	0x09,							// Class (9 = Hub)
19 	0,								// Subclass
20 	0,								// Protocol
21 	64,								// Max packet size on endpoint 0
22 	0,								// Vendor ID
23 	0,								// Product ID
24 	0x200,							// Version
25 	1,								// Index of manufacturer string
26 	2,								// Index of product string
27 	0,								// Index of serial number string
28 	1								// Number of configurations
29 };
30 
31 
32 struct ehci_root_hub_configuration_s {
33 	usb_configuration_descriptor	configuration;
34 	usb_interface_descriptor		interface;
35 	usb_endpoint_descriptor			endpoint;
36 	usb_hub_descriptor				hub;
37 } _PACKED;
38 
39 
40 static ehci_root_hub_configuration_s sEHCIRootHubConfig =
41 {
42 	{ // configuration descriptor
43 		9,								// Descriptor length
44 		USB_DESCRIPTOR_CONFIGURATION,	// Descriptor type
45 		34,								// Total length of configuration (including
46 										// interface, endpoint and hub descriptors)
47 		1,								// Number of interfaces
48 		1,								// Value of this configuration
49 		0,								// Index of configuration string
50 		0x40,							// Attributes (0x40 = self powered)
51 		0								// Max power (0, since self powered)
52 	},
53 
54 	{ // interface descriptor
55 		9,								// Descriptor length
56 		USB_DESCRIPTOR_INTERFACE,		// Descriptor type
57 		0,								// Interface number
58 		0,								// Alternate setting
59 		1,								// Number of endpoints
60 		0x09,							// Interface class (9 = Hub)
61 		0,								// Interface subclass
62 		0,								// Interface protocol
63 		0								// Index of interface string
64 	},
65 
66 	{ // endpoint descriptor
67 		7,								// Descriptor length
68 		USB_DESCRIPTOR_ENDPOINT,		// Descriptor type
69 		USB_REQTYPE_DEVICE_IN | 1,		// Endpoint address (first in IN endpoint)
70 		0x03,							// Attributes (0x03 = interrupt endpoint)
71 		8,								// Max packet size
72 		0xff							// Interval
73 	},
74 
75 	{ // hub descriptor
76 		9,								// Descriptor length (including
77 										// deprecated power control mask)
78 		USB_DESCRIPTOR_HUB,				// Descriptor type
79 		0x0f,							// Number of ports
80 		0x0000,							// Hub characteristics
81 		0,								// Power on to power good (in 2ms units)
82 		0,								// Maximum current (in mA)
83 		0x00,							// All ports are removable
84 		0xff							// Depricated power control mask
85 	}
86 };
87 
88 
89 struct ehci_root_hub_string_s {
90 	uint8	length;
91 	uint8	descriptor_type;
92 	uint16	unicode_string[12];
93 } _PACKED;
94 
95 
96 static ehci_root_hub_string_s sEHCIRootHubStrings[3] = {
97 	{
98 		4,								// Descriptor length
99 		USB_DESCRIPTOR_STRING,			// Descriptor type
100 		{
101 			0x0409						// Supported language IDs (English US)
102 		}
103 	},
104 
105 	{
106 		22,								// Descriptor length
107 		USB_DESCRIPTOR_STRING,			// Descriptor type
108 		{
109 			'H', 'A', 'I', 'K', 'U',	// Characters
110 			' ', 'I', 'n', 'c', '.'
111 		}
112 	},
113 
114 	{
115 		26,								// Descriptor length
116 		USB_DESCRIPTOR_STRING,			// Descriptor type
117 		{
118 			'E', 'H', 'C', 'I', ' ',	// Characters
119 			'R', 'o', 'o', 't', 'H',
120 			'u', 'b'
121 		}
122 	}
123 };
124 
125 
126 EHCIRootHub::EHCIRootHub(Object *rootObject, int8 deviceAddress)
127 	:	Hub(rootObject, 0, rootObject->GetStack()->IndexOfBusManager(rootObject->GetBusManager()),
128 			sEHCIRootHubDevice, deviceAddress, USB_SPEED_HIGHSPEED, true)
129 {
130 }
131 
132 
133 status_t
134 EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
135 {
136 	if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
137 		return B_ERROR;
138 
139 	usb_request_data *request = transfer->RequestData();
140 	TRACE_MODULE("request: %d\n", request->Request);
141 
142 	status_t status = B_TIMED_OUT;
143 	size_t actualLength = 0;
144 	switch (request->Request) {
145 		case USB_REQUEST_GET_STATUS: {
146 			if (request->Index == 0) {
147 				// get hub status
148 				actualLength = MIN(sizeof(usb_port_status),
149 					transfer->DataLength());
150 				// the hub reports whether the local power failed (bit 0)
151 				// and if there is a over-current condition (bit 1).
152 				// everything as 0 means all is ok.
153 				memset(transfer->Data(), 0, actualLength);
154 				status = B_OK;
155 				break;
156 			}
157 
158 			usb_port_status portStatus;
159 			if (ehci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
160 				actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
161 				memcpy(transfer->Data(), (void *)&portStatus, actualLength);
162 				status = B_OK;
163 			}
164 
165 			break;
166 		}
167 
168 		case USB_REQUEST_SET_ADDRESS:
169 			if (request->Value >= 128) {
170 				status = B_TIMED_OUT;
171 				break;
172 			}
173 
174 			TRACE_MODULE("set address: %d\n", request->Value);
175 			status = B_OK;
176 			break;
177 
178 		case USB_REQUEST_GET_DESCRIPTOR:
179 			TRACE_MODULE("get descriptor: %d\n", request->Value >> 8);
180 
181 			switch (request->Value >> 8) {
182 				case USB_DESCRIPTOR_DEVICE: {
183 					actualLength = MIN(sizeof(usb_device_descriptor),
184 						transfer->DataLength());
185 					memcpy(transfer->Data(), (void *)&sEHCIRootHubDevice,
186 						actualLength);
187 					status = B_OK;
188 					break;
189 				}
190 
191 				case USB_DESCRIPTOR_CONFIGURATION: {
192 					actualLength = MIN(sizeof(ehci_root_hub_configuration_s),
193 						transfer->DataLength());
194 					sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
195 					memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig,
196 						actualLength);
197 					status = B_OK;
198 					break;
199 				}
200 
201 				case USB_DESCRIPTOR_STRING: {
202 					uint8 index = request->Value & 0x00ff;
203 					if (index > 2)
204 						break;
205 
206 					actualLength = MIN(sEHCIRootHubStrings[index].length,
207 						transfer->DataLength());
208 					memcpy(transfer->Data(), (void *)&sEHCIRootHubStrings[index],
209 						actualLength);
210 					status = B_OK;
211 					break;
212 				}
213 
214 				case USB_DESCRIPTOR_HUB: {
215 					actualLength = MIN(sizeof(usb_hub_descriptor),
216 						transfer->DataLength());
217 					sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
218 					memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig.hub,
219 						actualLength);
220 					status = B_OK;
221 					break;
222 				}
223 			}
224 			break;
225 
226 		case USB_REQUEST_SET_CONFIGURATION:
227 			status = B_OK;
228 			break;
229 
230 		case USB_REQUEST_CLEAR_FEATURE: {
231 			if (request->Index == 0) {
232 				// we don't support any hub changes
233 				TRACE_MODULE_ERROR("clear feature: no hub changes\n");
234 				break;
235 			}
236 
237 			TRACE_MODULE("clear feature: %d\n", request->Value);
238 			if (ehci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
239 				status = B_OK;
240 			break;
241 		}
242 
243 		case USB_REQUEST_SET_FEATURE: {
244 			if (request->Index == 0) {
245 				// we don't support any hub changes
246 				TRACE_MODULE_ERROR("set feature: no hub changes\n");
247 				break;
248 			}
249 
250 			TRACE_MODULE("set feature: %d\n", request->Value);
251 			if (ehci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
252 				status = B_OK;
253 			break;
254 		}
255 	}
256 
257 	transfer->Finished(status, actualLength);
258 	delete transfer;
259 	return B_OK;
260 }
261