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 Transfer::Transfer(Pipe *pipe) 14 : fPipe(pipe), 15 fVector(&fData), 16 fVectorCount(0), 17 fBaseAddress(NULL), 18 fFragmented(false), 19 fActualLength(0), 20 fUserArea(-1), 21 fClonedArea(-1), 22 fCallback(NULL), 23 fCallbackCookie(NULL), 24 fRequestData(NULL) 25 { 26 } 27 28 29 Transfer::~Transfer() 30 { 31 // we take ownership of the request data 32 if (fRequestData) 33 delete fRequestData; 34 35 if (fVector && fVector != &fData) 36 delete[] fVector; 37 38 if (fClonedArea >= B_OK) 39 delete_area(fClonedArea); 40 } 41 42 43 void 44 Transfer::SetRequestData(usb_request_data *data) 45 { 46 fRequestData = data; 47 } 48 49 50 void 51 Transfer::SetData(uint8 *data, size_t dataLength) 52 { 53 fBaseAddress = data; 54 fData.iov_base = data; 55 fData.iov_len = dataLength; 56 57 if (data && dataLength > 0) 58 fVectorCount = 1; 59 } 60 61 62 void 63 Transfer::SetVector(iovec *vector, size_t vectorCount) 64 { 65 fVector = new(std::nothrow) iovec[vectorCount]; 66 memcpy(fVector, vector, vectorCount * sizeof(iovec)); 67 fVectorCount = vectorCount; 68 fBaseAddress = fVector[0].iov_base; 69 } 70 71 72 size_t 73 Transfer::VectorLength() 74 { 75 size_t length = 0; 76 for (size_t i = 0; i < fVectorCount; i++) 77 length += fVector[i].iov_len; 78 79 // the data is to large and would overflow the allocator 80 if (length > USB_MAX_FRAGMENT_SIZE) { 81 length = USB_MAX_FRAGMENT_SIZE; 82 fFragmented = true; 83 } 84 85 return length; 86 } 87 88 89 void 90 Transfer::AdvanceByFragment(size_t actualLength) 91 { 92 size_t length = USB_MAX_FRAGMENT_SIZE; 93 for (size_t i = 0; i < fVectorCount; i++) { 94 if (fVector[i].iov_len <= length) { 95 length -= fVector[i].iov_len; 96 fVector[i].iov_len = 0; 97 continue; 98 } 99 100 fVector[i].iov_base = (void *)((uint8 *)fVector[i].iov_base + length); 101 fVector[i].iov_len -= length; 102 break; 103 } 104 105 fActualLength += actualLength; 106 } 107 108 109 status_t 110 Transfer::InitKernelAccess() 111 { 112 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 113 // we might need to access a buffer in userspace. this will not 114 // be possible in the kernel space finisher thread unless we 115 // get the proper area id for the space we need and then clone it 116 // before reading from or writing to it. 117 iovec *vector = fVector; 118 for (size_t i = 0; i < fVectorCount; i++) { 119 if (IS_USER_ADDRESS(vector[i].iov_base)) { 120 fUserArea = area_for(vector[i].iov_base); 121 if (fUserArea < B_OK) 122 return B_BAD_ADDRESS; 123 break; 124 } 125 } 126 127 // no user area required for access 128 if (fUserArea < B_OK) 129 return B_OK; 130 131 area_info areaInfo; 132 if (fUserArea < B_OK || get_area_info(fUserArea, &areaInfo) < B_OK) 133 return B_BAD_ADDRESS; 134 135 for (size_t i = 0; i < fVectorCount; i++) { 136 (uint8 *)vector[i].iov_base -= (uint8 *)areaInfo.address; 137 138 if ((size_t)vector[i].iov_base > areaInfo.size 139 || (size_t)vector[i].iov_base + vector[i].iov_len > areaInfo.size) { 140 TRACE_ERROR(("USB Transfer: data buffer spans across multiple areas!\n")); 141 return B_BAD_ADDRESS; 142 } 143 } 144 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 145 146 return B_OK; 147 } 148 149 150 status_t 151 Transfer::PrepareKernelAccess() 152 { 153 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 154 // done if there is no userspace buffer or if we already cloned its area 155 if (fUserArea < B_OK || fClonedArea >= B_OK) 156 return B_OK; 157 158 void *clonedMemory = NULL; 159 // we got a userspace buffer, need to clone the area for that 160 // space first and map the iovecs to this cloned area. 161 fClonedArea = clone_area("userspace accessor", &clonedMemory, 162 B_ANY_ADDRESS, B_WRITE_AREA | B_KERNEL_WRITE_AREA, fUserArea); 163 164 if (fClonedArea < B_OK) 165 return fClonedArea; 166 167 for (size_t i = 0; i < fVectorCount; i++) 168 (uint8 *)fVector[i].iov_base += (addr_t)clonedMemory; 169 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 170 171 return B_OK; 172 } 173 174 175 void 176 Transfer::SetCallback(usb_callback_func callback, void *cookie) 177 { 178 fCallback = callback; 179 fCallbackCookie = cookie; 180 } 181 182 183 void 184 Transfer::Finished(uint32 status, size_t actualLength) 185 { 186 if (fCallback) 187 fCallback(fCallbackCookie, status, fBaseAddress, 188 fActualLength + actualLength); 189 } 190