Implement support for SuperSpeed USB Device Capability Descriptor.

This commit is contained in:
Klaus Reimer 2013-07-13 22:58:09 +02:00
parent c998b4f541
commit 68847f597f
10 changed files with 605 additions and 4 deletions

View File

@ -29,7 +29,8 @@
</action>
<action dev="kayahr" type="add" date="2013-07-13">
Implement support for BOS Descriptor, BOS Device Capability
Descriptor and USB 2.0 Extension Descriptor.
Descriptor, USB 2.0 Extension Descriptor and SuperSpeed USB Device
Capability Descriptor.
</action>
<action dev="kayahr" type="add" date="2013-07-13">
Using uninitialized descriptors now throw an IllegalStateException

View File

@ -26,6 +26,7 @@
#include "BosDescriptor.h"
#include "BosDevCapabilityDescriptor.h"
#include "Usb20ExtensionDescriptor.h"
#include "SsUsbDeviceCapabilityDescriptor.h"
#include "Transfer.h"
static JavaVM *jvm;
@ -822,6 +823,45 @@ JNIEXPORT void JNICALL METHOD_NAME(LibUsb, freeUsb20ExtensionDescriptor)
resetUsb20ExtensionDescriptor(env, extensionDescriptor);
}
/**
* int getSsUsbDeviceCapabilityDescriptor(Context, BosDevCapabilityDescriptor, SsUsbDeviceCapabilityDescriptor)
*/
JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, getSsUsbDeviceCapabilityDescriptor)
(
JNIEnv *env, jclass class, jobject context, jobject devCapDescriptor,
jobject ssUsbDeviceCapabilityDescriptor
)
{
NOT_NULL(env, devCapDescriptor, return 0);
NOT_NULL(env, ssUsbDeviceCapabilityDescriptor, return 0);
libusb_context *ctx = unwrapContext(env, context);
struct libusb_bos_dev_capability_descriptor *devcap_descriptor =
unwrapBosDevCapabilityDescriptor(env, devCapDescriptor);
if (!devcap_descriptor) return 0;
struct libusb_ss_usb_device_capability_descriptor *descriptor;
int result = libusb_get_ss_usb_device_capability_descriptor(ctx,
devcap_descriptor, &descriptor);
if (!result) setSsUsbDeviceCapabilityDescriptor(env, descriptor,
ssUsbDeviceCapabilityDescriptor);
return result;
}
/**
* void freeSsUsbDeviceCapabilityDescriptor(SsUsbDeviceCapabilityDescriptor)
*/
JNIEXPORT void JNICALL METHOD_NAME(LibUsb, freeSsUsbDeviceCapabilityDescriptor)
(
JNIEnv *env, jclass class, jobject ssUsbDeviceCapabilityDescriptor
)
{
if (!ssUsbDeviceCapabilityDescriptor) return;
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, ssUsbDeviceCapabilityDescriptor);
if (!descriptor) return;
libusb_free_ss_usb_device_capability_descriptor(descriptor);
resetSsUsbDeviceCapabilityDescriptor(env, ssUsbDeviceCapabilityDescriptor);
}
/**
* int getDescriptor(DeviceHandle, int, int, ByteBuffer)
*/

View File

@ -21,4 +21,5 @@ libusb4java_la_SOURCES = \
SsEndpointCompanionDescriptor.c \
BosDescriptor.c \
BosDevCapabilityDescriptor.c \
Usb20ExtensionDescriptor.c
Usb20ExtensionDescriptor.c \
SsUsbDeviceCapabilityDescriptor.c

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2013 Klaus Reimer (k@ailis.de)
* See COPYING file for copying conditions
*/
#include "SsUsbDeviceCapabilityDescriptor.h"
void setSsUsbDeviceCapabilityDescriptor(JNIEnv* env,
struct libusb_ss_usb_device_capability_descriptor* descriptor, jobject object)
{
SET_POINTER(env, descriptor, object, "ssUsbDeviceCapabilityDescriptorPointer");
}
struct libusb_ss_usb_device_capability_descriptor* unwrapSsUsbDeviceCapabilityDescriptor(
JNIEnv* env, jobject descriptor)
{
UNWRAP_POINTER(env, descriptor,
struct libusb_ss_usb_device_capability_descriptor*,
"ssUsbDeviceCapabilityDescriptorPointer");
}
void resetSsUsbDeviceCapabilityDescriptor(JNIEnv* env, jobject obj)
{
RESET_POINTER(env, obj, "ssUsbDeviceCapabilityDescriptorPointer");
}
/**
* byte bLength()
*/
JNIEXPORT jbyte JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor, bLength)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bLength;
}
/**
* byte bDescriptorType()
*/
JNIEXPORT jbyte JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor, bDescriptorType)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bDescriptorType;
}
/**
* byte bDevCapabilityType()
*/
JNIEXPORT jbyte JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor,
bDevCapabilityType)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bDevCapabilityType;
}
/**
* int bmAttributes()
*/
JNIEXPORT jbyte JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor,
bmAttributes)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bmAttributes;
}
/**
* short wSpeedSupported()
*/
JNIEXPORT jshort JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor,
wSpeedSupported)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->wSpeedSupported;
}
/**
* byte bFunctionalitySupport()
*/
JNIEXPORT jbyte JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor,
bFunctionalitySupport)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bFunctionalitySupport;
}
/**
* byte bU1DevExitLat()
*/
JNIEXPORT jbyte JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor,
bU1DevExitLat)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bU1DevExitLat;
}
/**
* short bU2DevExitLat()
*/
JNIEXPORT jshort JNICALL METHOD_NAME(SsUsbDeviceCapabilityDescriptor,
bU2DevExitLat)
(
JNIEnv *env, jobject this
)
{
struct libusb_ss_usb_device_capability_descriptor *descriptor =
unwrapSsUsbDeviceCapabilityDescriptor(env, this);
if (!descriptor) return 0;
return descriptor->bU2DevExitLat;
}

