/*
- * "$Id: usb-darwin.c 5630 2006-06-05 18:42:53Z mike $"
+ * "$Id: usb-darwin.c 6491 2007-04-30 18:21:52Z mike $"
*
- * © Copyright 2005-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright © 2005-2007 Apple Inc. All rights reserved.
*
* IMPORTANT: This Apple software is supplied to you by Apple Computer,
* Inc. ("Apple") in consideration of your agreement to the following
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#include <cups/debug.h>
+#include <cups/sidechannel.h>
+#include <cups/i18n.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/usb/IOUSBLib.h>
#include <pthread.h>
+
/*
* WAITEOF_DELAY is number of seconds we'll wait for responses from
* the printer after we've finished sending all the data
#define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
#define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/
+#define kWriteBufferSize 2048
#pragma mark -
UInt32 location;
Boolean waitEOF;
-
+
+ CFRunLoopTimerRef statusTimer;
+
+ pthread_cond_t reqWaitCompCond;
+ pthread_mutex_t reqWaitMutex;
+ pthread_mutex_t waitCloseMutex;
+ pthread_mutex_t writeCompMutex;
+ int writeDone;
+ int reqWaitDone;
+ int reqWqitFlag;
+ int directionalFlag; /* 0=uni, 1=bidi */
+ ssize_t dataSize;
+ ssize_t dataOffset;
+ char dataBuffer[kWriteBufferSize];
} printer_data_t;
static Boolean list_device_callback(void *refcon, io_service_t obj);
static Boolean find_device_callback(void *refcon, io_service_t obj);
+static void statusTimerCallback(CFRunLoopTimerRef timer, void *info);
static void iterate_printers(iterator_callback_t callBack, void *userdata);
static void device_added(void *userdata, io_iterator_t iterator);
static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_context_t ***driver);
static kern_return_t unload_classdriver(classdriver_context_t ***classDriver);
-static kern_return_t load_printerdriver(printer_data_t *printer);
-static kern_return_t registry_open(printer_data_t *printer);
+static kern_return_t load_printerdriver(printer_data_t *printer, CFStringRef *driverBundlePath);
+static kern_return_t registry_open(printer_data_t *printer, CFStringRef *driverBundlePath);
static kern_return_t registry_close(printer_data_t *printer);
static OSStatus copy_deviceid(classdriver_context_t **printer, CFStringRef *deviceID);
static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation);
static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
+static CFStringRef cfstr_create_and_trim(const char *cstr);
static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF);
static void setup_cfLanguage(void);
static void *read_thread(void *reference);
+static void *reqestWait_thread(void *reference);
+static void usbSoftReset(printer_data_t *userData, cups_sc_status_t *status);
+static void usbDrainOutput(printer_data_t *userData, cups_sc_status_t *status);
+static void usbGetBidirectional(printer_data_t *userData, cups_sc_status_t *status, char *data, int *datalen);
+static void usbGetDeviceID(printer_data_t *userData, cups_sc_status_t *status, char *data, int *datalen);
+static void usbGetDevState(printer_data_t *userData, cups_sc_status_t *status, char *data, int *datalen);
#if defined(__i386__)
int countdown = INITIAL_LOG_INTERVAL; /* Logging interval */
pthread_cond_t *readCompleteConditionPtr = NULL; /* Read complete condition */
pthread_mutex_t *readMutexPtr = NULL; /* Read mutex */
+ CFStringRef driverBundlePath; /* Class driver path */
+ int reqWait_create = 0; /* RequestWait thread created? */
+ pthread_t reqWaitThread; /* RequestWait thread */
+ pthread_cond_t *reqWaitCompCondPtr = NULL; /* RequestWait complete condition */
+ pthread_mutex_t *reqWaitMutexPtr = NULL; /* RequestWait mutex */
+ pthread_mutex_t *waitCloseMutexPtr = NULL; /* wait close mutex */
+ pthread_mutex_t *writeCompMutexPtr = NULL; /* write complete mutex */
setup_cfLanguage();
parse_options(options, serial, &printer_data.location, &printer_data.waitEOF);
resource++;
printer_data.uri = uri;
- printer_data.make = CFStringCreateWithCString(NULL, hostname, kCFStringEncodingUTF8);
- printer_data.model = CFStringCreateWithCString(NULL, resource, kCFStringEncodingUTF8);
- printer_data.serial = CFStringCreateWithCString(NULL, serial, kCFStringEncodingUTF8);
+
+ printer_data.make = cfstr_create_and_trim(hostname);
+ printer_data.model = cfstr_create_and_trim(resource);
+ printer_data.serial = cfstr_create_and_trim(serial);
fputs("STATE: +connecting-to-device\n", stderr);
printer_data.printerDriver = 0x0;
}
- fprintf(stderr, "INFO: Looking for '%s %s'\n", hostname, resource);
+ fprintf(stderr, "DEBUG: Looking for '%s %s'\n", hostname, resource);
iterate_printers(find_device_callback, &printer_data);
- fprintf(stderr, "INFO: Opening Connection\n");
- status = registry_open(&printer_data);
+ fputs("DEBUG: Opening connection\n", stderr);
+
+ driverBundlePath = NULL;
+ status = registry_open(&printer_data, &driverBundlePath);
#if defined(__i386__)
/*
* If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
/* Never returns here */
}
#endif /* __i386__ */
+ if (status == -2) {
+ /*
+ * If we still were unable to load the class drivers for this printer log
+ * the error and stop the queue...
+ */
+
+ if (driverBundlePath == NULL || !CFStringGetCString(driverBundlePath, buffer, sizeof(buffer), kCFStringEncodingUTF8))
+ strlcpy(buffer, "USB class driver", sizeof(buffer));
+
+ fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
+ fprintf(stderr, _("FATAL: Could not load %s\n"), buffer);
+
+ if (driverBundlePath)
+ CFRelease(driverBundlePath);
+
+ return CUPS_BACKEND_STOP;
+ }
+
+ if (driverBundlePath)
+ CFRelease(driverBundlePath);
if (status != noErr) {
sleep( PRINTER_POLLING_INTERVAL );
countdown -= PRINTER_POLLING_INTERVAL;
if ( countdown <= 0 ) {
- fprintf(stderr, "INFO: Printer busy (status:0x%08x)\n", (int)status);
+ fprintf(stderr, _("INFO: Printer busy (status:0x%08x)\n"), (int)status);
countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */
}
}
if (pthread_mutex_init(&printer_data.readMutex, NULL) == 0)
readMutexPtr = &printer_data.readMutex;
+ printer_data.done = 0;
+
if (pthread_create(&thr, NULL, read_thread, &printer_data) == 0)
thread_created = 1;
if (thread_created == 0)
- fprintf(stderr, "WARNING: Couldn't create read channel\n");
+ fputs(_("WARNING: Couldn't create read channel\n"), stderr);
+
+ if (pthread_cond_init(&printer_data.reqWaitCompCond, NULL) == 0)
+ reqWaitCompCondPtr = &printer_data.reqWaitCompCond;
+
+ if (pthread_mutex_init(&printer_data.reqWaitMutex, NULL) == 0)
+ reqWaitMutexPtr = &printer_data.reqWaitMutex;
+
+ printer_data.reqWaitDone = 0;
+ printer_data.reqWqitFlag = 0;
+
+ if (pthread_create(&reqWaitThread, NULL, reqestWait_thread, &printer_data) == 0)
+ reqWait_create = 1;
+
+ if (reqWait_create == 0)
+ fputs(_("WARNING: Couldn't create sidechannel thread!\n"), stderr);
+
+ if (pthread_mutex_init(&printer_data.waitCloseMutex, NULL) == 0)
+ waitCloseMutexPtr = &printer_data.waitCloseMutex;
+
+ if (pthread_mutex_init(&printer_data.writeCompMutex, NULL) == 0)
+ writeCompMutexPtr = &printer_data.writeCompMutex;
}
/*
* The main thread sends the print file...
*/
+ printer_data.writeDone = 0;
+ printer_data.dataSize = 0;
+ printer_data.dataOffset = 0;
+ pthread_mutex_lock(writeCompMutexPtr);
+
while (status == noErr && copies-- > 0) {
UInt32 wbytes; /* Number of bytes written */
ssize_t nbytes; /* Number of bytes read */
off_t tbytes = 0; /* Total number of bytes written */
- fprintf(stderr, "INFO: Sending data\n");
+ fputs(_("INFO: Sending data\n"), stderr);
if (STDIN_FILENO != fd) {
fputs("PAGE: 1 1", stderr);
tbytes += nbytes;
while (nbytes > 0 && status == noErr) {
+ if (printer_data.writeDone) {
+ printer_data.dataSize = nbytes;
+ printer_data.dataOffset = bufptr - buffer;
+ memcpy(printer_data.dataBuffer, buffer, nbytes);
+
+ status = -1;
+ break;
+ }
+
wbytes = nbytes;
status = (*(printer_data.printerDriver))->WritePipe( printer_data.printerDriver, (UInt8*)bufptr, &wbytes, 0 /* nbytes > wbytes? 0: feof(fp) */ );
if (wbytes < 0 || noErr != status) {
OSStatus err = (*(printer_data.printerDriver))->Abort(printer_data.printerDriver);
- fprintf(stderr, "ERROR: %ld: Unable to send print file to printer (canceled:%ld)\n", status, err);
+ fprintf(stderr, _("ERROR: %ld: Unable to send print file to printer (canceled:%ld)\n"), status, err);
break;
}
}
if (fd != 0 && status == noErr)
- fprintf(stderr, "DEBUG: Sending print file, %qd bytes...\n", (off_t)tbytes);
+ fprintf(stderr, "DEBUG: Sending print file, %lld bytes...\n", (off_t)tbytes);
}
}
+ printer_data.writeDone = 1;
+ pthread_mutex_unlock(writeCompMutexPtr);
+
if (thread_created) {
/* Signal the read thread that we are done... */
printer_data.done = 1;
pthread_join( thr,NULL); /* wait for the child thread to return */
}
+ if (reqWait_create) {
+ /* Signal the cupsSideChannelDoRequest wait thread that we are done... */
+ printer_data.reqWaitDone = 1;
+
+ /*
+ * Give the cupsSideChannelDoRequest wait thread WAITEOF_DELAY seconds to complete
+ * all the data. If we are not signaled in that time then force the thread to exit
+ * by setting the waiteof to be false. Plese note that this relies on us using the
+ * timeout class driver.
+ */
+ struct timespec reqWaitSleepUntil = { time(NULL) + WAITEOF_DELAY, 0 };
+ pthread_mutex_lock(&printer_data.reqWaitMutex);
+
+ while (!printer_data.reqWqitFlag) {
+ if (pthread_cond_timedwait(&printer_data.reqWaitCompCond,
+ &printer_data.reqWaitMutex,
+ (const struct timespec *)&reqWaitSleepUntil) != 0) {
+ printer_data.waitEOF = false;
+ printer_data.reqWqitFlag = 1;
+ }
+ }
+ pthread_mutex_unlock(&printer_data.reqWaitMutex);
+ pthread_join(reqWaitThread,NULL); /* wait for the child thread to return */
+ }
+
+ /* interface close wait mutex(for softreset) */
+ pthread_mutex_lock(waitCloseMutexPtr);
+ pthread_mutex_unlock(waitCloseMutexPtr);
+
/*
* Close the connection and input file and general clean up...
*/
if (readMutexPtr != NULL)
pthread_mutex_destroy(&printer_data.readMutex);
+ if (waitCloseMutexPtr != NULL)
+ pthread_mutex_destroy(&printer_data.waitCloseMutex);
+
+ if (writeCompMutexPtr != NULL)
+ pthread_mutex_destroy(&printer_data.writeCompMutex);
+
+ if (reqWaitCompCondPtr != NULL)
+ pthread_cond_destroy(&printer_data.reqWaitCompCond);
+
+ if (reqWaitMutexPtr != NULL)
+ pthread_mutex_destroy(&printer_data.reqWaitMutex);
+
if (printer_data.make != NULL)
CFRelease(printer_data.make);
copy_devicestring(obj, &deviceIDString, &deviceLocation);
if (deviceIDString != NULL) {
CFStringRef make = NULL, model = NULL, serial = NULL;
- char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024], optionsstr[1024];
- char idstr[1024];
+ char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
+ char optionsstr[1024], idstr[1024];
copy_deviceinfo(deviceIDString, &make, &model, &serial);
modelstr[0] = '/';
- CFStringGetCString(deviceIDString, idstr, sizeof(idstr), kCFStringEncodingUTF8);
- CFStringGetCString(make, makestr, sizeof(makestr), kCFStringEncodingUTF8);
- CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8);
-
- /*
- * Fix common HP 1284 bug...
- */
+ CFStringGetCString(deviceIDString, idstr, sizeof(idstr),
+ kCFStringEncodingUTF8);
- if (!strcasecmp(makestr, "Hewlett-Packard"))
- strcpy(makestr, "HP");
+ if (make)
+ CFStringGetCString(make, makestr, sizeof(makestr),
+ kCFStringEncodingUTF8);
+ else
+ strcpy(makestr, "Unknown");
- if (!strncasecmp(modelstr + 1, "hp ", 3))
- _cups_strcpy(modelstr + 1, modelstr + 4);
+ if (model)
+ CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1,
+ kCFStringEncodingUTF8);
+ else
+ strcpy(modelstr + 1, "Printer");
optionsstr[0] = '\0';
if (serial != NULL)
httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
strncat(uristr, optionsstr, sizeof(uristr));
+ /*
+ * Fix common HP 1284 bug...
+ */
+
+ if (!strcasecmp(makestr, "Hewlett-Packard"))
+ strcpy(makestr, "HP");
+
+ if (!strncasecmp(modelstr + 1, "hp ", 3))
+ _cups_strcpy(modelstr + 1, modelstr + 4);
+
printf("direct %s \"%s %s\" \"%s %s USB\" \"%s\"\n", uristr, makestr,
&modelstr[1], makestr, &modelstr[1], idstr);
static Boolean find_device_callback(void *refcon, io_service_t obj)
{
Boolean keepLooking = true;
+ printer_data_t *userData = (printer_data_t *)refcon;
- if (obj != 0x0 && refcon != NULL) {
+ if (obj != 0x0) {
CFStringRef idString = NULL;
UInt32 location = -1;
- printer_data_t *userData = (printer_data_t *)refcon;
copy_devicestring(obj, &idString, &location);
if (idString != NULL) {
copy_deviceinfo(idString, &make, &model, &serial);
if (CFStringCompare(make, userData->make, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
if (CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
- if (userData->serial != NULL) {
- if (serial != NULL && CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+ if (userData->serial != NULL && CFStringGetLength(userData->serial) > 0 ) {
+ if (serial != NULL && CFStringCompare(serial, userData->serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
IOObjectRetain(obj);
userData->printerObj = obj;
keepLooking = false;
}
}
else {
- keepLooking = (refcon != NULL && ((printer_data_t *)refcon)->printerObj == 0);
+ keepLooking = (userData->printerObj == 0);
+ if (obj == 0x0 && keepLooking) {
+ CFRunLoopTimerContext context = { 0, userData, NULL, NULL, NULL };
+ CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 1.0, 10, 0x0, 0x0, statusTimerCallback, &context);
+ if (timer != NULL) {
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+ userData->statusTimer = timer;
+ }
+ }
+ }
+
+ if (!keepLooking && userData->statusTimer != NULL) {
+ fputs("STATE: -offline-error\n", stderr);
+ fputs(_("INFO: Printer is now on-line.\n"), stderr);
+ CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), userData->statusTimer, kCFRunLoopDefaultMode);
+ CFRelease(userData->statusTimer);
+ userData->statusTimer = NULL;
}
return keepLooking;
}
+static void statusTimerCallback (CFRunLoopTimerRef timer, void *info)
+{
+ fputs("STATE: +offline-error\n", stderr);
+ fputs(_("INFO: Printer is currently off-line.\n"), stderr);
+}
#pragma mark -
/*
#ifdef DEBUG
char bundlestr[1024];
CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
- fprintf(stderr, "DEBUG:load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
+ fprintf(stderr, "DEBUG: load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
#endif /* DEBUG */
return kr;
/*
* 'load_printerdriver()' - Load a vendor's (or generic) classdriver.
+ *
+ * If driverBundlePath is not NULL on return it is the callers responsbility to release it!
*/
-static kern_return_t load_printerdriver(printer_data_t *printer)
+static kern_return_t load_printerdriver(printer_data_t *printer, CFStringRef *driverBundlePath)
{
- IOCFPlugInInterface **iodev = NULL;
- SInt32 score;
+ IOCFPlugInInterface **iodev = NULL;
+ SInt32 score;
+ kern_return_t kr;
+ printer_interface_t intf;
+ HRESULT res;
- kern_return_t kr = IOCreatePlugInInterfaceForService(printer->printerObj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
- if (kr == kIOReturnSuccess) {
- printer_interface_t intf;
- HRESULT res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
- if (res == noErr) {
- CFMutableDictionaryRef properties = NULL;
+ kr = IOCreatePlugInInterfaceForService(printer->printerObj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
+ if (kr == kIOReturnSuccess)
+ {
+ if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf)) == noErr)
+ {
+ *driverBundlePath = IORegistryEntryCreateCFProperty(printer->printerObj, kUSBClassDriverProperty, NULL, kNilOptions);
- kr = IORegistryEntryCreateCFProperties(printer->printerObj, &properties, NULL, kNilOptions);
- if (kr == kIOReturnSuccess) {
- CFStringRef driverBundlePath = NULL;
- if (properties != NULL) {
- driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
- }
- kr = load_classdriver(driverBundlePath, intf, &printer->printerDriver);
- }
+ kr = load_classdriver(*driverBundlePath, intf, &printer->printerDriver);
if (kr != kIOReturnSuccess)
(*intf)->Release(intf);
* 'registry_open()' - Open a connection to the printer.
*/
-static kern_return_t registry_open(printer_data_t *printer)
+static kern_return_t registry_open(printer_data_t *printer, CFStringRef *driverBundlePath)
{
- kern_return_t kr = load_printerdriver(printer);
+ printer->directionalFlag = 0;
+
+ kern_return_t kr = load_printerdriver(printer, driverBundlePath);
if (kr != kIOReturnSuccess) {
kr = -2;
}
kr = -1;
}
}
+ } else {
+ printer->directionalFlag = 1;
}
}
static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation)
{
- IOCFPlugInInterface **iodev = NULL;
- SInt32 score;
-
- kern_return_t kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID,
+ IOCFPlugInInterface **iodev = NULL;
+ SInt32 score;
+ kern_return_t kr;
+ printer_interface_t intf;
+ HRESULT res;
+ classdriver_context_t **klassDriver = NULL;
+ CFStringRef driverBundlePath;
+
+ kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID, &iodev, &score);
- if (kr == kIOReturnSuccess) {
- printer_interface_t intf;
-
- HRESULT res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
- if (res == noErr) {
+ if (kr == kIOReturnSuccess)
+ {
+ if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf)) == noErr)
+ {
/* ignore the result for location id... */
(void)(*intf)->GetLocationID(intf, deviceLocation);
- CFMutableDictionaryRef properties = NULL;
- kr = IORegistryEntryCreateCFProperties(usbInterface, &properties, NULL, kNilOptions);
- if (kIOReturnSuccess == kr) {
- classdriver_context_t **klassDriver = NULL;
- CFStringRef driverBundlePath = NULL;
+ driverBundlePath = IORegistryEntryCreateCFProperty( usbInterface, kUSBClassDriverProperty, NULL, kNilOptions );
- if (properties != NULL) {
- driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
- }
+ kr = load_classdriver(driverBundlePath, intf, &klassDriver);
+
+ if (kr != kIOReturnSuccess && driverBundlePath != NULL)
+ kr = load_classdriver(NULL, intf, &klassDriver);
- kr = load_classdriver(driverBundlePath, intf, &klassDriver);
- if (kr != kIOReturnSuccess && driverBundlePath != NULL)
- kr = load_classdriver(NULL, intf, &klassDriver);
- if (kr == kIOReturnSuccess && klassDriver != NULL) {
+ if (kr == kIOReturnSuccess && klassDriver != NULL)
kr = copy_deviceid(klassDriver, deviceID);
- }
- unload_classdriver(&klassDriver);
- if (properties != NULL)
- CFRelease(properties);
- }
+ unload_classdriver(&klassDriver);
+
+ if (driverBundlePath != NULL)
+ CFRelease(driverBundlePath);
/* (*intf)->Release(intf); */
}
}
+/*
+ * 'cfstr_create_and_trim()' - Create a CFString from a c-string and
+ * trim it's whitespace characters.
+ */
+
+CFStringRef cfstr_create_and_trim(const char *cstr)
+{
+ CFStringRef cfstr;
+ CFMutableStringRef cfmutablestr = NULL;
+
+ if ((cfstr = CFStringCreateWithCString(NULL, cstr, kCFStringEncodingUTF8)) != NULL)
+ {
+ if ((cfmutablestr = CFStringCreateMutableCopy(NULL, 1024, cfstr)) != NULL)
+ CFStringTrimWhitespace(cfmutablestr);
+
+ CFRelease(cfstr);
+ }
+ return (CFStringRef) cfmutablestr;
+}
+
+
#pragma mark -
/*
* 'parse_options()' - Parse uri options.
*waitEOF = false;
}
else {
- fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value);
+ fprintf(stderr, _("WARNING: Boolean expected for waiteof option \"%s\"\n"), value);
}
}
else if (strcasecmp(optionName, "serial") == 0) {
CFRelease(lang[0]);
CFRelease(langArray);
} else {
- fprintf(stderr, "DEBUG: usb: LANG environment variable missing.\n");
+ fputs("DEBUG: usb: LANG environment variable missing.\n", stderr);
}
}
}
}
else {
- fprintf(stderr, "DEBUG: usb child running i386 again\n");
+ fputs("DEBUG: usb child running i386 again\n", stderr);
exitstatus = ENOENT;
}
return NULL;
}
+/*
+ * 'reqestWait_thread()' - A thread cupsSideChannelDoRequest wait.
+ */
+static void *reqestWait_thread(void *reference) {
+ printer_data_t *userData = (printer_data_t *)reference;
+ int datalen;
+ cups_sc_command_t command;
+ cups_sc_status_t status;
+ uint64_t start, delay;
+ struct mach_timebase_info timeBaseInfo;
+ char data[2048];
+
+ /*
+ * Calculate what 100 milliSeconds are in mach absolute time...
+ */
+ mach_timebase_info(&timeBaseInfo);
+ delay = ((uint64_t)100000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
+
+ /* interface close wait mutex lock. */
+ pthread_mutex_lock(&(userData->waitCloseMutex));
+
+ do {
+ /*
+ * Remember when we started so we can throttle the loop after the cupsSideChannelDoRequest call...
+ */
+ start = mach_absolute_time();
+
+ /* Poll for a command... */
+ command=0;
+ datalen = sizeof(data);
+ bzero(data, sizeof(data));
+
+ if (!cupsSideChannelRead(&command, &status, data, &datalen, 0.0)) {
+ datalen = sizeof(data);
+
+ switch (command) {
+ case CUPS_SC_CMD_SOFT_RESET:
+ /* do a soft reset */
+ usbSoftReset(userData, &status);
+ datalen = 0;
+ userData->reqWaitDone = 1;
+ break;
+ case CUPS_SC_CMD_DRAIN_OUTPUT:
+ /* drain all pending output */
+ usbDrainOutput(userData, &status);
+ datalen = 0;
+ break;
+ case CUPS_SC_CMD_GET_BIDI:
+ /* return whether the connection is bidirectional */
+ usbGetBidirectional(userData, &status, data, &datalen);
+ break;
+ case CUPS_SC_CMD_GET_DEVICE_ID:
+ /* return the IEEE-1284 device ID */
+ usbGetDeviceID(userData, &status, data, &datalen);
+ break;
+ case CUPS_SC_CMD_GET_STATE:
+ /* return the device state */
+ usbGetDevState(userData, &status, data, &datalen);
+ break;
+ default:
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ if (userData->writeDone) {
+ status = CUPS_SC_STATUS_NONE;
+ }
+
+ /* Send a response... */
+ cupsSideChannelWrite(command, status, data, datalen, 1.0);
+ }
+
+ /*
+ * Make sure this loop executes no more than once every 500 miliseconds...
+ */
+ if ((userData->waitEOF) || (!userData->reqWaitDone)) {
+ mach_wait_until(start + delay);
+ }
+ } while(!userData->reqWaitDone);
+
+ sleep(1);
+ pthread_mutex_lock(&userData->reqWaitMutex);
+ userData->reqWqitFlag = 1;
+ pthread_cond_signal(&userData->reqWaitCompCond);
+ pthread_mutex_unlock(&userData->reqWaitMutex);
+
+ /* interface close wait mutex unlock. */
+ pthread_mutex_unlock(&(userData->waitCloseMutex));
+
+ return NULL;
+}
+
+#pragma mark -
+/*
+ * 'usbSoftReset'
+ */
+static void usbSoftReset(printer_data_t *userData, cups_sc_status_t *status) {
+ OSStatus err;
+
+ /* write stop. */
+ userData->writeDone = 1;
+
+ /* Abort (print_device()-WritePipe kIOReturnAborted return) */
+ if (userData->printerDriver != NULL)
+ err = (*(userData->printerDriver))->Abort(userData->printerDriver);
+
+ /* print_device() WritePipe_Loop break wait. */
+ pthread_mutex_lock(&(userData->writeCompMutex));
+ pthread_mutex_unlock(&(userData->writeCompMutex));
+
+ /* SoftReset */
+ if (userData->printerDriver != NULL)
+ (*(userData->printerDriver))->SoftReset(userData->printerDriver, 0);
+
+ if (status != NULL)
+ *status = CUPS_SC_STATUS_OK;
+}
+
+/*
+ * 'usbDrainOutput'
+ */
+static void usbDrainOutput(printer_data_t *userData, cups_sc_status_t *status) {
+ OSStatus osSts = noErr; /* Function results */
+ OSStatus err = noErr;
+ UInt32 wbytes; /* Number of bytes written */
+ ssize_t nbytes; /* Number of bytes read */
+ char *bufptr;
+
+ bufptr = userData->dataBuffer+userData->dataOffset;
+ nbytes = userData->dataSize;
+
+ while((nbytes > 0) && (osSts == noErr)) {
+ wbytes = nbytes;
+ osSts = (*(userData->printerDriver))->WritePipe(userData->printerDriver, (UInt8*)bufptr, &wbytes, 0);
+
+ if (wbytes < 0 || noErr != osSts) {
+ if (osSts != kIOReturnAborted) {
+ err = (*(userData->printerDriver))->Abort(userData->printerDriver);
+ break;
+ }
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+
+ if (status != NULL) {
+ if ((osSts != noErr) || (err != noErr)) {
+ *status = CUPS_SC_STATUS_IO_ERROR;
+ } else {
+ *status = CUPS_SC_STATUS_OK;
+ }
+ }
+}
+
+/*
+ * 'usbGetBidirectional'
+ */
+static void usbGetBidirectional(printer_data_t *userData, cups_sc_status_t *status, char *data, int *datalen) {
+ *data = userData->directionalFlag;
+ *datalen = 1;
+
+ if (status != NULL)
+ *status = CUPS_SC_STATUS_OK;
+}
+
+/*
+ * 'usbGetDeviceID'
+ */
+static void usbGetDeviceID(printer_data_t *userData, cups_sc_status_t *status, char *data, int *datalen) {
+ UInt32 deviceLocation = 0;
+ CFStringRef deviceIDString = NULL;
+
+ /* GetDeviceID */
+ copy_devicestring(userData->printerObj, &deviceIDString, &deviceLocation);
+ CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8);
+ *datalen = strlen(data);
+
+ if (status != NULL) {
+ *status = CUPS_SC_STATUS_OK;
+ }
+}
+
+/*
+ * 'usbGetDevState'
+ */
+static void usbGetDevState(printer_data_t *userData, cups_sc_status_t *status, char *data, int *datalen) {
+ *data = CUPS_SC_STATE_ONLINE;
+ *datalen = 1;
+
+ if (status != NULL) {
+ *status = CUPS_SC_STATUS_OK;
+ }
+}
/*
- * End of "$Id: usb-darwin.c 5630 2006-06-05 18:42:53Z mike $".
+ * End of "$Id: usb-darwin.c 6491 2007-04-30 18:21:52Z mike $".
*/