diff options
Diffstat (limited to 'rbutil/ipodpatcher/ipodio-posix.c')
-rw-r--r-- | rbutil/ipodpatcher/ipodio-posix.c | 154 |
1 files changed, 146 insertions, 8 deletions
diff --git a/rbutil/ipodpatcher/ipodio-posix.c b/rbutil/ipodpatcher/ipodio-posix.c index 065aae6303..881c09b54f 100644 --- a/rbutil/ipodpatcher/ipodio-posix.c +++ b/rbutil/ipodpatcher/ipodio-posix.c | |||
@@ -19,6 +19,7 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | |||
22 | #include <stdio.h> | 23 | #include <stdio.h> |
23 | #include <unistd.h> | 24 | #include <unistd.h> |
24 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -53,7 +54,7 @@ static void get_geometry(struct ipod_t* ipod) | |||
53 | } | 54 | } |
54 | } | 55 | } |
55 | 56 | ||
56 | /* Linux SCSI Inquiry code based on the documentation and example code from | 57 | /* Linux SCSI Inquiry code based on the documentation and example code from |
57 | http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html | 58 | http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html |
58 | */ | 59 | */ |
59 | 60 | ||
@@ -84,7 +85,7 @@ int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, | |||
84 | cdb[3] = 0; | 85 | cdb[3] = 0; |
85 | cdb[4] = 0xff; | 86 | cdb[4] = 0xff; |
86 | cdb[5] = 0; /* For control filed, just use 0 */ | 87 | cdb[5] = 0; /* For control filed, just use 0 */ |
87 | 88 | ||
88 | hdr.dxfer_direction = SG_DXFER_FROM_DEV; | 89 | hdr.dxfer_direction = SG_DXFER_FROM_DEV; |
89 | hdr.cmdp = cdb; | 90 | hdr.cmdp = cdb; |
90 | hdr.cmd_len = 6; | 91 | hdr.cmd_len = 6; |
@@ -123,7 +124,13 @@ int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, | |||
123 | } | 124 | } |
124 | 125 | ||
125 | #elif defined(__APPLE__) && defined(__MACH__) | 126 | #elif defined(__APPLE__) && defined(__MACH__) |
127 | /* OS X IOKit includes don't like VERSION being defined! */ | ||
128 | #undef VERSION | ||
126 | #include <sys/disk.h> | 129 | #include <sys/disk.h> |
130 | #include <CoreFoundation/CoreFoundation.h> | ||
131 | #include <IOKit/IOKitLib.h> | ||
132 | #include <IOKit/scsi-commands/SCSITaskLib.h> | ||
133 | #include <IOKit/scsi-commands/SCSICommandOperationCodes.h> | ||
127 | #define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE | 134 | #define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE |
128 | 135 | ||
129 | /* TODO: Implement this function for Mac OS X */ | 136 | /* TODO: Implement this function for Mac OS X */ |
@@ -137,12 +144,143 @@ static void get_geometry(struct ipod_t* ipod) | |||
137 | int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, | 144 | int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, |
138 | unsigned char* buf, int bufsize) | 145 | unsigned char* buf, int bufsize) |
139 | { | 146 | { |
140 | /* TODO: Implement for OS X */ | 147 | /* OS X doesn't allow to simply send out a SCSI inquiry request but |
148 | * requires registering an interface handler first. | ||
149 | * Currently this is done on each inquiry request which is somewhat | ||
150 | * inefficient but the current ipodpatcher API doesn't really fit here. | ||
151 | * Based on the documentation in Apple's document | ||
152 | * "SCSI Architecture Model Device Interface Guide". | ||
153 | * | ||
154 | * WARNING: this code currently doesn't take the selected device into | ||
155 | * account. It simply looks for an Ipod on the system and uses | ||
156 | * the first match. | ||
157 | */ | ||
141 | (void)ipod; | 158 | (void)ipod; |
142 | (void)page_code; | 159 | int result = 0; |
143 | (void)buf; | 160 | /* first, create a dictionary to match the device. This is needed to get the |
144 | (void)bufsize; | 161 | * service. */ |
145 | return -1; | 162 | CFMutableDictionaryRef match_dict; |
163 | match_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); | ||
164 | if(match_dict == NULL) | ||
165 | return -1; | ||
166 | |||
167 | /* set value to match. In case of the Ipod this is "iPodUserClientDevice". */ | ||
168 | CFMutableDictionaryRef sub_dict; | ||
169 | sub_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); | ||
170 | CFDictionarySetValue(sub_dict, CFSTR(kIOPropertySCSITaskDeviceCategory), | ||
171 | CFSTR("iPodUserClientDevice")); | ||
172 | CFDictionarySetValue(match_dict, CFSTR(kIOPropertyMatchKey), sub_dict); | ||
173 | |||
174 | if(sub_dict == NULL) | ||
175 | return -1; | ||
176 | |||
177 | /* get an iterator for searching for the service. */ | ||
178 | kern_return_t kr; | ||
179 | io_iterator_t iterator = IO_OBJECT_NULL; | ||
180 | /* get matching services from IO registry. Consumes one reference to | ||
181 | * the dictionary, so no need to release that. */ | ||
182 | kr = IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iterator); | ||
183 | |||
184 | if(!iterator | (kr != kIOReturnSuccess)) | ||
185 | return -1; | ||
186 | |||
187 | /* get interface and obtain exclusive access */ | ||
188 | SInt32 score; | ||
189 | HRESULT herr; | ||
190 | kern_return_t err; | ||
191 | IOCFPlugInInterface **plugin_interface = NULL; | ||
192 | SCSITaskDeviceInterface **interface = NULL; | ||
193 | io_service_t device = IO_OBJECT_NULL; | ||
194 | device = IOIteratorNext(iterator); | ||
195 | |||
196 | err = IOCreatePlugInInterfaceForService(device, kIOSCSITaskDeviceUserClientTypeID, | ||
197 | kIOCFPlugInInterfaceID, &plugin_interface, | ||
198 | &score); | ||
199 | |||
200 | if(err != noErr) { | ||
201 | return -1; | ||
202 | } | ||
203 | /* query the plugin interface for task interface */ | ||
204 | herr = (*plugin_interface)->QueryInterface(plugin_interface, | ||
205 | CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), (LPVOID*)&interface); | ||
206 | if(herr != S_OK) { | ||
207 | IODestroyPlugInInterface(plugin_interface); | ||
208 | return -1; | ||
209 | } | ||
210 | |||
211 | err = (*interface)->ObtainExclusiveAccess(interface); | ||
212 | if(err != noErr) { | ||
213 | (*interface)->Release(interface); | ||
214 | IODestroyPlugInInterface(plugin_interface); | ||
215 | return -1; | ||
216 | } | ||
217 | |||
218 | /* do the inquiry */ | ||
219 | SCSITaskInterface **task = NULL; | ||
220 | |||
221 | task = (*interface)->CreateSCSITask(interface); | ||
222 | if(task != NULL) { | ||
223 | kern_return_t err; | ||
224 | SCSITaskStatus task_status; | ||
225 | IOVirtualRange* range; | ||
226 | SCSI_Sense_Data sense_data; | ||
227 | SCSICommandDescriptorBlock cdb; | ||
228 | UInt64 transfer_count = 0; | ||
229 | memset(buf, 0, bufsize); | ||
230 | /* allocate virtual range for buffer. */ | ||
231 | range = (IOVirtualRange*) malloc(sizeof(IOVirtualRange)); | ||
232 | memset(&sense_data, 0, sizeof(sense_data)); | ||
233 | memset(cdb, 0, sizeof(cdb)); | ||
234 | /* set up range. address is buffer address, length is request size. */ | ||
235 | range->address = (IOVirtualAddress)buf; | ||
236 | range->length = bufsize; | ||
237 | /* setup CDB */ | ||
238 | cdb[0] = 0x12; /* inquiry */ | ||
239 | cdb[1] = 1; | ||
240 | cdb[2] = page_code; | ||
241 | cdb[4] = bufsize; | ||
242 | |||
243 | /* set cdb in task */ | ||
244 | err = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte); | ||
245 | if(err != kIOReturnSuccess) { | ||
246 | result = -1; | ||
247 | goto cleanup; | ||
248 | } | ||
249 | err = (*task)->SetScatterGatherEntries(task, range, 1, bufsize, | ||
250 | kSCSIDataTransfer_FromTargetToInitiator); | ||
251 | if(err != kIOReturnSuccess) { | ||
252 | result = -1; | ||
253 | goto cleanup; | ||
254 | } | ||
255 | /* set timeout */ | ||
256 | err = (*task)->SetTimeoutDuration(task, 10000); | ||
257 | if(err != kIOReturnSuccess) { | ||
258 | result = -1; | ||
259 | goto cleanup; | ||
260 | } | ||
261 | |||
262 | /* request data */ | ||
263 | err = (*task)->ExecuteTaskSync(task, &sense_data, &task_status, &transfer_count); | ||
264 | if(err != kIOReturnSuccess) { | ||
265 | result = -1; | ||
266 | goto cleanup; | ||
267 | } | ||
268 | /* cleanup */ | ||
269 | free(range); | ||
270 | |||
271 | /* release task interface */ | ||
272 | (*task)->Release(task); | ||
273 | } | ||
274 | else { | ||
275 | result = -1; | ||
276 | } | ||
277 | cleanup: | ||
278 | /* cleanup interface */ | ||
279 | (*interface)->ReleaseExclusiveAccess(interface); | ||
280 | (*interface)->Release(interface); | ||
281 | IODestroyPlugInInterface(plugin_interface); | ||
282 | |||
283 | return result; | ||
146 | } | 284 | } |
147 | 285 | ||
148 | #else | 286 | #else |
@@ -189,7 +327,7 @@ int ipod_open(struct ipod_t* ipod, int silent) | |||
189 | if (!silent) { | 327 | if (!silent) { |
190 | fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n" | 328 | fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n" |
191 | ,ipod->sector_size); | 329 | ,ipod->sector_size); |
192 | } | 330 | } |
193 | } | 331 | } |
194 | 332 | ||
195 | get_geometry(ipod); | 333 | get_geometry(ipod); |