From 2564604d1968bec8a651e7f9d1bca4bf87b3672f Mon Sep 17 00:00:00 2001
From: Antonio Ospite <ospite@studenti.unina.it>
Date: Fri, 11 May 2012 21:50:36 +0200
Subject: [PATCH] Add a simple usb_mode_switch clone for am7xxx devices

Add am7xxx_mode_switch, this is will be used on systems where
usb_mode_switch is not easily available (e.g. MS Windows).
---
 examples/CMakeLists.txt       | 14 +++++++
 examples/am7xxx_mode_switch.c | 97 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
 create mode 100644 examples/am7xxx_mode_switch.c

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index b7941ab..7e7b455 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -49,3 +49,17 @@ if(BUILD_AM7XXX-PLAY)
   install(TARGETS am7xxx-play
     DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
 endif()
+
+# Build a simple usb_mode_switch clone for am7xxx devices
+option(BUILD_AM7XXX_MODE_SWITCH "Build a simple usb_mode_switch clone for am7xxx devices" TRUE)
+if(BUILD_AM7XXX_MODE_SWITCH)
+
+  find_package(libusb-1.0 REQUIRED)
+  include_directories(${LIBUSB_1_INCLUDE_DIRS})
+
+  add_executable(am7xxx_mode_switch am7xxx_mode_switch.c)
+  target_link_libraries(am7xxx_mode_switch ${LIBUSB_1_LIBRARIES})
+  install(TARGETS am7xxx_mode_switch
+    DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
+endif()
+
diff --git a/examples/am7xxx_mode_switch.c b/examples/am7xxx_mode_switch.c
new file mode 100644
index 0000000..7509981
--- /dev/null
+++ b/examples/am7xxx_mode_switch.c
@@ -0,0 +1,97 @@
+/* am7xxx_mode_switch - a simple usb_mode_switch for am7xxx devices
+ *
+ * Copyright (C) 2012  Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * 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, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <libusb.h>
+
+#define AM7XXX_STORAGE_VID           0x1de1
+#define AM7XXX_STORAGE_PID           0x1101
+#define AM7XXX_STORAGE_CONFIGURATION 1
+#define AM7XXX_STORAGE_INTERFACE     0
+#define AM7XXX_STORAGE_OUT_EP        0x01
+
+static unsigned char switch_command[] =
+	"\x55\x53\x42\x43\x08\x70\x52\x89\x00\x00\x00\x00\x00\x00"
+	"\x0c\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+
+int main(void)
+{
+	int ret;
+	int transferred;
+	libusb_device_handle *usb_device = NULL;
+
+	unsigned int len;
+
+	ret = libusb_init(NULL);
+	if (ret < 0)
+		goto out;
+
+	libusb_set_debug(NULL, 3);
+
+	usb_device = libusb_open_device_with_vid_pid(NULL,
+						     AM7XXX_STORAGE_VID,
+						     AM7XXX_STORAGE_PID);
+	if (usb_device == NULL) {
+		fprintf(stderr, "cannot open the device: %d.\n", errno);
+		ret = -errno;
+		goto out;
+	}
+
+	if (libusb_kernel_driver_active(usb_device, AM7XXX_STORAGE_INTERFACE)) {
+		ret = libusb_detach_kernel_driver(usb_device,
+						  AM7XXX_STORAGE_INTERFACE);
+		if (ret < 0)
+			fprintf(stderr, "Warning: cannot detach kernel driver.\n");
+	} else {
+		fprintf(stderr, "kernel driver not active.\n");
+	}
+
+	ret = libusb_set_configuration(usb_device, AM7XXX_STORAGE_CONFIGURATION);
+	if (ret < 0) {
+		fprintf(stderr, "cannot set configuration.\n");
+		goto out_libusb_close;
+	}
+
+	ret = libusb_claim_interface(usb_device, AM7XXX_STORAGE_INTERFACE);
+	if (ret < 0) {
+		fprintf(stderr, "cannot claim interface.\n");
+		goto out_libusb_close;
+	}
+
+	len = sizeof(switch_command);
+	transferred = 0;
+	ret = libusb_bulk_transfer(usb_device, AM7XXX_STORAGE_OUT_EP,
+				   switch_command, len, &transferred, 0);
+	if (ret != 0 || (unsigned int)transferred != len) {
+		fprintf(stderr, "ret: %d\ttransferred: %d (expected %u)\n",
+		      ret, transferred, len);
+		goto out_libusb_close;
+	}
+
+	fprintf(stderr, "OK, command sent!\n");
+
+out_libusb_close:
+	libusb_release_interface(usb_device, AM7XXX_STORAGE_INTERFACE);
+	libusb_close(usb_device);
+	usb_device = NULL;
+
+out:
+	libusb_exit(NULL);
+	return ret;
+}
-- 
2.1.4