diff --git a/usb/device/USBHID/USBHID.cpp b/usb/device/USBHID/USBHID.cpp index c1028d78b6..8045459f16 100644 --- a/usb/device/USBHID/USBHID.cpp +++ b/usb/device/USBHID/USBHID.cpp @@ -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(); } // diff --git a/usb/device/USBHID/USBHID.h b/usb/device/USBHID/USBHID.h index 015ad35506..2cd984a661 100644 --- a/usb/device/USBHID/USBHID.h +++ b/usb/device/USBHID/USBHID.h @@ -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 _connect_list; - LinkedList _send_list; + OperationList _connect_list; + OperationList _send_list; bool _send_idle; - LinkedList _read_list; + OperationList _read_list; bool _read_idle; uint8_t _configuration_descriptor[41]; diff --git a/usb/device/USBSerial/USBCDC.cpp b/usb/device/USBSerial/USBCDC.cpp index 4eff925dee..b03ae1df3f 100644 --- a/usb/device/USBSerial/USBCDC.cpp +++ b/usb/device/USBSerial/USBCDC.cpp @@ -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(); } diff --git a/usb/device/USBSerial/USBCDC.h b/usb/device/USBSerial/USBCDC.h index 726ffb4419..fd00f227c7 100644 --- a/usb/device/USBSerial/USBCDC.h +++ b/usb/device/USBSerial/USBCDC.h @@ -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 _connected_list; + OperationList _connected_list; bool _terminal_connected; - LinkedList _tx_list; + OperationList _tx_list; bool _tx_in_progress; uint8_t _tx_buffer[64]; uint8_t *_tx_buf; uint32_t _tx_size; - LinkedList _rx_list; + OperationList _rx_list; bool _rx_in_progress; uint8_t _rx_buffer[64]; uint8_t *_rx_buf;