Added isochronous transfer
This commit is contained in:
@@ -13,6 +13,7 @@ type EndpointInfo struct {
|
|||||||
Address uint8
|
Address uint8
|
||||||
Attributes uint8
|
Attributes uint8
|
||||||
MaxPacketSize uint16
|
MaxPacketSize uint16
|
||||||
|
MaxIsoPacket uint32
|
||||||
PollInterval uint8
|
PollInterval uint8
|
||||||
RefreshRate uint8
|
RefreshRate uint8
|
||||||
SynchAddress uint8
|
SynchAddress uint8
|
||||||
@@ -27,11 +28,12 @@ func (e EndpointInfo) Direction() EndpointDirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e EndpointInfo) String() string {
|
func (e EndpointInfo) String() string {
|
||||||
return fmt.Sprintf("Endpoint %d %-3s %s - %s %s",
|
return fmt.Sprintf("Endpoint %d %-3s %s - %s %s [%d %d]",
|
||||||
e.Number(), e.Direction(),
|
e.Number(), e.Direction(),
|
||||||
TransferType(e.Attributes)&TRANSFER_TYPE_MASK,
|
TransferType(e.Attributes)&TRANSFER_TYPE_MASK,
|
||||||
IsoSyncType(e.Attributes)&ISO_SYNC_TYPE_MASK,
|
IsoSyncType(e.Attributes)&ISO_SYNC_TYPE_MASK,
|
||||||
IsoUsageType(e.Attributes)&ISO_USAGE_TYPE_MASK,
|
IsoUsageType(e.Attributes)&ISO_USAGE_TYPE_MASK,
|
||||||
|
e.MaxPacketSize, e.MaxIsoPacket,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +70,7 @@ func (c ConfigInfo) String() string {
|
|||||||
return fmt.Sprintf("Config %02x", c.Config)
|
return fmt.Sprintf("Config %02x", c.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo {
|
func newConfig(dev *C.libusb_device, cfg *C.struct_libusb_config_descriptor) ConfigInfo {
|
||||||
c := ConfigInfo{
|
c := ConfigInfo{
|
||||||
Config: uint8(cfg.bConfigurationValue),
|
Config: uint8(cfg.bConfigurationValue),
|
||||||
Attributes: uint8(cfg.bmAttributes),
|
Attributes: uint8(cfg.bmAttributes),
|
||||||
@@ -114,6 +116,7 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo {
|
|||||||
Address: uint8(end.bEndpointAddress),
|
Address: uint8(end.bEndpointAddress),
|
||||||
Attributes: uint8(end.bmAttributes),
|
Attributes: uint8(end.bmAttributes),
|
||||||
MaxPacketSize: uint16(end.wMaxPacketSize),
|
MaxPacketSize: uint16(end.wMaxPacketSize),
|
||||||
|
//MaxIsoPacket: uint32(C.libusb_get_max_iso_packet_size(dev, C.uchar(end.bEndpointAddress))),
|
||||||
PollInterval: uint8(end.bInterval),
|
PollInterval: uint8(end.bInterval),
|
||||||
RefreshRate: uint8(end.bRefresh),
|
RefreshRate: uint8(end.bRefresh),
|
||||||
SynchAddress: uint8(end.bSynchAddress),
|
SynchAddress: uint8(end.bSynchAddress),
|
||||||
|
@@ -38,7 +38,7 @@ func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
|||||||
if errno := C.libusb_get_config_descriptor(dev, C.uint8_t(i), &cfg); errno < 0 {
|
if errno := C.libusb_get_config_descriptor(dev, C.uint8_t(i), &cfg); errno < 0 {
|
||||||
return nil, usbError(errno)
|
return nil, usbError(errno)
|
||||||
}
|
}
|
||||||
cfgs = append(cfgs, newConfig(cfg))
|
cfgs = append(cfgs, newConfig(dev, cfg))
|
||||||
C.libusb_free_config_descriptor(cfg)
|
C.libusb_free_config_descriptor(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
176
usb/device.go
176
usb/device.go
@@ -4,6 +4,182 @@ package usb
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var DefaultReadTimeout = 1 * time.Second
|
||||||
|
var DefaultWriteTimeout = 1 * time.Second
|
||||||
|
var DefaultControlTimeout = 5 * time.Second
|
||||||
|
|
||||||
|
type Device struct {
|
||||||
|
handle *C.libusb_device_handle
|
||||||
|
|
||||||
|
// Embed the device information for easy access
|
||||||
|
*Descriptor
|
||||||
|
|
||||||
|
// Timeouts
|
||||||
|
ReadTimeout time.Duration
|
||||||
|
WriteTimeout time.Duration
|
||||||
|
ControlTimeout time.Duration
|
||||||
|
|
||||||
|
// Claimed interfaces
|
||||||
|
lock *sync.Mutex
|
||||||
|
claimed map[uint8]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDevice(handle *C.libusb_device_handle, desc *Descriptor) *Device {
|
||||||
|
ifaces := 0
|
||||||
|
d := &Device{
|
||||||
|
handle: handle,
|
||||||
|
Descriptor: desc,
|
||||||
|
ReadTimeout: DefaultReadTimeout,
|
||||||
|
WriteTimeout: DefaultWriteTimeout,
|
||||||
|
ControlTimeout: DefaultControlTimeout,
|
||||||
|
lock: new(sync.Mutex),
|
||||||
|
claimed: make(map[uint8]int, ifaces),
|
||||||
|
}
|
||||||
|
|
||||||
|
// This doesn't seem to actually get called
|
||||||
|
runtime.SetFinalizer(d, (*Device).Close)
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Reset() error {
|
||||||
|
if errno := C.libusb_reset_device(d.handle); errno != 0 {
|
||||||
|
return usbError(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
||||||
|
dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||||
|
n := C.libusb_control_transfer(
|
||||||
|
d.handle,
|
||||||
|
C.uint8_t(rType),
|
||||||
|
C.uint8_t(request),
|
||||||
|
C.uint16_t(val),
|
||||||
|
C.uint16_t(idx),
|
||||||
|
(*C.uchar)(unsafe.Pointer(dataSlice.Data)),
|
||||||
|
C.uint16_t(len(data)),
|
||||||
|
C.uint(d.ControlTimeout/time.Millisecond))
|
||||||
|
if n < 0 {
|
||||||
|
return int(n), usbError(n)
|
||||||
|
}
|
||||||
|
return int(n), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActiveConfig returns the config id (not the index) of the active configuration.
|
||||||
|
// This corresponds to the ConfigInfo.Config field.
|
||||||
|
func (d *Device) ActiveConfig() (uint8, error) {
|
||||||
|
var cfg C.int
|
||||||
|
if errno := C.libusb_get_configuration(d.handle, &cfg); errno < 0 {
|
||||||
|
return 0, usbError(errno)
|
||||||
|
}
|
||||||
|
return uint8(cfg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConfig attempts to change the active configuration.
|
||||||
|
// The cfg provided is the config id (not the index) of the configuration to set,
|
||||||
|
// which corresponds to the ConfigInfo.Config field.
|
||||||
|
func (d *Device) SetConfig(cfg uint8) error {
|
||||||
|
if errno := C.libusb_set_configuration(d.handle, C.int(cfg)); errno < 0 {
|
||||||
|
return usbError(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the device.
|
||||||
|
func (d *Device) Close() error {
|
||||||
|
if d.handle == nil {
|
||||||
|
return fmt.Errorf("usb: double close on device")
|
||||||
|
}
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
for iface := range d.claimed {
|
||||||
|
C.libusb_release_interface(d.handle, C.int(iface))
|
||||||
|
}
|
||||||
|
C.libusb_close(d.handle)
|
||||||
|
d.handle = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) OpenEndpoint(conf, iface, setup, epoint uint8) (Endpoint, error) {
|
||||||
|
end := &endpoint{
|
||||||
|
Device: d,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range d.Configs {
|
||||||
|
if c.Config != conf {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("found conf: %#v\n", c)
|
||||||
|
for _, i := range c.Interfaces {
|
||||||
|
if i.Number != iface {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("found iface: %#v\n", i)
|
||||||
|
for _, s := range i.Setups {
|
||||||
|
if s.Alternate != setup {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("found setup: %#v\n", s)
|
||||||
|
for _, e := range s.Endpoints {
|
||||||
|
fmt.Printf("ep %02x search: %#v\n", epoint, s)
|
||||||
|
if e.Address != epoint {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
end.InterfaceSetup = s
|
||||||
|
end.EndpointInfo = e
|
||||||
|
switch tt := TransferType(e.Attributes) & TRANSFER_TYPE_MASK; tt {
|
||||||
|
case TRANSFER_TYPE_BULK:
|
||||||
|
end.xfer = bulk_xfer
|
||||||
|
case TRANSFER_TYPE_INTERRUPT:
|
||||||
|
end.xfer = interrupt_xfer
|
||||||
|
case TRANSFER_TYPE_ISOCHRONOUS:
|
||||||
|
end.xfer = isochronous_xfer
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("usb: %s transfer is unsupported", tt)
|
||||||
|
}
|
||||||
|
goto found
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("usb: unknown endpoint %02x", epoint)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("usb: unknown setup %02x", setup)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("usb: unknown interface %02x", iface)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("usb: unknown configuration %02x", conf)
|
||||||
|
|
||||||
|
found:
|
||||||
|
|
||||||
|
// Claim the interface
|
||||||
|
if errno := C.libusb_claim_interface(d.handle, C.int(iface)); errno < 0 {
|
||||||
|
return nil, fmt.Errorf("usb: claim: %s", usbError(errno))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment the claim count
|
||||||
|
d.lock.Lock()
|
||||||
|
d.claimed[iface]++
|
||||||
|
d.lock.Unlock() // unlock immediately because the next calls may block
|
||||||
|
|
||||||
|
// Set the configuration
|
||||||
|
if errno := C.libusb_set_configuration(d.handle, C.int(conf)); errno < 0 {
|
||||||
|
return nil, fmt.Errorf("usb: setcfg: %s", usbError(errno))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose the alternate
|
||||||
|
// This doesn't seem to work...
|
||||||
|
if errno := C.libusb_set_interface_alt_setting(d.handle, C.int(iface), C.int(setup)); errno < 0 {
|
||||||
|
log.Printf("ignoring altsetting error: %s", usbError(errno))
|
||||||
|
//return nil, fmt.Errorf("usb: setalt: %s", usbError(errno))
|
||||||
|
}
|
||||||
|
|
||||||
|
return end, nil
|
||||||
|
}
|
||||||
|
@@ -6,8 +6,8 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Endpoint interface {
|
type Endpoint interface {
|
||||||
|
9
usb/iso.c
Normal file
9
usb/iso.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
|
void _callback(struct libusb_transfer *xfer) {
|
||||||
|
iso_callback(xfer->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_transfer_cb_fn callback() {
|
||||||
|
return &_callback;
|
||||||
|
}
|
225
usb/iso.go
225
usb/iso.go
@@ -1,182 +1,107 @@
|
|||||||
package usb
|
package usb
|
||||||
|
|
||||||
// #include <libusb-1.0/libusb.h>
|
/*
|
||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
|
libusb_transfer_cb_fn callback();
|
||||||
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultReadTimeout = 1 * time.Second
|
//export iso_callback
|
||||||
var DefaultWriteTimeout = 1 * time.Second
|
func iso_callback(cptr unsafe.Pointer) {
|
||||||
var DefaultControlTimeout = 5 * time.Second
|
ch := *(*chan struct{})(cptr)
|
||||||
|
close(ch)
|
||||||
type Device struct {
|
|
||||||
handle *C.libusb_device_handle
|
|
||||||
|
|
||||||
// Embed the device information for easy access
|
|
||||||
*Descriptor
|
|
||||||
|
|
||||||
// Timeouts
|
|
||||||
ReadTimeout time.Duration
|
|
||||||
WriteTimeout time.Duration
|
|
||||||
ControlTimeout time.Duration
|
|
||||||
|
|
||||||
// Claimed interfaces
|
|
||||||
lock *sync.Mutex
|
|
||||||
claimed map[uint8]int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDevice(handle *C.libusb_device_handle, desc *Descriptor) *Device {
|
func (end *endpoint) allocTransfer() *Transfer {
|
||||||
ifaces := 0
|
// Use libusb_get_max_iso_packet_size ?
|
||||||
d := &Device{
|
const (
|
||||||
handle: handle,
|
iso_packets = 242
|
||||||
Descriptor: desc,
|
packet_size = 1760
|
||||||
ReadTimeout: DefaultReadTimeout,
|
)
|
||||||
WriteTimeout: DefaultWriteTimeout,
|
|
||||||
ControlTimeout: DefaultControlTimeout,
|
xfer := C.libusb_alloc_transfer(C.int(iso_packets))
|
||||||
lock: new(sync.Mutex),
|
if xfer == nil {
|
||||||
claimed: make(map[uint8]int, ifaces),
|
log.Printf("usb: transfer allocation failed?!")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This doesn't seem to actually get called
|
xfer.dev_handle = end.Device.handle
|
||||||
runtime.SetFinalizer(d, (*Device).Close)
|
xfer.endpoint = C.uchar(end.Address)
|
||||||
|
xfer._type = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
|
||||||
|
|
||||||
return d
|
xfer.callback = C.callback()
|
||||||
|
xfer.timeout = C.uint(5 * time.Second / time.Millisecond)
|
||||||
|
|
||||||
|
buf := make([]byte, iso_packets*packet_size)
|
||||||
|
xfer.num_iso_packets = iso_packets
|
||||||
|
xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
|
||||||
|
xfer.length = C.int(len(buf))
|
||||||
|
C.libusb_set_iso_packet_lengths(xfer, C.uint(len(buf)))
|
||||||
|
pkts := *(*[]C.struct_libusb_packet_descriptor)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Data: uintptr(unsafe.Pointer(&xfer.iso_packet_desc)),
|
||||||
|
Len: iso_packets,
|
||||||
|
Cap: iso_packets,
|
||||||
|
}))
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
xfer.user_data = (unsafe.Pointer)(&done)
|
||||||
|
|
||||||
|
t := &Transfer{
|
||||||
|
xfer: xfer,
|
||||||
|
pkts: pkts,
|
||||||
|
done: done,
|
||||||
|
buf: buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) Reset() error {
|
runtime.SetFinalizer(t, (*Transfer).Close)
|
||||||
if errno := C.libusb_reset_device(d.handle); errno != 0 {
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
type Transfer struct {
|
||||||
|
xfer *C.struct_libusb_transfer
|
||||||
|
pkts []C.struct_libusb_packet_descriptor
|
||||||
|
done chan struct{}
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (xfer *Transfer) Submit() error {
|
||||||
|
if errno := C.libusb_submit_transfer(xfer.xfer); errno < 0 {
|
||||||
return usbError(errno)
|
return usbError(errno)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
func (xfer *Transfer) Wait() (n int, err error) {
|
||||||
dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
<-xfer.done
|
||||||
n := C.libusb_control_transfer(
|
n = int(xfer.xfer.actual_length)
|
||||||
d.handle,
|
for _, pkt := range xfer.pkts {
|
||||||
C.uint8_t(rType),
|
log.Printf("PACKET[%4d] - %#v", pkt)
|
||||||
C.uint8_t(request),
|
|
||||||
C.uint16_t(val),
|
|
||||||
C.uint16_t(idx),
|
|
||||||
(*C.uchar)(unsafe.Pointer(dataSlice.Data)),
|
|
||||||
C.uint16_t(len(data)),
|
|
||||||
C.uint(d.ControlTimeout/time.Millisecond))
|
|
||||||
if n < 0 {
|
|
||||||
return int(n), usbError(n)
|
|
||||||
}
|
}
|
||||||
return int(n), nil
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActiveConfig returns the config id (not the index) of the active configuration.
|
func (xfer *Transfer) Close() error {
|
||||||
// This corresponds to the ConfigInfo.Config field.
|
C.libusb_free_transfer(xfer.xfer)
|
||||||
func (d *Device) ActiveConfig() (uint8, error) {
|
|
||||||
var cfg C.int
|
|
||||||
if errno := C.libusb_get_configuration(d.handle, &cfg); errno < 0 {
|
|
||||||
return 0, usbError(errno)
|
|
||||||
}
|
|
||||||
return uint8(cfg), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig attempts to change the active configuration.
|
|
||||||
// The cfg provided is the config id (not the index) of the configuration to set,
|
|
||||||
// which corresponds to the ConfigInfo.Config field.
|
|
||||||
func (d *Device) SetConfig(cfg uint8) error {
|
|
||||||
if errno := C.libusb_set_configuration(d.handle, C.int(cfg)); errno < 0 {
|
|
||||||
return usbError(errno)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the device.
|
func isochronous_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) {
|
||||||
func (d *Device) Close() error {
|
xfer := e.allocTransfer()
|
||||||
if d.handle == nil {
|
defer xfer.Close()
|
||||||
return fmt.Errorf("usb: double close on device")
|
|
||||||
}
|
if err := xfer.Submit(); err != nil {
|
||||||
d.lock.Lock()
|
return 0, err
|
||||||
defer d.lock.Unlock()
|
|
||||||
for iface := range d.claimed {
|
|
||||||
C.libusb_release_interface(d.handle, C.int(iface))
|
|
||||||
}
|
|
||||||
C.libusb_close(d.handle)
|
|
||||||
d.handle = nil
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) OpenEndpoint(conf, iface, setup, epoint uint8) (Endpoint, error) {
|
return xfer.Wait()
|
||||||
end := &endpoint{
|
|
||||||
Device: d,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range d.Configs {
|
|
||||||
if c.Config != conf {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Printf("found conf: %#v\n", c)
|
|
||||||
for _, i := range c.Interfaces {
|
|
||||||
if i.Number != iface {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Printf("found iface: %#v\n", i)
|
|
||||||
for _, s := range i.Setups {
|
|
||||||
if s.Alternate != setup {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Printf("found setup: %#v\n", s)
|
|
||||||
for _, e := range s.Endpoints {
|
|
||||||
fmt.Printf("ep %02x search: %#v\n", epoint, s)
|
|
||||||
if e.Address != epoint {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
end.InterfaceSetup = s
|
|
||||||
end.EndpointInfo = e
|
|
||||||
switch tt := TransferType(e.Attributes) & TRANSFER_TYPE_MASK; tt {
|
|
||||||
case TRANSFER_TYPE_BULK:
|
|
||||||
end.xfer = bulk_xfer
|
|
||||||
case TRANSFER_TYPE_INTERRUPT:
|
|
||||||
end.xfer = interrupt_xfer
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("usb: %s transfer is unsupported", tt)
|
|
||||||
}
|
|
||||||
goto found
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("usb: unknown endpoint %02x", epoint)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("usb: unknown setup %02x", setup)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("usb: unknown interface %02x", iface)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("usb: unknown configuration %02x", conf)
|
|
||||||
|
|
||||||
found:
|
|
||||||
|
|
||||||
// Claim the interface
|
|
||||||
if errno := C.libusb_claim_interface(d.handle, C.int(iface)); errno < 0 {
|
|
||||||
return nil, fmt.Errorf("usb: claim: %s", usbError(errno))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment the claim count
|
|
||||||
d.lock.Lock()
|
|
||||||
d.claimed[iface]++
|
|
||||||
d.lock.Unlock() // unlock immediately because the next calls may block
|
|
||||||
|
|
||||||
// Set the configuration
|
|
||||||
if errno := C.libusb_set_configuration(d.handle, C.int(conf)); errno < 0 {
|
|
||||||
return nil, fmt.Errorf("usb: setcfg: %s", usbError(errno))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Choose the alternate
|
|
||||||
/* This doesn't seem to work...
|
|
||||||
if errno := C.libusb_set_interface_alt_setting(d.handle, C.int(iface), C.int(setup)); errno < 0 {
|
|
||||||
return nil, fmt.Errorf("usb: setalt: %s", usbError(errno))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return end, nil
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user