Imported Upstream version 3.2.2
[debian/gnuradio] / usrp / host / lib / legacy / fusb_darwin.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio.
6  *
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)
10  * any later version.
11  * 
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.
16  * 
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 // tell mld_threads to NOT use omni_threads,
28 // but rather Darwin's pthreads
29 #define _USE_OMNI_THREADS_
30 #define DO_DEBUG 0
31
32 #include <usb.h>
33 #include "fusb.h"
34 #include "fusb_darwin.h"
35 #include "darwin_libusb.h"
36
37 static const int USB_TIMEOUT = 100;     // in milliseconds
38 static const UInt8 NUM_QUEUE_ITEMS = 20;
39
40 fusb_devhandle_darwin::fusb_devhandle_darwin (usb_dev_handle* udh)
41   : fusb_devhandle (udh)
42 {
43   // that's it
44 }
45
46 fusb_devhandle_darwin::~fusb_devhandle_darwin ()
47 {
48   // nop
49 }
50
51 fusb_ephandle*
52 fusb_devhandle_darwin::make_ephandle (int endpoint, bool input_p,
53                                       int block_size, int nblocks)
54 {
55   return new fusb_ephandle_darwin (this, endpoint, input_p,
56                                    block_size, nblocks);
57 }
58
59 // ----------------------------------------------------------------
60
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)
68 {
69   d_bufLenBytes = fusb_sysconfig::max_block_size();
70
71 // create circular buffer
72   d_buffer = new circular_buffer<char> (NUM_QUEUE_ITEMS * d_bufLenBytes,
73                                         !d_input_p, d_input_p);
74
75 // create the queue
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 ();
79   while (l_node) {
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 ();
84     l_buf = NULL;
85   }
86
87   d_readRunning = new mld_mutex ();
88   d_runThreadRunning = new mld_mutex ();
89   d_runBlock = new mld_condition ();
90   d_readBlock = new mld_condition ();
91 }
92
93 fusb_ephandle_darwin::~fusb_ephandle_darwin ()
94 {
95   stop ();
96
97   d_queue->iterate_start ();
98   s_node_ptr l_node = d_queue->iterate_next ();
99   while (l_node) {
100     s_both_ptr l_both = l_node->both ();
101     delete l_both;
102     l_both = NULL;
103     l_node->both (NULL);
104     s_buffer_ptr l_buf = l_node->object ();
105     delete l_buf;
106     l_buf = NULL;
107     l_node->object (NULL);
108     l_node = d_queue->iterate_next ();
109   }
110   delete d_queue;
111   d_queue = NULL;
112   delete d_buffer;
113   d_buffer = NULL;
114   delete d_readRunning;
115   d_readRunning = NULL;
116   delete d_runThreadRunning;
117   d_runThreadRunning = NULL;
118   delete d_runBlock;
119   d_runBlock = NULL;
120   delete d_readBlock;
121   d_readBlock = NULL;
122 }
123
124 bool
125 fusb_ephandle_darwin::start ()
126 {
127   UInt8  direction, number, interval;
128   UInt16 maxPacketSize;
129
130 // reset circular buffer
131   d_buffer->reset ();
132
133 // reset the queue
134   d_queue->num_used (0);
135   d_queue->iterate_start ();
136   s_node_ptr l_node = d_queue->iterate_next ();
137   while (l_node) {
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 ();
142   }
143
144   d_pipeRef = d_transferType = 0;
145
146   usb_dev_handle* dev = d_devhandle->get_usb_dev_handle ();
147   if (! dev)
148     USB_ERROR_STR (false, -ENXIO, "fusb_ephandle_darwin::start: "
149                    "null device");
150
151   darwin_dev_handle* device = (darwin_dev_handle*) dev->impl_info;
152   if (! device)
153     USB_ERROR_STR (false, -ENOENT, "fusb_ephandle_darwin::start: "
154                    "device not initialized");
155
156   if (usb_debug)
157     fprintf (stderr, "fusb_ephandle_darwin::start: "
158              "dev = %p, device = %p\n", dev, device);
159
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;
165
166 // get read or write pipe info (depends on "d_input_p")
167
168   if (usb_debug > 3)
169     fprintf (stderr, "fusb_ephandle_darwin::start "
170              "d_endpoint = %d, d_input_p = %s\n",
171              d_endpoint, d_input_p ? "TRUE" : "FALSE");
172
173   int l_endpoint = (d_input_p ? USB_ENDPOINT_IN : USB_ENDPOINT_OUT);
174   int pipeRef = ep_to_pipeRef (device, d_endpoint | l_endpoint);
175   if (pipeRef < 0)
176     USB_ERROR_STR (false, -EINVAL, "fusb_ephandle_darwin::start "
177                    " invalid pipeRef.\n");
178
179   d_pipeRef = pipeRef;
180   d_interface->GetPipeProperties (d_interfaceRef,
181                                   d_pipeRef,
182                                   &direction,
183                                   &number,
184                                   &d_transferType,
185                                   &maxPacketSize,
186                                   &interval);
187   if (usb_debug == 3)
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);
193
194   // set global start boolean
195   d_started = true;
196
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 ();
200
201   // create the run thread, which allows OSX to process I/O separately
202   d_runThread = new mld_thread (run_thread, this);
203
204   // wait until the run thread (and possibky read thread) are -really-
205   // going; this will unlock the mutex before waiting for a signal ()
206   d_runBlock->wait ();
207
208   if (usb_debug)
209     fprintf (stderr, "fusb_ephandle_darwin::start: %s started.\n",
210              d_input_p ? "read" : "write");
211
212   return (true);
213 }
214
215 void
216 fusb_ephandle_darwin::run_thread (void* arg)
217 {
218   fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
219
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 ();
225
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 ();
229
230   bool l_input_p = This->d_input_p;
231
232   if (usb_debug)
233     fprintf (stderr, "fusb_ephandle_darwin::run_thread: "
234              "starting for %s.\n",
235              l_input_p ? "read" : "write");
236
237   usb_interface_t** l_interfaceRef = This->d_interfaceRef;
238   usb_interface_t* l_interface = This->d_interface;
239   CFRunLoopSourceRef l_cfSource;
240
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 ();
247
248   mld_thread_ptr l_rwThread = NULL;
249
250   if (l_input_p) {
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 ();
260   }
261
262   // now signal the run condition to release and finish ::start().
263
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 ();
268
269   // now that the lock is in place, signal the parent thread that
270   // things are running
271   This->d_runBlock->signal ();
272
273   // release the run_block mutex, just in case
274   l_run_block_mutex->unlock ();
275
276   // run the loop
277   CFRunLoopRun ();
278
279   if (l_input_p) {
280     // wait for read_thread () to finish, if needed
281     l_readRunning->lock ();
282     l_readRunning->unlock ();
283   }
284
285   // remove run loop stuff
286   CFRunLoopRemoveSource (CFRunLoopGetCurrent (),
287                          l_cfSource, kCFRunLoopDefaultMode);
288
289   if (usb_debug)
290     fprintf (stderr, "fusb_ephandle_darwin::run_thread: finished for %s.\n",
291              l_input_p ? "read" : "write");
292
293   // release the run thread running mutex
294   l_runThreadRunning->unlock ();
295 }
296
297 void
298 fusb_ephandle_darwin::read_thread (void* arg)
299 {
300   if (usb_debug)
301     fprintf (stderr, "fusb_ephandle_darwin::read_thread: starting.\n");
302
303   fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
304
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 ();
309
310   // signal the read condition from run_thread() to continue
311
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 ();
317
318   // now that the lock is in place, signal the parent thread that
319   // things are running here
320   l_readBlock->signal ();
321
322   // release the run_block mutex, just in case
323   l_read_block_mutex->unlock ();
324
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 ();
329   while (l_node) {
330     This->read_issue (l_node->both ());
331     l_node = l_queue->iterate_next ();
332   }
333
334   if (usb_debug)
335     fprintf (stderr, "fusb_ephandle_darwin::read_thread: finished.\n");
336
337   // release the read running mutex, to let the parent thread knows
338   // that this thread is finished
339   l_readRunning->unlock ();
340 }
341
342 void
343 fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
344 {
345   if ((! l_both) || (! d_started)) {
346     if (usb_debug > 4)
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");
350     return;
351   }
352
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 ();
357
358 // read up to d_bufLenBytes
359   UInt32 bufLen = d_bufLenBytes;
360   l_buf->n_used (bufLen);
361
362 // setup system call result
363   io_return_t result = kIOReturnSuccess;
364
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);
370   else
371     result = d_interface->ReadPipeAsyncTO
372       (d_interfaceRef, d_pipeRef, v_buffer, bufLen, 0, USB_TIMEOUT,
373        (IOAsyncCallback1) read_completed, (void*) l_both);
374
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);
384 }
385
386 void
387 fusb_ephandle_darwin::read_completed (void* refCon,
388                                       io_return_t result,
389                                       void* io_size)
390 {
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 ();
398
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",
402              l_i_size, l_size);
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);
407
408 // add this read to the transfer buffer
409   if (l_buffer->enqueue (l_buf->buffer (), l_size) == -1) {
410     fputs ("iU", stderr);
411     fflush (stderr);
412   }
413
414 // set buffer's # data to 0
415   l_buf->n_used (0);
416
417 // issue another read for this "both"
418   This->read_issue (l_both);
419 }
420
421 int
422 fusb_ephandle_darwin::read (void* buffer, int nbytes)
423 {
424   UInt32 l_nbytes = (UInt32) nbytes;
425   d_buffer->dequeue ((char*) buffer, &l_nbytes);
426
427   if (usb_debug > 4)
428     fprintf (stderr, "fusb_ephandle_darwin::read: request for %d bytes, %ld bytes retrieved.\n", nbytes, l_nbytes);
429
430   return ((int) l_nbytes);
431 }
432
433 int
434 fusb_ephandle_darwin::write (const void* buffer, int nbytes)
435 {
436   UInt32 l_nbytes = (UInt32) nbytes;
437
438   if (! d_started) {
439     if (usb_debug)
440       fprintf (stderr, "fusb_ephandle_darwin::write: Not yet started.\n");
441
442     return (0);
443   }
444
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;
448
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 ();
452
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 ();
457
458 // setup callback parameter & system call return
459     s_both_ptr l_both = l_node->both ();
460     io_return_t result = kIOReturnSuccess;
461
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);
467     else
468       result = d_interface->WritePipeAsyncTO
469         (d_interfaceRef, d_pipeRef, v_buffer, t_nbytes, 0, USB_TIMEOUT,
470          (IOAsyncCallback1) write_completed, (void*) l_both);
471
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);
481     }
482     l_nbytes -= t_nbytes;
483   }
484
485   return (nbytes);
486 }
487
488 void
489 fusb_ephandle_darwin::write_completed (void* refCon,
490                                        io_return_t result,
491                                        void* io_size)
492 {
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 ();
500
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",
504              l_i_size, l_size);
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);
508
509 // set buffer's # data to 0
510   l_buf->n_used (0);
511 // make the node available for reuse
512   l_queue->make_node_available (l_node);
513 }
514
515 void
516 fusb_ephandle_darwin::abort ()
517 {
518   if (usb_debug)
519     fprintf (stderr, "fusb_ephandle_darwin::abort: starting.\n");
520
521   io_return_t result = d_interface->AbortPipe (d_interfaceRef, d_pipeRef);
522
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));
527   if (usb_debug)
528     fprintf (stderr, "fusb_ephandle_darwin::abort: finished.\n");
529 }
530
531 bool
532 fusb_ephandle_darwin::stop ()
533 {
534   if (! d_started)
535     return (true);
536
537   if (usb_debug)
538     fprintf (stderr, "fusb_ephandle_darwin::stop: stopping %s.\n",
539              d_input_p ? "read" : "write");
540
541   d_started = false;
542
543 // abort any pending IO transfers
544   abort ();
545
546 // wait for write transfer to finish
547   wait_for_completion ();
548
549 // tell IO buffer to abort any waiting conditions
550   d_buffer->abort ();
551
552 // stop the run loop
553   CFRunLoopStop (d_CFRunLoopRef);
554
555 // wait for the runThread to stop
556   d_runThreadRunning->lock ();
557   d_runThreadRunning->unlock ();
558
559   if (usb_debug)
560     fprintf (stderr, "fusb_ephandle_darwin::stop: %s stopped.\n",
561              d_input_p ? "read" : "write");
562
563   return (true);
564 }
565
566 void
567 fusb_ephandle_darwin::wait_for_completion ()
568 {
569   if (d_queue)
570     while (d_queue->in_use ())
571       usleep (1000);
572 }