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