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
13static 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
32struct 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
40static 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
89struct ehci_root_hub_string_s {
90	uint8	length;
91	uint8	descriptor_type;
92	uint16	unicode_string[12];
93} _PACKED;
94
95
96static 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
126EHCIRootHub::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
133status_t
134EHCIRootHub::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