Author: laplace Date: 2009-10-10 17:08:58 +0200 (Sat, 10 Oct 2009) New Revision: 33501 Changeset: http://dev.haiku-os.org/changeset/33501/haiku Modified: haiku/trunk/build/jam/HaikuImage haiku/trunk/src/add-ons/kernel/drivers/Jamfile haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.cpp haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.h Log: - Cleaned up usb_printer driver. - Fixed issues sending data over USB bus (actually write data when requested to; increased timeout when writing data). - Added usb_printer to build and Haiku image. - Sending data to printer over USB bus works now in Haiku (cat ... > /dev/priner/usb/0). Not sure if it works when printing from an application as I don't have a driver that supports my printer yet. Modified: haiku/trunk/build/jam/HaikuImage =================================================================== --- haiku/trunk/build/jam/HaikuImage 2009-10-10 14:58:54 UTC (rev 33500) +++ haiku/trunk/build/jam/HaikuImage 2009-10-10 15:08:58 UTC (rev 33501) @@ -228,6 +228,7 @@ AddDriversToHaikuImage bus : usb_raw fw_raw ; AddDriversToHaikuImage disk floppy : $(X86_ONLY)pc_floppy ; AddDriversToHaikuImage disk usb : usb_disk ; +AddDriversToHaikuImage printer usb : usb_printer ; AddDriversToHaikuImage disk virtual : nbd ; AddDriversToHaikuImage dvb : cx23882 ; AddDriversToHaikuImage graphics : $(SYSTEM_ADD_ONS_DRIVERS_GRAPHICS) ; Modified: haiku/trunk/src/add-ons/kernel/drivers/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/Jamfile 2009-10-10 14:58:54 UTC (rev 33500) +++ haiku/trunk/src/add-ons/kernel/drivers/Jamfile 2009-10-10 15:08:58 UTC (rev 33501) @@ -14,6 +14,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network ; SubInclude HAIKU_TOP src add-ons kernel drivers ports ; SubInclude HAIKU_TOP src add-ons kernel drivers power ; +SubInclude HAIKU_TOP src add-ons kernel drivers printer ; SubInclude HAIKU_TOP src add-ons kernel drivers random ; SubInclude HAIKU_TOP src add-ons kernel drivers tty ; SubInclude HAIKU_TOP src add-ons kernel drivers video ; Modified: haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.cpp 2009-10-10 14:58:54 UTC (rev 33500) +++ haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.cpp 2009-10-10 15:08:58 UTC (rev 33501) @@ -20,8 +20,16 @@ #define DEVICE_NAME_BASE "printer/usb/" #define DEVICE_NAME DEVICE_NAME_BASE"%ld" +#define SECONDS ((bigtime_t)1000 * 1000) +#define MINUTES (60 * SECONDS) +#define HOURS (60 * MINUTES) -#define TRACE_USB_PRINTER 1 +// large timeout so user can fix any issues (for instance insert paper) +// before printing can start or continue +#define WRITE_TIMEOUT (1 * HOURS) +#define READ_TIMEOUT (2 * SECONDS) + +// #define TRACE_USB_PRINTER 1 #ifdef TRACE_USB_PRINTER #define TRACE(x...) dprintf(DRIVER_NAME": "x) #define TRACE_ALWAYS(x...) dprintf(DRIVER_NAME": "x) @@ -50,26 +58,7 @@ status_t usb_printer_transfer_data(printer_device *device, bool directionIn, void *data, size_t dataLength); -#if 0 -status_t usb_printer_mass_storage_reset(printer_device *device); -uint8 usb_printer_get_max_lun(printer_device *device); -void usb_printer_reset_recovery(printer_device *device); -status_t usb_printer_receive_csw(printer_device *device, - command_status_wrapper *status); -status_t usb_printer_operation(device_lun *lun, uint8 operation, - uint8 opLength, uint32 logicalBlockAddress, - uint16 transferLength, void *data, uint32 *dataLength, - bool directionIn); -status_t usb_printer_request_sense(device_lun *lun); -status_t usb_printer_mode_sense(device_lun *lun); -status_t usb_printer_test_unit_ready(device_lun *lun); -status_t usb_printer_inquiry(device_lun *lun); -status_t usb_printer_reset_capacity(device_lun *lun); -status_t usb_printer_update_capacity(device_lun *lun); -status_t usb_printer_synchronize(device_lun *lun, bool force); -#endif - // //#pragma mark - Device Allocation Helper Functions // @@ -110,7 +99,8 @@ } do { - result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 2000000); + bigtime_t timeout = directionIn ? READ_TIMEOUT : WRITE_TIMEOUT; + result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, timeout); if (result == B_TIMED_OUT) { // Cancel the transfer and collect the sem that should now be // released through the callback on cancel. Handling of device @@ -130,405 +120,8 @@ return B_OK; } -#if 0 -status_t -usb_printer_mass_storage_reset(printer_device *device) -{ - return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT - | USB_REQTYPE_CLASS, REQUEST_MASS_STORAGE_RESET, 0x0000, - device->interface, 0, NULL, NULL); -} - -uint8 -usb_printer_get_max_lun(printer_device *device) -{ - uint8 result = 0; - size_t actualLength = 0; - - // devices that do not support multiple LUNs may stall this request - if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN - | USB_REQTYPE_CLASS, REQUEST_GET_MAX_LUN, 0x0000, device->interface, - 1, &result, &actualLength) != B_OK || actualLength != 1) - return 0; - - if (result > MAX_LOGICAL_UNIT_NUMBER) { - // invalid max lun - return 0; - } - - return result; -} - - -status_t -usb_printer_receive_csw(printer_device *device, command_status_wrapper *status) -{ - status_t result = usb_printer_transfer_data(device, true, status, - sizeof(command_status_wrapper)); - if (result != B_OK) - return result; - - if (device->status != B_OK - || device->actual_length != sizeof(command_status_wrapper)) { - // receiving the command status wrapper failed - return B_ERROR; - } - - return B_OK; -} - - -status_t -usb_printer_operation(device_lun *lun, uint8 operation, uint8 opLength, - uint32 logicalBlockAddress, uint16 transferLength, void *data, - uint32 *dataLength, bool directionIn) -{ - TRACE("operation: lun: %u; op: %u; oplen: %u; lba: %lu; tlen: %u; data: %p; dlen: %p (%lu); in: %c\n", - lun->logical_unit_number, operation, opLength, logicalBlockAddress, - transferLength, data, dataLength, dataLength ? *dataLength : 0, - directionIn ? 'y' : 'n'); - - printer_device *device = lun->device; - command_block_wrapper command; - command.signature = CBW_SIGNATURE; - command.tag = device->current_tag++; - command.data_transfer_length = (dataLength != NULL ? *dataLength : 0); - command.flags = (directionIn ? CBW_DATA_INPUT : CBW_DATA_OUTPUT); - command.lun = lun->logical_unit_number; - command.command_block_length = opLength; - memset(command.command_block, 0, sizeof(command.command_block)); - - switch (opLength) { - case 6: { - scsi_command_6 *commandBlock = (scsi_command_6 *)command.command_block; - commandBlock->operation = operation; - commandBlock->lun = lun->logical_unit_number << 5; - commandBlock->allocation_length = (uint8)transferLength; - if (operation == SCSI_MODE_SENSE_6) { - // we hijack the lba argument to transport the desired page - commandBlock->reserved[1] = (uint8)logicalBlockAddress; - } - break; - } - - case 10: { - scsi_command_10 *commandBlock = (scsi_command_10 *)command.command_block; - commandBlock->operation = operation; - commandBlock->lun_flags = lun->logical_unit_number << 5; - commandBlock->logical_block_address = htonl(logicalBlockAddress); - commandBlock->transfer_length = htons(transferLength); - break; - } - - default: - TRACE_ALWAYS("unsupported operation length %d\n", opLength); - return B_BAD_VALUE; - } - - status_t result = usb_printer_transfer_data(device, false, &command, - sizeof(command_block_wrapper)); - if (result != B_OK) - return result; - - if (device->status != B_OK || - device->actual_length != sizeof(command_block_wrapper)) { - // sending the command block wrapper failed - TRACE_ALWAYS("sending the command block wrapper failed\n"); - usb_printer_reset_recovery(device); - return B_ERROR; - } - - size_t transferedData = 0; - if (data != NULL && dataLength != NULL && *dataLength > 0) { - // we have data to transfer in a data stage - result = usb_printer_transfer_data(device, directionIn, data, *dataLength); - if (result != B_OK) - return result; - - transferedData = device->actual_length; - if (device->status != B_OK || transferedData != *dataLength) { - // sending or receiving of the data failed - if (device->status == B_DEV_STALLED) { - TRACE("stall while transfering data\n"); - gUSBModule->clear_feature(directionIn ? device->bulk_in - : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); - } else { - TRACE_ALWAYS("sending or receiving of the data failed\n"); - usb_printer_reset_recovery(device); - return B_ERROR; - } - } - } - - command_status_wrapper status; - result = usb_printer_receive_csw(device, &status); - if (result != B_OK) { - // in case of a stall or error clear the stall and try again - gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); - result = usb_printer_receive_csw(device, &status); - } - - if (result != B_OK) { - TRACE_ALWAYS("receiving the command status wrapper failed\n"); - usb_printer_reset_recovery(device); - return result; - } - - if (status.signature != CSW_SIGNATURE || status.tag != command.tag) { - // the command status wrapper is not valid - TRACE_ALWAYS("command status wrapper is not valid\n"); - usb_printer_reset_recovery(device); - return B_ERROR; - } - - switch (status.status) { - case CSW_STATUS_COMMAND_PASSED: - case CSW_STATUS_COMMAND_FAILED: { - if (status.data_residue > command.data_transfer_length) { - // command status wrapper is not meaningful - TRACE_ALWAYS("command status wrapper has invalid residue\n"); - usb_printer_reset_recovery(device); - return B_ERROR; - } - - if (dataLength != NULL) { - *dataLength -= status.data_residue; - if (transferedData < *dataLength) { - TRACE_ALWAYS("less data transfered than indicated\n"); - *dataLength = transferedData; - } - } - - if (status.status == CSW_STATUS_COMMAND_PASSED) { - // the operation is complete and has succeeded - return B_OK; - } else { - // the operation is complete but has failed at the SCSI level - TRACE_ALWAYS("operation 0x%02x failed at the SCSI level\n", - operation); - result = usb_printer_request_sense(lun); - return result == B_OK ? B_ERROR : result; - } - } - - case CSW_STATUS_PHASE_ERROR: { - // a protocol or device error occured - TRACE_ALWAYS("phase error in operation 0x%02x\n", operation); - usb_printer_reset_recovery(device); - return B_ERROR; - } - - default: { - // command status wrapper is not meaningful - TRACE_ALWAYS("command status wrapper has invalid status\n"); - usb_printer_reset_recovery(device); - return B_ERROR; - } - } -} - - // -//#pragma mark - Helper/Convenience Functions -// - - -status_t -usb_printer_request_sense(device_lun *lun) -{ - uint32 dataLength = sizeof(scsi_request_sense_6_parameter); - scsi_request_sense_6_parameter parameter; - status_t result = usb_printer_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0, - dataLength, ¶meter, &dataLength, true); - if (result != B_OK) { - TRACE_ALWAYS("getting request sense data failed\n"); - return result; - } - - if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY) { - TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: 0x%02x;\n", - parameter.sense_key, parameter.additional_sense_code, - parameter.additional_sense_code_qualifier); - } - - switch (parameter.sense_key) { - case SCSI_SENSE_KEY_NO_SENSE: - case SCSI_SENSE_KEY_RECOVERED_ERROR: - return B_OK; - - case SCSI_SENSE_KEY_NOT_READY: - TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n", - parameter.additional_sense_code, - parameter.additional_sense_code_qualifier); - lun->media_present = false; - usb_printer_reset_capacity(lun); - return B_DEV_NO_MEDIA; - - case SCSI_SENSE_KEY_HARDWARE_ERROR: - case SCSI_SENSE_KEY_MEDIUM_ERROR: - TRACE_ALWAYS("request_sense: media or hardware error\n"); - return B_DEV_UNREADABLE; - - case SCSI_SENSE_KEY_ILLEGAL_REQUEST: - TRACE_ALWAYS("request_sense: illegal request\n"); - return B_DEV_INVALID_IOCTL; - - case SCSI_SENSE_KEY_UNIT_ATTENTION: - TRACE_ALWAYS("request_sense: media changed\n"); - lun->media_changed = true; - lun->media_present = true; - return B_DEV_MEDIA_CHANGED; - - case SCSI_SENSE_KEY_DATA_PROTECT: - TRACE_ALWAYS("request_sense: write protected\n"); - return B_READ_ONLY_DEVICE; - - case SCSI_SENSE_KEY_ABORTED_COMMAND: - TRACE_ALWAYS("request_sense: command aborted\n"); - return B_CANCELED; - } - - return B_ERROR; -} - - -status_t -usb_printer_mode_sense(device_lun *lun) -{ - uint32 dataLength = sizeof(scsi_mode_sense_6_parameter); - scsi_mode_sense_6_parameter parameter; - status_t result = usb_printer_operation(lun, SCSI_MODE_SENSE_6, 6, - SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, ¶meter, - &dataLength, true); - if (result != B_OK) { - TRACE_ALWAYS("getting mode sense data failed\n"); - return result; - } - - lun->write_protected - = (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) != 0; - TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no"); - return B_OK; -} - - -status_t -usb_printer_test_unit_ready(device_lun *lun) -{ - return usb_printer_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0, NULL, NULL, - true); -} - - -status_t -usb_printer_inquiry(device_lun *lun) -{ - uint32 dataLength = sizeof(scsi_inquiry_6_parameter); - scsi_inquiry_6_parameter parameter; - status_t result = B_ERROR; - for (uint32 tries = 0; tries < 3; tries++) { - result = usb_printer_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength, - ¶meter, &dataLength, true); - if (result == B_OK) - break; - } - if (result != B_OK) { - TRACE_ALWAYS("getting inquiry data failed\n"); - lun->device_type = B_DISK; - lun->removable = true; - return result; - } - - TRACE("peripherial_device_type 0x%02x\n", parameter.peripherial_device_type); - TRACE("peripherial_qualifier 0x%02x\n", parameter.peripherial_qualifier); - TRACE("removable_medium %s\n", parameter.removable_medium ? "yes" : "no"); - TRACE("version 0x%02x\n", parameter.version); - TRACE("response_data_format 0x%02x\n", parameter.response_data_format); - TRACE_ALWAYS("vendor_identification \"%.8s\"\n", parameter.vendor_identification); - TRACE_ALWAYS("product_identification \"%.16s\"\n", parameter.product_identification); - TRACE_ALWAYS("product_revision_level \"%.4s\"\n", parameter.product_revision_level); - lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ - lun->removable = (parameter.removable_medium == 1); - return B_OK; -} - - -status_t -usb_printer_reset_capacity(device_lun *lun) -{ - lun->block_size = 512; - lun->block_count = 0; - return B_OK; -} - - -status_t -usb_printer_update_capacity(device_lun *lun) -{ - uint32 dataLength = sizeof(scsi_read_capacity_10_parameter); - scsi_read_capacity_10_parameter parameter; - status_t result = B_ERROR; - - // Retry reading the capacity up to three times. The first try might only - // yield a unit attention telling us that the device or media status - // changed, which is more or less expected if it is the first operation - // on the device or the device only clears the unit atention for capacity - // reads. - for (int32 i = 0; i < 3; i++) { - result = usb_printer_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0, - ¶meter, &dataLength, true); - if (result == B_OK) - break; - } - - if (result != B_OK) { - TRACE_ALWAYS("failed to update capacity\n"); - lun->media_present = false; - lun->media_changed = false; - usb_printer_reset_capacity(lun); - return result; - } - - lun->media_present = true; - lun->media_changed = false; - lun->block_size = ntohl(parameter.logical_block_length); - lun->block_count = ntohl(parameter.last_logical_block_address) + 1; - return B_OK; -} - - -status_t -usb_printer_synchronize(device_lun *lun, bool force) -{ - if (lun->device->sync_support == 0) { - // this device reported an illegal request when syncing or repeatedly - // returned an other error, it apparently does not support syncing... - return B_UNSUPPORTED; - } - - if (!lun->should_sync && !force) - return B_OK; - - status_t result = usb_printer_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10, - 0, 0, NULL, NULL, false); - - if (result == B_OK) { - lun->device->sync_support = SYNC_SUPPORT_RELOAD; - lun->should_sync = false; - return B_OK; - } - - if (result == B_DEV_INVALID_IOCTL) - lun->device->sync_support = 0; - else - lun->device->sync_support--; - - return result; -} -#endif - -// //#pragma mark - Device Attach/Detach Notifications and Callback // @@ -537,7 +130,6 @@ usb_printer_callback(void *cookie, status_t status, void *data, size_t actualLength) { - //TRACE("callback()\n"); printer_device *device = (printer_device *)cookie; device->status = status; device->actual_length = actualLength; @@ -555,7 +147,6 @@ device->open_count = 0; device->interface = 0xff; device->current_tag = 0; - device->sync_support = SYNC_SUPPORT_RELOAD; device->block_size = 4096; // scan through the interfaces to find our bulk-only data interface @@ -693,78 +284,6 @@ // -//#pragma mark - Partial Buffer Functions -// - -#if 0 -static bool -usb_printer_needs_partial_buffer(printer_device *device, off_t position, size_t length, - uint32 &blockPosition, uint16 &blockCount) -{ - blockPosition = (uint32)(position / device->block_size); - if ((off_t)blockPosition * device->block_size != position) - return true; - - blockCount = (uint16)(length / device->block_size); - if ((size_t)blockCount * device->block_size != length) - return true; - - return false; -} - - -static status_t -usb_printer_block_read(printer_device *device, uint32 blockPosition, uint16 blockCount, - void *buffer, size_t *length) -{ - status_t result = usb_printer_operation(device, SCSI_READ_10, 10, blockPosition, - blockCount, buffer, length, true); - return result; -} - - -static status_t -usb_printer_block_write(printer_device *device, uint32 blockPosition, uint16 blockCount, - void *buffer, size_t *length) -{ - status_t result = usb_printer_operation(device, SCSI_WRITE_10, 10, blockPosition, - blockCount, buffer, length, false); - if (result == B_OK) - lun->should_sync = true; - return result; -} - - -static status_t -usb_printer_prepare_partial_buffer(printer_device *device, off_t position, size_t length, - void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, - uint16 &blockCount) -{ - blockPosition = (uint32)(position / lun->block_size); - blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) - / lun->block_size) - blockPosition); - size_t blockLength = blockCount * lun->block_size; - blockBuffer = malloc(blockLength); - if (blockBuffer == NULL) { - TRACE_ALWAYS("no memory to allocate partial buffer\n"); - return B_NO_MEMORY; - } - - status_t result = usb_printer_block_read(device, blockPosition, blockCount, - blockBuffer, &blockLength); - if (result != B_OK) { - TRACE_ALWAYS("block read failed when filling partial buffer\n"); - free(blockBuffer); - return result; - } - - off_t offset = position - (blockPosition * lun->block_size); - partialBuffer = (uint8 *)blockBuffer + offset; - return B_OK; -} -#endif - -// //#pragma mark - Driver Hooks // @@ -840,7 +359,7 @@ switch (op) { case USB_PRINTER_GET_DEVICE_ID: { // TODO implement - strcpy(buffer, "Not implemented"); + strncpy((char*)buffer, "Not implemented", length); result = B_OK; break; } @@ -863,7 +382,7 @@ return result; } - result = usb_printer_transfer_data(device, true, buffer, *length); + result = usb_printer_transfer_data(device, directionIn, buffer, *length); if (result != B_OK) { return result; } Modified: haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.h =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.h 2009-10-10 14:58:54 UTC (rev 33500) +++ haiku/trunk/src/add-ons/kernel/drivers/printer/usb/usb_printer.h 2009-10-10 15:08:58 UTC (rev 33501) @@ -31,21 +31,6 @@ #define REQUEST_GET_PORT_STATUS 0x01 #define REQUEST_SOFT_RESET 0x02 -#if 0 -#define CBW_SIGNATURE 0x43425355 -#define CBW_DATA_OUTPUT 0x00 -#define CBW_DATA_INPUT 0x80 - -#define CSW_SIGNATURE 0x53425355 -#define CSW_STATUS_COMMAND_PASSED 0x00 -#define CSW_STATUS_COMMAND_FAILED 0x01 -#define CSW_STATUS_PHASE_ERROR 0x02 - -#endif - -// TODO remove? -#define SYNC_SUPPORT_RELOAD 5 - typedef struct printer_device_s { usb_device device; uint32 device_number; @@ -60,7 +45,6 @@ usb_pipe bulk_out; uint8 interface; uint32 current_tag; - uint8 sync_support; // used to store callback information sem_id notify; @@ -71,42 +55,4 @@ uint32 block_size; } printer_device; -#if 0 -// represents a logical unit on the pointed to device - this gets published -struct device_lun_s { - disk_device *device; - char name[32]; - uint8 logical_unit_number; - bool should_sync; - - // device information through read capacity/inquiry - bool media_present; - bool media_changed; - uint32 block_count; - uint32 block_size; - uint8 device_type; - bool removable; - bool write_protected; -}; - - -typedef struct command_block_wrapper_s { - uint32 signature; - uint32 tag; - uint32 data_transfer_length; - uint8 flags; - uint8 lun; - uint8 command_block_length; - uint8 command_block[16]; -} _PACKED command_block_wrapper; - - -typedef struct command_status_wrapper_s { - uint32 signature; - uint32 tag; - uint32 data_residue; - uint8 status; -} _PACKED command_status_wrapper; -#endif - #endif // _USB_PRINTER_H_