View File

@ -0,0 +1,17 @@
/*
* Copyright (C) 2013 Klaus Reimer (k@ailis.de)
* See COPYING file for copying conditions
*/
#ifndef USB4JAVA_SS_USB_DEVICE_CAPABILITY_DESCRIPTOR_H
#define USB4JAVA_SS_USB_DEVICE_CAPABILITY_DESCRIPTOR_H
#include "usb4java.h"
void setSsUsbDeviceCapabilityDescriptor(JNIEnv*,
struct libusb_ss_usb_device_capability_descriptor*, jobject);
struct libusb_ss_usb_device_capability_descriptor*
unwrapSsUsbDeviceCapabilityDescriptor(JNIEnv*, jobject);
void resetSsUsbDeviceCapabilityDescriptor(JNIEnv*, jobject);
#endif

View File

@ -68,7 +68,7 @@ JNIEXPORT jbyte JNICALL METHOD_NAME(Usb20ExtensionDescriptor,
}
/**
* int bDevCapabilityType()
* int bmAttributes()
*/
JNIEXPORT jint JNICALL METHOD_NAME(Usb20ExtensionDescriptor,
bmAttributes)

View File

@ -1528,6 +1528,41 @@ public final class LibUsb
public static native void freeUsb20ExtensionDescriptor(
final Usb20ExtensionDescriptor extensionDescriptor);
/**
* Get a SuperSpeed USB Device Capability descriptor.
*
* @param context
* The context to operate on, or NULL for the default context.
* @param devCapDescriptor
* Device Capability descriptor with a bDevCapabilityType of
* {@link #BT_SS_USB_DEVICE_CAPABILITY}.
* @param ssUsbDeviceCapabilityDescriptor
* Output location for the SuperSpeed USB Device Capability
* descriptor. Only valid if {@link #SUCCESS} was returned.
* Must be freed with
* {@link #freeSsUsbDeviceCapabilityDescriptor(
* SsUsbDeviceCapabilityDescriptor)} after use.
* @return {@link #SUCCESS} on success, an error code on error.
*/
public static native int getSsUsbDeviceCapabilityDescriptor(
final Context context,
final BosDevCapabilityDescriptor devCapDescriptor,
final SsUsbDeviceCapabilityDescriptor ssUsbDeviceCapabilityDescriptor);
/**
* Free a SuperSpeed USB Device Capability descriptor obtained from
* {@link #getSsUsbDeviceCapabilityDescriptor(Context,
* BosDevCapabilityDescriptor, SsUsbDeviceCapabilityDescriptor)}.
*
* It is safe to call this function with a NULL parameter,
* in which case the function simply returns.
*
* @param ssUsbDeviceCapabilityDescriptor
* The descriptor to free.
*/
public static native void freeSsUsbDeviceCapabilityDescriptor(
final SsUsbDeviceCapabilityDescriptor ssUsbDeviceCapabilityDescriptor);
/**
* Retrieve a descriptor from the default control pipe.
*

View File

@ -0,0 +1,181 @@
/*
* Copyright 2013 Klaus Reimer <k@ailis.de>
* See LICENSE.md for licensing information.
*
* Based on libusb <http://www.libusb.org/>:
*
* Copyright 2001 Johannes Erdfelt <johannes@erdfelt.com>
* Copyright 2007-2009 Daniel Drake <dsd@gentoo.org>
* Copyright 2010-2012 Peter Stuge <peter@stuge.se>
* Copyright 2008-2011 Nathan Hjelm <hjelmn@users.sourceforge.net>
* Copyright 2009-2012 Pete Batard <pete@akeo.ie>
* Copyright 2009-2012 Ludovic Rousseau <ludovic.rousseau@gmail.com>
* Copyright 2010-2012 Michael Plante <michael.plante@gmail.com>
* Copyright 2011-2012 Hans de Goede <hdegoede@redhat.com>
* Copyright 2012 Martin Pieuchot <mpi@openbsd.org>
* Copyright 2012-2013 Toby Gray <toby.gray@realvnc.com>
*/
package de.ailis.usb4java.libusb;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
/**
* A structure representing the SuperSpeed USB Device Capability descriptor This
* descriptor is documented in section 9.6.2.2 of the USB 3.0 specification.
*
* All multiple-byte fields are represented in host-endian format.
*
* @author Klaus Reimer (k@ailis.de)
*/
public final class SsUsbDeviceCapabilityDescriptor
{
/** The native pointer to the descriptor structure. */
private long ssUsbDeviceCapabilityDescriptorPointer;
/**
* Constructs a new BOS descriptor which can be passed to the
* {@link LibUsb#getSsUsbDeviceCapabilityDescriptor(Context,
* BosDevCapabilityDescriptor, SsUsbDeviceCapabilityDescriptor)} method.
*/
public SsUsbDeviceCapabilityDescriptor()
{
// Empty
}
/**
* Returns the native pointer.
*
* @return The native pointer.
*/
public long getPointer()
{
return this.ssUsbDeviceCapabilityDescriptorPointer;
}
/**
* Returns the size of this descriptor (in bytes).
*
* @return The descriptor size in bytes;
*/
public native byte bLength();
/**
* Returns the descriptor type.
*
* @return The descriptor type.
*/
public native byte bDescriptorType();
/**
* Returns the device capability type.
*
* @return The device capability type.
*/
public native byte bDevCapabilityType();
/**
* Returns the bitmap of supported device level features.
*
* @return The supported device level features.
*/
public native byte bmAttributes();
/**
* Returns the bitmap encoding of the speed supported by this device when
* operating in SuperSpeed mode.
*
* @return The supported speed.
*/
public native short wSpeedSupported();
/**
* Returns the lowest speed at which all the functionality supported by the
* device is available to the user.
*
* @return The lowest speed.
*/
public native byte bFunctionalitySupport();
/**
* Returns the U1 Device Exit Latency.
*
* @return The U1 Device Exit Latency.
*/
public native byte bU1DevExitLat();
/**
* Returns the U2 Device Exit Latency.
*
* @return The U2 Device Exit Latency.
*/
public native short bU2DevExitLat();
/**
* Returns a dump of this descriptor.
*
* @return The descriptor dump.
*/
public String dump()
{
return String.format("SuperSpeed USB Device Capability descriptor:%n"
+ " bLength %18d%n"
+ " bDescriptorType %10d%n"
+ " bDevCapabilityType %7d%n"
+ " bmAttributes %13s%n"
+ " wSpeedSupported %10d%n"
+ " bFunctionalitySupport %4d%n"
+ " bU1DevExitLat %12d%n"
+ " bU2DevExitLat %12d%n",
bLength() & 0xff,
bDescriptorType() & 0xff,
bDevCapabilityType() & 0xff,
String.format("0x%02x", bmAttributes() & 0xff),
wSpeedSupported() & 0xffff,
bFunctionalitySupport() & 0xff,
bU1DevExitLat() & 0xff,
bU2DevExitLat() & 0xffff);
}
@Override
public boolean equals(final Object obj)
{
if (obj == null) return false;
if (obj == this) return true;
if (obj.getClass() != getClass()) return false;
final SsUsbDeviceCapabilityDescriptor other =
(SsUsbDeviceCapabilityDescriptor) obj;
return new EqualsBuilder()
.append(bDescriptorType(), other.bDescriptorType())
.append(bLength(), other.bLength())
.append(bDevCapabilityType(), other.bDevCapabilityType())
.append(bmAttributes(), other.bmAttributes())
.append(wSpeedSupported(), other.wSpeedSupported())
.append(bFunctionalitySupport(), other.bFunctionalitySupport())
.append(bU1DevExitLat(), other.bU1DevExitLat())
.append(bU2DevExitLat(), other.bU2DevExitLat())
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder()
.append(bLength())
.append(bDescriptorType())
.append(bDevCapabilityType())
.append(bmAttributes())
.append(wSpeedSupported())
.append(bFunctionalitySupport())
.append(bU1DevExitLat())
.append(bU2DevExitLat())
.toHashCode();
}
@Override
public String toString()
{
return dump();
}
}

