sbIPDMarshall.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4 //=BEGIN SONGBIRD GPL
5 //
6 // This file is part of the Songbird web player.
7 //
8 // Copyright(c) 2005-2009 POTI, Inc.
9 // http://www.songbirdnest.com
10 //
11 // This file may be licensed under the terms of of the
12 // GNU General Public License Version 2 (the GPL).
13 //
14 // Software distributed under the License is distributed
15 // on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either
16 // express or implied. See the GPL for the specific language
17 // governing rights and limitations.
18 //
19 // You should have received a copy of the GPL along with this
20 // program. If not, go to http://www.gnu.org/licenses/gpl.html
21 // or write to the Free Software Foundation, Inc.,
22 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=END SONGBIRD GPL
25 */
26 
27 //------------------------------------------------------------------------------
28 //
29 // iPod device marshall services.
30 //
31 // The iPod device marshall services scan for iPod devices at startup and
32 // listen for added and removed devices. The marshall communicates these events
33 // to the other device services.
34 //
35 // Thread strategy:
36 //
37 // Most marshall interfaces are not typically called from more than one
38 // thread. The marshall device event handlers are always called from the main
39 // thread. A single lock is thus used to serialize thread access since multiple
40 // threads are not expected to be blocked.
41 // A few exceptions to this strategy will use alternate methods or no locking
42 // (e.g., GetId).
43 //
44 //------------------------------------------------------------------------------
45 
46 
52 //------------------------------------------------------------------------------
53 //
54 // iPod device marshall imported services.
55 //
56 //------------------------------------------------------------------------------
57 
58 // Self import.
59 #include "sbIPDMarshall.h"
60 
61 // Local imports.
62 #include "sbIPDLog.h"
63 #include "sbIPDUtils.h"
64 
65 // Songbird imports.
66 #include <sbIDevice.h>
67 #include <sbIDeviceController.h>
68 #include <sbIDeviceControllerRegistrar.h>
69 #include <sbIDeviceEvent.h>
70 
71 // Mozilla imports.
72 #include <nsComponentManagerUtils.h>
73 #include <nsIClassInfoImpl.h>
74 #include <nsIProgrammingLanguage.h>
75 #include <nsIWritablePropertyBag.h>
76 #include <nsMemory.h>
77 #include <nsServiceManagerUtils.h>
78 
79 #include <sbDebugUtils.h>
80 
81 
82 //------------------------------------------------------------------------------
83 //
84 // iPod device marshall nsISupports and nsIClassInfo implementation.
85 //
86 //------------------------------------------------------------------------------
87 
88 // nsISupports implementation.
89 // NS_IMPL_THREADSAFE_ISUPPORTS1_CI(sbIPDMarshall, sbIDeviceMarshall)
92 NS_IMPL_QUERY_INTERFACE1_CI(sbIPDMarshall, sbIDeviceMarshall)
94 
95 // nsIClassInfo implementation.
96 NS_IMPL_THREADSAFE_CI(sbIPDMarshall)
97 
98 
99 //------------------------------------------------------------------------------
100 //
101 // iPod device marshall sbIDeviceMarshall implementation.
102 //
103 //------------------------------------------------------------------------------
104 
110 NS_IMETHODIMP
111 sbIPDMarshall::LoadControllers(sbIDeviceControllerRegistrar* aRegistrar)
112 {
113  // Validate parameters.
114  NS_ENSURE_ARG_POINTER(aRegistrar);
115 
116  // Register the controllers.
117  RegisterControllers(aRegistrar);
118 
119  return NS_OK;
120 }
121 
122 
128 NS_IMETHODIMP
129 sbIPDMarshall::BeginMonitoring()
130 {
131  nsresult rv;
132 
133  // Serialize.
134  nsAutoMonitor mon(mMonitor);
135 
136  // Initialize the monitor services.
137  rv = InitializeVolumeMonitor();
138  NS_ENSURE_SUCCESS(rv, rv);
139 
140  // Scan for connected devices.
141  rv = ScanForConnectedDevices();
142  NS_ENSURE_SUCCESS(rv, rv);
143 
144  return NS_OK;
145 }
146 
147 
153 NS_IMETHODIMP
154 sbIPDMarshall::StopMonitoring()
155 {
156  // Serialize.
157  nsAutoMonitor mon(mMonitor);
158 
159  // Finalize the monitor services.
160  FinalizeVolumeMonitor();
161 
162  return NS_OK;
163 }
164 
165 
166 //
167 // Getters/setters.
168 //
169 
174 NS_IMETHODIMP
175 sbIPDMarshall::GetId(nsID** aId)
176 {
177  // Validate parameters.
178  NS_ENSURE_ARG_POINTER(aId);
179 
180  // Allocate an nsID.
181  nsID* pId = static_cast<nsID*>(NS_Alloc(sizeof(nsID)));
182  NS_ENSURE_TRUE(pId, NS_ERROR_OUT_OF_MEMORY);
183 
184  // Return the ID.
185  static nsID const id = SB_IPDMARSHALL_CID;
186  *pId = id;
187  *aId = pId;
188 
189  return NS_OK;
190 }
191 
192 
197 NS_IMETHODIMP
198 sbIPDMarshall::GetName(nsAString& aName)
199 {
200  aName.AssignLiteral(SB_IPDMARSHALL_CLASSNAME);
201  return NS_OK;
202 }
203 
204 
205 //------------------------------------------------------------------------------
206 //
207 // iPod device marshall public services.
208 //
209 //------------------------------------------------------------------------------
210 
217  mVolumeEventHandler(NULL),
218  mVolumeEventHandlerRef(NULL)
219 {
220  nsresult rv;
221 
223 
224  // Create the device marshall services monitor.
225  mMonitor = nsAutoMonitor::NewMonitor("sbIPDMarshall.mMonitor");
226  NS_ENSURE_TRUE(mMonitor, /* void */);
227 
228  // Get the device manager and registrar.
229  mDeviceManager = do_GetService("@songbirdnest.com/Songbird/DeviceManager;2",
230  &rv);
231  NS_ENSURE_SUCCESS(rv, /* void */);
232  mDeviceRegistrar = do_QueryInterface(mDeviceManager, &rv);
233  NS_ENSURE_SUCCESS(rv, /* void */);
234 
235  // Initialize the device list.
236  mDeviceList.Init();
237 }
238 
239 
245 {
246  // Finalize the monitor services.
247  FinalizeVolumeMonitor();
248 
249  // Dispose of the device marshall services monitor.
250  if (mMonitor)
251  {
252  nsAutoMonitor::DestroyMonitor(mMonitor);
253  mMonitor = nsnull;
254  }
255 
256  // Release object references.
257  mDeviceManager = nsnull;
258  mDeviceRegistrar = nsnull;
259 }
260 
261 
262 //------------------------------------------------------------------------------
263 //
264 // iPod device marshall monitor services.
265 //
266 //------------------------------------------------------------------------------
267 
272 nsresult
273 sbIPDMarshall::InitializeVolumeMonitor()
274 {
275  EventTypeSpec volumeEventTypes[] =
276  { { kEventClassVolume, kEventVolumeMounted },
277  { kEventClassVolume, kEventVolumeUnmounted } };
278  OSStatus error = noErr;
279 
280  // Set up to finalize monitor services on error.
281  sbAutoFinalizeVolumeMonitor autoFinalizeVolumeMonitor(this);
282 
283  // Install a volume event handler.
284  mVolumeEventHandler = NewEventHandlerUPP(VolumeEventHandler);
285  NS_ENSURE_TRUE(mVolumeEventHandler, NS_ERROR_OUT_OF_MEMORY);
286  error = InstallApplicationEventHandler(mVolumeEventHandler,
287  GetEventTypeCount(volumeEventTypes),
288  volumeEventTypes,
289  this,
290  &mVolumeEventHandlerRef);
291  NS_ENSURE_TRUE(error == noErr, NS_ERROR_FAILURE);
292 
293  // Don't finalize monitor services.
294  autoFinalizeVolumeMonitor.forget();
295 
296  return NS_OK;
297 }
298 
299 
304 void
305 sbIPDMarshall::FinalizeVolumeMonitor()
306 {
307  // Remove the volume event handler.
308  if (mVolumeEventHandlerRef) {
309  RemoveEventHandler(mVolumeEventHandlerRef);
310  mVolumeEventHandlerRef = NULL;
311  }
312  if (mVolumeEventHandler) {
313  DisposeEventHandlerUPP(mVolumeEventHandler);
314  mVolumeEventHandler = NULL;
315  }
316 }
317 
318 
333 /* static */
334 pascal OSStatus
335 sbIPDMarshall::VolumeEventHandler(EventHandlerCallRef aNextHandler,
336  EventRef aEventRef,
337  void* aHandlerCtx)
338 {
339  // Validate arguments
340  NS_ENSURE_TRUE(aHandlerCtx, eventNotHandledErr);
341 
342  // Trace execution.
343  FIELD_LOG(("Enter: sbIPDMarshall::VolumeEventHandler\n"));
344 
345  // Handle the event.
346  sbIPDMarshall* psbIPDMarshall = (sbIPDMarshall *) aHandlerCtx;
347  psbIPDMarshall->VolumeEventHandler(aNextHandler, aEventRef);
348 
349  // Trace execution.
350  FIELD_LOG(("Exit: sbIPDMarshall::VolumeEventHandler\n"));
351 
352  // Indicate that the event was not consumed.
353  return eventNotHandledErr;
354 }
355 
356 void
357 sbIPDMarshall::VolumeEventHandler(EventHandlerCallRef aNextHandler,
358  EventRef aEventRef)
359 {
360  OSStatus error = noErr;
361 
362  // Get the volume reference number.
363  FSVolumeRefNum volumeRefNum = kFSInvalidVolumeRefNum;
364  error = GetEventParameter(aEventRef,
365  kEventParamDirectObject,
366  typeFSVolumeRefNum,
367  NULL,
368  sizeof(volumeRefNum),
369  NULL,
370  &volumeRefNum);
371  NS_ENSURE_TRUE(error == noErr, /* void */);
372 
373  // Get the event type.
374  UInt32 eventType = GetEventKind(aEventRef);
375 
376  // Dispatch event processing.
377  switch (eventType)
378  {
379  case kEventVolumeMounted :
380  // Send iPod added event if volume is an iPod volume.
381  if (IsIPod(volumeRefNum))
382  HandleAddedEvent(volumeRefNum);
383  break;
384 
385  case kEventVolumeUnmounted :
386  HandleRemovedEvent(volumeRefNum);
387  break;
388 
389  default :
390  break;
391  }
392 }
393 
394 
402 void
403 sbIPDMarshall::HandleAddedEvent(FSVolumeRefNum aVolumeRefNum)
404 {
405  nsCOMPtr<sbIDevice> device;
406  nsresult rv;
407 
408  // Serialize.
409  nsAutoMonitor mon(mMonitor);
410 
411  // Log progress.
412  FIELD_LOG(("Enter: HandleAddedEvent %d\n", aVolumeRefNum));
413 
414  // Do nothing if device has already been added.
415  if (mDeviceList.Get(aVolumeRefNum, getter_AddRefs(device)))
416  return;
417 
418  // Set up the device properties.
419  nsCOMPtr<nsIWritablePropertyBag>
420  propBag = do_CreateInstance("@mozilla.org/hash-property-bag;1", &rv);
421  NS_ENSURE_SUCCESS(rv, /* void */);
422  rv = propBag->SetProperty(NS_LITERAL_STRING("DeviceType"),
423  sbIPDVariant("iPod").get());
424  NS_ENSURE_SUCCESS(rv, /* void */);
425 
426  rv = propBag->SetProperty(NS_LITERAL_STRING("VolumeRefNum"),
427  sbIPDVariant(aVolumeRefNum).get());
428  NS_ENSURE_SUCCESS(rv, /* void */);
429  nsAutoString mountPoint;
430  rv = GetVolumePath(aVolumeRefNum, mountPoint);
431  NS_ENSURE_SUCCESS(rv, /* void */);
432  rv = propBag->SetProperty(NS_LITERAL_STRING("MountPath"),
433  sbIPDVariant(mountPoint).get());
434  NS_ENSURE_SUCCESS(rv, /* void */);
435 
436  nsAutoString firewireGUID;
437  rv = GetFirewireGUID(aVolumeRefNum, firewireGUID);
438  NS_ENSURE_SUCCESS(rv, /* void */);
439  rv = propBag->SetProperty(NS_LITERAL_STRING("FirewireGUID"),
440  sbIPDVariant(firewireGUID).get());
441  NS_ENSURE_SUCCESS(rv, /* void */);
442 
443  // Find a controller for the device. Do nothing more if none found.
444  nsCOMPtr<sbIDeviceController> controller = FindCompatibleControllers(propBag);
445  if (!controller)
446  return;
447 
448  // Create a device.
449  rv = controller->CreateDevice(propBag, getter_AddRefs(device));
450  NS_ENSURE_SUCCESS(rv, /* void */);
451 
452  // Register the device.
453  rv = mDeviceRegistrar->RegisterDevice(device);
454  NS_ENSURE_SUCCESS(rv, /* void */);
455 
456  // Add device to device list.
457  mDeviceList.Put(aVolumeRefNum, device);
458 
459  // Send device added notification.
461  sbIPDVariant(device).get(),
462  (sbIDeviceMarshall *) this);
463 }
464 
465 
473 void
474 sbIPDMarshall::HandleRemovedEvent(FSVolumeRefNum aVolumeRefNum)
475 {
476  nsresult rv;
477 
478  // Log progress.
479  FIELD_LOG(("Enter: HandleRemovedEvent %d\n", aVolumeRefNum));
480 
481  // Get removed device. Do nothing if device has not been added.
482  nsCOMPtr<sbIDevice> device;
483  if (!mDeviceList.Get(aVolumeRefNum, getter_AddRefs(device)))
484  return;
485 
486  // Get the device and device controller registrars.
487  nsCOMPtr<sbIDeviceRegistrar> deviceRegistrar =
488  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
489  NS_ENSURE_SUCCESS(rv, /* void */);
490  nsCOMPtr<sbIDeviceControllerRegistrar> deviceControllerRegistrar =
491  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
492  NS_ENSURE_SUCCESS(rv, /* void */);
493 
494  // Get the device controller ID and set it up for auto-disposal.
495  nsID *controllerID = nsnull;
496  rv = device->GetControllerId(&controllerID);
497  sbAutoNSMemPtr autoControllerID(controllerID);
498 
499  // Get the device controller.
500  nsCOMPtr<sbIDeviceController> deviceController;
501  if (NS_SUCCEEDED(rv)) {
502  rv = deviceControllerRegistrar->GetController
503  (controllerID,
504  getter_AddRefs(deviceController));
505  }
506  if (NS_FAILED(rv)) {
507  NS_WARNING("Failed to get device controller.");
508  deviceController = nsnull;
509  }
510 
511  // Release the device from the controller.
512  if (deviceController) {
513  rv = deviceController->ReleaseDevice(device);
514  if (NS_FAILED(rv))
515  NS_WARNING("Failed to release device.");
516  }
517 
518  // Unregister the device.
519  rv = deviceRegistrar->UnregisterDevice(device);
520  if (NS_FAILED(rv))
521  NS_WARNING("Failed to unregister device.");
522 
523  // Remove device from device list.
524  mDeviceList.Remove(aVolumeRefNum);
525 
526  // Send device removed notification.
528  sbIPDVariant(device).get(),
529  (sbIDeviceMarshall *) this);
530 
531  // Log progress.
532  FIELD_LOG(("Enter: HandleRemovedEvent\n"));
533 }
534 
535 
536 //------------------------------------------------------------------------------
537 //
538 // Internal iPod device marshall services.
539 //
540 //------------------------------------------------------------------------------
541 
546 nsresult
547 sbIPDMarshall::ScanForConnectedDevices()
548 {
549  OSStatus error;
550 
551  // Trace execution.
552  FIELD_LOG(("Enter: sbIPDMarshall::ScanForConnectedDevices\n"));
553 
554  // Search for iPod volumes and send iPod added events for all connected iPods.
555  for (ItemCount volumeIndex = 1; ; volumeIndex++) {
556  // Get the volume info.
557  FSVolumeInfo volumeInfo;
558  FSVolumeRefNum volumeRefNum;
559  HFSUniStr255 volumeName;
560  bzero(&volumeInfo, sizeof(volumeInfo));
561  error = FSGetVolumeInfo(kFSInvalidVolumeRefNum,
562  volumeIndex,
563  &volumeRefNum,
564  kFSVolInfoFSInfo,
565  &volumeInfo,
566  &volumeName,
567  NULL);
568  if (error == nsvErr)
569  break;
570  if (error != noErr)
571  continue;
572 
573  // Trace execution.
574  FIELD_LOG(("1: sbIPDMarshall::ScanForConnectedDevices %d\n", volumeRefNum));
575 
576  // Send iPod added event if volume is an iPod volume.
577  if (IsIPod(volumeRefNum)) {
578  HandleAddedEvent(volumeRefNum);
579  }
580  }
581 
582  // Trace execution.
583  FIELD_LOG(("Exit: sbIPDMarshall::ScanForConnectedDevices\n"));
584 
585  return NS_OK;
586 }
587 
588 
589 /*
590  * IsIPod
591  *
592  * --> volumeRefNum Device volume reference number.
593  *
594  * <-- True if device is an iPod.
595  *
596  * This function tests whether the device mounted on the volume specified by
597  * volumeRefNum is an iPod. If it is, this function returns true; otherwise, it
598  * returns false.
599  */
600 
601 PRBool
602 sbIPDMarshall::IsIPod(FSVolumeRefNum volumeRefNum)
603 {
604  GetVolParmsInfoBuffer volumeParms;
605  HParamBlockRec pb;
606  char *bsdDevName = NULL;
607  CFMutableDictionaryRef dictionaryRef;
608  io_service_t volNode = (io_service_t) NULL;
609  io_registry_entry_t scsiNode = (io_registry_entry_t) NULL;
610  PRBool isIPod = PR_FALSE;
611  OSStatus error = noErr;
612 
613  /* Trace execution. */
614  LOG("1: IPodDevIfIsIPod\n");
615 
616  /* Get the BSD device name. */
617  pb.ioParam.ioNamePtr = NULL;
618  pb.ioParam.ioVRefNum = volumeRefNum;
619  pb.ioParam.ioBuffer = (Ptr) &volumeParms;
620  pb.ioParam.ioReqCount = sizeof(volumeParms);
621  error = PBHGetVolParmsSync(&pb);
622  if (error == noErr) {
623  bsdDevName = (char *) volumeParms.vMDeviceID;
624  }
625 
626  /* Trace execution. */
627  LOG("2: IPodDevIfIsIPod %s\n", bsdDevName);
628 
629  /* Get the volume I/O registry node. */
630  if (error == noErr) {
631  dictionaryRef = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDevName);
632  if (dictionaryRef == NULL) {
633  error = -1;
634  }
635  }
636  if (error == noErr) {
637  volNode = IOServiceGetMatchingService(kIOMasterPortDefault,
638  dictionaryRef);
639  if (volNode == ((io_service_t) NULL)) {
640  error = -1;
641  }
642  }
643 
644  /* Trace execution. */
645  LOG("2: IPodDevIfIsIPod %d\n", (int) error);
646 
647  /* Search for a parent SCSI I/O node. */
648  if (error == noErr) {
649  io_registry_entry_t node = (io_registry_entry_t) NULL;
650  io_registry_entry_t parentNode;
651  kern_return_t result = KERN_SUCCESS;
652  Boolean done = FALSE;
653 
654  /* Search from the volume node. */
655  node = volNode;
656  while (!done) {
657  /* Get the node parent. */
658  result = IORegistryEntryGetParentEntry(node, kIOServicePlane,
659  &parentNode);
660  IOObjectRelease(node);
661  node = (io_registry_entry_t) NULL;
662  if (result == KERN_SUCCESS) {
663  node = parentNode;
664  } else {
665  done = TRUE;
666  }
667 
668  /* Check if parent is a SCSI peripheral device nub node. */
669  if (result == KERN_SUCCESS) {
670  if (IOObjectConformsTo(node, "IOSCSIPeripheralDeviceNub")) {
671  scsiNode = node;
672  node = (io_registry_entry_t) NULL;
673  done = TRUE;
674  }
675  }
676  }
677 
678  /* Clean up. */
679  if (node != ((io_registry_entry_t) NULL)) {
680  IOObjectRelease(node);
681  }
682  }
683 
684  /* Trace execution. */
685  LOG("3: IPodDevIfIsIPod 0x%08x\n", scsiNode);
686 
687  /* If a SCSI I/O node was found, check if device is an iPod. */
688  if ((error == noErr) && (scsiNode != ((io_registry_entry_t) NULL))) {
689  __CFString *vendorID = NULL;
690  __CFString *productID = NULL;
691 
692  /* Get the SCSI vendor and product IDs. */
693  vendorID = (__CFString *) IORegistryEntryCreateCFProperty(scsiNode,
694  CFSTR("Vendor Identification"), kCFAllocatorDefault, 0);
695  productID = (__CFString *) IORegistryEntryCreateCFProperty(scsiNode,
696  CFSTR("Product Identification"), kCFAllocatorDefault, 0);
697 
698  /* Trace execution. */
699  LOG("4: IPodDevIfIsIPod \"%s\" \"%s\"\n", (char *) vendorID,
700  (char *) productID);
701 
702  /* Check if SCSI device is an iPod. */
703  isIPod = PR_TRUE;
704  if (CFStringCompare(CFSTR("Apple"), vendorID, 0)) {
705  isIPod = PR_FALSE;
706  } else if (CFStringCompare(CFSTR("iPod"), productID, 0)) {
707  isIPod = PR_FALSE;
708  }
709 
710  /* Clean up. */
711  if (vendorID != NULL) {
712  CFRelease(vendorID);
713  }
714  if (productID != NULL) {
715  CFRelease(productID);
716  }
717  }
718 
719  /* Trace execution. */
720  LOG("5: IPodDevIfIsIPod %d\n", (int) error);
721 
722  /* Clean up. */
723  if (scsiNode != ((io_registry_entry_t) NULL)) {
724  IOObjectRelease(scsiNode);
725  }
726  if (volNode != ((io_service_t) NULL)) {
727  IOObjectRelease(volNode);
728  }
729 
730  return (isIPod);
731 }
732 
733 
734 /*
735  * GetVolumePath
736  *
737  * --> aVolumeRefNum Volume reference number.
738  * <-- aVolumePath Volume file path.
739  *
740  * This function returns in aVolumePath the file path to the volume specified
741  * by aVolumeRefNum.
742  */
743 
744 nsresult
745 sbIPDMarshall::GetVolumePath(FSVolumeRefNum aVolumeRefNum,
746  nsAString &aVolumePath)
747 {
748  OSStatus error;
749 
750  /* Get the volume root. */
751  FSRef volumeFSRef;
752  error = FSGetVolumeInfo(aVolumeRefNum,
753  0,
754  NULL,
755  kFSVolInfoNone,
756  NULL,
757  NULL,
758  &volumeFSRef);
759  NS_ENSURE_TRUE(error == noErr, NS_ERROR_FAILURE);
760 
761  /* Get the volume root URL. */
762  cfref<CFURLRef> volumeURLRef = CFURLCreateFromFSRef(kCFAllocatorDefault,
763  &volumeFSRef);
764  NS_ENSURE_TRUE(volumeURLRef, NS_ERROR_FAILURE);
765 
766  /* Get the volume root path CFStringRef. */
767  cfref<CFStringRef> volumePathStringRef =
768  CFURLCopyFileSystemPath(volumeURLRef,
769  kCFURLPOSIXPathStyle);
770  NS_ENSURE_TRUE(volumePathStringRef, NS_ERROR_FAILURE);
771 
772  /* Get the volume root path nsString. */
773  CFIndex volumePathLength = CFStringGetLength(volumePathStringRef);
774  PRUnichar* volumePath = aVolumePath.BeginWriting(volumePathLength);
775  NS_ENSURE_TRUE(volumePath, NS_ERROR_OUT_OF_MEMORY);
776  CFStringGetCharacters(volumePathStringRef,
777  CFRangeMake(0, volumePathLength),
778  volumePath);
779 
780  return NS_OK;
781 }
782 
783 
784 /*
785  * GetFirewireGUID
786  *
787  * --> aVolumeRefNum Volume reference number.
788  * <-- aFirewireGUID Volume Firewire GUID
789  *
790  * This function returns in aVolumePath the file path to the volume specified
791  * by aVolumeRefNum.
792  */
793 
794 nsresult
795 sbIPDMarshall::GetFirewireGUID(FSVolumeRefNum aVolumeRefNum,
796  nsAString &aFirewireGUID)
797 {
798  GetVolParmsInfoBuffer volumeParms;
799  HParamBlockRec pb;
800  char *bsdDevName = NULL;
801  CFMutableDictionaryRef dictionaryRef;
802  io_service_t volNode = (io_service_t) NULL;
803  io_registry_entry_t usbDevNode = (io_registry_entry_t) NULL;
804  OSStatus error = noErr;
805 
806  /* Get the BSD device name. */
807  pb.ioParam.ioNamePtr = NULL;
808  pb.ioParam.ioVRefNum = aVolumeRefNum;
809  pb.ioParam.ioBuffer = (Ptr) &volumeParms;
810  pb.ioParam.ioReqCount = sizeof(volumeParms);
811  error = PBHGetVolParmsSync(&pb);
812  if (error == noErr) {
813  bsdDevName = (char *) volumeParms.vMDeviceID;
814  }
815 
816  /* Get the volume I/O registry node. */
817  if (error == noErr) {
818  dictionaryRef = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDevName);
819  if (dictionaryRef == NULL) {
820  error = -1;
821  }
822  }
823  if (error == noErr) {
824  volNode = IOServiceGetMatchingService(kIOMasterPortDefault, dictionaryRef);
825  if (volNode == ((io_service_t) NULL)) {
826  error = -1;
827  }
828  }
829 
830  /* Search for a parent USB device node. */
831  if (error == noErr) {
832  io_registry_entry_t node = (io_registry_entry_t) NULL;
833  io_registry_entry_t parentNode;
834  kern_return_t result = KERN_SUCCESS;
835  Boolean done = FALSE;
836 
837  /* Search from the volume node. */
838  node = volNode;
839  IOObjectRetain(volNode);
840  while (!done) {
841  /* Get the node parent. */
842  result = IORegistryEntryGetParentEntry(node, kIOServicePlane,
843  &parentNode);
844  IOObjectRelease(node);
845  node = (io_registry_entry_t) NULL;
846  if (result == KERN_SUCCESS) {
847  node = parentNode;
848  } else {
849  done = TRUE;
850  }
851 
852  /* Check if parent is a USB device node. */
853  if (result == KERN_SUCCESS) {
854  if (IOObjectConformsTo(node, "IOUSBDevice")) {
855  usbDevNode = node;
856  node = (io_registry_entry_t) NULL;
857  done = TRUE;
858  }
859  }
860  }
861 
862  /* Clean up. */
863  if (node != ((io_registry_entry_t) NULL)) {
864  IOObjectRelease(node);
865  }
866  }
867 
868  /* If a USB device node was found, and the */
869  /* device is an iPod, get the serial number. */
870  if ((error == noErr) && (usbDevNode != ((io_registry_entry_t) NULL))) {
871  __CFString *serialNumber = NULL;
872  char cSerialNumber[256];
873  Boolean success;
874 
875  /* Get the serial number. */
876  serialNumber = (__CFString *) IORegistryEntryCreateCFProperty(usbDevNode,
877  CFSTR("USB Serial Number"), kCFAllocatorDefault, 0);
878 
879  /* Assign the Firewire GUID. */
880  if (serialNumber) {
881  success = CFStringGetCString(serialNumber, cSerialNumber,
882  sizeof(cSerialNumber), kCFStringEncodingUTF8);
883  if (success) {
884  aFirewireGUID.AssignLiteral(cSerialNumber);
885  }
886  }
887 
888  /* Clean up. */
889  if (serialNumber != NULL) {
890  CFRelease(serialNumber);
891  }
892  }
893 
894  /* Clean up. */
895  if (usbDevNode != ((io_registry_entry_t) NULL)) {
896  IOObjectRelease(usbDevNode);
897  }
898  if (volNode != ((io_service_t) NULL)) {
899  IOObjectRelease(volNode);
900  }
901 
902  return (error == noErr) ? NS_OK : NS_ERROR_UNEXPECTED;
903 }
904 
905 nsresult
906 sbIPDMarshall::RemoveDevice(sbIDevice* aDevice)
907 {
908  return NS_ERROR_NOT_IMPLEMENTED;
909 }
#define SB_PRLOG_SETUP(x)
Definition: sbDebugUtils.h:115
return NS_OK
nsresult CreateAndDispatchDeviceManagerEvent(PRUint32 aType, nsIVariant *aData, nsISupports *aOrigin, PRUint32 aDeviceState, PRBool aAsync)
Definition: sbIPDUtils.cpp:72
#define LOG(args)
Songbird iPod Device Utility Definitions.
NS_DECL_ISUPPORTS NS_DECL_SBIDEVICEMARSHALL NS_DECL_NSICLASSINFO sbIPDMarshall()
friend class sbAutoFinalizeVolumeMonitor
NS_IMPL_THREADSAFE_CI(sbMediaListEnumeratorWrapper)
const unsigned long EVENT_DEVICE_ADDED
NS_IMPL_THREADSAFE_RELEASE(sbRequestItem)
NS_IMPL_THREADSAFE_ADDREF(sbRequestItem)
sbIDeviceController * FindCompatibleControllers(nsIPropertyBag *deviceParams)
#define FIELD_LOG(args)
Definition: sbIPDLog.h:126
unique done
#define SB_IPDMARSHALL_CLASSNAME
Definition: sbIPDMarshall.h:74
Songbird iPod Device Logging Definitions.
const unsigned long EVENT_DEVICE_REMOVED
let node
[UNIMPLEMENTED UNTIL AFTER 0.3]
_updateCookies aName
virtual ~sbIPDMarshall()
#define SB_IPDMARSHALL_CID
Definition: sbIPDMarshall.h:76
#define SB_DEVICE_CONTROLLER_CATEGORY
readonly attribute nsIDPtr id
NS_INTERFACE_MAP_END NS_IMPL_CI_INTERFACE_GETTER1(CDatabaseQuery, sbIDatabaseQuery) CDatabaseQuery