kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			Added support for the MacOS X IOKit SCSI Architecture Model API. Added support
for Firewire scanners. Patch from Guy Brooker <guy_brooker@mac.com>.merge-requests/1/head
							rodzic
							
								
									a66b94a915
								
							
						
					
					
						commit
						2cf12103d8
					
				|  | @ -1,3 +1,9 @@ | |||
| 2003-08-21  Henning Meier-Geinitz <henning@meier-geinitz.de> | ||||
| 
 | ||||
| 	* README.darwin sanei/sanei_scsi.c: Added support for the | ||||
| 	  MacOS X IOKit SCSI Architecture Model API. Added support for | ||||
| 	  Firewire scanners. Patch from Guy Brooker <guy_brooker@mac.com>. | ||||
| 
 | ||||
| 2003-07-22  Oliver Schwartz <Oliver.Schwartz@gmx.de> | ||||
| 
 | ||||
| 	* backend/snapscan.c backend/snapscan.h backend/snapscan-scsi.c | ||||
|  |  | |||
|  | @ -19,12 +19,12 @@ sm3600 backend, disable sm3600 in dll.conf if you don't need it. | |||
| Backends that use the function "fork" may not work at least with USB scanners. | ||||
| That's a limitation of MacOS X (doesn't use file descriptors for USB access). | ||||
| 
 | ||||
| SCSI-scanners: | ||||
| -------------- | ||||
| There is support for SCSI scanners but hasn't had much testing. Please send  | ||||
| failure and success reports to the sane-devel mailing list. At least | ||||
| the Epson Perfection 1640SU and the CANON IX-06015C (CanoScan 600) are reported | ||||
| to work. | ||||
| SCSI-scanners and Firewire scanners: | ||||
| ------------------------------------ | ||||
| There is support for SCSI and Firewire scanners but hasn't had much | ||||
| testing. Please send failure and success reports to the sane-devel mailing | ||||
| list. At least the Epson Perfection 1640SU and the CANON IX-06015C (CanoScan | ||||
| 600) are reported to work. | ||||
| 
 | ||||
| sane-find-scanner is not able to find SCSI scanners on MacOS X yet. | ||||
| 
 | ||||
|  | @ -41,4 +41,4 @@ Parport-scanners: | |||
| I don't have any information about these. Please contact me or the SANE mailing | ||||
| list if you succeeded in using one of these. | ||||
| 
 | ||||
| 2003-06-12 Henning Meier-Geinitz <henning@meier-geinitz.de> | ||||
| 2003-08-21 Henning Meier-Geinitz <henning@meier-geinitz.de> | ||||
|  |  | |||
|  | @ -179,13 +179,42 @@ | |||
| # include <apollo/time.h> | ||||
| # include "sanei_DomainOS.h" | ||||
| #endif | ||||
| 
 | ||||
| /* OS X */ | ||||
| 
 | ||||
| #if defined (HAVE_IOKIT_IOKITLIB_H) | ||||
| # define USE MACOSX_INTERFACE | ||||
| 
 | ||||
| # if defined (OSX_ONLY_10_2_API) | ||||
| /* Ensure only one of these two defines are set if any */ | ||||
| #  if defined (OSX_ONLY_10_1_API) | ||||
| #   undef OSX_ONLY_10_1_API | ||||
| #  endif | ||||
| # endif | ||||
| 
 | ||||
| # include <CoreFoundation/CoreFoundation.h> | ||||
| # include <IOKit/IOKitLib.h> | ||||
| # include <IOKit/IOCFPlugIn.h> | ||||
| # include <IOKit/cdb/IOSCSILib.h> | ||||
| #endif | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_2_API | ||||
| 
 | ||||
| /* Includes for old API */ | ||||
| 
 | ||||
| #  include <IOKit/IOCFPlugIn.h> | ||||
| #  include <IOKit/cdb/IOSCSILib.h> | ||||
| # endif | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_1_API | ||||
| 
 | ||||
| /* Includes for STUC API */ | ||||
| /* The def of VERSION causes problems in the following include files */ | ||||
| 
 | ||||
| #  undef VERSION | ||||
| #  include <IOKit/scsi-commands/SCSICmds_INQUIRY_Definitions.h> | ||||
| #  include <IOKit/scsi-commands/SCSICommandOperationCodes.h> | ||||
| #  include <IOKit/scsi-commands/SCSITaskLib.h> | ||||
| # endif | ||||
| 
 | ||||
| #endif /* OS X */ | ||||
| 
 | ||||
