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(Device *device, pipeDirection direction, pipeSpeed speed, 14 uint8 endpointAddress, size_t maxPacketSize) 15 : Object(device->Manager()), 16 fDevice(device), 17 fDeviceAddress(device->Address()), 18 fBus(device->Manager()), 19 fDirection(direction), 20 fSpeed(speed), 21 fEndpoint(endpointAddress), 22 fMaxPacketSize(maxPacketSize), 23 fDataToggle(false) 24 { 25 } 26 27 28 Pipe::Pipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed, 29 size_t maxPacketSize) 30 : Object(bus), 31 fDevice(NULL), 32 fDeviceAddress(deviceAddress), 33 fBus(bus), 34 fDirection(Default), 35 fSpeed(speed), 36 fEndpoint(0), 37 fMaxPacketSize(maxPacketSize), 38 fDataToggle(true) 39 { 40 } 41 42 43 Pipe::~Pipe() 44 { 45 } 46 47 48 int8 49 Pipe::DeviceAddress() 50 { 51 if (!fDevice) 52 return fDeviceAddress; 53 54 return fDevice->Address(); 55 } 56 57 58 status_t 59 Pipe::SubmitTransfer(Transfer *transfer) 60 { 61 // ToDo: keep track of all submited transfers to be able to cancel them 62 return fBus->SubmitTransfer(transfer); 63 } 64 65 66 status_t 67 Pipe::CancelQueuedTransfers() 68 { 69 return B_ERROR; 70 } 71 72 73 status_t 74 Pipe::SetFeature(uint16 selector) 75 { 76 if (!fDevice) 77 return B_ERROR; 78 79 return fDevice->SendRequest( 80 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 81 USB_REQUEST_SET_FEATURE, 82 selector, 83 0, 84 0, 85 NULL, 86 0, 87 NULL); 88 } 89 90 91 status_t 92 Pipe::ClearFeature(uint16 selector) 93 { 94 if (!fDevice) 95 return B_ERROR; 96 97 return fDevice->SendRequest( 98 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 99 USB_REQUEST_CLEAR_FEATURE, 100 selector, 101 0, 102 0, 103 NULL, 104 0, 105 NULL); 106 } 107 108 109 status_t 110 Pipe::GetStatus(uint16 *status) 111 { 112 if (!fDevice) 113 return B_ERROR; 114 115 return fDevice->SendRequest( 116 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN, 117 USB_REQUEST_GET_STATUS, 118 0, 119 0, 120 2, 121 (void *)status, 122 2, 123 NULL); 124 } 125 126 127 // 128 // #pragma mark - 129 // 130 131 132 InterruptPipe::InterruptPipe(Device *device, pipeDirection direction, 133 pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) 134 : Pipe(device, direction, speed, endpointAddress, maxPacketSize) 135 { 136 } 137 138 139 status_t 140 InterruptPipe::QueueInterrupt(void *data, size_t dataLength, 141 usb_callback_func callback, void *callbackCookie) 142 { 143 Transfer *transfer = new(std::nothrow) Transfer(this); 144 if (!transfer) 145 return B_NO_MEMORY; 146 147 transfer->SetData((uint8 *)data, dataLength); 148 transfer->SetCallback(callback, callbackCookie); 149 150 status_t result = SubmitTransfer(transfer); 151 if (result < B_OK) 152 delete transfer; 153 return result; 154 } 155 156 157 // 158 // #pragma mark - 159 // 160 161 162 BulkPipe::BulkPipe(Device *device, pipeDirection direction, 163 pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) 164 : Pipe(device, direction, speed, endpointAddress, maxPacketSize) 165 { 166 } 167 168 169 status_t 170 BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback, 171 void *callbackCookie) 172 { 173 Transfer *transfer = new(std::nothrow) Transfer(this); 174 if (!transfer) 175 return B_NO_MEMORY; 176 177 transfer->SetData((uint8 *)data, dataLength); 178 transfer->SetCallback(callback, callbackCookie); 179 180 status_t result = SubmitTransfer(transfer); 181 if (result < B_OK) 182 delete transfer; 183 return result; 184 } 185 186 187 status_t 188 BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, 189 usb_callback_func callback, void *callbackCookie) 190 { 191 Transfer *transfer = new(std::nothrow) Transfer(this); 192 if (!transfer) 193 return B_NO_MEMORY; 194 195 transfer->SetVector(vector, vectorCount); 196 transfer->SetCallback(callback, callbackCookie); 197 198 status_t result = SubmitTransfer(transfer); 199 if (result < B_OK) 200 delete transfer; 201 return result; 202 } 203 204 205 // 206 // #pragma mark - 207 // 208 209 210 IsochronousPipe::IsochronousPipe(Device *device, pipeDirection direction, 211 pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) 212 : Pipe(device, direction, speed, endpointAddress, maxPacketSize) 213 { 214 } 215 216 217 status_t 218 IsochronousPipe::QueueIsochronous(void *data, size_t dataLength, 219 rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback, 220 void *callbackCookie) 221 { 222 return B_ERROR; 223 } 224 225 226 // 227 // #pragma mark - 228 // 229 230 231 struct transfer_result_data { 232 sem_id notify_sem; 233 uint32 status; 234 size_t actual_length; 235 }; 236 237 238 ControlPipe::ControlPipe(Device *device, pipeSpeed speed, 239 uint8 endpointAddress, size_t maxPacketSize) 240 : Pipe(device, Pipe::Default, speed, endpointAddress, maxPacketSize) 241 { 242 } 243 244 245 ControlPipe::ControlPipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed, 246 size_t maxPacketSize) 247 : Pipe(bus, deviceAddress, speed, maxPacketSize) 248 { 249 } 250 251 252 status_t 253 ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, 254 uint16 index, uint16 length, void *data, size_t dataLength, 255 size_t *actualLength) 256 { 257 transfer_result_data transferResult; 258 transferResult.notify_sem = create_sem(0, "Send Request Notify Sem"); 259 if (transferResult.notify_sem < B_OK) 260 return B_NO_MORE_SEMS; 261 262 status_t result = QueueRequest(requestType, request, value, index, length, 263 data, dataLength, SendRequestCallback, &transferResult); 264 if (result < B_OK) { 265 delete_sem(transferResult.notify_sem); 266 return result; 267 } 268 269 // the sem will be released in the callback after 270 // the result data was filled into the provided struct 271 acquire_sem(transferResult.notify_sem); 272 delete_sem(transferResult.notify_sem); 273 274 if (actualLength) 275 *actualLength = transferResult.actual_length; 276 277 if (transferResult.status == B_USB_STATUS_SUCCESS) 278 return B_OK; 279 280 return B_ERROR; 281 } 282 283 284 void 285 ControlPipe::SendRequestCallback(void *cookie, uint32 status, void *data, 286 size_t actualLength) 287 { 288 transfer_result_data *transferResult = (transfer_result_data *)cookie; 289 transferResult->status = status; 290 transferResult->actual_length = actualLength; 291 release_sem(transferResult->notify_sem); 292 } 293 294 295 status_t 296 ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value, 297 uint16 index, uint16 length, void *data, size_t dataLength, 298 usb_callback_func callback, void *callbackCookie) 299 { 300 usb_request_data *requestData = new(std::nothrow) usb_request_data; 301 if (!requestData) 302 return B_NO_MEMORY; 303 304 requestData->RequestType = requestType; 305 requestData->Request = request; 306 requestData->Value = value; 307 requestData->Index = index; 308 requestData->Length = length; 309 310 Transfer *transfer = new(std::nothrow) Transfer(this); 311 if (!transfer) { 312 delete requestData; 313 return B_NO_MEMORY; 314 } 315 316 transfer->SetRequestData(requestData); 317 transfer->SetData((uint8 *)data, dataLength); 318 transfer->SetCallback(callback, callbackCookie); 319 320 status_t result = SubmitTransfer(transfer); 321 if (result < B_OK) 322 delete transfer; 323 return result; 324 } 325