3 * Copyright 2006,2009 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 3, 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 #define _USE_OMNI_THREADS_
34 #include "fusb_darwin.h"
35 #include "darwin_libusb.h"
38 static const int USB_TIMEOUT = 100; // in milliseconds
39 static const UInt8 NUM_QUEUE_ITEMS = 20;
41 fusb_devhandle_darwin::fusb_devhandle_darwin (usb_dev_handle* udh)
42 : fusb_devhandle (udh)
47 fusb_devhandle_darwin::~fusb_devhandle_darwin ()
53 fusb_devhandle_darwin::make_ephandle (int endpoint, bool input_p,
54 int block_size, int nblocks)
56 return new fusb_ephandle_darwin (this, endpoint, input_p,
60 // ----------------------------------------------------------------
62 fusb_ephandle_darwin::fusb_ephandle_darwin (fusb_devhandle_darwin* dh,
63 int endpoint, bool input_p,
64 int block_size, int nblocks)
65 : fusb_ephandle (endpoint, input_p, block_size, nblocks),
66 d_devhandle (dh), d_pipeRef (0), d_transferType (0),
67 d_interfaceRef (0), d_interface (0), d_queue (0),
68 d_buffer (0), d_bufLenBytes (0)
70 d_bufLenBytes = fusb_sysconfig::max_block_size();
72 // create circular buffer
73 d_buffer = new circular_buffer<char> (NUM_QUEUE_ITEMS * d_bufLenBytes,
74 !d_input_p, d_input_p);
77 d_queue = new circular_linked_list <s_buffer_ptr> (NUM_QUEUE_ITEMS);
78 d_queue->iterate_start ();
79 s_node_ptr l_node = d_queue->iterate_next ();
81 l_node->both (new s_both<s_buffer_ptr> (l_node, this));
82 s_buffer_ptr l_buf = new s_buffer (d_bufLenBytes);
83 l_node->object (l_buf);
84 l_node = d_queue->iterate_next ();
88 d_readRunning = new mld_mutex ();
89 d_runThreadRunning = new mld_mutex ();
90 d_runBlock = new mld_condition ();
91 d_readBlock = new mld_condition ();
94 fusb_ephandle_darwin::~fusb_ephandle_darwin ()
98 d_queue->iterate_start ();
99 s_node_ptr l_node = d_queue->iterate_next ();
101 s_both_ptr l_both = l_node->both ();
105 s_buffer_ptr l_buf = l_node->object ();
108 l_node->object (NULL);
109 l_node = d_queue->iterate_next ();
115 delete d_readRunning;
116 d_readRunning = NULL;
117 delete d_runThreadRunning;
118 d_runThreadRunning = NULL;
126 fusb_ephandle_darwin::start ()
128 UInt8 direction, number, interval;
129 UInt16 maxPacketSize;
131 // reset circular buffer
135 d_queue->num_used (0);
136 d_queue->iterate_start ();
137 s_node_ptr l_node = d_queue->iterate_next ();
139 l_node->both()->set (l_node, this);
140 l_node->object()->reset ();
141 l_node->set_available ();
142 l_node = d_queue->iterate_next ();
145 d_pipeRef = d_transferType = 0;
147 usb_dev_handle* dev = d_devhandle->get_usb_dev_handle ();
149 USB_ERROR_STR (false, -ENXIO, "fusb_ephandle_darwin::start: "
152 darwin_dev_handle* device = (darwin_dev_handle*) dev->impl_info;
154 USB_ERROR_STR (false, -ENOENT, "fusb_ephandle_darwin::start: "
155 "device not initialized");
158 std::cerr << "fusb_ephandle_darwin::start: dev = " <<
159 (void*) dev << ", device = " << (void*) device << std::endl;
162 d_interfaceRef = device->interface;
163 if (! d_interfaceRef)
164 USB_ERROR_STR (false, -EACCES, "fusb_ephandle_darwin::start: "
165 "interface used without being claimed");
166 d_interface = *d_interfaceRef;
168 // get read or write pipe info (depends on "d_input_p")
171 std::cerr << "fusb_ephandle_darwin::start d_endpoint = " << d_endpoint
172 << ", d_input_p = " << (d_input_p ? "TRUE" : "FALSE") << std::endl;
175 int l_endpoint = (d_input_p ? USB_ENDPOINT_IN : USB_ENDPOINT_OUT);
176 int pipeRef = ep_to_pipeRef (device, d_endpoint | l_endpoint);
178 USB_ERROR_STR (false, -EINVAL, "fusb_ephandle_darwin::start "
179 " invalid pipeRef.\n");
182 d_interface->GetPipeProperties (d_interfaceRef,
189 if (usb_debug == 3) {
190 std::cerr << "fusb_ephandle_darwin::start: " << (d_input_p ? "read" : "write")
191 << ": ep = " << d_endpoint << ", pipeRef = " << d_pipeRef << "interface = "
192 << d_interface << ", interfaceRef = " << d_interfaceRef
193 << ", if_direction = " << direction << ", if_# = " << number
194 << ", if_interval = " << interval << ", if_maxPacketSize = "
195 << maxPacketSize << std::endl;
198 // set global start boolean
201 // lock the runBlock mutex, before creating the run thread.
202 // this guarantees that we can control execution between these 2 threads
203 d_runBlock->mutex ()->lock ();
205 // create the run thread, which allows OSX to process I/O separately
206 d_runThread = new mld_thread (run_thread, this);
208 // wait until the run thread (and possibky read thread) are -really-
209 // going; this will unlock the mutex before waiting for a signal ()
213 std::cerr << "fusb_ephandle_darwin::start: " << (d_input_p ? "read" : "write")
214 << " started." << std::endl;
221 fusb_ephandle_darwin::run_thread (void* arg)
223 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
225 // lock the run thread running mutex; if ::stop() is called, it will
226 // first abort() the pipe then wait for the run thread to finish,
227 // via a lock() on this mutex
228 mld_mutex_ptr l_runThreadRunning = This->d_runThreadRunning;
229 l_runThreadRunning->lock ();
231 mld_mutex_ptr l_readRunning = This->d_readRunning;
232 mld_condition_ptr l_readBlock = This->d_readBlock;
233 mld_mutex_ptr l_readBlock_mutex = l_readBlock->mutex ();
235 bool l_input_p = This->d_input_p;
238 std::cerr << "fusb_ephandle_darwin::run_thread: starting for "
239 << (l_input_p ? "read" : "write") << "." << std::endl;
242 usb_interface_t** l_interfaceRef = This->d_interfaceRef;
243 usb_interface_t* l_interface = This->d_interface;
244 CFRunLoopSourceRef l_cfSource;
246 // create async run loop
247 l_interface->CreateInterfaceAsyncEventSource (l_interfaceRef, &l_cfSource);
248 CFRunLoopAddSource (CFRunLoopGetCurrent (), l_cfSource,
249 kCFRunLoopDefaultMode);
250 // get run loop reference, to allow other threads to stop
251 This->d_CFRunLoopRef = CFRunLoopGetCurrent ();
253 mld_thread_ptr l_rwThread = NULL;
256 // lock the readBlock mutex, before creating the read thread.
257 // this guarantees that we can control execution between these 2 threads
258 l_readBlock_mutex->lock ();
259 // create the read thread, which just issues all of the starting
260 // async read commands, then returns
261 l_rwThread = new mld_thread (read_thread, arg);
262 // wait until the the read thread is -really- going; this will
263 // unlock the read block mutex before waiting for a signal ()
264 l_readBlock->wait ();
267 // now signal the run condition to release and finish ::start().
269 // lock the runBlock mutex first; this will force waiting until the
270 // ->wait() command is issued in ::start()
271 mld_mutex_ptr l_run_block_mutex = This->d_runBlock->mutex ();
272 l_run_block_mutex->lock ();
274 // now that the lock is in place, signal the parent thread that
275 // things are running
276 This->d_runBlock->signal ();
278 // release the run_block mutex, just in case
279 l_run_block_mutex->unlock ();
285 // wait for read_thread () to finish, if needed
286 l_readRunning->lock ();
287 l_readRunning->unlock ();
290 // remove run loop stuff
291 CFRunLoopRemoveSource (CFRunLoopGetCurrent (),
292 l_cfSource, kCFRunLoopDefaultMode);
295 std::cerr << "fusb_ephandle_darwin::run_thread: finished for "
296 << (l_input_p ? "read" : "write") << "." << std::endl;
299 // release the run thread running mutex
300 l_runThreadRunning->unlock ();
304 fusb_ephandle_darwin::read_thread (void* arg)
307 std::cerr << "fusb_ephandle_darwin::read_thread: starting." << std::endl;
310 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
312 // before doing anything else, lock the read running mutex. this
313 // mutex does flow control between this thread and the run_thread
314 mld_mutex_ptr l_readRunning = This->d_readRunning;
315 l_readRunning->lock ();
317 // signal the read condition from run_thread() to continue
319 // lock the readBlock mutex first; this will force waiting until the
320 // ->wait() command is issued in ::run_thread()
321 mld_condition_ptr l_readBlock = This->d_readBlock;
322 mld_mutex_ptr l_read_block_mutex = l_readBlock->mutex ();
323 l_read_block_mutex->lock ();
325 // now that the lock is in place, signal the parent thread that
326 // things are running here
327 l_readBlock->signal ();
329 // release the run_block mutex, just in case
330 l_read_block_mutex->unlock ();
332 // queue up all of the available read requests
333 s_queue_ptr l_queue = This->d_queue;
334 l_queue->iterate_start ();
335 s_node_ptr l_node = l_queue->iterate_next ();
337 This->read_issue (l_node->both ());
338 l_node = l_queue->iterate_next ();
342 std::cerr << "fusb_ephandle_darwin::read_thread: finished." << std::endl;
345 // release the read running mutex, to let the parent thread knows
346 // that this thread is finished
347 l_readRunning->unlock ();
351 fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
353 if ((! l_both) || (! d_started)) {
355 std::cerr << "fusb_ephandle_darwin::read_issue: Doing nothing; "
356 << "l_both is " << (void*) l_both << "; started is "
357 << (d_started ? "TRUE" : "FALSE") << std::endl;
362 // set the node and buffer from the input "both"
363 s_node_ptr l_node = l_both->node ();
364 s_buffer_ptr l_buf = l_node->object ();
365 void* v_buffer = (void*) l_buf->buffer ();
367 // read up to d_bufLenBytes
368 size_t bufLen = d_bufLenBytes;
369 l_buf->n_used (bufLen);
371 // setup system call result
372 io_return_t result = kIOReturnSuccess;
374 if (d_transferType == kUSBInterrupt)
375 /* This is an interrupt pipe. We can't specify a timeout. */
376 result = d_interface->ReadPipeAsync
377 (d_interfaceRef, d_pipeRef, v_buffer, bufLen,
378 (IOAsyncCallback1) read_completed, (void*) l_both);
380 result = d_interface->ReadPipeAsyncTO
381 (d_interfaceRef, d_pipeRef, v_buffer, bufLen, 0, USB_TIMEOUT,
382 (IOAsyncCallback1) read_completed, (void*) l_both);
384 if (result != kIOReturnSuccess)
385 USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
386 "fusb_ephandle_darwin::read_issue "
387 "(ReadPipeAsync%s): %s",
388 d_transferType == kUSBInterrupt ? "" : "TO",
389 darwin_error_str (result));
390 else if (usb_debug > 4) {
391 std::cerr << "fusb_ephandle_darwin::read_issue: Queued " << (void*) l_both
392 << " (" << bufLen << " Bytes)" << std::endl;
397 fusb_ephandle_darwin::read_completed (void* refCon,
401 size_t l_size = (size_t) io_size;
402 s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
403 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
404 s_node_ptr l_node = l_both->node ();
405 circular_buffer<char>* l_buffer = This->d_buffer;
406 s_buffer_ptr l_buf = l_node->object ();
407 size_t l_i_size = l_buf->n_used ();
409 if (This->d_started && (l_i_size != l_size)) {
410 std::cerr << "fusb_ephandle_darwin::read_completed: Expected " << l_i_size
411 << " bytes; read " << l_size << "." << std::endl;
412 } else if (usb_debug > 4) {
413 std::cerr << "fusb_ephandle_darwin::read_completed: Read " << (void*) l_both
414 << " (" << l_size << " bytes)" << std::endl;
417 // add this read to the transfer buffer, and check for overflow
418 // -> data is being enqueued faster than it can be dequeued
419 if (l_buffer->enqueue (l_buf->buffer (), l_size) == -1) {
420 // print out that there's an overflow
421 fputs ("uO", stderr);
425 // set buffer's # data to 0
428 // issue another read for this "both"
429 This->read_issue (l_both);
433 fusb_ephandle_darwin::read (void* buffer, int nbytes)
435 size_t l_nbytes = (size_t) nbytes;
436 d_buffer->dequeue ((char*) buffer, &l_nbytes);
439 std::cerr << "fusb_ephandle_darwin::read: request for " << nbytes
440 << " bytes, " << l_nbytes << " bytes retrieved." << std::endl;
443 return ((int) l_nbytes);
447 fusb_ephandle_darwin::write (const void* buffer, int nbytes)
449 size_t l_nbytes = (size_t) nbytes;
453 std::cerr << "fusb_ephandle_darwin::write: Not yet started." << std::endl;
458 while (l_nbytes != 0) {
459 // find out how much data to copy; limited to "d_bufLenBytes" per node
460 size_t t_nbytes = (l_nbytes > d_bufLenBytes) ? d_bufLenBytes : l_nbytes;
462 // get next available node to write into;
463 // blocks internally if none available
464 s_node_ptr l_node = d_queue->find_next_available_node ();
466 // copy the input into the node's buffer
467 s_buffer_ptr l_buf = l_node->object ();
468 l_buf->buffer ((char*) buffer, t_nbytes);
469 void* v_buffer = (void*) l_buf->buffer ();
471 // setup callback parameter & system call return
472 s_both_ptr l_both = l_node->both ();
473 io_return_t result = kIOReturnSuccess;
475 if (d_transferType == kUSBInterrupt)
476 /* This is an interrupt pipe ... can't specify a timeout. */
477 result = d_interface->WritePipeAsync
478 (d_interfaceRef, d_pipeRef, v_buffer, t_nbytes,
479 (IOAsyncCallback1) write_completed, (void*) l_both);
481 result = d_interface->WritePipeAsyncTO
482 (d_interfaceRef, d_pipeRef, v_buffer, t_nbytes, 0, USB_TIMEOUT,
483 (IOAsyncCallback1) write_completed, (void*) l_both);
485 if (result != kIOReturnSuccess)
486 USB_ERROR_STR (-1, - darwin_to_errno (result),
487 "fusb_ephandle_darwin::write_thread "
488 "(WritePipeAsync%s): %s",
489 d_transferType == kUSBInterrupt ? "" : "TO",
490 darwin_error_str (result));
491 else if (usb_debug > 4) {
492 std::cerr << "fusb_ephandle_darwin::write_thread: Queued " << (void*) l_both
493 << " (" << t_nbytes << " Bytes)" << std::endl;
495 l_nbytes -= t_nbytes;
502 fusb_ephandle_darwin::write_completed (void* refCon,
506 s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
507 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
508 size_t l_size = (size_t) io_size;
509 s_node_ptr l_node = l_both->node ();
510 s_queue_ptr l_queue = This->d_queue;
511 s_buffer_ptr l_buf = l_node->object ();
512 size_t l_i_size = l_buf->n_used ();
514 if (This->d_started && (l_i_size != l_size)) {
515 std::cerr << "fusb_ephandle_darwin::write_completed: Expected " << l_i_size
516 << " bytes written; wrote " << l_size << "." << std::endl;
517 } else if (usb_debug > 4) {
518 std::cerr << "fusb_ephandle_darwin::write_completed: Wrote " << (void*) l_both
519 << " (" << l_size << " Bytes)" << std::endl;
522 // set buffer's # data to 0
524 // make the node available for reuse
525 l_queue->make_node_available (l_node);
529 fusb_ephandle_darwin::abort ()
532 std::cerr << "fusb_ephandle_darwin::abort: starting." << std::endl;
535 io_return_t result = d_interface->AbortPipe (d_interfaceRef, d_pipeRef);
537 if (result != kIOReturnSuccess)
538 USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
539 "fusb_ephandle_darwin::abort "
540 "(AbortPipe): %s", darwin_error_str (result));
542 std::cerr << "fusb_ephandle_darwin::abort: finished." << std::endl;
547 fusb_ephandle_darwin::stop ()
553 std::cerr << "fusb_ephandle_darwin::stop: stopping "
554 << (d_input_p ? "read" : "write") << "." << std::endl;
559 // abort any pending IO transfers
562 // wait for write transfer to finish
563 wait_for_completion ();
565 // tell IO buffer to abort any waiting conditions
569 CFRunLoopStop (d_CFRunLoopRef);
571 // wait for the runThread to stop
572 d_runThreadRunning->lock ();
573 d_runThreadRunning->unlock ();
576 std::cerr << "fusb_ephandle_darwin::stop: " << (d_input_p ? "read" : "write")
577 << " stopped." << std::endl;
584 fusb_ephandle_darwin::wait_for_completion ()
587 while (d_queue->in_use ())