#include <grub/scsicmd.h>
#include <grub/misc.h>
+ GRUB_MOD_LICENSE ("GPLv3+");
+
#define GRUB_USBMS_DIRECTION_BIT 7
+/* Length of CBI command should be always 12 bytes */
+#define GRUB_USBMS_CBI_CMD_SIZE 12
+/* CBI class-specific USB request ADSC - it sends CBI (scsi) command to
+ * device in DATA stage */
+#define GRUB_USBMS_CBI_ADSC_REQ 0x00
+
/* The USB Mass Storage Command Block Wrapper. */
struct grub_usbms_cbw
{
static int first_available_slot = 0;
static grub_err_t
-grub_usbms_reset (grub_usb_device_t dev, int interface)
+grub_usbms_cbi_cmd (grub_usb_device_t dev, int interface,
+ grub_uint8_t *cbicb)
+{
+ return grub_usb_control_msg (dev,
+ GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
+ GRUB_USBMS_CBI_ADSC_REQ, 0, interface,
+ GRUB_USBMS_CBI_CMD_SIZE, (char*)cbicb);
+}
+
+static grub_err_t
+grub_usbms_cbi_reset (grub_usb_device_t dev, int interface)
+{
+ /* Prepare array with Command Block Reset (=CBR) */
+ /* CBI specific communication reset command should be send to device
+ * via CBI USB class specific request ADCS */
+ struct grub_cbi_reset
+ {
+ grub_uint8_t opcode; /* 0x1d = SEND DIAGNOSTIC */
+ grub_uint8_t lun; /* 7-5 LUN, 4-0 flags - for CBR always = 0x04 */
+ grub_uint8_t pad[10];
+ /* XXX: There is collision between CBI and UFI specifications:
+ * CBI says 0xff, UFI says 0x00 ... probably it does
+ * not matter ... (?) */
+ } cbicb = { 0x1d, 0x04,
+ { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff }
+ };
+
+ return grub_usbms_cbi_cmd (dev, interface, (grub_uint8_t *)&cbicb);
+}
+
+static grub_err_t
+grub_usbms_bo_reset (grub_usb_device_t dev, int interface)
{
- return grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0);
+ grub_usb_err_t u;
+ u = grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0);
+ if (u)
+ return grub_error (GRUB_ERR_IO, "USB error %d", u);
+ return GRUB_ERR_NONE;
}
+static grub_err_t
+grub_usbms_reset (grub_usbms_dev_t dev)
+{
+ if (dev->protocol == GRUB_USBMS_PROTOCOL_BULK)
+ return grub_usbms_bo_reset (dev->dev, dev->interface);
+ else
+ return grub_usbms_cbi_reset (dev->dev, dev->interface);
+}
+
static void
grub_usbms_detach (grub_usb_device_t usbdev, int config, int interface)
{