lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:   Thu, 26 Jan 2023 22:37:42 +0100
From:   Ondrej Zary <linux@...y.sk>
To:     Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Cc:     linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [RFC PATCH] bpck_usb_firmware: Micro Solutions Backpack USB firmware loader

Add driver for loading firmware into Micro Solutions USB optical and
hard drives. Once the firmware is loaded, they are USB mass storage
compliant and will be handled by the usb-storage driver.

Signed-off-by: Ondrej Zary <linux@...y.sk>
---
 drivers/usb/misc/Kconfig             |   8 ++
 drivers/usb/misc/Makefile            |   1 +
 drivers/usb/misc/bpck_usb_firmware.c | 113 +++++++++++++++++++++++++++
 drivers/usb/misc/ezusb.c             |   6 --
 include/linux/usb/ezusb.h            |   3 +
 5 files changed, 125 insertions(+), 6 deletions(-)
 create mode 100644 drivers/usb/misc/bpck_usb_firmware.c

diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a5f7652db7da..4c4e7cf35344 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -311,3 +311,11 @@ config USB_ONBOARD_HUB
 	  this config will enable the driver and it will automatically
 	  match the state of the USB subsystem. If this driver is a
 	  module it will be called onboard_usb_hub.
+
+config USB_BACKPACK_FW
+	tristate "Micro Solutions Backpack firmware loading support"
+	select USB_EZUSB_FX2
+	help
+	  This driver loads firmware for Micro Solutions Backpack USB optical
+	  and hard drives. Once the firmware is loaded, they're USB mass
+	  storage compliant and thus handled by the usb-storage driver.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 93581baec3a8..ef13699f50cc 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_USB_SISUSBVGA)		+= sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 obj-$(CONFIG_BRCM_USB_PINMAP)		+= brcmstb-usb-pinmap.o
 obj-$(CONFIG_USB_ONBOARD_HUB)		+= onboard_usb_hub.o
