From 500caaeda74dd9c660279036293f4b2997cf0b03 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 9 Sep 2017 09:42:37 +0200 Subject: Add vendor --- vendor/github.com/kylelemons/gousb/usb/transfer.go | 147 +++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 vendor/github.com/kylelemons/gousb/usb/transfer.go (limited to 'vendor/github.com/kylelemons/gousb/usb/transfer.go') diff --git a/vendor/github.com/kylelemons/gousb/usb/transfer.go b/vendor/github.com/kylelemons/gousb/usb/transfer.go new file mode 100644 index 0000000..e41713a --- /dev/null +++ b/vendor/github.com/kylelemons/gousb/usb/transfer.go @@ -0,0 +1,147 @@ +// Copyright 2016 the gousb Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package usb + +import ( + "errors" + "fmt" + "runtime" + "sync" + "time" +) + +type usbTransfer struct { + // mu protects the transfer state. + mu sync.Mutex + // xfer is the allocated libusb_transfer. + xfer *libusbTransfer + // buf is the buffer allocated for the transfer. Both buf and xfer.buffer + // point to the same piece of memory. + buf []byte + // done is blocking until the transfer is complete and data and transfer + // status are available. + done chan struct{} + // submitted is true if this transfer was passed to libusb through submit() + submitted bool +} + +// submits the transfer. After submit() the transfer is in flight and is owned by libusb. +// It's not safe to access the contents of the transfer until wait() returns. +// Once wait() returns, it's ok to re-use the same transfer structure by calling submit() again. +func (t *usbTransfer) submit() error { + t.mu.Lock() + defer t.mu.Unlock() + if t.submitted { + return errors.New("transfer was already submitted and is not finished yet.") + } + t.done = make(chan struct{}) + if err := libusb.submit(t.xfer, t.done); err != nil { + return err + } + t.submitted = true + return nil +} + +// wait waits for libusb to signal the release of transfer data. +// After wait returns, the transfer contents are safe to access +// via t.buf. The number returned by wait indicates how many bytes +// of the buffer were read or written by libusb, and it can be +// smaller than the length of t.buf. +func (t *usbTransfer) wait() (n int, err error) { + t.mu.Lock() + defer t.mu.Unlock() + if !t.submitted { + return 0, nil + } + select { + case <-time.After(10 * time.Second): + return 0, fmt.Errorf("wait timed out after 10s") + case <-t.done: + } + t.submitted = false + n, status := libusb.data(t.xfer) + if status != LIBUSB_TRANSFER_COMPLETED { + return n, status + } + return n, err +} + +// cancel aborts a submitted transfer. The transfer is cancelled +// asynchronously and the user still needs to wait() to return. +func (t *usbTransfer) cancel() error { + t.mu.Lock() + defer t.mu.Unlock() + if !t.submitted { + return nil + } + err := libusb.cancel(t.xfer) + if err == ERROR_NOT_FOUND { + // transfer already completed + return nil + } + return err +} + +// free releases the memory allocated for the transfer. +// free should be called only if the transfer is not used by libusb, +// i.e. it should not be called after submit() and before wait() returns. +func (t *usbTransfer) free() error { + t.mu.Lock() + defer t.mu.Unlock() + if t.submitted { + return errors.New("free() cannot be called on a submitted transfer until wait() returns") + } + libusb.free(t.xfer) + t.xfer = nil + t.buf = nil + t.done = nil + return nil +} + +// newUSBTransfer allocates a new transfer structure for communication with a +// given device/endpoint, with buf as the underlying transfer buffer. +func newUSBTransfer(dev *libusbDevHandle, ei EndpointInfo, buf []byte, timeout time.Duration) (*usbTransfer, error) { + var isoPackets int + var isoPktSize uint32 + tt := ei.TransferType() + if tt == TRANSFER_TYPE_ISOCHRONOUS { + isoPktSize = ei.MaxIsoPacket + if len(buf) < int(isoPktSize) { + isoPktSize = uint32(len(buf)) + } + isoPackets = len(buf) / int(isoPktSize) + debug.Printf("New isochronous transfer - buffer length %d, using %d packets of %d bytes each", len(buf), isoPackets, isoPktSize) + } + + xfer, err := libusb.alloc(dev, ei.Address, tt, timeout, isoPackets, buf) + if err != nil { + return nil, err + } + + if tt == TRANSFER_TYPE_ISOCHRONOUS { + libusb.setIsoPacketLengths(xfer, isoPktSize) + } + + t := &usbTransfer{ + xfer: xfer, + buf: buf, + } + runtime.SetFinalizer(t, func(t *usbTransfer) { + t.cancel() + t.wait() + t.free() + }) + return t, nil +} -- cgit v1.2.3