lkml.org 
[lkml]   [2005]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] Adaptec USBXchange and USB2Xchange support
Date
Hi all,

attached is a patch adding support for Adaptec's USBXchange and USB2Xchange
USB to SCSI converter dongles.

In 2004 Beier & Dauskardt IT <sda@bdit.de> already posted a patch, that was
not accepted because it was for 2.4 and included the firmware.

This patch is based on that work, but ported to 2.6 as well as to the new
firmware loader. Support for the USBXchange was added as well as cleanups
done.

Compatible firmware dumps, obtained by USB I/O logging, are available here:

http://dl.exactcode.de/adaptec-usbxchange/

Alternatively people can dump it out from the windows driver looking for the
offset.

After the firmware upload the devices behave as normal usb-storage devices.

This version was only tested with the USB 1.x version - but I get a
USB2Xchange, hopefully tomorrow.

Signed-off-by: René Rebe <rene@exactcode.de>

Please apply - suggestions welcome,

--
René Rebe - Rubensstr. 64 - 12157 Berlin (Europe / Germany)
http://www.exactcode.de | http://www.t2-project.org
+49 (0)30 255 897 45diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/Kconfig linux-2.6.13-usbxchg/drivers/usb/storage/Kconfig
--- linux-2.6.13/drivers/usb/storage/Kconfig 2005-08-29 01:41:01.000000000 +0200
+++ linux-2.6.13-usbxchg/drivers/usb/storage/Kconfig 2005-09-13 20:47:16.000000000 +0200
@@ -111,3 +111,17 @@
Say Y here to include additional code to support the Lexar Jumpshot
USB CompactFlash reader.

+config USB_STORAGE_USBXCHANGE
+ bool "Adaptec USBXchange and USB2Xchange support"
+ depends on USB_STORAGE
+ help
+ Say Y here to include additional code to support the Adaptec
+ USBXchange and USB2Xchange USB --> SCSI converter dongle.
+
+config USB_USBXCHANGE
+ tristate "Adaptec USBXchange and USB2Xchange firmware loader"
+ depends on USB_STORAGE_USBXCHANGE
+ help
+ Say Y here to include additional code to load the firmware into
+ Adaptec USBXchange and USB2Xchange USB --> SCSI converter dongle.
+
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/Makefile linux-2.6.13-usbxchg/drivers/usb/storage/Makefile
--- linux-2.6.13/drivers/usb/storage/Makefile 2005-08-29 01:41:01.000000000 +0200
+++ linux-2.6.13-usbxchg/drivers/usb/storage/Makefile 2005-09-13 20:41:19.000000000 +0200
@@ -19,5 +19,10 @@
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o

+usb-storage-obj-$(CONFIG_USB_STORAGE_USBXCHANGE) += usbxchange.o
+
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)
+
+obj-$(CONFIG_USB_USBXCHANGE) += usbxchange_fw.o
+
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/unusual_devs.h linux-2.6.13-usbxchg/drivers/usb/storage/unusual_devs.h
--- linux-2.6.13/drivers/usb/storage/unusual_devs.h 2005-08-29 01:41:01.000000000 +0200
+++ linux-2.6.13-usbxchg/drivers/usb/storage/unusual_devs.h 2005-09-13 22:34:30.000000000 +0200
@@ -1039,3 +1039,22 @@
US_SC_SCSI, US_PR_SDDR55, NULL,
US_FL_SINGLE_LUN),
#endif
+
+#ifdef CONFIG_USB_STORAGE_USBXCHANGE
+
+/* Adaptec USBXchange and USB2Xchange, after firmware download.
+ * Requires Ez-USB Style firmware loader. -Ren Rebe <rene@exactcode.de> */
+
+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,
+ 0 ),
+#endif
+
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/usb.c linux-2.6.13-usbxchg/drivers/usb/storage/usb.c
--- linux-2.6.13/drivers/usb/storage/usb.c 2005-08-29 01:41:01.000000000 +0200
+++ linux-2.6.13-usbxchg/drivers/usb/storage/usb.c 2005-09-13 21:23:03.000000000 +0200
@@ -90,6 +90,9 @@
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
#include "jumpshot.h"
#endif
+#ifdef CONFIG_USB_STORAGE_USBXCHANGE
+#include "usbxchange.h"
+#endif


