xref: /haiku/src/add-ons/kernel/bus_managers/usb/Hub.cpp (revision cd552c7a15cc10c36dae8d7439ba1d6c0bb168c5)
1 /*
2  * Copyright 2003-2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Niels S. Reedijk
7  */
8 
9 #include "usb_p.h"
10 
11 
12 #define TRACE_HUB
13 #ifdef TRACE_HUB
14 #define TRACE(x)	dprintf	x
15 #else
16 #define TRACE(x)	/* nothing */
17 #endif
18 
19 
20 Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc,
21 	int8 deviceAddress, bool lowSpeed)
22 	:	Device(bus, parent, desc, deviceAddress, lowSpeed)
23 {
24 	TRACE(("USB Hub is being initialised\n"));
25 
26 	if (!fInitOK) {
27 		TRACE(("USB Hub: Device failed to initialize\n"));
28 		return;
29 	}
30 
31 	// Set to false again for the hub init.
32 	fInitOK = false;
33 
34 	if (fDeviceDescriptor.device_subclass != 0
35 		|| fDeviceDescriptor.device_protocol != 0) {
36 		TRACE(("USB Hub: wrong class/subclass/protocol! Bailing out\n"));
37 		return;
38 	}
39 
40 	if (fCurrentConfiguration->number_interfaces > 1) {
41 		TRACE(("USB Hub: too many interfaces\n"));
42 		return;
43 	}
44 
45 	size_t actualLength;
46 	if (GetDescriptor(USB_DESCRIPTOR_INTERFACE, 0, (void *)&fInterruptInterface,
47 		sizeof(usb_interface_descriptor)) != sizeof(usb_interface_descriptor)) {
48 		TRACE(("USB Hub: error getting the interrupt interface\n"));
49 		return;
50 	}
51 
52 	if (fInterruptInterface.num_endpoints > 1) {
53 		TRACE(("USB Hub: too many endpoints\n"));
54 		return;
55 	}
56 
57 	if (GetDescriptor(USB_DESCRIPTOR_ENDPOINT, 0, (void *)&fInterruptEndpoint,
58 		sizeof(usb_endpoint_descriptor)) != sizeof(usb_endpoint_descriptor)) {
59 		TRACE(("USB Hub: Error getting the endpoint\n"));
60 		return;
61 	}
62 
63 	if (fInterruptEndpoint.attributes != 0x03) { // interrupt transfer
64 		TRACE(("USB Hub: Not an interrupt endpoint\n"));
65 		return;
66 	}
67 
68 	TRACE(("USB Hub: Getting hub descriptor...\n"));
69 	if (GetDescriptor(USB_DESCRIPTOR_HUB, 0, (void *)&fHubDescriptor,
70 		sizeof(usb_hub_descriptor)) != sizeof(usb_hub_descriptor)) {
71 		TRACE(("USB Hub: Error getting hub descriptor\n"));
72 		return;
73 	}
74 
75 	// Enable port power on all ports
76 	for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) {
77 		fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
78 			USB_REQUEST_SET_FEATURE,
79 			PORT_POWER,
80 			i + 1,
81 			0,
82 			NULL,
83 			0,
84 			&actualLength);
85 	}
86 
87 	// Wait for power to stabilize
88 	snooze(fHubDescriptor.bPwrOn2PwrGood * 2);
89 
90 	fInitOK = true;
91 	TRACE(("USB Hub: initialised ok\n"));
92 }
93 
94 
95 void
96 Hub::Explore()
97 {
98 	for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) {
99 		size_t actualLength;
100 
101 		// Get the current port status
102 		fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN,
103 			USB_REQUEST_GET_STATUS,
104 			0,
105 			i + 1,
106 			4,
107 			(void *)&fPortStatus[i],
108 			4,
109 			&actualLength);
110 
111 		if (actualLength < 4) {
112 			TRACE(("USB Hub: error getting port status\n"));
113 			return;
114 		}
115 
116 		//TRACE(("status: 0x%04x; change: 0x%04x\n", fPortStatus[i].status, fPortStatus[i].change));
117 
118 		// We need to test the port change against a number of things
119 		if (fPortStatus[i].status & PORT_RESET) {
120 			fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
121 				USB_REQUEST_CLEAR_FEATURE,
122 				PORT_RESET,
123 				i + 1,
124 				0,
125 				NULL,
126 				0,
127 				&actualLength);
128 		}
129 
130 		if (fPortStatus[i].change & PORT_STATUS_CONNECTION) {
131 			if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
132 				// New device attached!
133 
134 				if ((fPortStatus[i].status & PORT_STATUS_ENABLE) == 0) {
135 					// enable the port if it isn't
136 					fDefaultPipe->SendRequest(
137 						USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
138 						USB_REQUEST_SET_FEATURE,
139 						PORT_ENABLE,
140 						i + 1,
141 						0,
142 						NULL,
143 						0,
144 						NULL);
145 		        }
146 
147 				TRACE(("USB Hub: Explore(): New device connected\n"));
148 
149 				Device *newDevice;
150 				if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED)
151 					newDevice = fBus->AllocateNewDevice(this, true);
152 				else
153 					newDevice = fBus->AllocateNewDevice(this, false);
154 
155 				if (newDevice)
156 					fChildren[i] = newDevice;
157 			} else {
158 				// Device removed...
159 				// ToDo: do something
160 				TRACE(("USB Hub Explore(): Device removed\n"));
161 			}
162 
163 			// Clear status change
164 			fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
165 				USB_REQUEST_CLEAR_FEATURE,
166 				C_PORT_CONNECTION,
167 				i + 1,
168 				0,
169 				NULL,
170 				0,
171 				NULL);
172 		}
173 	}
174 }
175