1 | /** $Id: $ */
|
---|
2 | /** @file
|
---|
3 | * Main - Darwin IOKit Routines.
|
---|
4 | *
|
---|
5 | * Because IOKit makes use of COM like interfaces, it does not mix very
|
---|
6 | * well with COM/XPCOM and must therefore be isolated from it using a
|
---|
7 | * simpler C interface.
|
---|
8 | */
|
---|
9 |
|
---|
10 | /*
|
---|
11 | * Copyright (C) 2006 InnoTek Systemberatung GmbH
|
---|
12 | *
|
---|
13 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
14 | * available from http://www.virtualbox.org. This file is free software;
|
---|
15 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
16 | * General Public License as published by the Free Software Foundation,
|
---|
17 | * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
|
---|
18 | * distribution. VirtualBox OSE is distributed in the hope that it will
|
---|
19 | * be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
20 | *
|
---|
21 | * If you received this file as part of a commercial VirtualBox
|
---|
22 | * distribution, then only the terms of your commercial VirtualBox
|
---|
23 | * license agreement apply instead of the previous paragraph.
|
---|
24 | */
|
---|
25 |
|
---|
26 |
|
---|
27 | /*******************************************************************************
|
---|
28 | * Header Files *
|
---|
29 | *******************************************************************************/
|
---|
30 | #include <mach/mach.h>
|
---|
31 | #include <Carbon/Carbon.h>
|
---|
32 | #include <IOKit/IOKitLib.h>
|
---|
33 | #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
---|
34 | #include <IOKit/scsi-commands/SCSITaskLib.h>
|
---|
35 | #include <mach/mach_error.h>
|
---|
36 |
|
---|
37 | #include <iprt/mem.h>
|
---|
38 | #include <iprt/string.h>
|
---|
39 | #include <iprt/assert.h>
|
---|
40 |
|
---|
41 | #include "iokit.h"
|
---|
42 |
|
---|
43 |
|
---|
44 | /*******************************************************************************
|
---|
45 | * Global Variables *
|
---|
46 | *******************************************************************************/
|
---|
47 | /** The IO Master Port. */
|
---|
48 | static mach_port_t g_MasterPort = NULL;
|
---|
49 |
|
---|
50 |
|
---|
51 |
|
---|
52 | /**
|
---|
53 | * Enumerate the DVD drives returning a FIFO of device name strings.
|
---|
54 | *
|
---|
55 | * @returns Pointer to the head.
|
---|
56 | * The caller is responsible for calling RTMemFree() on each of the nodes.
|
---|
57 | */
|
---|
58 | PDARWINDVD DarwinGetDVDDrives(void)
|
---|
59 | {
|
---|
60 | PDARWINDVD pHead = NULL;
|
---|
61 | PDARWINDVD pTail = NULL;
|
---|
62 |
|
---|
63 | /*
|
---|
64 | * Open the master port on the first invocation.
|
---|
65 | */
|
---|
66 | if (!g_MasterPort)
|
---|
67 | {
|
---|
68 | kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &g_MasterPort);
|
---|
69 | AssertReturn(krc == KERN_SUCCESS, NULL);
|
---|
70 | }
|
---|
71 |
|
---|
72 | /*
|
---|
73 | * Create a matching dictionary for searching for DVD services in the IOKit.
|
---|
74 | *
|
---|
75 | * [If I understand this correctly, plain CDROMs doesn't show up as
|
---|
76 | * IODVDServices. Too keep things simple, we will only support DVDs
|
---|
77 | * until somebody complains about it and we get hardware to test it on.
|
---|
78 | * (Unless I'm much mistaken, there aren't any (orignal) intel macs with
|
---|
79 | * plain cdroms.)]
|
---|
80 | */
|
---|
81 | CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IODVDServices");
|
---|
82 | AssertReturn(RefMatchingDict, NULL);
|
---|
83 |
|
---|
84 | /*
|
---|
85 | * do the search and get a collection of keyboards.
|
---|
86 | */
|
---|
87 | io_iterator_t DVDServices = NULL;
|
---|
88 | IOReturn rc = IOServiceGetMatchingServices(g_MasterPort, RefMatchingDict, &DVDServices);
|
---|
89 | AssertMsgReturn(rc == kIOReturnSuccess, ("rc=%d\n", rc), NULL);
|
---|
90 | RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
|
---|
91 |
|
---|
92 | /*
|
---|
93 | * Enumerate the DVD drives (services).
|
---|
94 | * (This enumeration must be identical to the one performed in DrvHostBase.cpp.)
|
---|
95 | */
|
---|
96 | unsigned i = 0;
|
---|
97 | io_object_t DVDService;
|
---|
98 | while ((DVDService = IOIteratorNext(DVDServices)) != 0)
|
---|
99 | {
|
---|
100 | /*
|
---|
101 | * Get the properties we use to identify the DVD drive.
|
---|
102 | *
|
---|
103 | * While there is a (weird 12 byte) GUID, it isn't persistent
|
---|
104 | * accross boots. So, we have to use a combination of the
|
---|
105 | * vendor name and product name properties with an optional
|
---|
106 | * sequence number for identification.
|
---|
107 | */
|
---|
108 | CFMutableDictionaryRef PropsRef = 0;
|
---|
109 | kern_return_t krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);
|
---|
110 | if (krc == KERN_SUCCESS)
|
---|
111 | {
|
---|
112 | /* Get the Device Characteristics dictionary. */
|
---|
113 | CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));
|
---|
114 | if (DevCharRef)
|
---|
115 | {
|
---|
116 | /* The vendor name. */
|
---|
117 | char szVendor[128];
|
---|
118 | char *pszVendor = &szVendor[0];
|
---|
119 | CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey));
|
---|
120 | if ( ValueRef
|
---|
121 | && CFGetTypeID(ValueRef) == CFStringGetTypeID()
|
---|
122 | && CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8))
|
---|
123 | pszVendor = RTStrStrip(szVendor);
|
---|
124 | else
|
---|
125 | *pszVendor = '\0';
|
---|
126 |
|
---|
127 | /* The product name. */
|
---|
128 | char szProduct[128];
|
---|
129 | char *pszProduct = &szProduct[0];
|
---|
130 | ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey));
|
---|
131 | if ( ValueRef
|
---|
132 | && CFGetTypeID(ValueRef) == CFStringGetTypeID()
|
---|
133 | && CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8))
|
---|
134 | pszProduct = RTStrStrip(szProduct);
|
---|
135 | else
|
---|
136 | *pszProduct = '\0';
|
---|
137 |
|
---|
138 | /* Construct the name and check for duplicates. */
|
---|
139 | char szName[256 + 32];
|
---|
140 | if (*pszVendor || *pszProduct)
|
---|
141 | {
|
---|
142 | if (*pszVendor && *pszProduct)
|
---|
143 | RTStrPrintf(szName, sizeof(szName), "%s %s", pszVendor, pszProduct);
|
---|
144 | else
|
---|
145 | strcpy(szName, *pszVendor ? pszVendor : pszProduct);
|
---|
146 |
|
---|
147 | for (PDARWINDVD pCur = pHead; pCur; pCur = pCur->pNext)
|
---|
148 | {
|
---|
149 | if (!strcmp(szName, pCur->szName))
|
---|
150 | {
|
---|
151 | if (*pszVendor && *pszProduct)
|
---|
152 | RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", pszVendor, pszProduct, i);
|
---|
153 | else
|
---|
154 | RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
|
---|
155 | break;
|
---|
156 | }
|
---|
157 | }
|
---|
158 | }
|
---|
159 | else
|
---|
160 | RTStrPrintf(szName, sizeof(szName), "(#%u)", i);
|
---|
161 |
|
---|
162 | /* Create the device. */
|
---|
163 | size_t cbName = strlen(szName) + 1;
|
---|
164 | PDARWINDVD pNew = (PDARWINDVD)RTMemAlloc(RT_OFFSETOF(DARWINDVD, szName[cbName]));
|
---|
165 | if (pNew)
|
---|
166 | {
|
---|
167 | pNew->pNext = NULL;
|
---|
168 | memcpy(pNew->szName, szName, cbName);
|
---|
169 | if (pTail)
|
---|
170 | pTail = pTail->pNext = pNew;
|
---|
171 | else
|
---|
172 | pTail = pHead = pNew;
|
---|
173 | }
|
---|
174 | }
|
---|
175 | CFRelease(PropsRef);
|
---|
176 | }
|
---|
177 | else
|
---|
178 | AssertMsgFailed(("krc=%#x\n", krc));
|
---|
179 |
|
---|
180 | IOObjectRelease(DVDService);
|
---|
181 | i++;
|
---|
182 | }
|
---|
183 |
|
---|
184 | IOObjectRelease(DVDServices);
|
---|
185 |
|
---|
186 | return pHead;
|
---|
187 | }
|
---|