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