1 /* 2 * Copyright 2004-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 Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, 14 pipeDirection direction, usb_speed speed, size_t maxPacketSize) 15 : Object(parent), 16 fDeviceAddress(deviceAddress), 17 fEndpointAddress(endpointAddress), 18 fDirection(direction), 19 fSpeed(speed), 20 fMaxPacketSize(maxPacketSize), 21 fDataToggle(false) 22 { 23 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_CREATED); 24 } 25 26 27 Pipe::~Pipe() 28 { 29 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED); 30 } 31 32 33 status_t 34 Pipe::SubmitTransfer(Transfer *transfer) 35 { 36 // ToDo: keep track of all submited transfers to be able to cancel them 37 return GetBusManager()->SubmitTransfer(transfer); 38 } 39 40 41 status_t 42 Pipe::CancelQueuedTransfers() 43 { 44 return GetBusManager()->CancelQueuedTransfers(this); 45 } 46 47 48 status_t 49 Pipe::SetFeature(uint16 selector) 50 { 51 return ((Device *)Parent())->DefaultPipe()->SendRequest( 52 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 53 USB_REQUEST_SET_FEATURE, 54 selector, 55 fEndpointAddress, 56 0, 57 NULL, 58 0, 59 NULL); 60 } 61 62 63 status_t 64 Pipe::ClearFeature(uint16 selector) 65 { 66 // clearing a stalled condition resets the data toggle 67 if (selector == USB_FEATURE_ENDPOINT_HALT) 68 SetDataToggle(false); 69 70 return ((Device *)Parent())->DefaultPipe()->SendRequest( 71 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 72 USB_REQUEST_CLEAR_FEATURE, 73 selector, 74 fEndpointAddress, 75 0, 76 NULL, 77 0, 78 NULL); 79 } 80 81 82 status_t 83 Pipe::GetStatus(uint16 *status) 84 { 85 return ((Device *)Parent())->DefaultPipe()->SendRequest( 86 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN, 87 USB_REQUEST_GET_STATUS, 88 0, 89 fEndpointAddress, 90 2, 91 (void *)status, 92 2, 93 NULL); 94 } 95 96 97 // 98 // #pragma mark - 99 // 100 101 102 InterruptPipe::InterruptPipe(Object *parent, int8 deviceAddress, 103 uint8 endpointAddress, pipeDirection direction, usb_speed speed, 104 size_t maxPacketSize) 105 : Pipe(parent, deviceAddress, endpointAddress, direction, speed, 106 maxPacketSize) 107 { 108 } 109 110 111 status_t 112 InterruptPipe::QueueInterrupt(void *data, size_t dataLength, 113 usb_callback_func callback, void *callbackCookie) 114 { 115 Transfer *transfer = new(std::nothrow) Transfer(this); 116 if (!transfer) 117 return B_NO_MEMORY; 118 119 transfer->SetData((uint8 *)data, dataLength); 120 transfer->SetCallback(callback, callbackCookie); 121 122 status_t result = GetBusManager()->SubmitTransfer(transfer); 123 if (result < B_OK) 124 delete transfer; 125 return result; 126 } 127 128 129 // 130 // #pragma mark - 131 // 132 133 134 BulkPipe::BulkPipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, 135 pipeDirection direction, usb_speed speed, size_t maxPacketSize) 136 : Pipe(parent, deviceAddress, endpointAddress, direction, speed, 137 maxPacketSize) 138 { 139 } 140 141 142 status_t 143 BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback, 144 void *callbackCookie) 145 { 146 Transfer *transfer = new(std::nothrow) Transfer(this); 147 if (!transfer) 148 return B_NO_MEMORY; 149 150 transfer->SetData((uint8 *)data, dataLength); 151 transfer->SetCallback(callback, callbackCookie); 152 153 status_t result = GetBusManager()->SubmitTransfer(transfer); 154 if (result < B_OK) 155 delete transfer; 156 return result; 157 } 158 159 160 status_t 161 BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, 162 usb_callback_func callback, void *callbackCookie) 163 { 164 Transfer *transfer = new(std::nothrow) Transfer(this); 165 if (!transfer) 166 return B_NO_MEMORY; 167 168 transfer->SetVector(vector, vectorCount); 169 transfer->SetCallback(callback, callbackCookie); 170 171 status_t result = GetBusManager()->SubmitTransfer(transfer); 172 if (result < B_OK) 173 delete transfer; 174 return result; 175 } 176 177 178 // 179 // #pragma mark - 180 // 181 182 183 IsochronousPipe::IsochronousPipe(Object *parent, int8 deviceAddress, 184 uint8 endpointAddress, pipeDirection direction, usb_speed speed, 185 size_t maxPacketSize) 186 : Pipe(parent, deviceAddress, endpointAddress, direction, speed, 187 maxPacketSize), 188 fMaxQueuedPackets(0), 189 fMaxBufferDuration(0), 190 fSampleSize(0) 191 { 192 } 193 194 195 status_t 196 IsochronousPipe::QueueIsochronous(void *data, size_t dataLength, 197 usb_iso_packet_descriptor *packetDesc, uint32 packetCount, 198 uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback, 199 void *callbackCookie) 200 { 201 // TODO: Check if values of input parameters are set correctely 202 usb_isochronous_data *isochronousData 203 = new(std::nothrow) usb_isochronous_data; 204 205 if (!isochronousData) 206 return B_NO_MEMORY; 207 208 isochronousData->packet_descriptors = packetDesc; 209 isochronousData->packet_count = packetCount; 210 isochronousData->starting_frame_number = startingFrameNumber; 211 isochronousData->flags = flags; 212 213 Transfer *transfer = new(std::nothrow) Transfer(this); 214 if (!transfer) { 215 delete isochronousData; 216 return B_NO_MEMORY; 217 } 218 219 transfer->SetData((uint8 *)data, dataLength); 220 transfer->SetCallback(callback, callbackCookie); 221 transfer->SetIsochronousData(isochronousData); 222 223 status_t result = GetBusManager()->SubmitTransfer(transfer); 224 if (result < B_OK) 225 delete transfer; 226 return result; 227 } 228 229 230 status_t 231 IsochronousPipe::SetPipePolicy(uint8 maxQueuedPackets, 232 uint16 maxBufferDurationMS, uint16 sampleSize) 233 { 234 if (maxQueuedPackets == fMaxQueuedPackets 235 || maxBufferDurationMS == fMaxBufferDuration 236 || sampleSize == fSampleSize) 237 return B_OK; 238 239 fMaxQueuedPackets = maxQueuedPackets; 240 fMaxBufferDuration = maxBufferDurationMS; 241 fSampleSize = sampleSize; 242 243 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_PIPE_POLICY_CHANGED); 244 return B_OK; 245 } 246 247 248 status_t 249 IsochronousPipe::GetPipePolicy(uint8 *maxQueuedPackets, 250 uint16 *maxBufferDurationMS, uint16 *sampleSize) 251 { 252 if (maxQueuedPackets) 253 *maxQueuedPackets = fMaxQueuedPackets; 254 if (maxBufferDurationMS) 255 *maxBufferDurationMS = fMaxBufferDuration; 256 if (sampleSize) 257 *sampleSize = fSampleSize; 258 return B_OK; 259 } 260 261 262 // 263 // #pragma mark - 264 // 265 266 267 typedef struct transfer_result_data_s { 268 sem_id notify_sem; 269 status_t status; 270 size_t actual_length; 271 } transfer_result_data; 272 273 274 ControlPipe::ControlPipe(Object *parent, int8 deviceAddress, 275 uint8 endpointAddress, usb_speed speed, size_t maxPacketSize) 276 : Pipe(parent, deviceAddress, endpointAddress, Default, speed, 277 maxPacketSize) 278 { 279 } 280 281 282 status_t 283 ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, 284 uint16 index, uint16 length, void *data, size_t dataLength, 285 size_t *actualLength) 286 { 287 transfer_result_data *transferResult 288 = new(std::nothrow) transfer_result_data; 289 290 transferResult->notify_sem = create_sem(0, "usb send request notify"); 291 if (transferResult->notify_sem < B_OK) 292 return B_NO_MORE_SEMS; 293 294 status_t result = QueueRequest(requestType, request, value, index, length, 295 data, dataLength, SendRequestCallback, transferResult); 296 if (result < B_OK) { 297 delete_sem(transferResult->notify_sem); 298 return result; 299 } 300 301 // the sem will be released in the callback after the result data was 302 // filled into the provided struct. use a 5 seconds timeout to avoid 303 // hanging applications. 304 if (acquire_sem_etc(transferResult->notify_sem, 1, B_RELATIVE_TIMEOUT, 5000000) < B_OK) { 305 TRACE_ERROR(("USB ControlPipe: timeout waiting for queued request to complete\n")); 306 307 delete_sem(transferResult->notify_sem); 308 if (actualLength) 309 *actualLength = 0; 310 311 // ToDo: cancel the transfer at the bus manager 312 return B_TIMED_OUT; 313 } 314 315 delete_sem(transferResult->notify_sem); 316 if (actualLength) 317 *actualLength = transferResult->actual_length; 318 319 result = transferResult->status; 320 delete transferResult; 321 return result; 322 } 323 324 325 void 326 ControlPipe::SendRequestCallback(void *cookie, status_t status, void *data, 327 size_t actualLength) 328 { 329 transfer_result_data *transferResult = (transfer_result_data *)cookie; 330 transferResult->status = status; 331 transferResult->actual_length = actualLength; 332 if (release_sem(transferResult->notify_sem) < B_OK) { 333 // the request has timed out already - cleanup after us 334 delete transferResult; 335 } 336 } 337 338 339 status_t 340 ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value, 341 uint16 index, uint16 length, void *data, size_t dataLength, 342 usb_callback_func callback, void *callbackCookie) 343 { 344 usb_request_data *requestData = new(std::nothrow) usb_request_data; 345 if (!requestData) 346 return B_NO_MEMORY; 347 348 requestData->RequestType = requestType; 349 requestData->Request = request; 350 requestData->Value = value; 351 requestData->Index = index; 352 requestData->Length = length; 353 354 Transfer *transfer = new(std::nothrow) Transfer(this); 355 if (!transfer) { 356 delete requestData; 357 return B_NO_MEMORY; 358 } 359 360 transfer->SetRequestData(requestData); 361 transfer->SetData((uint8 *)data, dataLength); 362 transfer->SetCallback(callback, callbackCookie); 363 364 status_t result = GetBusManager()->SubmitTransfer(transfer); 365 if (result < B_OK) 366 delete transfer; 367 return result; 368 } 369