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