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