+obj-$(CONFIG_USB_BACKPACK_FW)		+= bpck_usb_firmware.o
diff --git a/drivers/usb/misc/bpck_usb_firmware.c b/drivers/usb/misc/bpck_usb_firmware.c
new file mode 100644
index 000000000000..d579a8cdc3ae
--- /dev/null
+++ b/drivers/usb/misc/bpck_usb_firmware.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for loading firmware into Micro Solutions USB optical and hard drives
+ *
+ * Copyright (C) 2023 Ondrej Zary <linux@...y.sk>
+ *
+ * Most Micro Solutions external drives are parallel port devices that can be
+ * connected directly to a parallel port or a PCMCIA card (Model 836 - also acts
+ * as a parallel port) - and handled by pata_parport driver.
+ *
+ * There are also special USB cables that translate the Backpack parallel
+ * protocol to standard USB mass storage protocol.
+ * Model 839 - based on Cypress EZ-USB FX (USB 1.1)
+ * Model 840 - based on Cypress EZ-USB FX2 (USB 2.0)
+ * Newer drives have integrated USB 2.0 port.
+ *
+ * All these USB devices require a firmware to be downloaded to chip's RAM after
+ * each USB (re)connect. Once the firmware is loaded, they are USB mass storage
+ * compliant and will be handled by the usb-storage driver.
+ *
+ * The cables need various firmware depending on the drive type connected. The
+ * cable appears first with USB device ID 0x0000 or 0x0001. First, a "scan"
+ * firmware is loaded that identifies the drive type and changes the USB device
+ * ID appropriately. Then a final firmware is loaded, depending on the chip
+ * type, drive version (5 or 6) and drive type (CD or HDD).
+ *
+ * The cable is pretty intelligent - if there's no drive connected (or it's not
+ * powered up), it keeps trying (and blinking its LED), eventually detecting a
+ * connected drive and changing the USB ID. When the drive is disconnected, the
+ * cable does an USB reconnect so the "scan" firmware is loaded again.
+ * This means that drives can be hot-pluggged at the parallel port end of the
+ * cable.
+ */
+
+#include <linux/usb.h>
+#include <linux/errno.h>
+#include <linux/usb/ezusb.h>
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x0ac9, 0x0000), .driver_info = (unsigned long) "backpack/BP1SCAN.fw" },
+	{ USB_DEVICE(0x0ac9, 0x0001), .driver_info = (unsigned long) "backpack/BP2SCAN.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1000), .driver_info = (unsigned long) "backpack/BP1CD5.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1001), .driver_info = (unsigned long) "backpack/BP1CD6.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1002), .driver_info = (unsigned long) "backpack/BP1HD5.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1003), .driver_info = (unsigned long) "backpack/BP1HD6.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1004), .driver_info = (unsigned long) "backpack/BP2CD5.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1005), .driver_info = (unsigned long) "backpack/BP2CD6.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1006), .driver_info = (unsigned long) "backpack/BP2HD5.fw" },
+	{ USB_DEVICE(0x0ac9, 0x1007), .driver_info = (unsigned long) "backpack/BP2HD6.fw" },
+	{ USB_DEVICE(0x0ac9, 0x0010), .driver_info = (unsigned long) "backpack/BPINTCD.fw" },
+	{ USB_DEVICE(0x0ac9, 0x0011), .driver_info = (unsigned long) "backpack/BPINTHD.fw" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int bpck_usb_fw_load(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	char *fw_name = (char *)id->driver_info;
+	int ret;
+
+	if (le16_to_cpu(dev->descriptor.bcdUSB) >= 0x0200) {
+		ezusb_fx2_set_reset(dev, 1);
+		ret = ezusb_fx2_ihex_firmware_download(dev, fw_name);
+	} else {
+		ezusb_fx1_set_reset(dev, 1);
+		ret = ezusb_fx1_ihex_firmware_download(dev, fw_name);
+	}
+
+	if (ret < 0) {
+		dev_err(&dev->dev, "failed to load firmware \"%s\"\n", fw_name);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+/* scan firmware */
+MODULE_FIRMWARE("backpack/BP1SCAN.fw"); /* USB 1.1 cable */
+MODULE_FIRMWARE("backpack/BP2SCAN.fw"); /* USB 2.0 cable */
+/* for USB 1.1 chips (integrated in cable) */
+MODULE_FIRMWARE("backpack/BP1CD5.fw"); /* series 5 optical drives */
+MODULE_FIRMWARE("backpack/BP1CD6.fw"); /* series 6 optical drives */
+MODULE_FIRMWARE("backpack/BP1HD5.fw"); /* series 5 hard drives */
+MODULE_FIRMWARE("backpack/BP1HD6.fw"); /* series 6 hard drives */
+/* for USB 2.0 chips (integrated in cable) */
+MODULE_FIRMWARE("backpack/BP2CD5.fw"); /* series 5 optical drives */
+MODULE_FIRMWARE("backpack/BP2CD6.fw"); /* series 6 optical drives */
+MODULE_FIRMWARE("backpack/BP2HD5.fw"); /* series 5 hard drives */
+MODULE_FIRMWARE("backpack/BP2HD6.fw"); /* series 6 hard drives */
+/* for device-integrated USB 2.0 chips */
+MODULE_FIRMWARE("backpack/BPINTCD.fw"); /* optical drives */
+MODULE_FIRMWARE("backpack/BPINTHD.fw"); /* hard drives */
+
+static void bpck_usb_fw_disconnect(struct usb_interface *intf)
+{
+	/* nothing to do here but mandatory */
+}
+
+static struct usb_driver bpck_usb_fw_driver = {
+	.name = "bpck_usb_firwmare",
+	.probe = bpck_usb_fw_load,
+	.disconnect = bpck_usb_fw_disconnect,
+	.id_table = id_table,
+};
+
+module_usb_driver(bpck_usb_fw_driver);
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("Micro Solutions Backpack USB firmware loader");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c
index 78aaee56c2b7..30d6b1d8e265 100644
--- a/drivers/usb/misc/ezusb.c
+++ b/drivers/usb/misc/ezusb.c
@@ -124,11 +124,6 @@ int ezusb_fx1_ihex_firmware_download(struct usb_device *dev,
 }
 EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download);
 
-#if 0
-/*
- * Once someone one needs these fx2 functions, uncomment them
- * and add them to ezusb.h and all should be good.
- */
 static struct ezusb_fx_type ezusb_fx2 = {
 	.cpucs_reg = 0xE600,
 	.max_internal_adress = 0x3FFF,
@@ -146,6 +141,5 @@ int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
 	return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path);
 }
 EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
-#endif
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/ezusb.h b/include/linux/usb/ezusb.h
index 487047162ca8..f00895cc7a8e 100644
--- a/include/linux/usb/ezusb.h
+++ b/include/linux/usb/ezusb.h
@@ -5,5 +5,8 @@
 extern int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit);
 extern int ezusb_fx1_ihex_firmware_download(struct usb_device *dev,
 					    const char *firmware_path);
+extern int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit);
+extern int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
+				     const char *firmware_path);
 
 #endif /* __EZUSB_H */
-- 
Ondrej Zary

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