xref: /haiku/src/add-ons/kernel/bus_managers/usb/BusManager.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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 
12 
13 BusManager::BusManager(Stack *stack)
14 	:	fInitOK(false),
15 		fStack(stack),
16 		fRootHub(NULL)
17 {
18 	mutex_init(&fLock, "usb busmanager lock");
19 
20 	fRootObject = new(std::nothrow) Object(stack, this);
21 	if (!fRootObject)
22 		return;
23 
24 	// Clear the device map
25 	for (int32 i = 0; i < 128; i++)
26 		fDeviceMap[i] = false;
27 	fDeviceIndex = 0;
28 
29 	// Set the default pipes to NULL (these will be created when needed)
30 	for (int32 i = 0; i <= USB_SPEED_MAX; i++)
31 		fDefaultPipes[i] = NULL;
32 
33 	fInitOK = true;
34 }
35 
36 
37 BusManager::~BusManager()
38 {
39 	Lock();
40 	mutex_destroy(&fLock);
41 	for (int32 i = 0; i <= USB_SPEED_MAX; i++)
42 		delete fDefaultPipes[i];
43 	delete fRootObject;
44 }
45 
46 
47 status_t
48 BusManager::InitCheck()
49 {
50 	if (fInitOK)
51 		return B_OK;
52 
53 	return B_ERROR;
54 }
55 
56 
57 bool
58 BusManager::Lock()
59 {
60 	return (mutex_lock(&fLock) == B_OK);
61 }
62 
63 
64 void
65 BusManager::Unlock()
66 {
67 	mutex_unlock(&fLock);
68 }
69 
70 
71 int8
72 BusManager::AllocateAddress()
73 {
74 	if (!Lock())
75 		return -1;
76 
77 	int8 tries = 127;
78 	int8 address = fDeviceIndex;
79 	while (tries-- > 0) {
80 		if (fDeviceMap[address] == false) {
81 			fDeviceIndex = (address + 1) % 127;
82 			fDeviceMap[address] = true;
83 			Unlock();
84 			return address + 1;
85 		}
86 
87 		address = (address + 1) % 127;
88 	}
89 
90 	TRACE_ERROR("the busmanager has run out of device addresses\n");
91 	Unlock();
92 	return -1;
93 }
94 
95 
96 void
97 BusManager::FreeAddress(int8 address)
98 {
99 	address--;
100 	if (address < 0)
101 		return;
102 
103 	if (!Lock())
104 		return;
105 
106 	if (!fDeviceMap[address]) {
107 		TRACE_ERROR("freeing address %d which was not allocated\n", address);
108 	}
109 
110 	fDeviceMap[address] = false;
111 	Unlock();
112 }
113 
114 
115 Device *
116 BusManager::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
117 	usb_speed speed)
118 {
119 	// Check if there is a free entry in the device map (for the device number)
120 	int8 deviceAddress = AllocateAddress();
121 	if (deviceAddress < 0) {
122 		TRACE_ERROR("could not allocate an address\n");
123 		return NULL;
124 	}
125 
126 	TRACE("setting device address to %d\n", deviceAddress);
127 	ControlPipe *defaultPipe = _GetDefaultPipe(speed);
128 
129 	if (!defaultPipe) {
130 		TRACE_ERROR("error getting the default pipe for speed %d\n", speed);
131 		FreeAddress(deviceAddress);
132 		return NULL;
133 	}
134 
135 	defaultPipe->SetHubInfo(hubAddress, hubPort);
136 
137 	status_t result = B_ERROR;
138 	for (int32 i = 0; i < 3; i++) {
139 		// Set the address of the device USB 1.1 spec p202
140 		result = defaultPipe->SendRequest(
141 			USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,	// type
142 			USB_REQUEST_SET_ADDRESS,						// request
143 			deviceAddress,									// value
144 			0,												// index
145 			0,												// length
146 			NULL,											// buffer
147 			0,												// buffer length
148 			NULL);											// actual length
149 
150 		if (result >= B_OK)
151 			break;
152 
153 		snooze(USB_DELAY_SET_ADDRESS_RETRY);
154 	}
155 
156 	if (result < B_OK) {
157 		TRACE_ERROR("error while setting device address\n");
158 		FreeAddress(deviceAddress);
159 		return NULL;
160 	}
161 
162 	// Wait a bit for the device to complete addressing
163 	snooze(USB_DELAY_SET_ADDRESS);
164 
165 	// Create a temporary pipe with the new address
166 	ControlPipe pipe(fRootObject);
167 	pipe.InitCommon(deviceAddress, 0, speed, Pipe::Default, 8, 0, hubAddress,
168 		hubPort);
169 
170 	// Get the device descriptor
171 	// Just retrieve the first 8 bytes of the descriptor -> minimum supported
172 	// size of any device. It is enough because it includes the device type.
173 
174 	size_t actualLength = 0;
175 	usb_device_descriptor deviceDescriptor;
176 
177 	TRACE("getting the device descriptor\n");
178 	pipe.SendRequest(
179 		USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD,		// type
180 		USB_REQUEST_GET_DESCRIPTOR,							// request
181 		USB_DESCRIPTOR_DEVICE << 8,							// value
182 		0,													// index
183 		8,													// length
184 		(void *)&deviceDescriptor,							// buffer
185 		8,													// buffer length
186 		&actualLength);										// actual length
187 
188 	if (actualLength != 8) {
189 		TRACE_ERROR("error while getting the device descriptor\n");
190 		FreeAddress(deviceAddress);
191 		return NULL;
192 	}
193 
194 	TRACE("short device descriptor for device %d:\n", deviceAddress);
195 	TRACE("\tlength:..............%d\n", deviceDescriptor.length);
196 	TRACE("\tdescriptor_type:.....0x%04x\n", deviceDescriptor.descriptor_type);
197 	TRACE("\tusb_version:.........0x%04x\n", deviceDescriptor.usb_version);
198 	TRACE("\tdevice_class:........0x%02x\n", deviceDescriptor.device_class);
199 	TRACE("\tdevice_subclass:.....0x%02x\n", deviceDescriptor.device_subclass);
200 	TRACE("\tdevice_protocol:.....0x%02x\n", deviceDescriptor.device_protocol);
201 	TRACE("\tmax_packet_size_0:...%d\n", deviceDescriptor.max_packet_size_0);
202 
203 	// Create a new instance based on the type (Hub or Device)
204 	if (deviceDescriptor.device_class == 0x09) {
205 		TRACE("creating new hub\n");
206 		Hub *hub = new(std::nothrow) Hub(parent, hubAddress, hubPort,
207 			deviceDescriptor, deviceAddress, speed, false);
208 		if (!hub) {
209 			TRACE_ERROR("no memory to allocate hub\n");
210 			FreeAddress(deviceAddress);
211 			return NULL;
212 		}
213 
214 		if (hub->InitCheck() < B_OK) {
215 			TRACE_ERROR("hub failed init check\n");
216 			FreeAddress(deviceAddress);
217 			delete hub;
218 			return NULL;
219 		}
220 
221 		return (Device *)hub;
222 	}
223 
224 	TRACE("creating new device\n");
225 	Device *device = new(std::nothrow) Device(parent, hubAddress, hubPort,
226 		deviceDescriptor, deviceAddress, speed, false);
227 	if (!device) {
228 		TRACE_ERROR("no memory to allocate device\n");
229 		FreeAddress(deviceAddress);
230 		return NULL;
231 	}
232 
233 	if (device->InitCheck() < B_OK) {
234 		TRACE_ERROR("device failed init check\n");
235 		FreeAddress(deviceAddress);
236 		delete device;
237 		return NULL;
238 	}
239 
240 	return device;
241 }
242 
243 
244 void
245 BusManager::FreeDevice(Device *device)
246 {
247 	FreeAddress(device->DeviceAddress());
248 	delete device;
249 }
250 
251 
252 status_t
253 BusManager::Start()
254 {
255 	return B_OK;
256 }
257 
258 
259 status_t
260 BusManager::Stop()
261 {
262 	return B_OK;
263 }
264 
265 
266 status_t
267 BusManager::SubmitTransfer(Transfer *transfer)
268 {
269 	// virtual function to be overridden
270 	return B_ERROR;
271 }
272 
273 
274 status_t
275 BusManager::CancelQueuedTransfers(Pipe *pipe, bool force)
276 {
277 	// virtual function to be overridden
278 	return B_ERROR;
279 }
280 
281 
282 status_t
283 BusManager::NotifyPipeChange(Pipe *pipe, usb_change change)
284 {
285 	// virtual function to be overridden
286 	return B_ERROR;
287 }
288 
289 
290 ControlPipe *
291 BusManager::_GetDefaultPipe(usb_speed speed)
292 {
293 	if (!Lock())
294 		return NULL;
295 
296 	if (fDefaultPipes[speed] == NULL) {
297 		fDefaultPipes[speed] = new(std::nothrow) ControlPipe(fRootObject);
298 		fDefaultPipes[speed]->InitCommon(0, 0, speed, Pipe::Default, 8, 0, 0, 0);
299 	}
300 
301 	if (!fDefaultPipes[speed]) {
302 		TRACE_ERROR("failed to allocate default pipe for speed %d\n", speed);
303 	}
304 
305 	Unlock();
306 	return fDefaultPipes[speed];
307 }
308