# --- T2-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # T2 SDE: package/.../linux26mm/adaptec-usbxchange.patch # Copyright (C) 2006 The T2 SDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- T2-COPYRIGHT-NOTE-END --- Support for the Adaptec USB*Xchange family of USB<->SCSI cables. - Rene Rebe --- linux-2.6.15-mm4/drivers/usb/storage/Kconfig 2006-01-30 12:16:10.838447250 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/Kconfig 2006-01-30 12:09:28.857325000 +0100 @@ -134,6 +134,13 @@ this input in any keybinding software. (e.g. gnome's keyboard short- cuts) +config USB_USBXCHANGE + tristate "Adaptec USBXchange and USB2Xchange firmware loader" + depends on USB_STORAGE + help + Say Y here to include additional code to load the firmware into the + Adaptec USBXchange and USB2Xchange USB --> SCSI converter dongle. + config USB_LIBUSUAL bool "The shared table of common (or usual) storage devices" depends on USB --- linux-2.6.15-mm4/drivers/usb/storage/Makefile 2006-01-30 12:16:10.838447250 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/Makefile 2006-01-30 12:08:29.781633000 +0100 @@ -24,6 +24,8 @@ usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ initializers.o $(usb-storage-obj-y) +obj-$(CONFIG_USB_USBXCHANGE) += usbxchange_fw.o + ifneq ($(CONFIG_USB_LIBUSUAL),) obj-$(CONFIG_USB) += libusual.o endif --- linux-2.6.15-mm4/drivers/usb/storage/initializers.c 2006-01-30 12:16:10.826446500 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/initializers.c 2006-01-30 12:08:09.340355500 +0100 @@ -164,3 +164,27 @@ return USB_STOR_TRANSPORT_FAILED; } +/* Firmware Initialisation for the Adaptec USB2Xchange, needed for + * to recognize devices properly. René Rebe */ +int usb2xchange_init(struct us_data *us) +{ + int result; + + US_DEBUGP ("usb2xchange_init: initialising after reenumeration.\n"); + + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, + 0x5a, 0x40, 0x01, + 0, 0, // buffer, + 0, // length, + 300); + US_DEBUGP ("usb2xchange_init: reset #1 (%d)\n", result); + + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, + 0x5a, 0x40, 0x02, + 0, 0, // buffer, + 0, // length, + 300); + US_DEBUGP ("usb2xchange_init: reset #2 (%d)\n", result); + + return result; +} --- linux-2.6.15-mm4/drivers/usb/storage/initializers.h 2006-01-30 12:16:10.826446500 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/initializers.h 2006-01-30 12:04:35.110967000 +0100 @@ -49,3 +49,6 @@ * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); int rio_karma_init(struct us_data *us); + +/* Firmware Initialization for the Adaptec USB2Xchange */ +int usb2xchange_init(struct us_data *us); --- linux-2.6.15-mm4/drivers/usb/storage/unusual_devs.h 2006-01-30 12:16:10.870449250 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/unusual_devs.h 2006-01-27 21:49:46.570867000 +0100 @@ -1180,6 +1180,21 @@ US_FL_SINGLE_LUN), #endif +/* Adaptec USBXchange and USB2Xchange, after firmware download. + * Requires Ez-USB Style firmware loader. René Rebe */ + +UNUSUAL_DEV( 0x03f3, 0x2001, 0x0000, 0xffff, + "Adaptec", + "USBXchange", + US_SC_SCSI, US_PR_BULK, NULL, + 0 ), + +UNUSUAL_DEV( 0x03f3, 0x2003, 0x0000, 0xffff, + "Adaptec", + "USB2Xchange", + US_SC_SCSI, US_PR_BULK, usb2xchange_init, + US_FL_SCM_MULT_TARG ), + /* Control/Bulk transport for all SubClass values */ USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR), USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR), --- linux-2.6.15-mm4/drivers/usb/storage/usbxchange_fw.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/usbxchange_fw.c 2006-01-28 09:45:14.308438000 +0100 @@ -0,0 +1,215 @@ +/* + * Firmware loader for Adaptec USBXchange / USB2Xchange. + * + * Uploads device firmware into the Adaptec USBXchange and USB2Xchange + * USB --> SCSI dongle. + * + * Current development and maintenance by: + * (c) 2005 René Rebe + * + * Initial work by: + * (c) 2004 Beier & Dauskardt IT + * + * Based on emi26.c: + * (c) 2002 Tapio Laxström + * + * To use this driver, you need to get the devices firmware from some + * windows driver: + * usbxchg_win_v120.exe - for USBXchange + * usb2xchg_win_drv_v200.exe - for USB2Xchange + * + * Hotplug firmware loader compatible files can be found at: + * http://dl.exactcode.de/adaptec-usbxchange/ + * + * Note: + * The USB2Xchange seems to have some internal buffer < 64K. + * Sending 64K requests crashes the device. Possibly it needs a + * "max_sectors: 8" setting. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, as published by + * the Free Software Foundation, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "usbxchange_fw.h" + +static int usbxchange_writememory(struct usb_device *dev, int address, + unsigned char *data, int length, + __u8 bRequest); +static int usbxchange_set_reset(struct usb_device *dev, int cpureg, + unsigned char reset_bit); +static int usbxchange_load_firmware(struct usb_device *dev); + +static int usbxchange_probe(struct usb_interface *iface, + const struct usb_device_id *id); +static void usbxchange_disconnect(struct usb_interface *iface); +static int __init usbxchange_init(void); +static void __exit usbxchange_exit(void); + +#define usbxchange_VENDOR_ID 0x03f3 +#define usbxchange_PRODUCT_ID 0x2000 +#define usb2xchange_PRODUCT_ID 0x2002 + +static struct usb_device_id usbxchange_usb_ids[] = { + {USB_DEVICE(usbxchange_VENDOR_ID, usbxchange_PRODUCT_ID)}, + {USB_DEVICE(usbxchange_VENDOR_ID, usb2xchange_PRODUCT_ID)}, + {} /* terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, usbxchange_usb_ids); + +/* thanks to drivers/usb/serial/keyspan_pda.c code */ +static int usbxchange_writememory(struct usb_device *dev, int address, + unsigned char *data, int length, __u8 request) +{ + int result; + unsigned char *buffer = kmalloc(length, GFP_KERNEL); + + if (!buffer) { + printk(KERN_ERR "usbxchange: kmalloc(%d) failed.\n", length); + return -ENOMEM; + } + memcpy(buffer, data, length); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, 0x40, + address, 0, buffer, length, 300); + kfree(buffer); + return result; +} + +/* thanks to drivers/usb/serial/keyspan_pda.c code */ +static int usbxchange_set_reset(struct usb_device *dev, int cpureg, + unsigned char reset_bit) +{ + int response; + printk(KERN_INFO "%s - %d\n", __FUNCTION__, reset_bit); + response = + usbxchange_writememory(dev, cpureg, &reset_bit, 1, + ANCHOR_LOAD_INTERNAL); + if (response < 0) { + printk(KERN_ERR "usbxchange: set_reset (%d) failed\n", + reset_bit); + } + return response; +} + +static int usbxchange_load_firmware(struct usb_device *dev) +{ + INTEL_HEX_RECORD *record; + int err, cpureg; + + const struct firmware *firmware; + + switch (le16_to_cpu(dev->descriptor.idProduct)) { + case usbxchange_PRODUCT_ID: + err = request_firmware(&firmware, "usbxchange.fw", &dev->dev); + cpureg = CPUCS_REG; + break; + case usb2xchange_PRODUCT_ID: + err = request_firmware(&firmware, "usb2xchange.fw", &dev->dev); + cpureg = CPUCS_REG_FX2; + break; + default: + printk(KERN_ERR "%s - device not recognized %x\n", __FUNCTION__, + le16_to_cpu(dev->descriptor.idProduct)); + return 1; + } + + if (err != 0) { + printk(KERN_ERR "Hotplug firmware request failed.\n"); + return err; + } + + /* Stop CPU */ + err = usbxchange_set_reset(dev, cpureg, 1); + err = usbxchange_set_reset(dev, cpureg, 1); + if (err < 0) { + printk(KERN_ERR "%s - error stopping dongle CPU: error = %d\n", + __FUNCTION__, err); + return err; + } + + /* Upload firmware */ + for (record = (INTEL_HEX_RECORD *)firmware->data; + record->type == 0; record++) { + + err = usbxchange_writememory(dev, le32_to_cpu(record->address), + record->data, + le32_to_cpu(record->length), + ANCHOR_LOAD_INTERNAL); + if (err < 0) { + printk(KERN_ERR + "%s - error loading firmware: error = %d\n", + __FUNCTION__, err); + return err; + } + } + + /* De-assert reset (let the CPU run) */ + err = usbxchange_set_reset(dev, cpureg, 1); + err = usbxchange_set_reset(dev, cpureg, 0); + if (err < 0) { + printk(KERN_ERR "%s - error resetting dongle CPU: error = %d\n", + __FUNCTION__, err); + return err; + } + + return 0; +} + +static int usbxchange_probe(struct usb_interface *iface, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(iface); + + printk(KERN_INFO "%s start\n", __FUNCTION__); + + usbxchange_load_firmware(dev); + + /* forcing an unload would save some kB of kernel memory ... */ + return 0; +} + +static void usbxchange_disconnect(struct usb_interface *iface) +{ +} + +static struct usb_driver usbxchange_driver = { + .name = "usbxchange_fw", + .probe = usbxchange_probe, + .disconnect = usbxchange_disconnect, + .id_table = usbxchange_usb_ids, +}; + +static int __init usbxchange_init(void) +{ + usb_register(&usbxchange_driver); + return 0; +} + +static void __exit usbxchange_exit(void) +{ + usb_deregister(&usbxchange_driver); +} + +module_init(usbxchange_init); +module_exit(usbxchange_exit); + +MODULE_AUTHOR("René Rebe , Sancho Dauskardt "); +MODULE_DESCRIPTION("Adaptec USBXchange firmware loader."); +MODULE_LICENSE("GPL"); + +/* vi:ai:syntax=c:sw=8:ts=8:tw=80 + */ --- linux-2.6.15-mm4/drivers/usb/storage/usbxchange_fw.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.15-usb2x/drivers/usb/storage/usbxchange_fw.h 2006-01-27 17:18:18.246377000 +0100 @@ -0,0 +1,45 @@ +/* + * Firmware loader for Adaptec USBXchange / USB2Xchange. + * + * Uploads device firmware into the Adaptec USBXchange and USB2Xchange + * USB --> SCSI dongle. + * + * Current development and maintenance by: + * (c) 2005 René Rebe + * + * Initial work by: + * (c) 2004 Beier & Dauskardt IT + * + * Based on emi26.c: + * (c) 2002 Tapio Laxström + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, as published by + * the Free Software Foundation, version 2. + */ + +#ifndef _USB_USBXCHANGE_FW_H_INCLUDED +#define _USB_USBXCHANGE_FW_H_INCLUDED + +#define MAX_INTEL_HEX_RECORD_LENGTH 16 +typedef struct _INTEL_HEX_RECORD { + __u32 length; + __u32 address; + __u32 type; + __u8 data[MAX_INTEL_HEX_RECORD_LENGTH]; +} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD; + +/* Vendor specific request code for Anchor Upload/Download + (This one is implemented in the core). */ +#define ANCHOR_LOAD_INTERNAL 0xA0 + +/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ +#define CPUCS_REG 0x7F92 /* original / FX */ +#define CPUCS_REG_FX2 0xE600 /* FX2 */ + +#endif --- linux-2.6.15/drivers/usb/storage/transport.c 2006-01-03 04:21:10.000000000 +0100 +++ ./drivers/usb/storage/transport.c 2006-01-30 19:41:26.727402000 +0100 @@ -984,6 +984,11 @@ bcb->Lun = srb->device->lun; if (us->flags & US_FL_SCM_MULT_TARG) bcb->Lun |= srb->device->id << 4; + /* Adaptec USB2Xchange */ + if (us->pusb_dev->descriptor.idVendor == 0x03f3 && + us->pusb_dev->descriptor.idProduct == 0x2003) + bcb->Lun = srb->device->id; + bcb->Length = srb->cmd_len; /* copy the command payload */ @@ -1069,6 +1074,20 @@ US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, residue, bcs->Status); + if (bcs->Status > US_BULK_STAT_FAIL) { + /* Adaptec USB2XCHANGE ? */ + if (us->pusb_dev->descriptor.idVendor == 0x03f3 && + us->pusb_dev->descriptor.idProduct == 0x2003) { + + /* This device will send + * bcs->Status == 0x8a for unused LUN's + * bcs->Status == 0x02 for SRB's that require SENSE. + */ + bcs->Status = US_BULK_STAT_OK; + fake_sense = 1; + US_DEBUGP("Patched Bulk status to %d.\n", bcs->Status); + } + } if (bcs->Tag != us->tag || bcs->Status > US_BULK_STAT_PHASE) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR;