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 16 Transfer::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 35 Transfer::~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 49 void 50 Transfer::SetRequestData(usb_request_data *data) 51 { 52 fRequestData = data; 53 } 54 55 56 void 57 Transfer::SetIsochronousData(usb_isochronous_data *data) 58 { 59 fIsochronousData = data; 60 } 61 62 63 void 64 Transfer::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 84 void 85 Transfer::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 101 void 102 Transfer::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 118 void 119 Transfer::_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 129 size_t 130 Transfer::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 143 void 144 Transfer::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 163 status_t 164 Transfer::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 209 status_t 210 Transfer::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 231 void 232 Transfer::SetCallback(usb_callback_func callback, void *cookie) 233 { 234 fCallback = callback; 235 fCallbackCookie = cookie; 236 } 237 238 239 void 240 Transfer::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 */ 258 status_t 259 Transfer::_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