From c8d13b6a7dc76e80663ca71338fed4020e2be132 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Sat, 30 Jan 2010 17:02:37 +0000 Subject: Implement ipod_scsi_inquiry() on OS X. This implements the basic functionality for sending inquiries on OS X. The current implementation has some limitations: - it will not respect the selected device but pick the first Ipod found. - it is inefficient due to the way ipodpatcher expects this which doesn't really match how it works on OS X. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24382 a1c6a512-1295-4272-9138-f99709370657 --- rbutil/ipodpatcher/Makefile | 14 +++- rbutil/ipodpatcher/ipodio-posix.c | 154 ++++++++++++++++++++++++++++++++++++-- rbutil/rbutilqt/rbutilqt.pro | 2 +- 3 files changed, 157 insertions(+), 13 deletions(-) diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile index 34b4dd6b43..7c203a94aa 100644 --- a/rbutil/ipodpatcher/Makefile +++ b/rbutil/ipodpatcher/Makefile @@ -39,8 +39,14 @@ OUTPUT=ipodpatcher CROSS=i586-mingw32msvc- endif endif +ifeq ($(findstring Darwin,$(shell uname)),Darwin) +# building against SDK 10.4 is not compatible with gcc-4.2 (default on newer Xcode) +# might need adjustment for older Xcode. +NATIVECC ?= gcc-4.0 +CFLAGS+=-framework CoreFoundation -framework IOKit -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 +endif -NATIVECC = gcc +NATIVECC ?= gcc CC = $(CROSS)gcc WINDRES = $(CROSS)windres @@ -49,7 +55,7 @@ SRC = main.c ipodpatcher.c fat32format.c arc4.c all: $(OUTPUT) ipodpatcher: $(SRC) ipodio-posix.c $(BOOTSRC) - gcc $(CFLAGS) -o ipodpatcher $(SRC) ipodio-posix.c $(BOOTSRC) + $(NATIVECC) $(CFLAGS) -o ipodpatcher $(SRC) ipodio-posix.c $(BOOTSRC) strip ipodpatcher ipodpatcher.exe: $(SRC) ipodio-win32.c ipodio-win32-scsi.c ipodpatcher-rc.o $(BOOTSRC) @@ -63,11 +69,11 @@ ipodpatcher-mac: ipodpatcher-i386 ipodpatcher-ppc lipo -create ipodpatcher-ppc ipodpatcher-i386 -output ipodpatcher-mac ipodpatcher-i386: $(SRC) ipodio-posix.c $(BOOTSRC) - gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -arch i386 $(CFLAGS) -o ipodpatcher-i386 $(SRC) ipodio-posix.c $(BOOTSRC) + $(NATIVECC) -arch i386 $(CFLAGS) -o ipodpatcher-i386 $(SRC) ipodio-posix.c $(BOOTSRC) strip ipodpatcher-i386 ipodpatcher-ppc: $(SRC) ipodio-posix.c $(BOOTSRC) - gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -arch ppc $(CFLAGS) -o ipodpatcher-ppc $(SRC) ipodio-posix.c $(BOOTSRC) + $(NATIVECC) -arch ppc $(CFLAGS) -o ipodpatcher-ppc $(SRC) ipodio-posix.c $(BOOTSRC) strip ipodpatcher-ppc ipod2c: ipod2c.c 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 @@ * ****************************************************************************/ + #include #include #include @@ -53,7 +54,7 @@ static void get_geometry(struct ipod_t* ipod) } } -/* Linux SCSI Inquiry code based on the documentation and example code from +/* Linux SCSI Inquiry code based on the documentation and example code from http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html */ @@ -84,7 +85,7 @@ int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, cdb[3] = 0; cdb[4] = 0xff; cdb[5] = 0; /* For control filed, just use 0 */ - + hdr.dxfer_direction = SG_DXFER_FROM_DEV; hdr.cmdp = cdb; hdr.cmd_len = 6; @@ -123,7 +124,13 @@ int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, } #elif defined(__APPLE__) && defined(__MACH__) +/* OS X IOKit includes don't like VERSION being defined! */ +#undef VERSION #include +#include +#include +#include +#include #define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE /* TODO: Implement this function for Mac OS X */ @@ -137,12 +144,143 @@ static void get_geometry(struct ipod_t* ipod) int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code, unsigned char* buf, int bufsize) { - /* TODO: Implement for OS X */ + /* OS X doesn't allow to simply send out a SCSI inquiry request but + * requires registering an interface handler first. + * Currently this is done on each inquiry request which is somewhat + * inefficient but the current ipodpatcher API doesn't really fit here. + * Based on the documentation in Apple's document + * "SCSI Architecture Model Device Interface Guide". + * + * WARNING: this code currently doesn't take the selected device into + * account. It simply looks for an Ipod on the system and uses + * the first match. + */ (void)ipod; - (void)page_code; - (void)buf; - (void)bufsize; - return -1; + int result = 0; + /* first, create a dictionary to match the device. This is needed to get the + * service. */ + CFMutableDictionaryRef match_dict; + match_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); + if(match_dict == NULL) + return -1; + + /* set value to match. In case of the Ipod this is "iPodUserClientDevice". */ + CFMutableDictionaryRef sub_dict; + sub_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); + CFDictionarySetValue(sub_dict, CFSTR(kIOPropertySCSITaskDeviceCategory), + CFSTR("iPodUserClientDevice")); + CFDictionarySetValue(match_dict, CFSTR(kIOPropertyMatchKey), sub_dict); + + if(sub_dict == NULL) + return -1; + + /* get an iterator for searching for the service. */ + kern_return_t kr; + io_iterator_t iterator = IO_OBJECT_NULL; + /* get matching services from IO registry. Consumes one reference to + * the dictionary, so no need to release that. */ + kr = IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iterator); + + if(!iterator | (kr != kIOReturnSuccess)) + return -1; + + /* get interface and obtain exclusive access */ + SInt32 score; + HRESULT herr; + kern_return_t err; + IOCFPlugInInterface **plugin_interface = NULL; + SCSITaskDeviceInterface **interface = NULL; + io_service_t device = IO_OBJECT_NULL; + device = IOIteratorNext(iterator); + + err = IOCreatePlugInInterfaceForService(device, kIOSCSITaskDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &plugin_interface, + &score); + + if(err != noErr) { + return -1; + } + /* query the plugin interface for task interface */ + herr = (*plugin_interface)->QueryInterface(plugin_interface, + CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), (LPVOID*)&interface); + if(herr != S_OK) { + IODestroyPlugInInterface(plugin_interface); + return -1; + } + + err = (*interface)->ObtainExclusiveAccess(interface); + if(err != noErr) { + (*interface)->Release(interface); + IODestroyPlugInInterface(plugin_interface); + return -1; + } + + /* do the inquiry */ + SCSITaskInterface **task = NULL; + + task = (*interface)->CreateSCSITask(interface); + if(task != NULL) { + kern_return_t err; + SCSITaskStatus task_status; + IOVirtualRange* range; + SCSI_Sense_Data sense_data; + SCSICommandDescriptorBlock cdb; + UInt64 transfer_count = 0; + memset(buf, 0, bufsize); + /* allocate virtual range for buffer. */ + range = (IOVirtualRange*) malloc(sizeof(IOVirtualRange)); + memset(&sense_data, 0, sizeof(sense_data)); + memset(cdb, 0, sizeof(cdb)); + /* set up range. address is buffer address, length is request size. */ + range->address = (IOVirtualAddress)buf; + range->length = bufsize; + /* setup CDB */ + cdb[0] = 0x12; /* inquiry */ + cdb[1] = 1; + cdb[2] = page_code; + cdb[4] = bufsize; + + /* set cdb in task */ + err = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte); + if(err != kIOReturnSuccess) { + result = -1; + goto cleanup; + } + err = (*task)->SetScatterGatherEntries(task, range, 1, bufsize, + kSCSIDataTransfer_FromTargetToInitiator); + if(err != kIOReturnSuccess) { + result = -1; + goto cleanup; + } + /* set timeout */ + err = (*task)->SetTimeoutDuration(task, 10000); + if(err != kIOReturnSuccess) { + result = -1; + goto cleanup; + } + + /* request data */ + err = (*task)->ExecuteTaskSync(task, &sense_data, &task_status, &transfer_count); + if(err != kIOReturnSuccess) { + result = -1; + goto cleanup; + } + /* cleanup */ + free(range); + + /* release task interface */ + (*task)->Release(task); + } + else { + result = -1; + } +cleanup: + /* cleanup interface */ + (*interface)->ReleaseExclusiveAccess(interface); + (*interface)->Release(interface); + IODestroyPlugInInterface(plugin_interface); + + return result; } #else @@ -189,7 +327,7 @@ int ipod_open(struct ipod_t* ipod, int silent) if (!silent) { fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n" ,ipod->sector_size); - } + } } get_geometry(ipod); diff --git a/rbutil/rbutilqt/rbutilqt.pro b/rbutil/rbutilqt/rbutilqt.pro index a1983719b4..f2f96e70d8 100644 --- a/rbutil/rbutilqt/rbutilqt.pro +++ b/rbutil/rbutilqt/rbutilqt.pro @@ -276,7 +276,7 @@ macx { QMAKE_LFLAGS_PPC=-mmacosx-version-min=10.4 -arch ppc QMAKE_LFLAGS_X86=-mmacosx-version-min=10.4 -arch i386 CONFIG+=x86 ppc - LIBS += -L/usr/local/lib -framework IOKit -lz + LIBS += -L/usr/local/lib -framework IOKit -framework CoreFoundation -lz INCLUDEPATH += /usr/local/include QMAKE_INFO_PLIST = Info.plist RC_FILE = icons/rbutilqt.icns -- cgit v1.2.3