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