| #ifdef DISABLE_LINUX_SG_IO | ||||
| #undef SG_IO | ||||
|  | @ -1112,17 +1141,40 @@ sanei_scsi_open (const char *dev, int *fdp, | |||
|        fd = (int)pt_handle;  | ||||
|    }  | ||||
| #elif USE == MACOSX_INTERFACE | ||||
|   if (sscanf (dev, "u%dt%dl%d", &bus, &target, &lun) != 3) | ||||
|     { | ||||
|       DBG (1, "sanei_scsi_open: device name %s is not valid\n", dev); | ||||
|       return SANE_STATUS_INVAL; | ||||
|     } | ||||
|    { | ||||
|     | ||||
|      /* Verify the device name */ | ||||
|     | ||||
|     pdata = NULL; | ||||
|      | ||||
| # ifndef OSX_ONLY_10_1_API | ||||
| 
 | ||||
|   /* Find fake fd. */ | ||||
|   for (fd = 0; fd < num_alloced; ++fd) | ||||
|     if (!fd_info[fd].in_use) | ||||
|       break; | ||||
|   fake_fd = 1; | ||||
|     /* For the new implementation, copy the device SCSI GUID into the pdata */ | ||||
| 
 | ||||
|     pdata = CreateGUIDFromDevName(dev); | ||||
|     /* New API
 | ||||
|        if (strncmp("iokitscsi@<",dev, 11) == 0) { | ||||
|        pdata = strdup(dev); | ||||
|        } | ||||
|     */ | ||||
| # endif | ||||
| 
 | ||||
|     if ( (pdata == NULL) | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_2_API    | ||||
|          && (sscanf (dev, "u%dt%dl%d", &bus, &target, &lun) != 3)	/* Old API */ | ||||
| # endif | ||||
|             ) { | ||||
|             DBG (1, "sanei_scsi_open: device name %s is not valid\n", dev); | ||||
|             return SANE_STATUS_INVAL; | ||||
|         } | ||||
|      | ||||
|     /* Find fake fd. */ | ||||
|     for (fd = 0; fd < num_alloced; ++fd) | ||||
|         if (!fd_info[fd].in_use) | ||||
|         break; | ||||
|     fake_fd = 1; | ||||
|   } | ||||
| #else | ||||
| #if defined(SGIOCSTL) || (USE == SOLARIS_INTERFACE) | ||||
|   { | ||||
|  | @ -1508,6 +1560,10 @@ sanei_scsi_close (int fd) | |||
| #if USE == OS2_INTERFACE | ||||
|   close_aspi (); | ||||
| #endif /* USE == OS2_INTERFACE */ | ||||
| 
 | ||||
| #if USE == MACOSX_INTERFACE | ||||
|   if (fd_info[fd].pdata) CFRelease(fd_info[fd].pdata); | ||||
| #endif /* USE == MACOSX_INTERFACE */ | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -4435,8 +4491,10 @@ unit_ready (int fd) | |||
| 
 | ||||
| #if USE == MACOSX_INTERFACE | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_2_API | ||||
| 
 | ||||
| SANE_Status | ||||
| sanei_scsi_cmd2 (int fd, | ||||
| sanei_scsi_cmd2_old_api (int fd, | ||||
| 		 const void *cmd, size_t cmd_size, | ||||
| 		 const void *src, size_t src_size, | ||||
| 		 void *dst, size_t * dst_size) | ||||
|  | @ -4598,7 +4656,7 @@ sanei_scsi_cmd2 (int fd, | |||
| 
 | ||||
| 
 | ||||
| void | ||||
| sanei_scsi_find_devices (const char *findvendor, const char *findmodel, | ||||
| sanei_scsi_find_devices_old_api (const char *findvendor, const char *findmodel, | ||||
| 			 const char *findtype, | ||||
| 			 int findbus, int findchannel, int findid, int findlun, | ||||
| 			 SANE_Status (*attach) (const char *dev)) | ||||
|  | @ -4712,6 +4770,644 @@ sanei_scsi_find_devices (const char *findvendor, const char *findmodel, | |||
|     } | ||||
| } | ||||
| 
 | ||||
| # endif /* ifndef OSX_ONLY_10_2_API */ | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_1_API     | ||||
| 
 | ||||
| void CreateMatchingDictionaryForSTUC(SInt32 peripheralDeviceType, | ||||
|                                      const char *findvendor, const char *findmodel,  | ||||
|                                      const CFDataRef scsiguid, | ||||
|                                      CFMutableDictionaryRef *matchingDict) | ||||
| { | ||||
|     CFMutableDictionaryRef 	subDict; | ||||
|      | ||||
|     /* assert(matchingDict != NULL); */ | ||||
|      | ||||
|     /* Create the dictionaries */ | ||||
|     *matchingDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,  | ||||
|                                                &kCFTypeDictionaryValueCallBacks); | ||||
|     if (*matchingDict != NULL) { | ||||
|         subDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,  | ||||
|                                                &kCFTypeDictionaryValueCallBacks); | ||||
|      | ||||
|         if (subDict != NULL) { | ||||
| 	  /* Create a dictionary with the "SCSITaskDeviceCategory" key with the appropriate value */ | ||||
| 	  /* for the device type we're interested in. */ | ||||
|             SInt32	deviceTypeNumber = peripheralDeviceType; | ||||
|             CFNumberRef	deviceTypeRef = NULL; | ||||
|              | ||||
|             CFDictionarySetValue(subDict, CFSTR(kIOPropertySCSITaskDeviceCategory), | ||||
|                                  CFSTR(kIOPropertySCSITaskUserClientDevice));     | ||||
| 
 | ||||
|             deviceTypeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &deviceTypeNumber); | ||||
|             CFDictionarySetValue(subDict, CFSTR(kIOPropertySCSIPeripheralDeviceType), deviceTypeRef); | ||||
|             CFRelease (deviceTypeRef); | ||||
| 
 | ||||
|             /* Add search for a vendor or model */ | ||||
|              | ||||
|             if (findvendor) { | ||||
|                 CFDictionarySetValue(subDict, CFSTR(kIOPropertySCSIVendorIdentification), | ||||
|                         CFStringCreateWithCString(kCFAllocatorDefault, findvendor, kCFStringEncodingUTF8));     | ||||
|             } | ||||
|             if (findmodel) { | ||||
|                 CFDictionarySetValue(subDict, CFSTR(kIOPropertySCSIProductIdentification), | ||||
|                         CFStringCreateWithCString(kCFAllocatorDefault, findmodel, kCFStringEncodingUTF8));     | ||||
|             } | ||||
|              | ||||
|             if (scsiguid) { | ||||
|                 CFDictionarySetValue(subDict, CFSTR(kIOPropertySCSITaskUserClientInstanceGUID), | ||||
|                         scsiguid);     | ||||
|                  | ||||
|             } | ||||
|              | ||||
|         } | ||||
|          | ||||
|         /* Add the dictionary to the main dictionary with the key "IOPropertyMatch" to
 | ||||
| 	   narrow the search to the above dictionary. */ | ||||
|         CFDictionarySetValue(*matchingDict, CFSTR(kIOPropertyMatchKey), subDict); | ||||
|                              | ||||
|         CFRelease(subDict); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| CFDataRef | ||||
| CreateGUIDFromDevName(char *devname) { | ||||
| 
 | ||||
|   /* Decode a fake devname */ | ||||
|      | ||||
|     if (strncmp("iokitscsi@<", devname, 11) != 0) return NULL; | ||||
| 
 | ||||
|     char *p = devname + 11; | ||||
|     int L = strlen(p) - 1; | ||||
|      | ||||
|     if ((L < 2) || ((L % 2 ) != 0)) return NULL; | ||||
|     L = L / 2; | ||||
|      | ||||
|     /* Allocate a buffer for the GUID */ | ||||
|      | ||||
|     UInt8 *guid = (UInt8 *)malloc(L); | ||||
|     UInt8 *g = guid; | ||||
|     int i, d; | ||||
|      | ||||
|     for (i = L; i > 0; i--, p+=2) { | ||||
|         if (sscanf(p, "%02x", &d) != 1) return NULL; | ||||
|         *g++ = d & 0xff; | ||||
|     } | ||||
|      | ||||
|     /* Create the CFData */ | ||||
|      | ||||
|     CFDataRef dataDesc = CFDataCreate(kCFAllocatorDefault, guid, L); | ||||
|     free(guid); | ||||
|      | ||||
|     return dataDesc; | ||||
| } | ||||
| 
 | ||||
| char * | ||||
| CreateDevNameFromGUID(CFDataRef dataDesc) { | ||||
|      | ||||
|     if (dataDesc == NULL) return NULL; | ||||
|      | ||||
|     /* Create a fake device name */ | ||||
|      | ||||
|     int L = CFDataGetLength(dataDesc); | ||||
|     char *p = CFDataGetBytePtr(dataDesc); | ||||
|     char *devname = (char*)malloc(13+2*L); | ||||
|     char *d = devname+11; | ||||
|      | ||||
|     sprintf(devname, "iokitscsi@<"); | ||||
|     for(;L>0;L--,d+=2) { | ||||
|         sprintf(d, "%02x",(*p++)&0xff); | ||||
|     } | ||||
|     sprintf(d, ">"); | ||||
|      | ||||
|     return devname; | ||||
|      | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void CreateDeviceInterfaceUsingSTUC(io_object_t scsiDevice, | ||||
|                                     IOCFPlugInInterface ***thePlugInInterface,        | ||||
|                                     SCSITaskDeviceInterface ***theInterface) | ||||
| { | ||||
|     kern_return_t		kr = kIOReturnSuccess; | ||||
|     IOCFPlugInInterface		**plugInInterface = NULL; | ||||
|     SCSITaskDeviceInterface	**interface = NULL; | ||||
|     HRESULT			plugInResult = S_OK; | ||||
|     SInt32			score = 0; | ||||
| 
 | ||||
|     /* assert(scsiDevice != NULL); */ | ||||
| 
 | ||||
|     /* Create the base interface of type IOCFPlugInInterface.
 | ||||
|        This object will be used to create the SCSI device interface object. */ | ||||
|     kr = IOCreatePlugInInterfaceForService(scsiDevice, | ||||
|                                            kIOSCSITaskDeviceUserClientTypeID, | ||||
|                                            kIOCFPlugInInterfaceID, | ||||
|                                            &plugInInterface, | ||||
|                                            &score); | ||||
| 
 | ||||
|     if (kr != kIOReturnSuccess) { | ||||
|         DBG(5, "Couldn't create a plugin interface for the io_service_t. (0x%08x)\n", kr); | ||||
|     } | ||||
|     else { | ||||
|       /* Query the base plugin interface for an instance of the specific SCSI device interface
 | ||||
|          object. */ | ||||
|         plugInResult = (*plugInInterface)->QueryInterface(plugInInterface,  | ||||
|                                             CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), | ||||
|                                             (LPVOID) &interface); | ||||
|          | ||||
|         if (plugInResult != S_OK) { | ||||
|             DBG(5, "Couldn't create SCSI device interface. (%ld)\n", plugInResult); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /* Set the return values. */ | ||||
|     *thePlugInInterface = plugInInterface; | ||||
|     *theInterface = interface; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| SANE_Status | ||||
| ExecuteSCSITask (SCSITaskInterface **task, | ||||
| 		 const void *cmd, size_t cmd_size, | ||||
| 		 const void *src, size_t src_size, | ||||
| 		 void *dst, size_t * dst_size) { | ||||
| 
 | ||||
|     SCSITaskStatus			taskStatus; | ||||
|     SCSI_Sense_Data			senseData; | ||||
|     SCSICommandDescriptorBlock		cdb; | ||||
|     IOReturn				kr = kIOReturnSuccess; | ||||
|     IOVirtualRange			range; | ||||
|     UInt64				transferCount = 0; | ||||
|     UInt32				transferCountHi = 0; | ||||
|     UInt32				transferCountLo = 0; | ||||
|     size_t 				data_length = 0;	 | ||||
|     int 				transferType = 0; | ||||
|                   | ||||
|     if (dst && dst_size) /* isRead */ | ||||
|         { | ||||
|         DBG(6,"isRead dst_size:%d\n",*dst_size); | ||||
| 
 | ||||
|         /* Zero the buffer. */ | ||||
|         bzero (dst, *dst_size); | ||||
|          | ||||
|         /* Configure the virtual range for the buffer. */ | ||||
|         range.address = (IOVirtualAddress) dst; | ||||
|         range.length = *dst_size; | ||||
|          | ||||
|         data_length = *dst_size; | ||||
|         transferType = kSCSIDataTransfer_FromTargetToInitiator; | ||||
|     } else { | ||||
|         DBG(6,"isWrite src_size:%d\n",src_size); | ||||
|          | ||||
|         /* Configure the virtual range for the buffer. */ | ||||
|         range.address = (IOVirtualAddress) src; | ||||
|         range.length = src_size; | ||||
|          | ||||
|         data_length = src_size; | ||||
|         transferType = kSCSIDataTransfer_FromInitiatorToTarget; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     /* zero the senseData and CDB */ | ||||
|     bzero(&senseData, sizeof(senseData)); | ||||
|     bzero(cdb, sizeof(cdb)); | ||||
|      | ||||
|     /* copy the command data */ | ||||
|     memcpy (cdb, cmd, cmd_size); | ||||
|      | ||||
|     /* Set the actual cdb in the task */ | ||||
|     kr = (*task)->SetCommandDescriptorBlock(task, cdb, cmd_size); | ||||
|     if (kr != kIOReturnSuccess) { | ||||
|         DBG(5, "Error setting CDB. (0x%08x)\n", kr);             | ||||
|         return SANE_STATUS_IO_ERROR; | ||||
|     } | ||||
|      | ||||
|     /* Set the scatter-gather entry in the task */ | ||||
|     kr = (*task)->SetScatterGatherEntries(task, &range, 1, data_length, transferType); | ||||
|      | ||||
|     if (kr != kIOReturnSuccess) { | ||||
|         DBG(5, "Error setting scatter-gather entries. (0x%08x)\n", kr);             | ||||
|         return SANE_STATUS_IO_ERROR; | ||||
|     } | ||||
| 
 | ||||
|     /* Set the timeout in the task */ | ||||
|     kr = (*task)->SetTimeoutDuration(task, sane_scsicmd_timeout * 100); | ||||
|     if (kr != kIOReturnSuccess) { | ||||
|         DBG(5, "Error setting timeout. (0x%08x)\n", kr);             | ||||
|         return SANE_STATUS_IO_ERROR; | ||||
|     } | ||||
|      | ||||
|     DBG(5, "Executing command\n");             | ||||
|      | ||||
|     /* Send it! */ | ||||
|     kr = (*task)->ExecuteTaskSync(task, &senseData, &taskStatus, &transferCount); | ||||
|     if (kr != kIOReturnSuccess) { | ||||
|         DBG(5, "Error executing task. (0x%08x)\n", kr);             | ||||
|         return SANE_STATUS_IO_ERROR; | ||||
|     } | ||||
| 
 | ||||
|     DBG(5,"ExecuteTaskSync OK Trasferred %ld bytes\n",transferCount); | ||||
|      | ||||
|     /* Get the transfer counts */ | ||||
|     transferCountHi = ((transferCount >> 32) & 0xFFFFFFFF); | ||||
|     transferCountLo = (transferCount & 0xFFFFFFFF); | ||||
|      | ||||
|     if (taskStatus == kSCSITaskStatus_GOOD) { | ||||
|       /* Task worked correctly */ | ||||
|         if (dst && dst_size) *dst_size = transferCount; | ||||
|         return SANE_STATUS_GOOD; | ||||
|     } | ||||
|     else if (taskStatus == kSCSITaskStatus_CHECK_CONDITION) { | ||||
|       /* Something happened. Print the sense string */ | ||||
|         DBG(5, "taskStatus = 0x%08x Something Happened...\n", taskStatus); | ||||
|         /* PrintSenseString(&senseData, false); */ | ||||
|     } | ||||
|     else { | ||||
|         DBG(5, "taskStatus = 0x%08x\n", taskStatus); | ||||
|     } | ||||
|      | ||||
|     return SANE_STATUS_IO_ERROR; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| SANE_Status | ||||
| ExecuteCommandUsingSTUC (SCSITaskDeviceInterface **interface, | ||||
| 		 const void *cmd, size_t cmd_size, | ||||
| 		 const void *src, size_t src_size, | ||||
| 		 void *dst, size_t * dst_size) { | ||||
| 
 | ||||
|     SCSITaskInterface 			**task = NULL; | ||||
|     IOReturn				kr = kIOReturnSuccess; | ||||
|     			 | ||||
|     /* assert(interface != NULL); */ | ||||
| 
 | ||||
|      | ||||
|     /* Get exclusive access for the device if we can. This must be done
 | ||||
|        before any SCSITasks can be created and sent to the device. */ | ||||
|     kr = (*interface)->ObtainExclusiveAccess(interface); | ||||
| 
 | ||||
|     if (kr != kIOReturnSuccess) { | ||||
|         DBG(5, "ObtainExclusiveAccess failed. (0x%08x)\n", kr);             | ||||
|         return SANE_STATUS_NO_MEM; | ||||
|     } | ||||
|      | ||||
|     /* Create a task now that we have exclusive access */ | ||||
|     task = (*interface)->CreateSCSITask(interface); | ||||
|      | ||||
|     if (task == NULL) { | ||||
|         DBG(5, "CreateSCSITask returned NULL.\n");             | ||||
|         (*interface)->ReleaseExclusiveAccess(interface); | ||||
|         return SANE_STATUS_NO_MEM; | ||||
|     } | ||||
|     else { | ||||
|      | ||||
|         SANE_Status returnValue = ExecuteSCSITask(task,  | ||||
|                                     cmd, cmd_size, src, src_size, dst, dst_size); | ||||
|          | ||||
|          | ||||
|         /* Release the task interface */ | ||||
|         (*task)->Release(task); | ||||
|          | ||||
|         /* Release exclusive access */ | ||||
|         (*interface)->ReleaseExclusiveAccess(interface); | ||||
|          | ||||
|         return returnValue; | ||||
| 
 | ||||
|     }     | ||||
| } | ||||
| 
 | ||||
| SANE_Status | ||||
| sanei_scsi_cmd2_stuc_api (int fd, | ||||
| 		 const void *cmd, size_t cmd_size, | ||||
| 		 const void *src, size_t src_size, | ||||
| 		 void *dst, size_t * dst_size) { | ||||
| 
 | ||||
|   IOReturn ioReturnValue; | ||||
|    | ||||
|   CFDataRef guid = (CFDataRef)fd_info[fd].pdata; | ||||
|   if (!guid) return SANE_STATUS_INVAL; | ||||
| 
 | ||||
| 
 | ||||
|   DBG (2, "cmd2: cmd_size:%d src_size:%d dst_size:%d isWrite:%d\n",  | ||||
|         cmd_size, src_size, (!dst_size)?0:dst_size, (!dst_size)?1:0); | ||||
| 
 | ||||
|   /* Use default master port */ | ||||
|    | ||||
|   mach_port_t masterPort = kIOMasterPortDefault; | ||||
| 
 | ||||
|   io_object_t scsiDevice = NULL; | ||||
| 
 | ||||
|   /* Search for both Scanner type and Processor type devices */ | ||||
|    | ||||
|   /* GB TDB This should only be needed for find */ | ||||
|    | ||||
|   int i; | ||||
|   for (i = 0; !scsiDevice && i < 2; i++)  | ||||
|     { | ||||
|     SInt32 peripheralDeviceType = | ||||
| 	(i == 0 ? kINQUIRY_PERIPHERAL_TYPE_ScannerSCSI2Device : | ||||
|                   kINQUIRY_PERIPHERAL_TYPE_ProcessorSPCDevice); | ||||
| 
 | ||||
| 
 | ||||
|     /* Set up a matching dictionary to search the I/O Registry for the SCSI device */ | ||||
|     /* we are interested in, specifying the SCSITaskUserClient GUID. */ | ||||
| 
 | ||||
|     CFMutableDictionaryRef matchingDict = NULL; | ||||
|    | ||||
|     CreateMatchingDictionaryForSTUC(peripheralDeviceType, NULL, NULL, guid, &matchingDict); | ||||
|     if (matchingDict == NULL) { | ||||
|         DBG(5, "CreateMatchingDictionaryForSTUC Failed\n"); | ||||
|         return SANE_STATUS_NO_MEM; | ||||
|     } | ||||
|          | ||||
|     /* Now search I/O Registry for the matching device */ | ||||
|      | ||||
|     io_iterator_t iokIterator = NULL; | ||||
| 
 | ||||
|     ioReturnValue = IOServiceGetMatchingServices(masterPort, matchingDict, &iokIterator); | ||||
|     if (ioReturnValue != kIOReturnSuccess) { | ||||
|         DBG(5, "IOServiceGetMatchingServices Failed\n"); | ||||
|         return SANE_STATUS_NO_MEM; | ||||
|     } | ||||
|      | ||||
|     /* Check device */ | ||||
|      | ||||
|     io_service_t nextDevice = NULL; | ||||
|      | ||||
|     while (nextDevice = IOIteratorNext(iokIterator)) { | ||||
|         scsiDevice = nextDevice; | ||||
|     } | ||||
| 
 | ||||
|     IOObjectRelease (iokIterator); | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   if (!scsiDevice) { | ||||
|     DBG(5, "Device not found %s\n", devname); | ||||
|     return SANE_STATUS_INVAL; | ||||
|   } | ||||
|    | ||||
|   /* Found Device */ | ||||
| 
 | ||||
|   /* Create interface */ | ||||
| 
 | ||||
|   IOCFPlugInInterface		**plugInInterface = NULL; | ||||
|   SCSITaskDeviceInterface	**interface = NULL; | ||||
|          | ||||
|   CreateDeviceInterfaceUsingSTUC(scsiDevice, | ||||
|                                 &plugInInterface, | ||||
|                                 &interface); | ||||
| 
 | ||||
|   ioReturnValue = IOObjectRelease(scsiDevice); /* Done with SCSI object from I/O Registry. */ | ||||
| 
 | ||||
|   SANE_Status returnValue = SANE_STATUS_IO_ERROR; | ||||
|    | ||||
|   if (ioReturnValue != kIOReturnSuccess) { | ||||
|    | ||||
|     DBG(5, "Error releasing SCSI device. (0x%08x)\n", ioReturnValue); | ||||
| 
 | ||||
|   } else if (interface != NULL) { | ||||
|       | ||||
|     /* Execute the command */ | ||||
|       | ||||
|     returnValue = ExecuteCommandUsingSTUC(interface, cmd, cmd_size, src, src_size, dst, dst_size); | ||||
|      | ||||
|   } | ||||
| 
 | ||||
|   if (interface != NULL) { | ||||
|     (*interface)->Release(interface); | ||||
|   } | ||||
| 
 | ||||
|   if (plugInInterface != NULL) { | ||||
|     IODestroyPlugInInterface(plugInInterface); | ||||
|   } | ||||
| 
 | ||||
|   return returnValue; | ||||
|    | ||||
| } | ||||
| 
 | ||||
| boolean_t | ||||
| sanei_scsi_find_devices_stuc_api (const char *findvendor, const char *findmodel, | ||||
| 			 const char *findtype, | ||||
| 			 int findbus, int findchannel, int findid, int findlun, | ||||
| 			 SANE_Status (*attach) (const char *dev)) | ||||
| { | ||||
|   /* sanei_debug_sanei_scsi=8; */ | ||||
| 
 | ||||
|   IOReturn ioReturnValue; | ||||
|    | ||||
|   boolean_t foundDevices = false; | ||||
| 
 | ||||
|   /* Use default master port */ | ||||
|    | ||||
|   mach_port_t masterPort = kIOMasterPortDefault; | ||||
| 
 | ||||
|   io_object_t scsiDevice = NULL; | ||||
|    | ||||
|   DBG(5, "Search for Vendor:%s Model:%s\n",(findvendor)?findvendor:"",(findmodel)?findmodel:""); | ||||
| 
 | ||||
|   /* Search for both Scanner type and Processor type devices */ | ||||
|      | ||||
|   int i; | ||||
|   for (i = 0; !scsiDevice && i < 2; i++)  | ||||
|     { | ||||
|     SInt32 peripheralDeviceType = | ||||
| 	(i == 0 ? kINQUIRY_PERIPHERAL_TYPE_ScannerSCSI2Device : | ||||
|                   kINQUIRY_PERIPHERAL_TYPE_ProcessorSPCDevice); | ||||
| 
 | ||||
| 
 | ||||
|     /* Set up a matching dictionary to search the I/O Registry for SCSI devices 
 | ||||
|        we are interested in. */ | ||||
| 
 | ||||
|     CFMutableDictionaryRef matchingDict = NULL; | ||||
|    | ||||
|     CreateMatchingDictionaryForSTUC(peripheralDeviceType, findvendor, findmodel, NULL, &matchingDict); | ||||
|     if (matchingDict == NULL) { | ||||
|         DBG(5, "CreateMatchingDictionaryForSTUC Failed\n"); | ||||
|         return false; | ||||
|     } | ||||
|          | ||||
|     /* Now search I/O Registry for matching devices. */ | ||||
|      | ||||
|     io_iterator_t iokIterator = NULL; | ||||
| 
 | ||||
|     ioReturnValue = IOServiceGetMatchingServices(masterPort, matchingDict, &iokIterator); | ||||
|     if (ioReturnValue != kIOReturnSuccess) { | ||||
|         DBG(5, "IOServiceGetMatchingServices Failed\n"); | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     /* Check device */ | ||||
|      | ||||
|     io_service_t nextDevice = NULL; | ||||
|      | ||||
|     while (nextDevice = IOIteratorNext(iokIterator)) { | ||||
| 
 | ||||
|       /* Create a fake device name from the SCSITaskUserClient GUID */ | ||||
|          | ||||
|         CFMutableDictionaryRef properties; | ||||
|         ioReturnValue = IORegistryEntryCreateCFProperties(nextDevice, &properties,  | ||||
|                         kCFAllocatorDefault, kNilOptions); | ||||
|         if (ioReturnValue == kIOReturnSuccess) { | ||||
| 
 | ||||
| 	  /* Create a fake device name */ | ||||
| 
 | ||||
|             char *devname = CreateDevNameFromGUID( | ||||
|                                 (CFDataRef)CFDictionaryGetValue(properties,  | ||||
|                                         CFSTR(kIOPropertySCSITaskUserClientInstanceGUID))); | ||||
|             if (devname) { | ||||
|                  | ||||
|                 DBG(1,"Found:%s\n", devname); | ||||
|                                  | ||||
|                 foundDevices = true; | ||||
|                  | ||||
|                 /* Attach to the device */ | ||||
|                 (*attach) (devname); | ||||
|                  | ||||
|                 free(devname); | ||||
|             } else { | ||||
|                 DBG(1,"Can't find SCSITaskUserClient GUID\n"); | ||||
|             } | ||||
|             CFRelease(properties); | ||||
|         } else { | ||||
|            DBG(1,"ERROR creating property table\n"); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
| /*        
 | ||||
|         //Create interface
 | ||||
|          | ||||
|         IOCFPlugInInterface		**plugInInterface = NULL; | ||||
|         SCSITaskDeviceInterface		**interface = NULL; | ||||
|                  | ||||
|         CreateDeviceInterfaceUsingSTUC(nextDevice, | ||||
|                                         &plugInInterface, | ||||
|                                         &interface); | ||||
|          | ||||
|         ioReturnValue = IOObjectRelease(nextDevice); // Done with SCSI object from I/O Registry.
 | ||||
|          | ||||
|         SANE_Status returnValue = SANE_STATUS_IO_ERROR; | ||||
|          | ||||
|         SCSICmd_INQUIRY_StandardData	inqBuffer; | ||||
|          | ||||
|         if (ioReturnValue != kIOReturnSuccess) { | ||||
|          | ||||
|             DBG(5, "Error releasing SCSI device. (0x%08x)\n", ioReturnValue); | ||||
|          | ||||
|         } else if (interface != NULL) { | ||||
|              | ||||
|             // Perform an inquiry
 | ||||
|              | ||||
|             SCSICommandDescriptorBlock		cdb; | ||||
|             size_t inq_size			= sizeof(SCSICmd_INQUIRY_StandardData); | ||||
|          | ||||
|             // We're going to execute an INQUIRY to the device as a
 | ||||
|             // test of exclusive commands.
 | ||||
|             bzero(cdb, sizeof(cdb)); | ||||
|             cdb[0] = kSCSICmd_INQUIRY; | ||||
|             cdb[4] = sizeof(SCSICmd_INQUIRY_StandardData); | ||||
|              | ||||
|             returnValue = ExecuteCommandUsingSTUC(interface, cdb, kSCSICDBSize_6Byte, NULL, 0,  | ||||
|                                                     &inqBuffer, &inq_size); | ||||
|              | ||||
|         } | ||||
|              | ||||
|         if (interface != NULL) { | ||||
|             (*interface)->Release(interface); | ||||
|         } | ||||
|          | ||||
|         if (plugInInterface != NULL) { | ||||
|             IODestroyPlugInInterface(plugInInterface); | ||||
|         } | ||||
| 
 | ||||
|         if (returnValue == SANE_STATUS_GOOD) { | ||||
|              | ||||
|             // Match Vendor and Product IDs
 | ||||
|             DBG(6, "Vendor:%s Model:%s\n",inqBuffer.VENDOR_IDENTIFICATION,inqBuffer.PRODUCT_INDENTIFICATION); | ||||
|              | ||||
|             if ((findvendor == NULL || strncmp (findvendor, | ||||
|                                             inqBuffer.VENDOR_IDENTIFICATION, | ||||
|                                             strlen (findvendor)) == 0) && | ||||
|                 (findmodel == NULL || strncmp (findmodel, | ||||
|                                             inqBuffer.PRODUCT_INDENTIFICATION, | ||||
|                                             strlen (findmodel)) == 0)) | ||||
|             { | ||||
|                 char devname [40]; | ||||
|                 UInt64 guid = 0x0d001234abcd1234L; | ||||
|                 sprintf (devname, "iokitscsi@0x%llx", guid); | ||||
|                 (*attach) (devname); | ||||
|                 foundDevices = true; | ||||
|             } | ||||
|         } | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     IOObjectRelease (iokIterator); | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   return foundDevices; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| # endif /* ifndef OSX_ONLY_10_1_API */    | ||||
| 
 | ||||
| 
 | ||||
| SANE_Status | ||||
| sanei_scsi_cmd2 (int fd, | ||||
| 		 const void *cmd, size_t cmd_size, | ||||
| 		 const void *src, size_t src_size, | ||||
| 		 void *dst, size_t * dst_size) { | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_1_API     | ||||
| 
 | ||||
|     char * devname = (char *)fd_info[fd].pdata; | ||||
|      | ||||
|     if (devname) { | ||||
|       /* STUC i/f */ | ||||
|         return sanei_scsi_cmd2_stuc_api (fd, cmd, cmd_size, src, src_size, dst, dst_size); | ||||
|     } else { | ||||
| #endif | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_2_API     | ||||
|         return sanei_scsi_cmd2_old_api (fd, cmd, cmd_size, src, src_size, dst, dst_size); | ||||
| #endif | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_1_API     | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void | ||||
| sanei_scsi_find_devices (const char *findvendor, const char *findmodel, | ||||
| 			 const char *findtype, | ||||
| 			 int findbus, int findchannel, int findid, int findlun, | ||||
| 			 SANE_Status (*attach) (const char *dev)) | ||||
| { | ||||
| 
 | ||||
|   /* Try to use new API first */ | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_1_API     | ||||
|    | ||||
|   if (!sanei_scsi_find_devices_stuc_api(findvendor, findmodel, findtype,  | ||||
|                                     findbus, findchannel, findid, findlun, | ||||
|                                     attach) ) { | ||||
| # endif | ||||
| # ifndef OSX_ONLY_10_2_API     | ||||
| 
 | ||||
|     sanei_scsi_find_devices_old_api(findvendor, findmodel, findtype,  | ||||
|                                         findbus, findchannel, findid, findlun, | ||||
|                                         attach); | ||||
| # endif | ||||
| 
 | ||||
| # ifndef OSX_ONLY_10_1_API     | ||||
|    } | ||||
| # endif | ||||
| } | ||||
| 
 | ||||
| #define WE_HAVE_FIND_DEVICES | ||||
| 
 | ||||
| #endif /* USE == MACOSX_INTERFACE */ | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Henning Geinitz
						Henning Geinitz