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