mirror of https://github.com/ARMmbed/mbed-os.git
Update USBHID and USBCDC for new AsyncOp
Update USB classes to use the new AsyncOp API.feature-hal-spec-usb-device
parent
bfa9992c7d
commit
6984060b9f
|
@ -21,24 +21,91 @@
|
|||
|
||||
class USBHID::AsyncSend: public AsyncOp {
|
||||
public:
|
||||
AsyncSend(const HID_REPORT *report): AsyncOp(NULL), report(report), result(false)
|
||||
AsyncSend(USBHID *hid, const HID_REPORT *report): hid(hid), report(report), result(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~AsyncSend()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual bool process()
|
||||
{
|
||||
if (!hid->configured()) {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hid->send_nb(report)) {
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
USBHID *hid;
|
||||
const HID_REPORT *report;
|
||||
bool result;
|
||||
};
|
||||
|
||||
class USBHID::AsyncRead: public AsyncOp {
|
||||
public:
|
||||
AsyncRead(HID_REPORT *report): AsyncOp(NULL), report(report), result(false)
|
||||
AsyncRead(USBHID *hid, HID_REPORT *report): hid(hid), report(report), result(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~AsyncRead()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual bool process()
|
||||
{
|
||||
if (!hid->configured()) {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hid->read_nb(report)) {
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
USBHID *hid;
|
||||
HID_REPORT *report;
|
||||
bool result;
|
||||
};
|
||||
|
||||
class USBHID::AsyncWait: public AsyncOp {
|
||||
public:
|
||||
AsyncWait(USBHID *hid): hid(hid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~AsyncWait()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual bool process()
|
||||
{
|
||||
if (hid->configured()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
USBHID *hid;
|
||||
};
|
||||
|
||||
USBHID::USBHID(bool connect_blocking, uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
|
||||
: USBDevice(get_usb_phy(), vendor_id, product_id, product_release)
|
||||
|
@ -88,15 +155,12 @@ void USBHID::wait_ready()
|
|||
{
|
||||
lock();
|
||||
|
||||
AsyncOp wait_op(NULL);
|
||||
wait_op.start(&_connect_list);
|
||||
if (configured()) {
|
||||
wait_op.complete();
|
||||
}
|
||||
AsyncWait wait_op(this);
|
||||
_connect_list.add(&wait_op);
|
||||
|
||||
unlock();
|
||||
|
||||
wait_op.wait();
|
||||
wait_op.wait(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,23 +168,12 @@ bool USBHID::send(const HID_REPORT *report)
|
|||
{
|
||||
lock();
|
||||
|
||||
if (!configured()) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (send_nb(report)) {
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncSend send_op(report);
|
||||
send_op.start(&_send_list);
|
||||
AsyncSend send_op(this, report);
|
||||
_send_list.add(&send_op);
|
||||
|
||||
unlock();
|
||||
|
||||
send_op.wait();
|
||||
|
||||
send_op.wait(NULL);
|
||||
return send_op.result;
|
||||
}
|
||||
|
||||
|
@ -149,23 +202,12 @@ bool USBHID::read(HID_REPORT *report)
|
|||
{
|
||||
lock();
|
||||
|
||||
if (!configured()) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read_nb(report)) {
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncRead read_op(report);
|
||||
read_op.start(&_read_list);
|
||||
AsyncRead read_op(this, report);
|
||||
_read_list.add(&read_op);
|
||||
|
||||
unlock();
|
||||
|
||||
read_op.wait();
|
||||
|
||||
read_op.wait(NULL);
|
||||
return read_op.result;
|
||||
}
|
||||
|
||||
|
@ -198,13 +240,8 @@ void USBHID::_send_isr(usb_ep_t endpoint)
|
|||
write_finish(_int_in);
|
||||
_send_idle = true;
|
||||
|
||||
AsyncSend *send_op = _send_list.head();
|
||||
if (send_op != NULL) {
|
||||
if (send_nb(send_op->report)) {
|
||||
send_op->result = true;
|
||||
send_op->complete();
|
||||
}
|
||||
} else {
|
||||
_send_list.process();
|
||||
if (_send_idle) {
|
||||
report_tx();
|
||||
}
|
||||
|
||||
|
@ -217,60 +254,12 @@ void USBHID::_read_isr(usb_ep_t endpoint)
|
|||
_output_report.length = read_finish(_int_out);
|
||||
_read_idle = true;
|
||||
|
||||
AsyncRead *read_op = _read_list.head();
|
||||
if (read_op != NULL) {
|
||||
if (read_nb(read_op->report)) {
|
||||
read_op->result = true;
|
||||
read_op->complete();
|
||||
}
|
||||
} else {
|
||||
_read_list.process();
|
||||
if (_read_idle) {
|
||||
report_rx();
|
||||
}
|
||||
}
|
||||
|
||||
void USBHID::_connect_wake_all()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
AsyncOp *wait_op = _connect_list.head();
|
||||
while (wait_op != NULL) {
|
||||
wait_op->complete();
|
||||
wait_op = _connect_list.head();
|
||||
}
|
||||
}
|
||||
|
||||
void USBHID::_send_abort_all()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
if (!_send_idle) {
|
||||
endpoint_abort(_int_in);
|
||||
_send_idle = true;
|
||||
}
|
||||
AsyncSend *tx_cur = _send_list.head();
|
||||
while (tx_cur != NULL) {
|
||||
tx_cur->result = false;
|
||||
tx_cur->complete();
|
||||
tx_cur = _send_list.head();
|
||||
}
|
||||
}
|
||||
|
||||
void USBHID::_read_abort_all()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
if (!_read_idle) {
|
||||
endpoint_abort(_int_out);
|
||||
_read_idle = true;
|
||||
}
|
||||
AsyncRead *rx_cur = _read_list.head();
|
||||
while (rx_cur != NULL) {
|
||||
rx_cur->result = false;
|
||||
rx_cur->complete();
|
||||
rx_cur = _read_list.head();
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t USBHID::report_desc_length()
|
||||
{
|
||||
report_desc();
|
||||
|
@ -280,12 +269,19 @@ uint16_t USBHID::report_desc_length()
|
|||
|
||||
void USBHID::callback_state_change(DeviceState new_state)
|
||||
{
|
||||
if (new_state == Configured) {
|
||||
_connect_wake_all();
|
||||
} else {
|
||||
_send_abort_all();
|
||||
_read_abort_all();
|
||||
if (new_state != Configured) {
|
||||
if (!_send_idle) {
|
||||
endpoint_abort(_int_in);
|
||||
_send_idle = true;
|
||||
}
|
||||
if (!_read_idle) {
|
||||
endpoint_abort(_int_out);
|
||||
_read_idle = true;
|
||||
}
|
||||
}
|
||||
_send_list.process();
|
||||
_read_list.process();
|
||||
_connect_list.process();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -22,8 +22,7 @@
|
|||
#include "USBDevice.h"
|
||||
|
||||
#include "USBHID_Types.h"
|
||||
#include "AsyncOp.h"
|
||||
#include "LinkedList.h"
|
||||
#include "OperationList.h"
|
||||
|
||||
|
||||
|
||||
|
@ -249,17 +248,14 @@ private:
|
|||
void _send_isr(usb_ep_t endpoint);
|
||||
void _read_isr(usb_ep_t endpoint);
|
||||
|
||||
void _connect_wake_all();
|
||||
void _send_abort_all();
|
||||
void _read_abort_all();
|
||||
|
||||
class AsyncSend;
|
||||
class AsyncRead;
|
||||
class AsyncWait;
|
||||
|
||||
LinkedList<AsyncOp> _connect_list;
|
||||
LinkedList<AsyncSend> _send_list;
|
||||
OperationList<AsyncWait> _connect_list;
|
||||
OperationList<AsyncSend> _send_list;
|
||||
bool _send_idle;
|
||||
LinkedList<AsyncRead> _read_list;
|
||||
OperationList<AsyncRead> _read_list;
|
||||
bool _read_idle;
|
||||
|
||||
uint8_t _configuration_descriptor[41];
|
||||
|
|
|
@ -36,10 +36,39 @@ static const uint8_t cdc_line_coding_default[7] = {0x80, 0x25, 0x00, 0x00, 0x00,
|
|||
|
||||
class USBCDC::AsyncWrite: public AsyncOp {
|
||||
public:
|
||||
AsyncWrite(uint8_t *buf, uint32_t size): AsyncOp(NULL), tx_buf(buf), tx_size(size), result(false)
|
||||
AsyncWrite(USBCDC *serial, uint8_t *buf, uint32_t size):
|
||||
serial(serial), tx_buf(buf), tx_size(size), result(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~AsyncWrite()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual bool process()
|
||||
{
|
||||
if (!serial->_terminal_connected) {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t actual_size = 0;
|
||||
serial->send_nb(tx_buf, tx_size, &actual_size, true);
|
||||
tx_size -= actual_size;
|
||||
tx_buf += actual_size;
|
||||
if (tx_size == 0) {
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start transfer if it hasn't been
|
||||
serial->_send_isr_start();
|
||||
return false;
|
||||
}
|
||||
|
||||
USBCDC *serial;
|
||||
uint8_t *tx_buf;
|
||||
uint32_t tx_size;
|
||||
bool result;
|
||||
|
@ -47,11 +76,40 @@ public:
|
|||
|
||||
class USBCDC::AsyncRead: public AsyncOp {
|
||||
public:
|
||||
AsyncRead(uint8_t *buf, uint32_t size, uint32_t *size_read, bool read_all)
|
||||
: AsyncOp(NULL), rx_buf(buf), rx_size(size), rx_actual(size_read), all(read_all), result(false)
|
||||
AsyncRead(USBCDC *serial, uint8_t *buf, uint32_t size, uint32_t *size_read, bool read_all)
|
||||
: serial(serial), rx_buf(buf), rx_size(size), rx_actual(size_read), all(read_all), result(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~AsyncRead()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual bool process()
|
||||
{
|
||||
if (!serial->_terminal_connected) {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t actual_size = 0;
|
||||
serial->receive_nb(rx_buf, rx_size, &actual_size);
|
||||
rx_buf += actual_size;
|
||||
*rx_actual += actual_size;
|
||||
rx_size -= actual_size;
|
||||
if ((!all && *rx_actual > 0) || (rx_size == 0)) {
|
||||
// Wake thread if request is done
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
serial->_receive_isr_start();
|
||||
return false;
|
||||
}
|
||||
|
||||
USBCDC *serial;
|
||||
uint8_t *rx_buf;
|
||||
uint32_t rx_size;
|
||||
uint32_t *rx_actual;
|
||||
|
@ -59,6 +117,31 @@ public:
|
|||
bool result;
|
||||
};
|
||||
|
||||
class USBCDC::AsyncWait: public AsyncOp {
|
||||
public:
|
||||
AsyncWait(USBCDC *serial)
|
||||
: serial(serial)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~AsyncWait()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual bool process()
|
||||
{
|
||||
if (serial->_terminal_connected) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
USBCDC *serial;
|
||||
};
|
||||
|
||||
USBCDC::USBCDC(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
|
||||
: USBDevice(get_usb_phy(), vendor_id, product_id, product_release)
|
||||
|
||||
|
@ -230,13 +313,30 @@ void USBCDC::_change_terminal_connected(bool connected)
|
|||
{
|
||||
assert_locked();
|
||||
|
||||
if (connected) {
|
||||
_connect_wake_all();
|
||||
} else {
|
||||
_send_abort_all();
|
||||
_receive_abort_all();
|
||||
}
|
||||
_terminal_connected = connected;
|
||||
if (!_terminal_connected) {
|
||||
// Abort TX
|
||||
if (_tx_in_progress) {
|
||||
endpoint_abort(_bulk_in);
|
||||
_tx_in_progress = false;
|
||||
}
|
||||
_tx_buf = _tx_buffer;
|
||||
_tx_size = 0;
|
||||
_tx_list.process();
|
||||
MBED_ASSERT(_tx_list.empty());
|
||||
|
||||
// Abort RX
|
||||
if (_rx_in_progress) {
|
||||
endpoint_abort(_bulk_in);
|
||||
_rx_in_progress = false;
|
||||
}
|
||||
_rx_buf = _rx_buffer;
|
||||
_rx_size = 0;
|
||||
_rx_list.process();
|
||||
MBED_ASSERT(_rx_list.empty());
|
||||
|
||||
}
|
||||
_connected_list.process();
|
||||
}
|
||||
|
||||
bool USBCDC::ready()
|
||||
|
@ -253,89 +353,27 @@ void USBCDC::wait_ready()
|
|||
{
|
||||
lock();
|
||||
|
||||
AsyncOp wait_op(NULL);
|
||||
wait_op.start(&_connected_list);
|
||||
if (_terminal_connected) {
|
||||
wait_op.complete();
|
||||
}
|
||||
AsyncWait wait_op(this);
|
||||
_connected_list.add(&wait_op);
|
||||
|
||||
unlock();
|
||||
|
||||
wait_op.wait();
|
||||
}
|
||||
|
||||
void USBCDC::_connect_wake_all()
|
||||
{
|
||||
AsyncOp *wait_op = _connected_list.head();
|
||||
while (wait_op != NULL) {
|
||||
wait_op->complete();
|
||||
wait_op = _connected_list.head();
|
||||
}
|
||||
wait_op.wait(NULL);
|
||||
}
|
||||
|
||||
bool USBCDC::send(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
lock();
|
||||
|
||||
if (!_terminal_connected) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
AsyncWrite write_op(buffer, size);
|
||||
write_op.start(&_tx_list);
|
||||
_send_next();
|
||||
AsyncWrite write_op(this, buffer, size);
|
||||
_tx_list.add(&write_op);
|
||||
|
||||
unlock();
|
||||
|
||||
write_op.wait();
|
||||
write_op.wait(NULL);
|
||||
return write_op.result;
|
||||
}
|
||||
|
||||
void USBCDC::_send_next()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
uint32_t actual_size;
|
||||
do {
|
||||
// Set current TX operation or return if there are none left
|
||||
AsyncWrite *tx_cur = _tx_list.head();
|
||||
if (tx_cur == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
actual_size = 0;
|
||||
send_nb(tx_cur->tx_buf, tx_cur->tx_size, &actual_size, false);
|
||||
tx_cur->tx_size -= actual_size;
|
||||
tx_cur->tx_buf += actual_size;
|
||||
if (tx_cur->tx_size == 0) {
|
||||
tx_cur->result = true;
|
||||
tx_cur->complete();
|
||||
}
|
||||
} while (actual_size > 0);
|
||||
|
||||
// Start transfer if it hasn't been
|
||||
_send_isr_start();
|
||||
}
|
||||
|
||||
void USBCDC::_send_abort_all()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
if (_tx_in_progress) {
|
||||
endpoint_abort(_bulk_in);
|
||||
_tx_in_progress = false;
|
||||
}
|
||||
_tx_buf = _tx_buffer;
|
||||
_tx_size = 0;
|
||||
|
||||
AsyncWrite *tx_cur = _tx_list.head();
|
||||
while (tx_cur != NULL) {
|
||||
tx_cur->result = false;
|
||||
tx_cur->complete();
|
||||
tx_cur = _tx_list.head();
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::send_nb(uint8_t *buffer, uint32_t size, uint32_t *actual, bool now)
|
||||
{
|
||||
lock();
|
||||
|
@ -357,7 +395,6 @@ void USBCDC::send_nb(uint8_t *buffer, uint32_t size, uint32_t *actual, bool now)
|
|||
unlock();
|
||||
}
|
||||
|
||||
|
||||
void USBCDC::_send_isr_start()
|
||||
{
|
||||
assert_locked();
|
||||
|
@ -382,7 +419,7 @@ void USBCDC::_send_isr(usb_ep_t endpoint)
|
|||
_tx_size = 0;
|
||||
_tx_in_progress = false;
|
||||
|
||||
_send_next();
|
||||
_tx_list.process();
|
||||
if (!_tx_in_progress) {
|
||||
data_tx();
|
||||
}
|
||||
|
@ -392,72 +429,19 @@ bool USBCDC::receive(uint8_t *buffer, uint32_t size, uint32_t *size_read)
|
|||
{
|
||||
lock();
|
||||
|
||||
if (!_terminal_connected) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
bool read_all = size_read == NULL;
|
||||
uint32_t size_read_dummy;
|
||||
uint32_t *size_read_ptr = read_all ? &size_read_dummy : size_read;
|
||||
*size_read_ptr = 0;
|
||||
AsyncRead read_op(buffer, size, size_read_ptr, read_all);
|
||||
read_op.start(&_rx_list);
|
||||
_receive_next();
|
||||
AsyncRead read_op(this, buffer, size, size_read_ptr, read_all);
|
||||
_rx_list.add(&read_op);
|
||||
|
||||
unlock();
|
||||
|
||||
read_op.wait();
|
||||
read_op.wait(NULL);
|
||||
return read_op.result;
|
||||
}
|
||||
|
||||
void USBCDC::_receive_next()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
uint32_t actual_size;
|
||||
do {
|
||||
// Set current RX operation or return if there are none left
|
||||
AsyncRead *rx_cur = _rx_list.head();
|
||||
if (rx_cur == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
actual_size = 0;
|
||||
receive_nb(rx_cur->rx_buf, rx_cur->rx_size, &actual_size);
|
||||
rx_cur->rx_buf += actual_size;
|
||||
*rx_cur->rx_actual += actual_size;
|
||||
rx_cur->rx_size -= actual_size;
|
||||
if ((!rx_cur->all && *rx_cur->rx_actual > 0) || (rx_cur->rx_size == 0)) {
|
||||
// Wake thread if request is done
|
||||
rx_cur->result = true;
|
||||
rx_cur->complete();
|
||||
rx_cur = NULL;
|
||||
}
|
||||
} while (actual_size > 0);
|
||||
|
||||
_receive_isr_start();
|
||||
|
||||
}
|
||||
|
||||
void USBCDC::_receive_abort_all()
|
||||
{
|
||||
assert_locked();
|
||||
|
||||
if (_rx_in_progress) {
|
||||
endpoint_abort(_bulk_in);
|
||||
_rx_in_progress = false;
|
||||
}
|
||||
_rx_buf = _rx_buffer;
|
||||
_rx_size = 0;
|
||||
|
||||
AsyncRead *rx_cur = _rx_list.head();
|
||||
while (rx_cur != NULL) {
|
||||
rx_cur->result = false;
|
||||
rx_cur->complete();
|
||||
rx_cur = _rx_list.head();
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::receive_nb(uint8_t *buffer, uint32_t size, uint32_t *size_read)
|
||||
{
|
||||
|
||||
|
@ -496,7 +480,7 @@ void USBCDC::_receive_isr(usb_ep_t endpoint)
|
|||
_rx_buf = _rx_buffer;
|
||||
_rx_size = read_finish(_bulk_out);
|
||||
_rx_in_progress = false;
|
||||
_receive_next();
|
||||
_rx_list.process();
|
||||
if (!_rx_in_progress) {
|
||||
data_rx();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "USBDevice_Types.h"
|
||||
|
||||
#include "USBDevice.h"
|
||||
#include "LinkedList.h"
|
||||
#include "OperationList.h"
|
||||
|
||||
class AsyncOp;
|
||||
|
||||
|
@ -180,6 +180,7 @@ protected:
|
|||
|
||||
class AsyncWrite;
|
||||
class AsyncRead;
|
||||
class AsyncWait;
|
||||
|
||||
virtual void callback_reset();
|
||||
virtual void callback_state_change(DeviceState new_state);
|
||||
|
@ -191,15 +192,10 @@ protected:
|
|||
void _init();
|
||||
|
||||
void _change_terminal_connected(bool connected);
|
||||
void _connect_wake_all();
|
||||
|
||||
void _send_next();
|
||||
void _send_abort_all();
|
||||
void _send_isr_start();
|
||||
void _send_isr(usb_ep_t endpoint);
|
||||
|
||||
void _receive_next();
|
||||
void _receive_abort_all();
|
||||
void _receive_isr_start();
|
||||
void _receive_isr(usb_ep_t endpoint);
|
||||
|
||||
|
@ -211,16 +207,16 @@ protected:
|
|||
uint8_t _cdc_new_line_coding[7];
|
||||
uint8_t _config_descriptor[75];
|
||||
|
||||
LinkedList<AsyncOp> _connected_list;
|
||||
OperationList<AsyncWait> _connected_list;
|
||||
bool _terminal_connected;
|
||||
|
||||
LinkedList<AsyncWrite> _tx_list;
|
||||
OperationList<AsyncWrite> _tx_list;
|
||||
bool _tx_in_progress;
|
||||
uint8_t _tx_buffer[64];
|
||||
uint8_t *_tx_buf;
|
||||
uint32_t _tx_size;
|
||||
|
||||
LinkedList<AsyncRead> _rx_list;
|
||||
OperationList<AsyncRead> _rx_list;
|
||||
bool _rx_in_progress;
|
||||
uint8_t _rx_buffer[64];
|
||||
uint8_t *_rx_buf;
|
||||
|
|
Loading…
Reference in New Issue