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
11#include "usb_private.h"
12
13#include <kernel.h>
14
15
16Transfer::Transfer(Pipe *pipe)
17	:	fPipe(pipe),
18		fVector(&fData),
19		fVectorCount(0),
20		fBaseAddress(NULL),
21		fPhysical(false),
22		fFragmented(false),
23		fActualLength(0),
24		fUserArea(-1),
25		fClonedArea(-1),
26		fCallback(NULL),
27		fCallbackCookie(NULL),
28		fRequestData(NULL),
29		fIsochronousData(NULL),
30		fBandwidth(0)
31{
32}
33
34
35Transfer::~Transfer()
36{
37	// we take ownership of the request data
38	if (fRequestData)
39		delete fRequestData;
40
41	if (fVector && fVector != &fData)
42		delete[] fVector;
43
44	if (fClonedArea >= B_OK)
45		delete_area(fClonedArea);
46}
47
48
49void
50Transfer::SetRequestData(usb_request_data *data)
51{
52	fRequestData = data;
53}
54
55
56void
57Transfer::SetIsochronousData(usb_isochronous_data *data)
58{
59	fIsochronousData = data;
60}
61
62
63void
64Transfer::SetData(uint8 *data, size_t dataLength)
65{
66	fPhysical = false;
67	fBaseAddress = data;
68	fData.base = (generic_addr_t)data;
69	fData.length = dataLength;
70
71	if (data && dataLength > 0)
72		fVectorCount = 1;
73
74	fFragmented = dataLength > USB_MAX_FRAGMENT_SIZE;
75
76	// Calculate the bandwidth (only if it is not a bulk transfer)
77	if (!(fPipe->Type() & USB_OBJECT_BULK_PIPE)) {
78		if (_CalculateBandwidth() < B_OK)
79			TRACE_ERROR("can't calculate bandwidth\n");
80	}
81}
82
83
84void
85Transfer::SetVector(iovec *vector, size_t vectorCount)
86{
87	fPhysical = false;
88
89	fVector = new(std::nothrow) generic_io_vec[vectorCount];
90	for (size_t i = 0; i < vectorCount; i++) {
91		fVector[i].base = (generic_addr_t)vector[i].iov_base;
92		fVector[i].length = vector[i].iov_len;
93	}
94	fVectorCount = vectorCount;
95	fBaseAddress = vector[0].iov_base;
96
97	_CheckFragmented();
98}
99
100
101void
102Transfer::SetVector(physical_entry *vector, size_t vectorCount)
103{
104	fPhysical = true;
105
106	fVector = new(std::nothrow) generic_io_vec[vectorCount];
107	for (size_t i = 0; i < vectorCount; i++) {
108		fVector[i].base = (generic_addr_t)vector[i].address;
109		fVector[i].length = vector[i].size;
110	}
111	fVectorCount = vectorCount;
112	fBaseAddress = NULL;
113
114	_CheckFragmented();
115}
116
117
118void
119Transfer::_CheckFragmented()
120{
121	size_t length = 0;
122	for (size_t i = 0; i < fVectorCount && length <= USB_MAX_FRAGMENT_SIZE; i++)
123		length += fVector[i].length;
124
125	fFragmented = length > USB_MAX_FRAGMENT_SIZE;
126}
127
128
129size_t
130Transfer::FragmentLength() const
131{
132	size_t length = 0;
133	for (size_t i = 0; i < fVectorCount; i++)
134		length += fVector[i].length;
135
136	if (length > USB_MAX_FRAGMENT_SIZE)
137		length = USB_MAX_FRAGMENT_SIZE;
138
139	return length;
140}
141
142
143void
144Transfer::AdvanceByFragment(size_t actualLength)
145{
146	size_t length = USB_MAX_FRAGMENT_SIZE;
147	for (size_t i = 0; i < fVectorCount; i++) {
148		if (fVector[i].length <= length) {
149			length -= fVector[i].length;
150			fVector[i].length = 0;
151			continue;
152		}
153
154		fVector[i].base = fVector[i].base + length;
155		fVector[i].length -= length;
156		break;
157	}
158
159	fActualLength += actualLength;
160}
161
162
163status_t
164Transfer::InitKernelAccess()
165{
166	// nothing to do if we are already prepared, or have a physical request
167	if (fClonedArea >= B_OK || fPhysical)
168		return B_OK;
169
170	// we might need to access a buffer in userspace. this will not
171	// be possible in the kernel space finisher thread unless we
172	// get the proper area id for the space we need and then clone it
173	// before reading from or writing to it.
174	generic_io_vec *vector = fVector;
175	for (size_t i = 0; i < fVectorCount; i++) {
176		if (IS_USER_ADDRESS(vector[i].base)) {
177			fUserArea = area_for((void*)vector[i].base);
178			if (fUserArea < B_OK) {
179				TRACE_ERROR("failed to find area for user space buffer!\n");
180				return B_BAD_ADDRESS;
181			}
182			break;
183		}
184	}
185
186	// no user area required for access
187	if (fUserArea < B_OK)
188		return B_OK;
189
190	area_info areaInfo;
191	if (fUserArea < B_OK || get_area_info(fUserArea, &areaInfo) < B_OK) {
192		TRACE_ERROR("couldn't get user area info\n");
193		return B_BAD_ADDRESS;
194	}
195
196	for (size_t i = 0; i < fVectorCount; i++) {
197		vector[i].base = vector[i].base - (addr_t)areaInfo.address;
198
199		if (vector[i].base > areaInfo.size
200				|| (vector[i].base + vector[i].length) > areaInfo.size) {
201			TRACE_ERROR("data buffer spans across multiple areas!\n");
202			return B_BAD_ADDRESS;
203		}
204	}
205	return B_OK;
206}
207
208
209status_t
210Transfer::PrepareKernelAccess()
211{
212	// done if there is no userspace buffer or if we already cloned its area
213	if (fUserArea < B_OK || fClonedArea >= B_OK)
214		return B_OK;
215
216	void *clonedMemory = NULL;
217	// we got a userspace buffer, need to clone the area for that
218	// space first and map the iovecs to this cloned area.
219	fClonedArea = clone_area("userspace accessor", &clonedMemory,
220		B_ANY_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, fUserArea);
221
222	if (fClonedArea < B_OK)
223		return fClonedArea;
224
225	for (size_t i = 0; i < fVectorCount; i++)
226		fVector[i].base = fVector[i].base + (addr_t)clonedMemory;
227	return B_OK;
228}
229
230
231void
232Transfer::SetCallback(usb_callback_func callback, void *cookie)
233{
234	fCallback = callback;
235	fCallbackCookie = cookie;
236}
237
238
239void
240Transfer::Finished(uint32 status, size_t actualLength)
241{
242	if (fCallback)
243		fCallback(fCallbackCookie, status, fBaseAddress,
244			fActualLength + actualLength);
245}
246
247
248/*
249 * USB 2.0 Spec function, pag 64.
250 * This function sets fBandwidth in microsecond
251 * to the bandwidth needed to transfer fData.iov_len bytes.
252 * The calculation is based on
253 * 1. Speed of the transfer
254 * 2. Pipe direction
255 * 3. Type of pipe
256 * 4. Number of bytes to transfer
257 */
258status_t
259Transfer::_CalculateBandwidth()
260{
261	uint16 bandwidthNS;
262	uint32 type = fPipe->Type();
263
264	switch (fPipe->Speed()) {
265		case USB_SPEED_HIGHSPEED:
266		{
267			// Direction doesn't matter for highspeed
268			if (type & USB_OBJECT_ISO_PIPE)
269				bandwidthNS = (uint16)((38 * 8 * 2.083)
270					+ (2.083 * ((uint32)(3.167 * (1.1667 * 8 * fData.length))))
271					+ USB_BW_HOST_DELAY);
272			else
273				bandwidthNS = (uint16)((55 * 8 * 2.083)
274					+ (2.083 * ((uint32)(3.167 * (1.1667 * 8 * fData.length))))
275					+ USB_BW_HOST_DELAY);
276			break;
277		}
278		case USB_SPEED_FULLSPEED:
279		{
280			// Direction does matter this time for isochronous
281			if (type & USB_OBJECT_ISO_PIPE)
282				bandwidthNS = (uint16)
283					(((fPipe->Direction() == Pipe::In) ? 7268 : 6265)
284					+ (83.54 * ((uint32)(3.167 + (1.1667 * 8 * fData.length))))
285					+ USB_BW_HOST_DELAY);
286			else
287				bandwidthNS = (uint16)(9107
288					+ (83.54 * ((uint32)(3.167 + (1.1667 * 8 * fData.length))))
289					+ USB_BW_HOST_DELAY);
290			break;
291		}
292		case USB_SPEED_LOWSPEED:
293		{
294			if (fPipe->Direction() == Pipe::In)
295				bandwidthNS = (uint16) (64060 + (2 * USB_BW_SETUP_LOW_SPEED_PORT_DELAY)
296					+ (676.67 * ((uint32)(3.167 + (1.1667 * 8 * fData.length))))
297					+ USB_BW_HOST_DELAY);
298			else
299				bandwidthNS = (uint16)(64107 + (2 * USB_BW_SETUP_LOW_SPEED_PORT_DELAY)
300					+ (667.0 * ((uint32)(3.167 + (1.1667 * 8 * fData.length))))
301					+ USB_BW_HOST_DELAY);
302			break;
303		}
304
305		case USB_SPEED_SUPERSPEED:
306		{
307			// TODO it should only be useful for isochronous type
308			bandwidthNS = 0;
309			break;
310		}
311
312		default:
313			// We should never get here
314			TRACE("speed unknown");
315			return B_ERROR;
316	}
317
318	// Round up and set the value in microseconds
319	fBandwidth = (bandwidthNS + 500) / 1000;
320
321	return B_OK;
322}
323