3 * Copyright 2006 Free Software Foundation, Inc.
5 * This file is part of GNU Radio.
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
27 // tell mld_threads to NOT use omni_threads,
28 // but rather Darwin's pthreads
29 #undef _USE_OMNI_THREADS_
33 #include "fusb_darwin.h"
34 #include "darwin_libusb.h"
36 static const int USB_TIMEOUT = 100; // in milliseconds
37 static const UInt8 NUM_QUEUE_ITEMS = 20;
39 fusb_devhandle_darwin::fusb_devhandle_darwin (usb_dev_handle* udh)
40 : fusb_devhandle (udh)
45 fusb_devhandle_darwin::~fusb_devhandle_darwin ()
51 fusb_devhandle_darwin::make_ephandle (int endpoint, bool input_p,
52 int block_size, int nblocks)
54 return new fusb_ephandle_darwin (this, endpoint, input_p,
58 // ----------------------------------------------------------------
60 fusb_ephandle_darwin::fusb_ephandle_darwin (fusb_devhandle_darwin* dh,
61 int endpoint, bool input_p,
62 int block_size, int nblocks)
63 : fusb_ephandle (endpoint, input_p, block_size, nblocks),
64 d_devhandle (dh), d_pipeRef (0), d_transferType (0),
65 d_interfaceRef (0), d_interface (0), d_queue (0),
66 d_buffer (0), d_bufLenBytes (0)
68 d_bufLenBytes = fusb_sysconfig::max_block_size();
70 // create circular buffer
71 d_buffer = new circular_buffer<char> (NUM_QUEUE_ITEMS * d_bufLenBytes,
72 !d_input_p, d_input_p);
75 d_queue = new circular_linked_list <s_buffer_ptr> (NUM_QUEUE_ITEMS);
76 d_queue->iterate_start ();
77 s_node_ptr l_node = d_queue->iterate_next ();
79 l_node->both (new s_both<s_buffer_ptr> (l_node, this));
80 s_buffer_ptr l_buf = new s_buffer (d_bufLenBytes);
81 l_node->object (l_buf);
82 l_node = d_queue->iterate_next ();
86 d_readRunning = new mld_mutex ();
87 d_runThreadRunning = new mld_mutex ();
88 d_runBlock = new mld_condition ();
89 d_readBlock = new mld_condition ();
92 fusb_ephandle_darwin::~fusb_ephandle_darwin ()
96 d_queue->iterate_start ();
97 s_node_ptr l_node = d_queue->iterate_next ();
99 s_both_ptr l_both = l_node->both ();
103 s_buffer_ptr l_buf = l_node->object ();
106 l_node->object (NULL);
107 l_node = d_queue->iterate_next ();
113 delete d_readRunning;
114 d_readRunning = NULL;
115 delete d_runThreadRunning;
116 d_runThreadRunning = NULL;
124 fusb_ephandle_darwin::start ()
126 UInt8 direction, number, interval;
127 UInt16 maxPacketSize;
129 // reset circular buffer
133 d_queue->num_used (0);
134 d_queue->iterate_start ();
135 s_node_ptr l_node = d_queue->iterate_next ();
137 l_node->both()->set (l_node, this);
138 l_node->object()->reset ();
139 l_node->set_available ();
140 l_node = d_queue->iterate_next ();
143 d_pipeRef = d_transferType = 0;
145 usb_dev_handle* dev = d_devhandle->get_usb_dev_handle ();
147 USB_ERROR_STR (false, -ENXIO, "fusb_ephandle_darwin::start: "
150 darwin_dev_handle* device = (darwin_dev_handle*) dev->impl_info;
152 USB_ERROR_STR (false, -ENOENT, "fusb_ephandle_darwin::start: "
153 "device not initialized");
156 fprintf (stderr, "fusb_ephandle_darwin::start: "
157 "dev = %p, device = %p\n", dev, device);
159 d_interfaceRef = device->interface;
160 if (! d_interfaceRef)
161 USB_ERROR_STR (false, -EACCES, "fusb_ephandle_darwin::start: "
162 "interface used without being claimed");
163 d_interface = *d_interfaceRef;
165 // get read or write pipe info (depends on "d_input_p")
168 fprintf (stderr, "fusb_ephandle_darwin::start "
169 "d_endpoint = %d, d_input_p = %s\n",
170 d_endpoint, d_input_p ? "TRUE" : "FALSE");
172 int l_endpoint = (d_input_p ? USB_ENDPOINT_IN : USB_ENDPOINT_OUT);
173 int pipeRef = ep_to_pipeRef (device, d_endpoint | l_endpoint);
175 USB_ERROR_STR (false, -EINVAL, "fusb_ephandle_darwin::start "
176 " invalid pipeRef.\n");
179 d_interface->GetPipeProperties (d_interfaceRef,
187 fprintf (stderr, "fusb_ephandle_darwin::start: %s: ep = 0x%02x, "
188 "pipeRef = %d, d_i = %p, d_iR = %p, if_dir = %d, if_# = %d, "
189 "if_int = %d, if_maxPS = %d\n", d_input_p ? "read" : "write",
190 d_endpoint, d_pipeRef, d_interface, d_interfaceRef, direction,
191 number, interval, maxPacketSize);
193 // set global start boolean
196 // create the run thread, which allows OSX to process I/O separately
197 d_runThread = new mld_thread (run_thread, this);
199 // wait until the threads are -really- going
203 fprintf (stderr, "fusb_ephandle_darwin::start: %s started.\n",
204 d_input_p ? "read" : "write");
210 fusb_ephandle_darwin::run_thread (void* arg)
212 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
213 mld_mutex_ptr l_runThreadRunning = This->d_runThreadRunning;
214 l_runThreadRunning->lock ();
216 mld_mutex_ptr l_readRunning = This->d_readRunning;
217 mld_condition_ptr l_readBlock = This->d_readBlock;
219 bool l_input_p = This->d_input_p;
222 fprintf (stderr, "fusb_ephandle_darwin::run_thread: "
223 "starting for %s.\n",
224 l_input_p ? "read" : "write");
226 usb_interface_t** l_interfaceRef = This->d_interfaceRef;
227 usb_interface_t* l_interface = This->d_interface;
228 CFRunLoopSourceRef l_cfSource;
230 // create async run loop
231 l_interface->CreateInterfaceAsyncEventSource (l_interfaceRef, &l_cfSource);
232 CFRunLoopAddSource (CFRunLoopGetCurrent (), l_cfSource,
233 kCFRunLoopDefaultMode);
234 // get run loop reference, to allow other threads to stop
235 This->d_CFRunLoopRef = CFRunLoopGetCurrent ();
237 mld_thread_ptr l_rwThread = NULL;
240 l_rwThread = new mld_thread (read_thread, arg);
241 // wait until the the rwThread is -really- going
242 l_readBlock->wait ();
245 // now signal the run condition to release and finish ::start()
246 This->d_runBlock->signal ();
252 // wait for read_thread () to finish
253 l_readRunning->lock ();
254 l_readRunning->unlock ();
257 // remove run loop stuff
258 CFRunLoopRemoveSource (CFRunLoopGetCurrent (),
259 l_cfSource, kCFRunLoopDefaultMode);
262 fprintf (stderr, "fusb_ephandle_darwin::run_thread: finished for %s.\n",
263 l_input_p ? "read" : "write");
265 l_runThreadRunning->unlock ();
269 fusb_ephandle_darwin::read_thread (void* arg)
272 fprintf (stderr, "fusb_ephandle_darwin::read_thread: starting.\n");
274 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
276 mld_mutex_ptr l_readRunning = This->d_readRunning;
277 l_readRunning->lock ();
279 // signal the read condition from run_thread() to continue
280 mld_condition_ptr l_readBlock = This->d_readBlock;
281 l_readBlock->signal ();
283 s_queue_ptr l_queue = This->d_queue;
284 l_queue->iterate_start ();
285 s_node_ptr l_node = l_queue->iterate_next ();
287 This->read_issue (l_node->both ());
288 l_node = l_queue->iterate_next ();
292 fprintf (stderr, "fusb_ephandle_darwin::read_thread: finished.\n");
294 l_readRunning->unlock ();
298 fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
300 if ((! l_both) || (! d_started))
303 // set the node and buffer from the input "both"
304 s_node_ptr l_node = l_both->node ();
305 s_buffer_ptr l_buf = l_node->object ();
306 void* v_buffer = (void*) l_buf->buffer ();
308 // read up to d_bufLenBytes
309 UInt32 bufLen = d_bufLenBytes;
310 l_buf->n_used (bufLen);
312 // setup system call result
313 io_return_t result = kIOReturnSuccess;
315 if (d_transferType == kUSBInterrupt)
316 /* This is an interrupt pipe. We can't specify a timeout. */
317 result = d_interface->ReadPipeAsync
318 (d_interfaceRef, d_pipeRef, v_buffer, bufLen,
319 (IOAsyncCallback1) read_completed, (void*) l_both);
321 result = d_interface->ReadPipeAsyncTO
322 (d_interfaceRef, d_pipeRef, v_buffer, bufLen, 0, USB_TIMEOUT,
323 (IOAsyncCallback1) read_completed, (void*) l_both);
325 if (result != kIOReturnSuccess)
326 USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
327 "fusb_ephandle_darwin::read_issue "
328 "(ReadPipeAsync%s): %s",
329 d_transferType == kUSBInterrupt ? "" : "TO",
330 darwin_error_str (result));
334 fusb_ephandle_darwin::read_completed (void* refCon,
338 UInt32 l_size = (UInt32) io_size;
339 s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
340 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
341 s_node_ptr l_node = l_both->node ();
342 circular_buffer<char>* l_buffer = This->d_buffer;
343 s_buffer_ptr l_buf = l_node->object ();
344 UInt32 l_i_size = l_buf->n_used ();
346 if (This->d_started && (l_i_size != l_size))
347 fprintf (stderr, "fusb_ephandle_darwin::read_completed: "
348 "Expected %ld bytes; read %ld.\n",
351 // add this read to the transfer buffer
352 if (l_buffer->enqueue (l_buf->buffer (), l_size) == -1) {
353 fputs ("iU", stderr);
357 // set buffer's # data to 0
360 // issue another read for this "both"
361 This->read_issue (l_both);
365 fusb_ephandle_darwin::read (void* buffer, int nbytes)
367 UInt32 l_nbytes = (UInt32) nbytes;
368 d_buffer->dequeue ((char*) buffer, &l_nbytes);
369 return ((int) l_nbytes);
373 fusb_ephandle_darwin::write (const void* buffer, int nbytes)
375 UInt32 l_nbytes = (UInt32) nbytes;
377 if (! d_started) return (0);
379 while (l_nbytes != 0) {
380 // find out how much data to copy; limited to "d_bufLenBytes" per node
381 UInt32 t_nbytes = (l_nbytes > d_bufLenBytes) ? d_bufLenBytes : l_nbytes;
383 // get next available node to write into;
384 // blocks internally if none available
385 s_node_ptr l_node = d_queue->find_next_available_node ();
387 // copy the input into the node's buffer
388 s_buffer_ptr l_buf = l_node->object ();
389 l_buf->buffer ((char*) buffer, t_nbytes);
390 void* v_buffer = (void*) l_buf->buffer ();
392 // setup callback parameter & system call return
393 s_both_ptr l_both = l_node->both ();
394 io_return_t result = kIOReturnSuccess;
396 if (d_transferType == kUSBInterrupt)
397 /* This is an interrupt pipe ... can't specify a timeout. */
398 result = d_interface->WritePipeAsync
399 (d_interfaceRef, d_pipeRef, v_buffer, l_nbytes,
400 (IOAsyncCallback1) write_completed, (void*) l_both);
402 result = d_interface->WritePipeAsyncTO
403 (d_interfaceRef, d_pipeRef, v_buffer, l_nbytes, 0, USB_TIMEOUT,
404 (IOAsyncCallback1) write_completed, (void*) l_both);
406 if (result != kIOReturnSuccess)
407 USB_ERROR_STR (-1, - darwin_to_errno (result),
408 "fusb_ephandle_darwin::write_thread "
409 "(WritePipeAsync%s): %s",
410 d_transferType == kUSBInterrupt ? "" : "TO",
411 darwin_error_str (result));
412 l_nbytes -= t_nbytes;
419 fusb_ephandle_darwin::write_completed (void* refCon,
423 s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
424 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
425 UInt32 l_size = (UInt32) io_size;
426 s_node_ptr l_node = l_both->node ();
427 s_queue_ptr l_queue = This->d_queue;
428 s_buffer_ptr l_buf = l_node->object ();
429 UInt32 l_i_size = l_buf->n_used ();
431 if (This->d_started && (l_i_size != l_size))
432 fprintf (stderr, "fusb_ephandle_darwin::write_completed: "
433 "Expected %ld bytes written; wrote %ld.\n",
436 // set buffer's # data to 0
438 // make the node available for reuse
439 l_queue->make_node_available (l_node);
443 fusb_ephandle_darwin::abort ()
446 fprintf (stderr, "fusb_ephandle_darwin::abort: starting.\n");
448 io_return_t result = d_interface->AbortPipe (d_interfaceRef, d_pipeRef);
450 if (result != kIOReturnSuccess)
451 USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
452 "fusb_ephandle_darwin::abort "
453 "(AbortPipe): %s", darwin_error_str (result));
455 fprintf (stderr, "fusb_ephandle_darwin::abort: finished.\n");
459 fusb_ephandle_darwin::stop ()
465 fprintf (stderr, "fusb_ephandle_darwin::stop: stopping %s.\n",
466 d_input_p ? "read" : "write");
470 // abort any pending IO transfers
473 // wait for write transfer to finish
474 wait_for_completion ();
476 // tell IO buffer to abort any waiting conditions
480 CFRunLoopStop (d_CFRunLoopRef);
482 // wait for the runThread to stop
483 d_runThreadRunning->lock ();
484 d_runThreadRunning->unlock ();
487 fprintf (stderr, "fusb_ephandle_darwin::stop: %s stopped.\n",
488 d_input_p ? "read" : "write");
494 fusb_ephandle_darwin::wait_for_completion ()
497 while (d_queue->in_use ())