2 * Copyright 2004-2006, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz <mmlr@mlotz.ch>
10 #include "usb_private.h"
13 Pipe::Pipe(Object
*parent
)
16 fControllerCookie(NULL
)
18 // all other init is to be done in InitCommon()
24 CancelQueuedTransfers(true);
25 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED
);
30 Pipe::InitCommon(int8 deviceAddress
, uint8 endpointAddress
, usb_speed speed
,
31 pipeDirection direction
, size_t maxPacketSize
, uint8 interval
,
32 int8 hubAddress
, uint8 hubPort
)
34 fDeviceAddress
= deviceAddress
;
35 fEndpointAddress
= endpointAddress
;
37 fDirection
= direction
;
38 fMaxPacketSize
= maxPacketSize
;
40 fHubAddress
= hubAddress
;
43 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_CREATED
);
48 Pipe::SetHubInfo(int8 address
, uint8 port
)
50 fHubAddress
= address
;
56 Pipe::SubmitTransfer(Transfer
*transfer
)
58 // ToDo: keep track of all submited transfers to be able to cancel them
59 return GetBusManager()->SubmitTransfer(transfer
);
64 Pipe::CancelQueuedTransfers(bool force
)
66 return GetBusManager()->CancelQueuedTransfers(this, force
);
71 Pipe::SetFeature(uint16 selector
)
73 TRACE("set feature %u\n", selector
);
74 return ((Device
*)Parent())->DefaultPipe()->SendRequest(
75 USB_REQTYPE_STANDARD
| USB_REQTYPE_ENDPOINT_OUT
,
76 USB_REQUEST_SET_FEATURE
,
78 fEndpointAddress
| (fDirection
== In
? USB_ENDPOINT_ADDR_DIR_IN
79 : USB_ENDPOINT_ADDR_DIR_OUT
),
88 Pipe::ClearFeature(uint16 selector
)
90 // clearing a stalled condition resets the data toggle
91 if (selector
== USB_FEATURE_ENDPOINT_HALT
)
94 TRACE("clear feature %u\n", selector
);
95 return ((Device
*)Parent())->DefaultPipe()->SendRequest(
96 USB_REQTYPE_STANDARD
| USB_REQTYPE_ENDPOINT_OUT
,
97 USB_REQUEST_CLEAR_FEATURE
,
99 fEndpointAddress
| (fDirection
== In
? USB_ENDPOINT_ADDR_DIR_IN
100 : USB_ENDPOINT_ADDR_DIR_OUT
),
109 Pipe::GetStatus(uint16
*status
)
111 TRACE("get status\n");
112 return ((Device
*)Parent())->DefaultPipe()->SendRequest(
113 USB_REQTYPE_STANDARD
| USB_REQTYPE_ENDPOINT_IN
,
114 USB_REQUEST_GET_STATUS
,
116 fEndpointAddress
| (fDirection
== In
? USB_ENDPOINT_ADDR_DIR_IN
117 : USB_ENDPOINT_ADDR_DIR_OUT
),
130 InterruptPipe::InterruptPipe(Object
*parent
)
137 InterruptPipe::QueueInterrupt(void *data
, size_t dataLength
,
138 usb_callback_func callback
, void *callbackCookie
)
140 if (dataLength
> 0 && data
== NULL
)
143 Transfer
*transfer
= new(std::nothrow
) Transfer(this);
147 transfer
->SetData((uint8
*)data
, dataLength
);
148 transfer
->SetCallback(callback
, callbackCookie
);
150 status_t result
= GetBusManager()->SubmitTransfer(transfer
);
162 BulkPipe::BulkPipe(Object
*parent
)
169 BulkPipe::InitCommon(int8 deviceAddress
, uint8 endpointAddress
,
170 usb_speed speed
, pipeDirection direction
, size_t maxPacketSize
,
171 uint8 interval
, int8 hubAddress
, uint8 hubPort
)
173 // some devices have bogus descriptors
174 if (speed
== USB_SPEED_HIGHSPEED
&& maxPacketSize
!= 512)
177 Pipe::InitCommon(deviceAddress
, endpointAddress
, speed
, direction
,
178 maxPacketSize
, interval
, hubAddress
, hubPort
);
183 BulkPipe::QueueBulk(void *data
, size_t dataLength
, usb_callback_func callback
,
184 void *callbackCookie
)
186 if (dataLength
> 0 && data
== NULL
)
189 Transfer
*transfer
= new(std::nothrow
) Transfer(this);
193 transfer
->SetData((uint8
*)data
, dataLength
);
194 transfer
->SetCallback(callback
, callbackCookie
);
196 status_t result
= GetBusManager()->SubmitTransfer(transfer
);
204 BulkPipe::QueueBulkV(iovec
*vector
, size_t vectorCount
,
205 usb_callback_func callback
, void *callbackCookie
, bool physical
)
207 if (vectorCount
> 0 && vector
== NULL
)
210 Transfer
*transfer
= new(std::nothrow
) Transfer(this);
214 transfer
->SetPhysical(physical
);
215 transfer
->SetVector(vector
, vectorCount
);
216 transfer
->SetCallback(callback
, callbackCookie
);
218 status_t result
= GetBusManager()->SubmitTransfer(transfer
);
230 IsochronousPipe::IsochronousPipe(Object
*parent
)
232 fMaxQueuedPackets(0),
233 fMaxBufferDuration(0),
240 IsochronousPipe::QueueIsochronous(void *data
, size_t dataLength
,
241 usb_iso_packet_descriptor
*packetDesc
, uint32 packetCount
,
242 uint32
*startingFrameNumber
, uint32 flags
, usb_callback_func callback
,
243 void *callbackCookie
)
245 if ((dataLength
> 0 && data
== NULL
)
246 || (packetCount
> 0 && packetDesc
== NULL
))
249 usb_isochronous_data
*isochronousData
250 = new(std::nothrow
) usb_isochronous_data
;
252 if (!isochronousData
)
255 isochronousData
->packet_descriptors
= packetDesc
;
256 isochronousData
->packet_count
= packetCount
;
257 isochronousData
->starting_frame_number
= startingFrameNumber
;
258 isochronousData
->flags
= flags
;
260 Transfer
*transfer
= new(std::nothrow
) Transfer(this);
262 delete isochronousData
;
266 transfer
->SetData((uint8
*)data
, dataLength
);
267 transfer
->SetCallback(callback
, callbackCookie
);
268 transfer
->SetIsochronousData(isochronousData
);
270 status_t result
= GetBusManager()->SubmitTransfer(transfer
);
278 IsochronousPipe::SetPipePolicy(uint8 maxQueuedPackets
,
279 uint16 maxBufferDurationMS
, uint16 sampleSize
)
281 if (maxQueuedPackets
== fMaxQueuedPackets
282 || maxBufferDurationMS
== fMaxBufferDuration
283 || sampleSize
== fSampleSize
)
286 fMaxQueuedPackets
= maxQueuedPackets
;
287 fMaxBufferDuration
= maxBufferDurationMS
;
288 fSampleSize
= sampleSize
;
290 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_PIPE_POLICY_CHANGED
);
296 IsochronousPipe::GetPipePolicy(uint8
*maxQueuedPackets
,
297 uint16
*maxBufferDurationMS
, uint16
*sampleSize
)
299 if (maxQueuedPackets
)
300 *maxQueuedPackets
= fMaxQueuedPackets
;
301 if (maxBufferDurationMS
)
302 *maxBufferDurationMS
= fMaxBufferDuration
;
304 *sampleSize
= fSampleSize
;
314 ControlPipe::ControlPipe(Object
*parent
)
318 mutex_init(&fSendRequestLock
, "control pipe send request");
322 ControlPipe::~ControlPipe()
325 delete_sem(fNotifySem
);
326 mutex_lock(&fSendRequestLock
);
327 mutex_destroy(&fSendRequestLock
);
332 ControlPipe::SendRequest(uint8 requestType
, uint8 request
, uint16 value
,
333 uint16 index
, uint16 length
, void *data
, size_t dataLength
,
334 size_t *actualLength
)
336 status_t result
= mutex_lock(&fSendRequestLock
);
340 if (fNotifySem
< 0) {
341 fNotifySem
= create_sem(0, "usb send request notify");
342 if (fNotifySem
< 0) {
343 mutex_unlock(&fSendRequestLock
);
344 return B_NO_MORE_SEMS
;
348 result
= QueueRequest(requestType
, request
, value
, index
, length
, data
,
349 dataLength
, SendRequestCallback
, this);
351 mutex_unlock(&fSendRequestLock
);
355 // The sem will be released unconditionally in the callback after the
356 // result data was filled in. Use a 2 seconds timeout for control transfers.
357 if (acquire_sem_etc(fNotifySem
, 1, B_RELATIVE_TIMEOUT
, 2000000) < B_OK
) {
358 TRACE_ERROR("timeout waiting for queued request to complete\n");
360 CancelQueuedTransfers(false);
362 // After the above cancel returns it is guaranteed that the callback
363 // has been invoked. Therefore we can simply grab that released
364 // semaphore again to clean up.
365 acquire_sem_etc(fNotifySem
, 1, B_RELATIVE_TIMEOUT
, 0);
370 mutex_unlock(&fSendRequestLock
);
375 *actualLength
= fActualLength
;
377 mutex_unlock(&fSendRequestLock
);
378 return fTransferStatus
;
383 ControlPipe::SendRequestCallback(void *cookie
, status_t status
, void *data
,
386 ControlPipe
*pipe
= (ControlPipe
*)cookie
;
387 pipe
->fTransferStatus
= status
;
388 pipe
->fActualLength
= actualLength
;
389 release_sem(pipe
->fNotifySem
);
394 ControlPipe::QueueRequest(uint8 requestType
, uint8 request
, uint16 value
,
395 uint16 index
, uint16 length
, void *data
, size_t dataLength
,
396 usb_callback_func callback
, void *callbackCookie
)
398 if (dataLength
> 0 && data
== NULL
)
401 usb_request_data
*requestData
= new(std::nothrow
) usb_request_data
;
405 requestData
->RequestType
= requestType
;
406 requestData
->Request
= request
;
407 requestData
->Value
= value
;
408 requestData
->Index
= index
;
409 requestData
->Length
= length
;
411 Transfer
*transfer
= new(std::nothrow
) Transfer(this);
417 transfer
->SetRequestData(requestData
);
418 transfer
->SetData((uint8
*)data
, dataLength
);
419 transfer
->SetCallback(callback
, callbackCookie
);
421 status_t result
= GetBusManager()->SubmitTransfer(transfer
);