Skip to content

Commit

Permalink
Merge pull request #381 from magnusja/develop
Browse files Browse the repository at this point in the history
core v0.10.0 libusbcommunication v0.4.0
  • Loading branch information
magnusja committed Mar 11, 2023
2 parents 37d2ed3 + e5a31e9 commit af89120
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -13,7 +13,7 @@ A library to access USB mass storage devices (pen drives, external HDDs, card re
The library can be included into your project like this:

```ruby
implementation 'me.jahnen.libaums:core:0.9.4'
implementation 'me.jahnen.libaums:core:0.10.0'
```

If you need the HTTP or the storage provider module:
Expand Down
2 changes: 1 addition & 1 deletion libaums/build.gradle
Expand Up @@ -9,7 +9,7 @@ jacoco {

ext {
PUBLISH_GROUP_ID = 'me.jahnen.libaums'
PUBLISH_VERSION = '0.9.4'
PUBLISH_VERSION = '0.10.0'
PUBLISH_ARTIFACT_ID = 'core'
}

Expand Down
@@ -0,0 +1,70 @@
package com.github.mjdev.libaums.partition.gpt

import android.util.Log
import me.jahnen.libaums.core.driver.BlockDeviceDriver
import me.jahnen.libaums.core.partition.PartitionTable
import me.jahnen.libaums.core.partition.PartitionTableEntry
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.ArrayList

class GPT private constructor(): PartitionTable {

// See also https://en.wikipedia.org/wiki/GUID_Partition_Table

private val partitions = ArrayList<PartitionTableEntry>()

override val size: Int get() = partitions.size * 128
override val partitionTableEntries: List<PartitionTableEntry>
get() = partitions

companion object {
private val TAG = GPT::class.java.simpleName
const val EFI_PART = "EFI PART"

const val GPT_OFFSET = 512 // GPT has a protective MBR, GPT starts after

const val ENTRY_SIZE = 128

const val FIRST_LBA_OFFSET = 32
const val LAST_LBA_OFFSET = 40

@Throws(IOException::class)
fun read(blockDevice: BlockDeviceDriver): GPT? {
val result = GPT()
var buffer = ByteBuffer.allocate(512 * 2)
blockDevice.read(0, buffer)

val efiTestString = String(buffer.array(), GPT_OFFSET, 8, Charsets.US_ASCII)
Log.d(TAG, "EFI test string $efiTestString")

if (efiTestString != EFI_PART) {
return null
}
Log.d(TAG, "EFI test string matches!")


buffer = ByteBuffer.allocate(512 * 34) // at LBA 34 GPT should stop
blockDevice.read(0, buffer)
buffer.order(ByteOrder.LITTLE_ENDIAN)

var entry_offset = 1024

while (buffer[entry_offset].toInt() != 0) {
val firstLba = buffer.getLong(entry_offset + FIRST_LBA_OFFSET)
val entry = PartitionTableEntry(-1, // Unknown
firstLba,
buffer.getLong(entry_offset + LAST_LBA_OFFSET) - firstLba)

result.partitions.add(entry)

entry_offset += ENTRY_SIZE
}


return result
}
}

}
@@ -0,0 +1,10 @@
package com.github.mjdev.libaums.partition.gpt

import me.jahnen.libaums.core.driver.BlockDeviceDriver
import me.jahnen.libaums.core.partition.PartitionTable
import me.jahnen.libaums.core.partition.PartitionTableFactory


class GPTCreator: PartitionTableFactory.PartitionTableCreator {
override fun read(blockDevice: BlockDeviceDriver): PartitionTable? = GPT.read(blockDevice)
}
Expand Up @@ -9,7 +9,7 @@ import java.nio.ByteBuffer
* and [ByteBlockDevice.read]. Uses [BlockDeviceDriver.getBlockSize]
* to calculate device offsets.
*/
open class ByteBlockDevice @JvmOverloads constructor(private val targetBlockDevice: BlockDeviceDriver, private val logicalOffsetToAdd: Int = 0) : BlockDeviceDriver {
open class ByteBlockDevice @JvmOverloads constructor(private val targetBlockDevice: BlockDeviceDriver, private val logicalOffsetToAdd: Long = 0) : BlockDeviceDriver {
override val blockSize: Int
get() = targetBlockDevice.blockSize

Expand Down
Expand Up @@ -28,14 +28,14 @@ class PartitionTableEntry
* Construct a new PartitionTableEntry with the given information.
*
* @param partitionType
* The file system type of the partition (eg. FAT32).
* The file system type of the partition (eg. FAT32). -1 if unknown
* @param logicalBlockAddress
* The logical block address on the device where this partition
* starts.
* @param totalNumberOfSectors
* The total numbers of sectors occupied by the partition.
*/
(partitionType: Int, logicalBlockAddress: Int, totalNumberOfSectors: Int) {
(partitionType: Int, logicalBlockAddress: Long, totalNumberOfSectors: Long) {

/**
*
Expand All @@ -48,15 +48,15 @@ class PartitionTableEntry
* @return The logical block address where this partitions starts on the
* device.
*/
var logicalBlockAddress: Int = 0
var logicalBlockAddress: Long = 0
internal set
/**
*
* @return The total numbers of sectors occupied by this partition. This
* value is often unused because the same information is also stored
* in the specific file system.
*/
var totalNumberOfSectors: Int = 0
var totalNumberOfSectors: Long = 0
internal set

init {
Expand Down
Expand Up @@ -17,8 +17,11 @@

package me.jahnen.libaums.core.partition

import android.util.Log
import com.github.mjdev.libaums.partition.gpt.GPTCreator
import me.jahnen.libaums.core.driver.BlockDeviceDriver
import me.jahnen.libaums.core.partition.fs.FileSystemPartitionTableCreator
import me.jahnen.libaums.core.partition.mbr.MasterBootRecord
import me.jahnen.libaums.core.partition.mbr.MasterBootRecordCreator
import java.io.IOException
import java.util.*
Expand All @@ -29,6 +32,7 @@ import java.util.*
* @author mjahnen
*/
object PartitionTableFactory {
private val TAG = PartitionTableFactory::class.java.simpleName

private val partitionTables = ArrayList<PartitionTableCreator>()

Expand All @@ -41,6 +45,7 @@ object PartitionTableFactory {

init {
registerPartitionTable(FileSystemPartitionTableCreator())
registerPartitionTable(GPTCreator())
registerPartitionTable(MasterBootRecordCreator())
}

Expand All @@ -60,8 +65,10 @@ object PartitionTableFactory {
for (creator in partitionTables) {
val table = creator.read(blockDevice)
if (table != null) {
Log.d(TAG, "Found partition table ${creator::class.java.simpleName}")
return table
}
Log.d(TAG, "${creator::class.java.simpleName} returned null")
}

throw UnsupportedPartitionTableException()
Expand Down
Expand Up @@ -24,7 +24,7 @@ class FileSystemPartitionTable(blockDevice: BlockDeviceDriver, fs: FileSystem) :

init {
Log.i(TAG, "Found a device without partition table, yay!")
val totalNumberOfSectors = fs.capacity.toInt() / blockDevice.blockSize
val totalNumberOfSectors = fs.capacity / blockDevice.blockSize
if (fs.capacity % blockDevice.blockSize != 0L) {
Log.w(TAG, "fs capacity is not multiple of block size")
}
Expand Down
Expand Up @@ -111,7 +111,7 @@ class MasterBootRecord private constructor() : PartitionTable {
}

val entry = PartitionTableEntry(type,
buffer.getInt(offset + 8), buffer.getInt(offset + 12))
buffer.getInt(offset + 8).toLong(), buffer.getInt(offset + 12).toLong())

result.partitions.add(entry)
}
Expand Down
Expand Up @@ -17,7 +17,7 @@ internal abstract class AndroidUsbCommunication(

private var isNativeInited: Boolean = false
var deviceConnection: UsbDeviceConnection? = null
private var isClosed = false
protected var isClosed = false

init {
initNativeLibrary()
Expand Down Expand Up @@ -49,10 +49,14 @@ internal abstract class AndroidUsbCommunication(
}

override fun controlTransfer(requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int): Int {
require(!isClosed) { "device is closed" }

return deviceConnection!!.controlTransfer(requestType, request, value, index, buffer, length, TRANSFER_TIMEOUT)
}

override fun resetDevice() {
require(!isClosed) { "device is closed" }

Log.d(TAG, "Performing native reset")

if (!deviceConnection!!.releaseInterface(usbInterface)) {
Expand All @@ -70,6 +74,8 @@ internal abstract class AndroidUsbCommunication(
}

override fun clearFeatureHalt(endpoint: UsbEndpoint) {
require(!isClosed) { "device is closed" }

Log.w(TAG, "Clearing halt on endpoint $endpoint (direction ${endpoint.direction})")
val result = clearHaltNative(deviceConnection!!.fileDescriptor, endpoint.address)
if (!result) {
Expand All @@ -90,6 +96,8 @@ internal abstract class AndroidUsbCommunication(
}

override fun close() {
require(!isClosed) { "device is already closed" }

Log.d(TAG, "close device")
closeUsbConnection()
isClosed = true
Expand Down
Expand Up @@ -25,6 +25,8 @@ internal class HoneyCombMr1Communication(

@Throws(IOException::class)
override fun bulkOutTransfer(src: ByteBuffer): Int {
require(!isClosed) { "device is closed" }

val offset = src.position()

if (offset == 0) {
Expand Down Expand Up @@ -54,6 +56,8 @@ internal class HoneyCombMr1Communication(

@Throws(IOException::class)
override fun bulkInTransfer(dest: ByteBuffer): Int {
require(!isClosed) { "device is closed" }

val offset = dest.position()

if (offset == 0) {
Expand Down
Expand Up @@ -30,6 +30,8 @@ internal class JellyBeanMr2Communication(

@Throws(IOException::class)
override fun bulkOutTransfer(src: ByteBuffer): Int {
require(!isClosed) { "device is closed" }

val result = deviceConnection!!.bulkTransfer(outEndpoint,
src.array(), src.position(), src.remaining(), UsbCommunication.TRANSFER_TIMEOUT)

Expand All @@ -46,6 +48,8 @@ internal class JellyBeanMr2Communication(

@Throws(IOException::class)
override fun bulkInTransfer(dest: ByteBuffer): Int {
require(!isClosed) { "device is closed" }

val result = deviceConnection!!.bulkTransfer(inEndpoint,
dest.array(), dest.position(), dest.remaining(), UsbCommunication.TRANSFER_TIMEOUT)

Expand Down
2 changes: 1 addition & 1 deletion libusbcommunication/README.md
Expand Up @@ -38,7 +38,7 @@ Refer to the following blog where someone claims that LPGL cannot be used in clo
#### Inclusion in your build.gradle

```ruby
implementation 'me.jahnen.libaums:libusbcommunication:0.2.4'
implementation 'me.jahnen.libaums:libusbcommunication:0.3.0'
```

### Activate libusb communication
Expand Down
2 changes: 1 addition & 1 deletion libusbcommunication/build.gradle
Expand Up @@ -8,7 +8,7 @@ String libusbDir = props['libusb.dir']

ext {
PUBLISH_GROUP_ID = 'me.jahnen.libaums'
PUBLISH_VERSION = '0.2.4'
PUBLISH_VERSION = '0.3.0'
PUBLISH_ARTIFACT_ID = 'libusbcommunication'
}

Expand Down
Expand Up @@ -28,6 +28,7 @@ class LibusbCommunication(
private val libUsbHandle: Long
get() = libUsbHandleArray[0]
private var deviceConnection: UsbDeviceConnection?
private var closed = false

init {
System.loadLibrary("libusbcom")
Expand Down Expand Up @@ -59,6 +60,8 @@ class LibusbCommunication(
private external fun nativeControlTransfer(handle: Long, requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int, timeout: Int): Int

override fun bulkOutTransfer(src: ByteBuffer): Int {
require(!closed) { "device is closed" }

val transferred = nativeBulkTransfer(
libUsbHandle, outEndpoint.address, src.array(), src.position(), src.remaining(),
TRANSFER_TIMEOUT
Expand All @@ -74,6 +77,8 @@ class LibusbCommunication(
}

override fun bulkInTransfer(dest: ByteBuffer): Int {
require(!closed) { "device is closed" }

val transferred = nativeBulkTransfer(
libUsbHandle, inEndpoint.address, dest.array(), dest.position(), dest.remaining(),
TRANSFER_TIMEOUT
Expand All @@ -89,6 +94,8 @@ class LibusbCommunication(
}

override fun controlTransfer(requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int): Int {
require(!closed) { "device is closed" }

val ret = nativeControlTransfer(libUsbHandle, requestType, request, value, index, buffer, length, TRANSFER_TIMEOUT)
if (ret < 0) {
throw LibusbException("libusb control transfer failed", LibusbError.fromCode(ret))
Expand All @@ -97,6 +104,8 @@ class LibusbCommunication(
}

override fun resetDevice() {
require(!closed) { "device is closed" }

if (!deviceConnection!!.releaseInterface(usbInterface)) {
Log.w(TAG, "Failed to release interface, errno: ${ErrNo.errno} ${ErrNo.errstr}")
}
Expand All @@ -118,14 +127,22 @@ class LibusbCommunication(
}

override fun clearFeatureHalt(endpoint: UsbEndpoint) {
require(!closed) { "device is closed" }

val ret = nativeClearHalt(libUsbHandle, endpoint.address)
Log.d(TAG, "libusb clearFeatureHalt returned $ret: ${LibusbError.fromCode(ret).message}")
}

override fun close() {
deviceConnection!!.releaseInterface(usbInterface)
nativeClose(libUsbHandle, usbInterface.id)
deviceConnection!!.close()
require(!closed) { "device is already closed" }

try {
deviceConnection!!.releaseInterface(usbInterface)
nativeClose(libUsbHandle, usbInterface.id)
deviceConnection!!.close()
} finally {
closed = true
}
}

companion object {
Expand Down

0 comments on commit af89120

Please sign in to comment.