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 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"
37 static const int USB_TIMEOUT = 100; // in milliseconds
38 static const UInt8 NUM_QUEUE_ITEMS = 20;
40 fusb_devhandle_darwin::fusb_devhandle_darwin (usb_dev_handle* udh)
41 : fusb_devhandle (udh)
46 fusb_devhandle_darwin::~fusb_devhandle_darwin ()
52 fusb_devhandle_darwin::make_ephandle (int endpoint, bool input_p,
53 int block_size, int nblocks)
55 return new fusb_ephandle_darwin (this, endpoint, input_p,
59 // ----------------------------------------------------------------
61 fusb_ephandle_darwin::fusb_ephandle_darwin (fusb_devhandle_darwin* dh,
62 int endpoint, bool input_p,
63 int block_size, int nblocks)
64 : fusb_ephandle (endpoint, input_p, block_size, nblocks),
65 d_devhandle (dh), d_pipeRef (0), d_transferType (0),
66 d_interfaceRef (0), d_interface (0), d_queue (0),
67 d_buffer (0), d_bufLenBytes (0)
69 d_bufLenBytes = fusb_sysconfig::max_block_size();
71 // create circular buffer
72 d_buffer = new circular_buffer<char> (NUM_QUEUE_ITEMS * d_bufLenBytes,
73 !d_input_p, d_input_p);
76 d_queue = new circular_linked_list <s_buffer_ptr> (NUM_QUEUE_ITEMS);
77 d_queue->iterate_start ();
78 s_node_ptr l_node = d_queue->iterate_next ();
80 l_node->both (new s_both<s_buffer_ptr> (l_node, this));
81 s_buffer_ptr l_buf = new s_buffer (d_bufLenBytes);
82 l_node->object (l_buf);
83 l_node = d_queue->iterate_next ();
87 d_readRunning = new mld_mutex ();
88 d_runThreadRunning = new mld_mutex ();
89 d_runBlock = new mld_condition ();
90 d_readBlock = new mld_condition ();
93 fusb_ephandle_darwin::~fusb_ephandle_darwin ()
97 d_queue->iterate_start ();
98 s_node_ptr l_node = d_queue->iterate_next ();
100 s_both_ptr l_both = l_node->both ();
104 s_buffer_ptr l_buf = l_node->object ();
107 l_node->object (NULL);
108 l_node = d_queue->iterate_next ();
114 delete d_readRunning;
115 d_readRunning = NULL;
116 delete d_runThreadRunning;
117 d_runThreadRunning = NULL;
125 fusb_ephandle_darwin::start ()
127 UInt8 direction, number, interval;
128 UInt16 maxPacketSize;
130 // reset circular buffer
134 d_queue->num_used (0);
135 d_queue->iterate_start ();
136 s_node_ptr l_node = d_queue->iterate_next ();
138 l_node->both()->set (l_node, this);
139 l_node->object()->reset ();
140 l_node->set_available ();
141 l_node = d_queue->iterate_next ();
144 d_pipeRef = d_transferType = 0;
146 usb_dev_handle* dev = d_devhandle->get_usb_dev_handle ();
148 USB_ERROR_STR (false, -ENXIO, "fusb_ephandle_darwin::start: "
151 darwin_dev_handle* device = (darwin_dev_handle*) dev->impl_info;
153 USB_ERROR_STR (false, -ENOENT, "fusb_ephandle_darwin::start: "
154 "device not initialized");
157 fprintf (stderr, "fusb_ephandle_darwin::start: "
158 "dev = %p, device = %p\n", dev, device);
160 d_interfaceRef = device->interface;
161 if (! d_interfaceRef)
162 USB_ERROR_STR (false, -EACCES, "fusb_ephandle_darwin::start: "
163 "interface used without being claimed");
164 d_interface = *d_interfaceRef;
166 // get read or write pipe info (depends on "d_input_p")
169 fprintf (stderr, "fusb_ephandle_darwin::start "
170 "d_endpoint = %d, d_input_p = %s\n",
171 d_endpoint, d_input_p ? "TRUE" : "FALSE");
173 int l_endpoint = (d_input_p ? USB_ENDPOINT_IN : USB_ENDPOINT_OUT);
174 int pipeRef = ep_to_pipeRef (device, d_endpoint | l_endpoint);
176 USB_ERROR_STR (false, -EINVAL, "fusb_ephandle_darwin::start "
177 " invalid pipeRef.\n");
180 d_interface->GetPipeProperties (d_interfaceRef,
188 fprintf (stderr, "fusb_ephandle_darwin::start: %s: ep = 0x%02x, "
189 "pipeRef = %d, d_i = %p, d_iR = %p, if_dir = %d, if_# = %d, "
190 "if_int = %d, if_maxPS = %d\n", d_input_p ? "read" : "write",
191 d_endpoint, d_pipeRef, d_interface, d_interfaceRef, direction,
192 number, interval, maxPacketSize);
194 // set global start boolean
197 // lock the runBlock mutex, before creating the run thread.
198 // this guarantees that we can control execution between these 2 threads
199 d_runBlock->mutex ()->lock ();
201 // create the run thread, which allows OSX to process I/O separately
202 d_runThread = new mld_thread (run_thread, this);
204 // wait until the run thread (and possibky read thread) are -really-
205 // going; this will unlock the mutex before waiting for a signal ()
209 fprintf (stderr, "fusb_ephandle_darwin::start: %s started.\n",
210 d_input_p ? "read" : "write");
216 fusb_ephandle_darwin::run_thread (void* arg)
218 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
220 // lock the run thread running mutex; if ::stop() is called, it will
221 // first abort() the pipe then wait for the run thread to finish,
222 // via a lock() on this mutex
223 mld_mutex_ptr l_runThreadRunning = This->d_runThreadRunning;
224 l_runThreadRunning->lock ();
226 mld_mutex_ptr l_readRunning = This->d_readRunning;
227 mld_condition_ptr l_readBlock = This->d_readBlock;
228 mld_mutex_ptr l_readBlock_mutex = l_readBlock->mutex ();
230 bool l_input_p = This->d_input_p;
233 fprintf (stderr, "fusb_ephandle_darwin::run_thread: "
234 "starting for %s.\n",
235 l_input_p ? "read" : "write");
237 usb_interface_t** l_interfaceRef = This->d_interfaceRef;
238 usb_interface_t* l_interface = This->d_interface;
239 CFRunLoopSourceRef l_cfSource;
241 // create async run loop
242 l_interface->CreateInterfaceAsyncEventSource (l_interfaceRef, &l_cfSource);
243 CFRunLoopAddSource (CFRunLoopGetCurrent (), l_cfSource,
244 kCFRunLoopDefaultMode);
245 // get run loop reference, to allow other threads to stop
246 This->d_CFRunLoopRef = CFRunLoopGetCurrent ();
248 mld_thread_ptr l_rwThread = NULL;
251 // lock the readBlock mutex, before creating the read thread.
252 // this guarantees that we can control execution between these 2 threads
253 l_readBlock_mutex->lock ();
254 // create the read thread, which just issues all of the starting
255 // async read commands, then returns
256 l_rwThread = new mld_thread (read_thread, arg);
257 // wait until the the read thread is -really- going; this will
258 // unlock the read block mutex before waiting for a signal ()
259 l_readBlock->wait ();
262 // now signal the run condition to release and finish ::start().
264 // lock the runBlock mutex first; this will force waiting until the
265 // ->wait() command is issued in ::start()
266 mld_mutex_ptr l_run_block_mutex = This->d_runBlock->mutex ();
267 l_run_block_mutex->lock ();
269 // now that the lock is in place, signal the parent thread that
270 // things are running
271 This->d_runBlock->signal ();
273 // release the run_block mutex, just in case
274 l_run_block_mutex->unlock ();
280 // wait for read_thread () to finish, if needed
281 l_readRunning->lock ();
282 l_readRunning->unlock ();
285 // remove run loop stuff
286 CFRunLoopRemoveSource (CFRunLoopGetCurrent (),
287 l_cfSource, kCFRunLoopDefaultMode);
290 fprintf (stderr, "fusb_ephandle_darwin::run_thread: finished for %s.\n",
291 l_input_p ? "read" : "write");
293 // release the run thread running mutex
294 l_runThreadRunning->unlock ();
298 fusb_ephandle_darwin::read_thread (void* arg)
301 fprintf (stderr, "fusb_ephandle_darwin::read_thread: starting.\n");
303 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
305 // before doing anything else, lock the read running mutex. this
306 // mutex does flow control between this thread and the run_thread
307 mld_mutex_ptr l_readRunning = This->d_readRunning;
308 l_readRunning->lock ();
310 // signal the read condition from run_thread() to continue
312 // lock the readBlock mutex first; this will force waiting until the
313 // ->wait() command is issued in ::run_thread()
314 mld_condition_ptr l_readBlock = This->d_readBlock;
315 mld_mutex_ptr l_read_block_mutex = l_readBlock->mutex ();
316 l_read_block_mutex->lock ();
318 // now that the lock is in place, signal the parent thread that
319 // things are running here
320 l_readBlock->signal ();
322 // release the run_block mutex, just in case
323 l_read_block_mutex->unlock ();
325 // queue up all of the available read requests
326 s_queue_ptr l_queue = This->d_queue;
327 l_queue->iterate_start ();
328 s_node_ptr l_node = l_queue->iterate_next ();
330 This->read_issue (l_node->both ());
331 l_node = l_queue->iterate_next ();
335 fprintf (stderr, "fusb_ephandle_darwin::read_thread: finished.\n");
337 // release the read running mutex, to let the parent thread knows
338 // that this thread is finished
339 l_readRunning->unlock ();
343 fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
345 if ((! l_both) || (! d_started)) {
347 fprintf (stderr, "fusb_ephandle_darwin::read_issue: Doing nothing; "
348 "l_both is %X; started is %s\n", (unsigned int) l_both,
349 d_started ? "TRUE" : "FALSE");
353 // set the node and buffer from the input "both"
354 s_node_ptr l_node = l_both->node ();
355 s_buffer_ptr l_buf = l_node->object ();
356 void* v_buffer = (void*) l_buf->buffer ();
358 // read up to d_bufLenBytes
359 UInt32 bufLen = d_bufLenBytes;
360 l_buf->n_used (bufLen);
362 // setup system call result
363 io_return_t result = kIOReturnSuccess;
365 if (d_transferType == kUSBInterrupt)
366 /* This is an interrupt pipe. We can't specify a timeout. */
367 result = d_interface->ReadPipeAsync
368 (d_interfaceRef, d_pipeRef, v_buffer, bufLen,
369 (IOAsyncCallback1) read_completed, (void*) l_both);
371 result = d_interface->ReadPipeAsyncTO
372 (d_interfaceRef, d_pipeRef, v_buffer, bufLen, 0, USB_TIMEOUT,
373 (IOAsyncCallback1) read_completed, (void*) l_both);
375 if (result != kIOReturnSuccess)
376 USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
377 "fusb_ephandle_darwin::read_issue "
378 "(ReadPipeAsync%s): %s",
379 d_transferType == kUSBInterrupt ? "" : "TO",
380 darwin_error_str (result));
381 else if (usb_debug > 4)
382 fprintf (stderr, "fusb_ephandle_darwin::read_issue: "
383 "Queued %X (%ld Bytes)\n", (unsigned int) l_both, bufLen);
387 fusb_ephandle_darwin::read_completed (void* refCon,
391 UInt32 l_size = (UInt32) io_size;
392 s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
393 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
394 s_node_ptr l_node = l_both->node ();
395 circular_buffer<char>* l_buffer = This->d_buffer;
396 s_buffer_ptr l_buf = l_node->object ();
397 UInt32 l_i_size = l_buf->n_used ();
399 if (This->d_started && (l_i_size != l_size))
400 fprintf (stderr, "fusb_ephandle_darwin::read_completed: "
401 "Expected %ld bytes; read %ld.\n",
403 else if (usb_debug > 4)
404 fprintf (stderr, "fusb_ephandle_darwin::read_completed: "
405 "Read %X (%ld bytes)\n",
406 (unsigned int) l_both, l_size);
408 // add this read to the transfer buffer
409 if (l_buffer->enqueue (l_buf->buffer (), l_size) == -1) {
410 fputs ("iU", stderr);
414 // set buffer's # data to 0
417 // issue another read for this "both"
418 This->read_issue (l_both);
422 fusb_ephandle_darwin::read (void* buffer, int nbytes)
424 UInt32 l_nbytes = (UInt32) nbytes;
425 d_buffer->dequeue ((char*) buffer, &l_nbytes);
428 fprintf (stderr, "fusb_ephandle_darwin::read: request for %d bytes, %ld bytes retrieved.\n", nbytes, l_nbytes);
430 return ((int) l_nbytes);
434 fusb_ephandle_darwin::write (const void* buffer, int nbytes)
436 UInt32 l_nbytes = (UInt32) nbytes;
440 fprintf (stderr, "fusb_ephandle_darwin::write: Not yet started.\n");
445 while (l_nbytes != 0) {
446 // find out how much data to copy; limited to "d_bufLenBytes" per node
447 UInt32 t_nbytes = (l_nbytes > d_bufLenBytes) ? d_bufLenBytes : l_nbytes;
449 // get next available node to write into;
450 // blocks internally if none available
451 s_node_ptr l_node = d_queue->find_next_available_node ();
453 // copy the input into the node's buffer
454 s_buffer_ptr l_buf = l_node->object ();
455 l_buf->buffer ((char*) buffer, t_nbytes);
456 void* v_buffer = (void*) l_buf->buffer ();
458 // setup callback parameter & system call return
459 s_both_ptr l_both = l_node->both ();
460 io_return_t result = kIOReturnSuccess;
462 if (d_transferType == kUSBInterrupt)
463 /* This is an interrupt pipe ... can't specify a timeout. */
464 result = d_interface->WritePipeAsync
465 (d_interfaceRef, d_pipeRef, v_buffer, t_nbytes,
466 (IOAsyncCallback1) write_completed, (void*) l_both);
468 result = d_interface->WritePipeAsyncTO
469 (d_interfaceRef, d_pipeRef, v_buffer, t_nbytes, 0, USB_TIMEOUT,
470 (IOAsyncCallback1) write_completed, (void*) l_both);
472 if (result != kIOReturnSuccess)
473 USB_ERROR_STR (-1, - darwin_to_errno (result),
474 "fusb_ephandle_darwin::write_thread "
475 "(WritePipeAsync%s): %s",
476 d_transferType == kUSBInterrupt ? "" : "TO",
477 darwin_error_str (result));
478 else if (usb_debug > 4) {
479 fprintf (stderr, "fusb_ephandle_darwin::write_thread: "
480 "Queued %X (%ld Bytes)\n", (unsigned int) l_both, t_nbytes);
482 l_nbytes -= t_nbytes;
489 fusb_ephandle_darwin::write_completed (void* refCon,
493 s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
494 fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
495 UInt32 l_size = (UInt32) io_size;
496 s_node_ptr l_node = l_both->node ();
497 s_queue_ptr l_queue = This->d_queue;
498 s_buffer_ptr l_buf = l_node->object ();
499 UInt32 l_i_size = l_buf->n_used ();
501 if (This->d_started && (l_i_size != l_size))
502 fprintf (stderr, "fusb_ephandle_darwin::write_completed: "
503 "Expected %ld bytes written; wrote %ld.\n",
505 else if (usb_debug > 4)
506 fprintf (stderr, "fusb_ephandle_darwin::write_completed: "
507 "Wrote %X (%ld Bytes)\n", (unsigned int) l_both, l_size);
509 // set buffer's # data to 0
511 // make the node available for reuse
512 l_queue->make_node_available (l_node);
516 fusb_ephandle_darwin::abort ()
519 fprintf (stderr, "fusb_ephandle_darwin::abort: starting.\n");
521 io_return_t result = d_interface->AbortPipe (d_interfaceRef, d_pipeRef);
523 if (result != kIOReturnSuccess)
524 USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
525 "fusb_ephandle_darwin::abort "
526 "(AbortPipe): %s", darwin_error_str (result));
528 fprintf (stderr, "fusb_ephandle_darwin::abort: finished.\n");
532 fusb_ephandle_darwin::stop ()
538 fprintf (stderr, "fusb_ephandle_darwin::stop: stopping %s.\n",
539 d_input_p ? "read" : "write");
543 // abort any pending IO transfers
546 // wait for write transfer to finish
547 wait_for_completion ();
549 // tell IO buffer to abort any waiting conditions
553 CFRunLoopStop (d_CFRunLoopRef);
555 // wait for the runThread to stop
556 d_runThreadRunning->lock ();
557 d_runThreadRunning->unlock ();
560 fprintf (stderr, "fusb_ephandle_darwin::stop: %s stopped.\n",
561 d_input_p ? "read" : "write");
567 fusb_ephandle_darwin::wait_for_completion ()
570 while (d_queue->in_use ())