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 TRACE_ERROR(("Pipe: cancelling transfers is not implemented!\n")); 45 return B_ERROR; 46 } 47 48 49 status_t 50 Pipe::SetFeature(uint16 selector) 51 { 52 return ((Device *)Parent())->DefaultPipe()->SendRequest( 53 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 54 USB_REQUEST_SET_FEATURE, 55 selector, 56 fEndpointAddress, 57 0, 58 NULL, 59 0, 60 NULL); 61 } 62 63 64 status_t 65 Pipe::ClearFeature(uint16 selector) 66 { 67 // clearing a stalled condition resets the data toggle 68 if (selector == USB_FEATURE_ENDPOINT_HALT) 69 SetDataToggle(false); 70 71 return ((Device *)Parent())->DefaultPipe()->SendRequest( 72 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 73 USB_REQUEST_CLEAR_FEATURE, 74 selector, 75 fEndpointAddress, 76 0, 77 NULL, 78 0, 79 NULL); 80 } 81 82 83 status_t 84 Pipe::GetStatus(uint16 *status) 85 { 86 return ((Device *)Parent())->DefaultPipe()->SendRequest( 87 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN, 88 USB_REQUEST_GET_STATUS, 89 0, 90 fEndpointAddress, 91 2, 92 (void *)status, 93 2, 94 NULL); 95 } 96 97 98 // 99 // #pragma mark - 100 // 101 102 103 InterruptPipe::InterruptPipe(Object *parent, int8 deviceAddress, 104 uint8 endpointAddress, pipeDirection direction, usb_speed speed, 105 size_t maxPacketSize) 106 : Pipe(parent, deviceAddress, endpointAddress, direction, speed, 107 maxPacketSize) 108 { 109 } 110 111 112 status_t 113 InterruptPipe::QueueInterrupt(void *data, size_t dataLength, 114 usb_callback_func callback, void *callbackCookie) 115 { 116 Transfer *transfer = new(std::nothrow) Transfer(this); 117 if (!transfer) 118 return B_NO_MEMORY; 119 120 transfer->SetData((uint8 *)data, dataLength); 121 transfer->SetCallback(callback, callbackCookie); 122 123 status_t result = SubmitTransfer(transfer); 124 if (result < B_OK) 125 delete transfer; 126 return result; 127 } 128 129 130 // 131 // #pragma mark - 132 // 133 134 135 BulkPipe::BulkPipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, 136 pipeDirection direction, usb_speed speed, size_t maxPacketSize) 137 : Pipe(parent, deviceAddress, endpointAddress, direction, speed, 138 maxPacketSize) 139 { 140 } 141 142 143 status_t 144 BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback, 145 void *callbackCookie) 146 { 147 Transfer *transfer = new(std::nothrow) Transfer(this); 148 if (!transfer) 149 return B_NO_MEMORY; 150 151 transfer->SetData((uint8 *)data, dataLength); 152 transfer->SetCallback(callback, callbackCookie); 153 154 status_t result = SubmitTransfer(transfer); 155 if (result < B_OK) 156 delete transfer; 157 return result; 158 } 159 160 161 status_t 162 BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, 163 usb_callback_func callback, void *callbackCookie) 164 { 165 Transfer *transfer = new(std::nothrow) Transfer(this); 166 if (!transfer) 167 return B_NO_MEMORY; 168 169 transfer->SetVector(vector, vectorCount); 170 transfer->SetCallback(callback, callbackCookie); 171 172 status_t result = SubmitTransfer(transfer); 173 if (result < B_OK) 174 delete transfer; 175 return result; 176 } 177 178 179 // 180 // #pragma mark - 181 // 182 183 184 IsochronousPipe::IsochronousPipe(Object *parent, int8 deviceAddress, 185 uint8 endpointAddress, pipeDirection direction, usb_speed speed, 186 size_t maxPacketSize) 187 : Pipe(parent, deviceAddress, endpointAddress, direction, speed, 188 maxPacketSize), 189 fMaxQueuedPackets(0), 190 fMaxBufferDuration(0), 191 fSampleSize(0) 192 { 193 } 194 195 196 status_t 197 IsochronousPipe::QueueIsochronous(void *data, size_t dataLength, 198 usb_iso_packet_descriptor *packetDesc, uint32 packetCount, 199 uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback, 200 void *callbackCookie) 201 { 202 return B_ERROR; 203 } 204 205 206 status_t 207 IsochronousPipe::SetPipePolicy(uint8 maxQueuedPackets, 208 uint16 maxBufferDurationMS, uint16 sampleSize) 209 { 210 if (maxQueuedPackets == fMaxQueuedPackets 211 || maxBufferDurationMS == fMaxBufferDuration 212 || sampleSize == fSampleSize) 213 return B_OK; 214 215 fMaxQueuedPackets = maxQueuedPackets; 216 fMaxBufferDuration = maxBufferDurationMS; 217 fSampleSize = sampleSize; 218 219 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_PIPE_POLICY_CHANGED); 220 return B_OK; 221 } 222 223 224 status_t 225 IsochronousPipe::GetPipePolicy(uint8 *maxQueuedPackets, 226 uint16 *maxBufferDurationMS, uint16 *sampleSize) 227 { 228 if (maxQueuedPackets) 229 *maxQueuedPackets = fMaxQueuedPackets; 230 if (maxBufferDurationMS) 231 *maxBufferDurationMS = fMaxBufferDuration; 232 if (sampleSize) 233 *sampleSize = fSampleSize; 234 return B_OK; 235 } 236 237 238 // 239 // #pragma mark - 240 // 241 242 243 typedef struct transfer_result_data_s { 244 sem_id notify_sem; 245 status_t status; 246 size_t actual_length; 247 } transfer_result_data; 248 249 250 ControlPipe::ControlPipe(Object *parent, int8 deviceAddress, 251 uint8 endpointAddress, usb_speed speed, size_t maxPacketSize) 252 : Pipe(parent, deviceAddress, endpointAddress, Default, speed, 253 maxPacketSize) 254 { 255 } 256 257 258 status_t 259 ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, 260 uint16 index, uint16 length, void *data, size_t dataLength, 261 size_t *actualLength) 262 { 263 transfer_result_data transferResult; 264 transferResult.notify_sem = create_sem(0, "Send Request Notify Sem"); 265 if (transferResult.notify_sem < B_OK) 266 return B_NO_MORE_SEMS; 267 268 status_t result = QueueRequest(requestType, request, value, index, length, 269 data, dataLength, SendRequestCallback, &transferResult); 270 if (result < B_OK) { 271 delete_sem(transferResult.notify_sem); 272 return result; 273 } 274 275 // the sem will be released in the callback after 276 // the result data was filled into the provided struct 277 acquire_sem(transferResult.notify_sem); 278 delete_sem(transferResult.notify_sem); 279 280 if (actualLength) 281 *actualLength = transferResult.actual_length; 282 283 return transferResult.status; 284 } 285 286 287 void 288 ControlPipe::SendRequestCallback(void *cookie, status_t status, void *data, 289 size_t actualLength) 290 { 291 transfer_result_data *transferResult = (transfer_result_data *)cookie; 292 transferResult->status = status; 293 transferResult->actual_length = actualLength; 294 release_sem(transferResult->notify_sem); 295 } 296 297 298 status_t 299 ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value, 300 uint16 index, uint16 length, void *data, size_t dataLength, 301 usb_callback_func callback, void *callbackCookie) 302 { 303 usb_request_data *requestData = new(std::nothrow) usb_request_data; 304 if (!requestData) 305 return B_NO_MEMORY; 306 307 requestData->RequestType = requestType; 308 requestData->Request = request; 309 requestData->Value = value; 310 requestData->Index = index; 311 requestData->Length = length; 312 313 Transfer *transfer = new(std::nothrow) Transfer(this); 314 if (!transfer) { 315 delete requestData; 316 return B_NO_MEMORY; 317 } 318 319 transfer->SetRequestData(requestData); 320 transfer->SetData((uint8 *)data, dataLength); 321 transfer->SetCallback(callback, callbackCookie); 322 323 status_t result = SubmitTransfer(transfer); 324 if (result < B_OK) 325 delete transfer; 326 return result; 327 } 328