diff --git a/libaums/CMakeLists.txt b/libaums/CMakeLists.txt index 577e727e..0e2ec0f9 100644 --- a/libaums/CMakeLists.txt +++ b/libaums/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.4.1) add_library( errno-lib - - # Sets the library as a shared library. SHARED + src/c/errno.c ) - # Provides a relative path to your source file(s). - src/c/errno.c ) \ No newline at end of file +add_library( usb-lib + SHARED + src/c/usb.c ) \ No newline at end of file diff --git a/libaums/src/c/usb.c b/libaums/src/c/usb.c new file mode 100644 index 00000000..f68340b8 --- /dev/null +++ b/libaums/src/c/usb.c @@ -0,0 +1,9 @@ +#include +#include +#include + +JNIEXPORT jboolean JNICALL +Java_com_github_mjdev_libaums_usb_AndroidUsbCommunication_resetUsbDeviceNative(JNIEnv *env, jobject thiz, jint fd) { + int ret = ioctl(fd, USBDEVFS_RESET); + return (ret == 0) ? JNI_TRUE : JNI_FALSE; +} \ No newline at end of file diff --git a/libaums/src/main/java/com/github/mjdev/libaums/UsbMassStorageDevice.kt b/libaums/src/main/java/com/github/mjdev/libaums/UsbMassStorageDevice.kt index 48c393d1..3abcdbad 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/UsbMassStorageDevice.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/UsbMassStorageDevice.kt @@ -131,7 +131,7 @@ private constructor(private val usbManager: UsbManager, throw IOException("could not claim interface!") } - val communication = UsbCommunicationFactory.createUsbCommunication(deviceConnection, outEndpoint, inEndpoint) + val communication = UsbCommunicationFactory.createUsbCommunication(deviceConnection, usbInterface, outEndpoint, inEndpoint) val maxLun = ByteArray(1) deviceConnection.controlTransfer(161, 254, 0, usbInterface.id, maxLun, 1, 5000) Log.i(TAG, "MAX LUN " + maxLun[0].toInt()) diff --git a/libaums/src/main/java/com/github/mjdev/libaums/driver/scsi/ScsiBlockDevice.kt b/libaums/src/main/java/com/github/mjdev/libaums/driver/scsi/ScsiBlockDevice.kt index c5f4aa8e..d2fd911e 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/driver/scsi/ScsiBlockDevice.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/driver/scsi/ScsiBlockDevice.kt @@ -48,6 +48,8 @@ class ScsiBlockDevice(private val usbCommunication: UsbCommunication, private va private val readCommand = ScsiRead10(lun=lun) private val csw = CommandStatusWrapper() + private var cbwTagCounter = 0 + /** * The size of the block device, in blocks of [blockSize] bytes, * @@ -135,9 +137,32 @@ class ScsiBlockDevice(private val usbCommunication: UsbCommunication, private va */ @Throws(IOException::class) private fun transferCommand(command: CommandBlockWrapper, inBuffer: ByteBuffer): Boolean { + for(i in 0..3) { + try { + return transferOneCommand(command, inBuffer) + } catch(e: IOException) { + if (i == 3) { + throw e + } + + Log.e(TAG, "error transferring command, sending bulk only reset") + usbCommunication.resetRecovery() + Thread.sleep(1500); + } + } + + throw IllegalStateException("This should never happen.. ") + } + + + @Throws(IOException::class) + private fun transferOneCommand(command: CommandBlockWrapper, inBuffer: ByteBuffer): Boolean { val outArray = outBuffer.array() Arrays.fill(outArray, 0.toByte()) + command.dCbwTag = cbwTagCounter + cbwTagCounter++ + outBuffer.clear() command.serialize(outBuffer) outBuffer.clear() diff --git a/libaums/src/main/java/com/github/mjdev/libaums/usb/AndroidUsbCommunication.kt b/libaums/src/main/java/com/github/mjdev/libaums/usb/AndroidUsbCommunication.kt new file mode 100644 index 00000000..3ef28289 --- /dev/null +++ b/libaums/src/main/java/com/github/mjdev/libaums/usb/AndroidUsbCommunication.kt @@ -0,0 +1,75 @@ +package com.github.mjdev.libaums.usb + +import android.hardware.usb.UsbDeviceConnection +import android.hardware.usb.UsbEndpoint +import android.hardware.usb.UsbInterface +import android.util.Log +import com.github.mjdev.libaums.usb.UsbCommunication.Companion.TRANSFER_TIMEOUT +import java.io.IOException + + +internal abstract class AndroidUsbCommunication(private val deviceConnection: UsbDeviceConnection, private val usbInterface: UsbInterface, private val outEndpoint: UsbEndpoint, private val inEndpoint: UsbEndpoint) : UsbCommunication { + + private var isNativeInited: Boolean = false + + init { + try { + System.loadLibrary("usb-lib") + isNativeInited = true + } catch (e: UnsatisfiedLinkError) { + isNativeInited = false + Log.e(TAG, "could not load usb-lib", e) + } + + } + + override fun controlTransfer(requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int): Int { + return deviceConnection.controlTransfer(requestType, request, value, index, buffer, length, TRANSFER_TIMEOUT) + } + + override fun resetRecovery() { + bulkOnlyMassStorageReset() + Thread.sleep(10000) + clearFeatureHalt(inEndpoint) + Thread.sleep(10000) + clearFeatureHalt(outEndpoint) + Thread.sleep(10000) + + if (isNativeInited) { + Log.w(TAG, "Native reset") + if (!resetUsbDeviceNative(deviceConnection.fileDescriptor)) { + throw IOException("native reset unsuccessful!") + } + } + Thread.sleep(10000) + } + + override fun bulkOnlyMassStorageReset() { + Log.w(TAG, "sending bulk only mass storage request") + val bArr = ByteArray(2) + // REQUEST_BULK_ONLY_MASS_STORAGE_RESET = 255 + // REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET = 33 + val transferred: Int = controlTransfer(33, 255, 0, usbInterface.id, bArr, 0) + if (transferred == -1) { + throw IOException("bulk only mass storage reset failed!") + } + } + + override fun clearFeatureHalt(endpoint: UsbEndpoint) { + Log.w(TAG, "sending clear feature halt") + val bArr = ByteArray(2) + val address: Int = endpoint.address + // REQUEST_CLEAR_FEATURE = 1 + // REQUEST_TYPE_CLEAR_FEATURE = 2 + val transferred: Int = controlTransfer(2, 1, 0, address, bArr, 0) + if (transferred == -1) { + throw IOException("bulk only mass storage reset failed!") + } + } + + private external fun resetUsbDeviceNative(fd: Int): Boolean + + companion object { + private val TAG = AndroidUsbCommunication::class.java.simpleName + } +} \ No newline at end of file diff --git a/libaums/src/main/java/com/github/mjdev/libaums/usb/HoneyCombMr1Communication.kt b/libaums/src/main/java/com/github/mjdev/libaums/usb/HoneyCombMr1Communication.kt index 3a52259c..9b7388c7 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/usb/HoneyCombMr1Communication.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/usb/HoneyCombMr1Communication.kt @@ -2,6 +2,7 @@ package com.github.mjdev.libaums.usb import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbEndpoint +import android.hardware.usb.UsbInterface import java.io.IOException import java.nio.ByteBuffer @@ -14,7 +15,7 @@ import java.nio.ByteBuffer * * @author mjahnen */ -internal class HoneyCombMr1Communication(private val deviceConnection: UsbDeviceConnection, private val outEndpoint: UsbEndpoint, private val inEndpoint: UsbEndpoint) : UsbCommunication { +internal class HoneyCombMr1Communication(private val deviceConnection: UsbDeviceConnection, private val usbInterface: UsbInterface, private val outEndpoint: UsbEndpoint, private val inEndpoint: UsbEndpoint) : AndroidUsbCommunication(deviceConnection, usbInterface, outEndpoint, inEndpoint) { @Throws(IOException::class) override fun bulkOutTransfer(src: ByteBuffer): Int { diff --git a/libaums/src/main/java/com/github/mjdev/libaums/usb/JellyBeanMr2Communication.kt b/libaums/src/main/java/com/github/mjdev/libaums/usb/JellyBeanMr2Communication.kt index de2a3f1b..45492ade 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/usb/JellyBeanMr2Communication.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/usb/JellyBeanMr2Communication.kt @@ -7,6 +7,7 @@ package com.github.mjdev.libaums.usb import android.annotation.TargetApi import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbEndpoint +import android.hardware.usb.UsbInterface import android.os.Build import android.system.ErrnoException @@ -23,7 +24,7 @@ import java.nio.ByteBuffer * @author mjahnen */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) -internal class JellyBeanMr2Communication(private val deviceConnection: UsbDeviceConnection, private val outEndpoint: UsbEndpoint, private val inEndpoint: UsbEndpoint) : UsbCommunication { +internal class JellyBeanMr2Communication(private val deviceConnection: UsbDeviceConnection, private val usbInterface: UsbInterface, private val outEndpoint: UsbEndpoint, private val inEndpoint: UsbEndpoint) : AndroidUsbCommunication(deviceConnection, usbInterface, outEndpoint, inEndpoint) { @Throws(IOException::class) override fun bulkOutTransfer(src: ByteBuffer): Int { diff --git a/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunication.kt b/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunication.kt index 0a85a0ea..56ac7816 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunication.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunication.kt @@ -17,6 +17,7 @@ package com.github.mjdev.libaums.usb +import android.hardware.usb.UsbEndpoint import java.io.IOException import java.nio.ByteBuffer @@ -52,6 +53,15 @@ interface UsbCommunication { @Throws(IOException::class) fun bulkInTransfer(dest: ByteBuffer): Int + fun controlTransfer(requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int): Int + + @Throws(IOException::class) + fun resetRecovery() + @Throws(IOException::class) + fun bulkOnlyMassStorageReset() + @Throws(IOException::class) + fun clearFeatureHalt(endpoint: UsbEndpoint) + companion object { const val TRANSFER_TIMEOUT = 5000 } diff --git a/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunicationFactory.kt b/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunicationFactory.kt index 1b6e2433..74cf1971 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunicationFactory.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbCommunicationFactory.kt @@ -2,6 +2,7 @@ package com.github.mjdev.libaums.usb import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbEndpoint +import android.hardware.usb.UsbInterface import android.os.Build import android.util.Log @@ -21,16 +22,16 @@ object UsbCommunicationFactory { DEVICE_CONNECTION_SYNC } - fun createUsbCommunication(deviceConnection: UsbDeviceConnection, outEndpoint: UsbEndpoint, inEndpoint: UsbEndpoint): UsbCommunication { + fun createUsbCommunication(deviceConnection: UsbDeviceConnection, usbInterface: UsbInterface, outEndpoint: UsbEndpoint, inEndpoint: UsbEndpoint): UsbCommunication { return if (underlyingUsbCommunication == UnderlyingUsbCommunication.DEVICE_CONNECTION_SYNC) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - JellyBeanMr2Communication(deviceConnection, outEndpoint, inEndpoint) + JellyBeanMr2Communication(deviceConnection, usbInterface, outEndpoint, inEndpoint) } else { Log.i(TAG, "using workaround usb communication") - HoneyCombMr1Communication(deviceConnection, outEndpoint, inEndpoint) + HoneyCombMr1Communication(deviceConnection, usbInterface, outEndpoint, inEndpoint) } } else { - UsbRequestCommunication(deviceConnection, outEndpoint, inEndpoint) + UsbRequestCommunication(deviceConnection, usbInterface, outEndpoint, inEndpoint) } } } diff --git a/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbRequestCommunication.kt b/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbRequestCommunication.kt index 912e4c57..f8dd58ef 100644 --- a/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbRequestCommunication.kt +++ b/libaums/src/main/java/com/github/mjdev/libaums/usb/UsbRequestCommunication.kt @@ -2,6 +2,7 @@ package com.github.mjdev.libaums.usb import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbEndpoint +import android.hardware.usb.UsbInterface import android.hardware.usb.UsbRequest import java.io.IOException @@ -11,7 +12,7 @@ import java.nio.ByteBuffer * Created by magnusja on 21/12/16. */ -internal class UsbRequestCommunication(private val deviceConnection: UsbDeviceConnection, outEndpoint: UsbEndpoint, inEndpoint: UsbEndpoint) : UsbCommunication { +internal class UsbRequestCommunication(private val deviceConnection: UsbDeviceConnection, private val usbInterface: UsbInterface, outEndpoint: UsbEndpoint, inEndpoint: UsbEndpoint) : AndroidUsbCommunication(deviceConnection, usbInterface, outEndpoint, inEndpoint) { private val outRequest = UsbRequest().apply { initialize(deviceConnection, outEndpoint) } private val inRequest = UsbRequest().apply { initialize(deviceConnection, inEndpoint) } private val workaroundBuffer = ByteBuffer.allocate(1024 * 32 * 4)