xref: /haiku/src/add-ons/kernel/busses/usb/uhci_rh.cpp (revision f14fe767bf568186bbd0678e35b03c99d8a264c6)
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 
14 static 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 
33 struct 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 
41 static 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 
90 struct uhci_root_hub_string_s {
91 	uint8	length;
92 	uint8	descriptor_type;
93 	uint16	unicode_string[12];
94 } _PACKED;
95 
96 
97 static 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 
UHCIRootHub(Object * rootObject,int8 deviceAddress)127 UHCIRootHub::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 
134 status_t
ProcessTransfer(UHCI * uhci,Transfer * transfer)135 UHCIRootHub::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