xref: /haiku/src/add-ons/kernel/bus_managers/usb/Hub.cpp (revision 9d6d3fcf5fe8308cd020cecf89dede440346f8c4)
1 /*
2  * Copyright 2003-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 "usb_p.h"
11 #include <stdio.h>
12 
13 
14 Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
15 	usb_speed speed)
16 	:	Device(parent, desc, deviceAddress, speed)
17 {
18 	TRACE(("USB Hub is being initialised\n"));
19 
20 	if (!fInitOK) {
21 		TRACE_ERROR(("USB Hub: Device failed to initialize\n"));
22 		return;
23 	}
24 
25 	// Set to false again for the hub init.
26 	fInitOK = false;
27 
28 	for (int32 i = 0; i < 8; i++)
29 		fChildren[i] = NULL;
30 
31 	if (fDeviceDescriptor.device_class != 9) {
32 		TRACE_ERROR(("USB Hub: wrong class! Bailing out\n"));
33 		return;
34 	}
35 
36 	TRACE(("USB Hub: Getting hub descriptor...\n"));
37 	size_t actualLength;
38 	status_t status = GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
39 		(void *)&fHubDescriptor, sizeof(usb_hub_descriptor), &actualLength);
40 
41 	// we need at least 8 bytes
42 	if (status < B_OK || actualLength < 8) {
43 		TRACE_ERROR(("USB Hub: Error getting hub descriptor\n"));
44 		return;
45 	}
46 
47 	TRACE(("USB Hub: Hub descriptor (%d bytes):\n", actualLength));
48 	TRACE(("\tlength:..............%d\n", fHubDescriptor.length));
49 	TRACE(("\tdescriptor_type:.....0x%02x\n", fHubDescriptor.descriptor_type));
50 	TRACE(("\tnum_ports:...........%d\n", fHubDescriptor.num_ports));
51 	TRACE(("\tcharacteristics:.....0x%04x\n", fHubDescriptor.characteristics));
52 	TRACE(("\tpower_on_to_power_g:.%d\n", fHubDescriptor.power_on_to_power_good));
53 	TRACE(("\tdevice_removeable:...0x%02x\n", fHubDescriptor.device_removeable));
54 	TRACE(("\tpower_control_mask:..0x%02x\n", fHubDescriptor.power_control_mask));
55 
56 	Object *object = GetStack()->GetObject(Configuration()->interface->active->endpoint[0].handle);
57 	if (!object || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0) {
58 		TRACE_ERROR(("USB Hub: no interrupt pipe found\n"));
59 		return;
60 	}
61 
62 	fInterruptPipe = (InterruptPipe *)object;
63 	fInterruptPipe->QueueInterrupt(fInterruptStatus, sizeof(fInterruptStatus),
64 		InterruptCallback, this);
65 
66 	// Wait some time before powering up the ports
67 	snooze(USB_DELAY_HUB_POWER_UP);
68 
69 	// Enable port power on all ports
70 	for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
71 		status = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
72 			USB_REQUEST_SET_FEATURE, PORT_POWER, i + 1, 0, NULL, 0, NULL);
73 
74 		if (status < B_OK)
75 			TRACE_ERROR(("USB Hub: power up failed on port %ld\n", i));
76 	}
77 
78 	// Wait for power to stabilize
79 	snooze(fHubDescriptor.power_on_to_power_good * 2000);
80 
81 	fInitOK = true;
82 	TRACE(("USB Hub: initialised ok\n"));
83 }
84 
85 
86 status_t
87 Hub::UpdatePortStatus(uint8 index)
88 {
89 	// get the current port status
90 	size_t actualLength = 0;
91 	status_t result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN,
92 		USB_REQUEST_GET_STATUS, 0, index + 1, 4, (void *)&fPortStatus[index],
93 		4, &actualLength);
94 
95 	if (result < B_OK || actualLength < 4) {
96 		TRACE_ERROR(("USB Hub: error updating port status\n"));
97 		return B_ERROR;
98 	}
99 
100 	return B_OK;
101 }
102 
103 
104 status_t
105 Hub::ResetPort(uint8 index)
106 {
107 	status_t result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
108 		USB_REQUEST_SET_FEATURE, PORT_RESET, index + 1, 0, NULL, 0, NULL);
109 
110 	if (result < B_OK)
111 		return result;
112 
113 	for (int32 i = 0; i < 10; i++) {
114 		snooze(USB_DELAY_PORT_RESET);
115 
116 		result = UpdatePortStatus(index);
117 		if (result < B_OK)
118 			return result;
119 
120 		if ((fPortStatus[index].status & PORT_STATUS_CONNECTION) == 0) {
121 			// device disappeared, this is no error
122 			TRACE(("USB Hub: device disappeared on reset\n"));
123 			return B_OK;
124 		}
125 
126 		if (fPortStatus[index].change & C_PORT_RESET) {
127 			// reset is done
128 			break;
129 		}
130 	}
131 
132 	if ((fPortStatus[index].change & C_PORT_RESET) == 0) {
133 		TRACE_ERROR(("USB Hub: port %d won't reset\n", index));
134 		return B_ERROR;
135 	}
136 
137 	// clear the reset change
138 	result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
139 		USB_REQUEST_CLEAR_FEATURE, C_PORT_RESET, index + 1, 0, NULL, 0, NULL);
140 	if (result < B_OK)
141 		return result;
142 
143 	// wait for reset recovery
144 	snooze(USB_DELAY_PORT_RESET_RECOVERY);
145 	TRACE(("USB Hub: port %d was reset successfully\n", index));
146 	return B_OK;
147 }
148 
149 
150 void
151 Hub::Explore()
152 {
153 	for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
154 		status_t result = UpdatePortStatus(i);
155 		if (result < B_OK)
156 			continue;
157 
158 #ifdef TRACE_USB
159 		if (fPortStatus[i].change)
160 			TRACE(("USB Hub: port %d: status: 0x%04x; change: 0x%04x\n", i, fPortStatus[i].status, fPortStatus[i].change));
161 #endif
162 
163 		if (fPortStatus[i].change & PORT_STATUS_CONNECTION) {
164 			// clear status change
165 			DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
166 				USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1,
167 				0, NULL, 0, NULL);
168 
169 			if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
170 				// new device attached!
171 				TRACE(("USB Hub: Explore(): New device connected\n"));
172 
173 				// wait some time for the device to power up
174 				snooze(USB_DELAY_DEVICE_POWER_UP);
175 
176 				// reset the port, this will also enable it
177 				result = ResetPort(i);
178 				if (result < B_OK)
179 					continue;
180 
181 				result = UpdatePortStatus(i);
182 				if (result < B_OK)
183 					continue;
184 
185 				if ((fPortStatus[i].status & PORT_STATUS_CONNECTION) == 0) {
186 					// device has vanished after reset, ignore
187 					continue;
188 				}
189 
190 				usb_speed speed = USB_SPEED_FULLSPEED;
191 				if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED)
192 					speed = USB_SPEED_LOWSPEED;
193 				if (fPortStatus[i].status & PORT_STATUS_HIGH_SPEED)
194 					speed = USB_SPEED_HIGHSPEED;
195 
196 				Device *newDevice = GetBusManager()->AllocateNewDevice(this,
197 					speed);
198 
199 				if (newDevice) {
200 					fChildren[i] = newDevice;
201 					GetStack()->NotifyDeviceChange(fChildren[i], true);
202 				} else {
203 					// the device failed to setup correctly, disable the port
204 					// so that the device doesn't get in the way of future
205 					// addressing.
206 					DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
207 						USB_REQUEST_CLEAR_FEATURE, PORT_ENABLE, i + 1,
208 						0, NULL, 0, NULL);
209 				}
210 			} else {
211 				// Device removed...
212 				TRACE(("USB Hub Explore(): Device removed\n"));
213 				if (fChildren[i]) {
214 					GetStack()->NotifyDeviceChange(fChildren[i], false);
215 					delete fChildren[i];
216 					fChildren[i] = NULL;
217 				}
218 			}
219 		}
220 	}
221 
222 	// explore down the tree if we have hubs connected
223 	for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
224 		if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0)
225 			continue;
226 
227 		((Hub *)fChildren[i])->Explore();
228 	}
229 }
230 
231 
232 void
233 Hub::InterruptCallback(void *cookie, status_t status, void *data,
234 	size_t actualLength)
235 {
236 	TRACE(("USB Hub: interrupt callback!\n"));
237 }
238 
239 
240 status_t
241 Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
242 	void *data, size_t dataLength, size_t *actualLength)
243 {
244 	return DefaultPipe()->SendRequest(
245 		USB_REQTYPE_DEVICE_IN | USB_REQTYPE_CLASS,			// type
246 		USB_REQUEST_GET_DESCRIPTOR,							// request
247 		(descriptorType << 8) | index,						// value
248 		languageID,											// index
249 		dataLength,											// length
250 		data,												// buffer
251 		dataLength,											// buffer length
252 		actualLength);										// actual length
253 }
254 
255 
256 status_t
257 Hub::ReportDevice(usb_support_descriptor *supportDescriptors,
258 	uint32 supportDescriptorCount, const usb_notify_hooks *hooks,
259 	usb_driver_cookie **cookies, bool added)
260 {
261 	TRACE(("USB Hub ReportDevice\n"));
262 
263 	// Report ourselfs first
264 	status_t result = Device::ReportDevice(supportDescriptors,
265 		supportDescriptorCount, hooks, cookies, added);
266 
267 	// Then report all of our children
268 	for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
269 		if (!fChildren[i])
270 			continue;
271 
272 		if (fChildren[i]->ReportDevice(supportDescriptors,
273 				supportDescriptorCount, hooks, cookies, added) == B_OK)
274 			result = B_OK;
275 	}
276 
277 	return result;
278 }
279 
280 
281 status_t
282 Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
283 	Device *device)
284 {
285 	status_t result = Device::BuildDeviceName(string, index, bufferSize, device);
286 	if (result < B_OK) {
287 		// recursion to parent failed, we're at the root(hub)
288 		int32 managerIndex = GetStack()->IndexOfBusManager(GetBusManager());
289 		*index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex);
290 	}
291 
292 	if (!device) {
293 		// no device was specified - report the hub
294 		*index += snprintf(string + *index, bufferSize - *index, "/hub");
295 	} else {
296 		// find out where the requested device sitts
297 		for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
298 			if (fChildren[i] == device) {
299 				*index += snprintf(string + *index, bufferSize - *index, "/%ld", i);
300 				break;
301 			}
302 		}
303 	}
304 
305 	return B_OK;
306 }
307