/* Some informational data */
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/usbxchange.c linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange.c
--- linux-2.6.13/drivers/usb/storage/usbxchange.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange.c 2005-09-13 22:33:00.000000000 +0200
@@ -0,0 +1,60 @@
+/*
+ * Firmware Initialisation for the Adaptec USB2Xchange.
+ *
+ * Current development and maintenance by:
+ * (c) 2005 Ren Rebe <rene@exactcode.de>
+ *
+ * Initial work by:
+ * (c) 2004 Beier & Dauskardt IT <sda@bdit.de>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include "usb.h"
+
+#include "usbxchange.h"
+
+int usb2xchange_init(struct us_data *us)
+{
+ int result;
+ struct usb_device *dev = us->pusb_dev;
+
+ /* This two-command 'reset' sequence is needed, otherwise
+ * the UISB2Xchange won't recognise devices properly.
+ */
+ printk(KERN_INFO
+ "usb2xchange_init: initialising after reenumeration.\n");
+
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x5a, 0x40, 0x01,
+ 0, 0, // buffer,
+ 0, // length,
+ 300);
+
+ if (result < 0)
+ printk(KERN_ERR "usb2xchange_init: reset #1 (%d)\n", result);
+
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x5a, 0x40, 0x02,
+ 0, 0, // buffer,
+ 0, // length,
+ 300);
+
+ if (result < 0)
+ printk(KERN_ERR "usb2xchange_init: reset #2 (%d)\n", result);
+
+ return 1;
+}
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/usbxchange.h linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange.h
--- linux-2.6.13/drivers/usb/storage/usbxchange.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange.h 2005-09-13 22:33:00.000000000 +0200
@@ -0,0 +1,25 @@
+/*
+ * Firmware Initialisation for the Adaptec USB2Xchange.
+ *
+ * Current development and maintenance by:
+ * (c) 2005 Ren Rebe <rene@exactcode.de>
+ *
+ * Initial work by:
+ * (c) 2004 Beier & Dauskardt IT <sda@bdit.de>
+ *
+ * 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_H_INCLUDED
+#define _USB_USBXCHANGE_H_INCLUDED
+
+extern int usb2xchange_init(struct us_data *us);
+
+#endif
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/usbxchange_fw.c linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange_fw.c
--- linux-2.6.13/drivers/usb/storage/usbxchange_fw.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange_fw.c 2005-09-13 22:33:30.000000000 +0200
@@ -0,0 +1,233 @@
+/*
+ * Firmware loader for Adaptec USB2Xchange.
+ *
+ * Downloads device firmware to the Adaptec USBXchange and USB2Xchange
+ * USB --> SCSI Converter dongle.
+ *
+ * Current development and maintenance by:
+ * (c) 2005 Ren Rebe <rene@exactcode.de>
+ *
+ * Initial work by:
+ * (c) 2004 Beier & Dauskardt IT <sda@bdit.de>
+ *
+ * Based on emi26.c:
+ * (c) 2002 Tapio Laxstrm <tapio.laxstrom@iptime.fi>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+#include <linux/firmware.h>
+
+#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);
+ /* Note: usb_control_msg returns negative value on error or length of the
+ * data that was written! */
+
+ /*printk("writing to %X, length %d\n", address, 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;
+ }
+
+ /*printk(KERN_INFO "cpu register %X\n", cpureg);*/
+
+ /* Stop CPU
+ */
+ err = usbxchange_set_reset(dev, cpureg, 1);
+ err = usbxchange_set_reset(dev, cpureg, 1);
+ if (err < 0) {
+ printk(KERN_ERR "%s - error loading firmware: error = %d\n",
+ __FUNCTION__, err);
+ return err;
+ }
+
+ /* download Code.
+ */
+
+ /*printk("Firmware size: %ld\n", firmware->size);*/
+ record = (INTEL_HEX_RECORD *) firmware->data;
+
+ for (; 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 loading firmware: error = %d\n",
+ __FUNCTION__, err);
+ return err;
+ }
+
+ /* return 1 to fail the driver inialization
+ * and give real driver change to load */
+ return 1;
+}
+
+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);
+
+ /* do not return the driver context, let real driver do that */
+ return 0;
+}
+
+static void usbxchange_disconnect(struct usb_interface *iface)
+{
+}
+
+static struct usb_driver usbxchange_driver = {
+ .owner = THIS_MODULE,
+ .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 <rene@exactcode.de>, Sancho Dauskardt <sda@bdit.de>");
+MODULE_DESCRIPTION("Adaptec USBXchange firmware loader.");
+MODULE_LICENSE("GPL");
+
+/* vi:ai:syntax=c:sw=8:ts=8:tw=80
+ */
diff -urN --exclude '*.ko' --exclude '*mod*' --exclude '*cmd' --exclude '*.o' --exclude '*.rej' --exclude '*~' linux-2.6.13/drivers/usb/storage/usbxchange_fw.h linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange_fw.h
--- linux-2.6.13/drivers/usb/storage/usbxchange_fw.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-usbxchg/drivers/usb/storage/usbxchange_fw.h 2005-09-13 22:34:00.000000000 +0200
@@ -0,0 +1,60 @@
+/*
+ * Firmware loader for Adaptec USB2Xchange.
+ *
+ * Downloads device firmware to the Adaptec USBXchange and USB2Xchange
+ * USB --> SCSI Converter dongle.
+ *
+ * Current development and maintenance by:
+ * (c) 2005 Ren Rebe <rene@exactcode.de>
+ *
+ * Initial work by:
+ * (c) 2004 Beier & Dauskardt IT <sda@bdit.de>
+ *
+ * Based on emi26.c:
+ * (c) 2002 Tapio Laxstrm <tapio.laxstrom@iptime.fi>
+ *
+ * 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.
+ */
+
+#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[unhandled content-type:application/pgp-signature]
\
 
 \ /
  Last update: 2005-09-13 22:57    [from the cache]
©2003-2011 Jasper Spaans