xref: /haiku/src/add-ons/kernel/busses/usb/ehci_rh.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
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 		50,								// 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, sEHCIRootHubDevice, deviceAddress, USB_SPEED_HIGHSPEED)
126 {
127 }
128 
129 
130 status_t
131 EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
132 {
133 	if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
134 		return B_ERROR;
135 
136 	usb_request_data *request = transfer->RequestData();
137 	TRACE(("usb_ehci_roothub: request: %d\n", request->Request));
138 
139 	status_t status = B_TIMED_OUT;
140 	size_t actualLength = 0;
141 	switch (request->Request) {
142 		case USB_REQUEST_GET_STATUS: {
143 			if (request->Index == 0) {
144 				// get hub status
145 				actualLength = MIN(sizeof(usb_port_status),
146 					transfer->DataLength());
147 				// the hub reports whether the local power failed (bit 0)
148 				// and if there is a over-current condition (bit 1).
149 				// everything as 0 means all is ok.
150 				memset(transfer->Data(), 0, actualLength);
151 				status = B_OK;
152 				break;
153 			}
154 
155 			usb_port_status portStatus;
156 			if (ehci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
157 				actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
158 				memcpy(transfer->Data(), (void *)&portStatus, actualLength);
159 				status = B_OK;
160 			}
161 
162 			break;
163 		}
164 
165 		case USB_REQUEST_SET_ADDRESS:
166 			if (request->Value >= 128) {
167 				status = B_TIMED_OUT;
168 				break;
169 			}
170 
171 			TRACE(("usb_ehci_roothub:  set address: %d\n", request->Value));
172 			status = B_OK;
173 			break;
174 
175 		case USB_REQUEST_GET_DESCRIPTOR:
176 			TRACE(("usb_ehci_roothub: get descriptor: %d\n", request->Value >> 8));
177 
178 			switch (request->Value >> 8) {
179 				case USB_DESCRIPTOR_DEVICE: {
180 					actualLength = MIN(sizeof(usb_device_descriptor),
181 						transfer->DataLength());
182 					memcpy(transfer->Data(), (void *)&sEHCIRootHubDevice,
183 						actualLength);
184 					status = B_OK;
185 					break;
186 				}
187 
188 				case USB_DESCRIPTOR_CONFIGURATION: {
189 					actualLength = MIN(sizeof(ehci_root_hub_configuration_s),
190 						transfer->DataLength());
191 					sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
192 					memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig,
193 						actualLength);
194 					status = B_OK;
195 					break;
196 				}
197 
198 				case USB_DESCRIPTOR_STRING: {
199 					uint8 index = request->Value & 0x00ff;
200 					if (index > 2)
201 						break;
202 
203 					actualLength = MIN(sEHCIRootHubStrings[index].length,
204 						transfer->DataLength());
205 					memcpy(transfer->Data(), (void *)&sEHCIRootHubStrings[index],
206 						actualLength);
207 					status = B_OK;
208 					break;
209 				}
210 
211 				case USB_DESCRIPTOR_HUB: {
212 					actualLength = MIN(sizeof(usb_hub_descriptor),
213 						transfer->DataLength());
214 					sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
215 					memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig.hub,
216 						actualLength);
217 					status = B_OK;
218 					break;
219 				}
220 			}
221 			break;
222 
223 		case USB_REQUEST_SET_CONFIGURATION:
224 			status = B_OK;
225 			break;
226 
227 		case USB_REQUEST_CLEAR_FEATURE: {
228 			if (request->Index == 0) {
229 				// we don't support any hub changes
230 				TRACE_ERROR(("usb_ehci_roothub: clear feature: no hub changes\n"));
231 				break;
232 			}
233 
234 			TRACE(("usb_ehci_roothub: clear feature: %d\n", request->Value));
235 			if (ehci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
236 				status = B_OK;
237 			break;
238 		}
239 
240 		case USB_REQUEST_SET_FEATURE: {
241 			if (request->Index == 0) {
242 				// we don't support any hub changes
243 				TRACE_ERROR(("usb_ehci_roothub: set feature: no hub changes\n"));
244 				break;
245 			}
246 
247 			TRACE(("usb_ehci_roothub: set feature: %d\n", request->Value));
248 			if (ehci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
249 				status = B_OK;
250 			break;
251 		}
252 	}
253 
254 	transfer->Finished(status, actualLength);
255 	delete transfer;
256 	return B_OK;
257 }
258