xref: /haiku/src/add-ons/kernel/bus_managers/usb/Hub.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
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(BusManager *bus, Device *parent, usb_device_descriptor &desc,
15 	int8 deviceAddress, bool lowSpeed)
16 	:	Device(bus, parent, desc, deviceAddress, lowSpeed)
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 = 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 = 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 = 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 = 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 		if (DeviceAddress() > 1)
159 			TRACE(("USB Hub (%d): port %d: status: 0x%04x; change: 0x%04x\n", DeviceAddress(), i, fPortStatus[i].status, fPortStatus[i].change));
160 
161 		if (fPortStatus[i].change & PORT_STATUS_CONNECTION) {
162 			if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
163 				// new device attached!
164 				TRACE(("USB Hub: Explore(): New device connected\n"));
165 
166 				// wait some time for the device to power up
167 				snooze(USB_DELAY_DEVICE_POWER_UP);
168 
169 				// reset the port, this will also enable it
170 				result = ResetPort(i);
171 				if (result < B_OK)
172 					continue;
173 
174 				result = UpdatePortStatus(i);
175 				if (result < B_OK)
176 					continue;
177 
178 				if ((fPortStatus[i].status & PORT_STATUS_CONNECTION) == 0) {
179 					// device has vanished after reset, ignore
180 					continue;
181 				}
182 
183 				Device *newDevice = fBus->AllocateNewDevice(this,
184 					(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
185 
186 				if (newDevice) {
187 					fChildren[i] = newDevice;
188 					GetStack()->NotifyDeviceChange(fChildren[i], true);
189 				} else {
190 					// the device failed to setup correctly, disable the port
191 					// so that the device doesn't get in the way of future
192 					// addressing.
193 					SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
194 						USB_REQUEST_CLEAR_FEATURE, PORT_ENABLE, i + 1,
195 						0, NULL, 0, NULL);
196 				}
197 			} else {
198 				// Device removed...
199 				TRACE(("USB Hub Explore(): Device removed\n"));
200 				if (fChildren[i]) {
201 					GetStack()->NotifyDeviceChange(fChildren[i], false);
202 					GetStack()->PutUSBID(fChildren[i]->USBID());
203 					delete fChildren[i];
204 					fChildren[i] = NULL;
205 				}
206 			}
207 
208 			// clear status change
209 			SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
210 				USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1,
211 				0, NULL, 0, NULL);
212 		}
213 	}
214 
215 	// explore down the tree if we have hubs connected
216 	for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
217 		if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0)
218 			continue;
219 
220 		((Hub *)fChildren[i])->Explore();
221 	}
222 }
223 
224 
225 void
226 Hub::InterruptCallback(void *cookie, uint32 status, void *data,
227 	uint32 actualLength)
228 {
229 	TRACE(("USB Hub: interrupt callback!\n"));
230 }
231 
232 
233 status_t
234 Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
235 	void *data, size_t dataLength, size_t *actualLength)
236 {
237 	return SendRequest(
238 		USB_REQTYPE_DEVICE_IN | USB_REQTYPE_CLASS,			// type
239 		USB_REQUEST_GET_DESCRIPTOR,							// request
240 		(descriptorType << 8) | index,						// value
241 		languageID,											// index
242 		dataLength,											// length
243 		data,												// buffer
244 		dataLength,											// buffer length
245 		actualLength);										// actual length
246 }
247 
248 
249 void
250 Hub::ReportDevice(usb_support_descriptor *supportDescriptors,
251 	uint32 supportDescriptorCount, const usb_notify_hooks *hooks, bool added)
252 {
253 	TRACE(("USB Hub ReportDevice\n"));
254 
255 	// Report ourselfs first
256 	Device::ReportDevice(supportDescriptors, supportDescriptorCount, hooks, added);
257 
258 	// Then report all of our children
259 	for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
260 		if (!fChildren[i])
261 			continue;
262 
263 		fChildren[i]->ReportDevice(supportDescriptors,
264 				supportDescriptorCount, hooks, added);
265 	}
266 }
267 
268 
269 status_t
270 Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
271 	Device *device)
272 {
273 	status_t result = Device::BuildDeviceName(string, index, bufferSize, device);
274 	if (result < B_OK) {
275 		// recursion to parent failed, we're at the root(hub)
276 		int32 managerIndex = GetStack()->IndexOfBusManager(Manager());
277 		*index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex);
278 	}
279 
280 	if (!device) {
281 		// no device was specified - report the hub
282 		*index += snprintf(string + *index, bufferSize - *index, "/hub");
283 	} else {
284 		// find out where the requested device sitts
285 		for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
286 			if (fChildren[i] == device) {
287 				*index += snprintf(string + *index, bufferSize - *index, "/%ld", i);
288 				break;
289 			}
290 		}
291 	}
292 
293 	return B_OK;
294 }
295