xref: /haiku/src/add-ons/kernel/bus_managers/usb/Pipe.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
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