View File

@ -735,7 +735,7 @@ public class LibUSBTest
* Tests the
* {@link LibUsb#getUsb20ExtensionDescriptor(Context,
* BosDevCapabilityDescriptor, Usb20ExtensionDescriptor)}
* method with uninitialized endpoint.
* method with uninitialized device capability descriptor.
*/
@Test(expected = IllegalStateException.class)
public void testGetUsb20ExtensionDescriptorWithUninitializedEndpoint()
@ -782,6 +782,58 @@ public class LibUSBTest
assumeUsbTestsEnabled();
LibUsb.freeUsb20ExtensionDescriptor(null);
}
/**
* Tests the
* {@link LibUsb#getSsUsbDeviceCapabilityDescriptor(Context,
* BosDevCapabilityDescriptor, SsUsbDeviceCapabilityDescriptor)}
* method with uninitialized device capability descriptor.
*/
@Test(expected = IllegalStateException.class)
public void testGetSsUsbDeviceCapabilityDescriptorWithUninitializedEndpoint()
{
assumeUsbTestsEnabled();
LibUsb.getSsUsbDeviceCapabilityDescriptor(null,
new BosDevCapabilityDescriptor(),
new SsUsbDeviceCapabilityDescriptor());
}
/**
* Tests the
* {@link LibUsb#getSsUsbDeviceCapabilityDescriptor(Context,
* BosDevCapabilityDescriptor, SsUsbDeviceCapabilityDescriptor)}
* method without descriptors.
*/
@Test(expected = IllegalArgumentException.class)
public void testGetSsUsbDeviceCapabilityDescriptorWithoutDescriptors()
{
assumeUsbTestsEnabled();
LibUsb.getSsUsbDeviceCapabilityDescriptor(null, null, null);
}
/**
* Tests the
* {@link LibUsb#freeSsUsbDeviceCapabilityDescriptor(SsUsbDeviceCapabilityDescriptor)}
* method with uninitialized descriptor.
*/
@Test(expected = IllegalStateException.class)
public void testFreeSsUsbDeviceCapabilityDescriptorWithUninitializedDescriptor()
{
assumeUsbTestsEnabled();
LibUsb.freeSsUsbDeviceCapabilityDescriptor(new SsUsbDeviceCapabilityDescriptor());
}
/**
* Tests the
* {@link LibUsb#freeSsUsbDeviceCapabilityDescriptor(SsUsbDeviceCapabilityDescriptor)}
* method with null parameter. Must do nothing.
*/
@Test
public void testFreeSsUsbDeviceCapabilityDescriptorWithNull()
{
assumeUsbTestsEnabled();
LibUsb.freeSsUsbDeviceCapabilityDescriptor(null);
}
/**
* Tests the

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2013 Klaus Reimer <k@ailis.de>
* See LICENSE.md for licensing information.
*/
package de.ailis.usb4java.libusb;
import static de.ailis.usb4java.test.UsbAssume.assumeUsbTestsEnabled;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Tests the {@link SsUsbDeviceCapabilityDescriptor} class.
*
* @author Klaus Reimer (k@ailis.de)
*/
public class SsUsbDeviceCapabilityDescriptorTest
{
/** The test subject. */
private SsUsbDeviceCapabilityDescriptor descriptor;
/**
* Setup test.
*/
@Before
public void setUp()
{
assumeUsbTestsEnabled();
LibUsb.init(null);
this.descriptor = new SsUsbDeviceCapabilityDescriptor();
}
/**
* Tear down test.
*/
@After
public void tearDown()
{
LibUsb.exit(null);
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bLength()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedLength()
{
assumeUsbTestsEnabled();
this.descriptor.bLength();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bDescriptorType()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedDescriptorType()
{
assumeUsbTestsEnabled();
this.descriptor.bDescriptorType();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bDevCapabilityType()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedDevCapabilityType()
{
assumeUsbTestsEnabled();
this.descriptor.bDevCapabilityType();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bmAttributes()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedAttributes()
{
assumeUsbTestsEnabled();
this.descriptor.bmAttributes();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#wSpeedSupported()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedSpeedSupported()
{
assumeUsbTestsEnabled();
this.descriptor.wSpeedSupported();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bFunctionalitySupport()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedFunctionalitySupport()
{
assumeUsbTestsEnabled();
this.descriptor.bFunctionalitySupport();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bU1DevExitLat()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedU1DevExitLat()
{
assumeUsbTestsEnabled();
this.descriptor.bU1DevExitLat();
}
/**
* Tests uninitialized access to
* {@link SsUsbDeviceCapabilityDescriptor#bU2DevExitLat()}
*/
@Test(expected = IllegalStateException.class)
public void testUninitializedU2DevExitLat()
{
assumeUsbTestsEnabled();
this.descriptor.bU2DevExitLat();
}
}