aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabien Poussin <fabien.poussin@gmail.com>2018-03-08 17:09:26 +0100
committerGitHub <noreply@github.com>2018-03-08 17:09:26 +0100
commit11066ebbd353a4a4c0e1add129b9d60202a9803e (patch)
tree62e67ed9ddb904d94ee1aa2d286b9c4441a01896
parent14c851fdabae5799830103c208c6a900b1fb4159 (diff)
parentb7f761313c11d94b89b605f81a89ced34a57c603 (diff)
downloadChibiOS-Contrib-11066ebbd353a4a4c0e1add129b9d60202a9803e.tar.gz
ChibiOS-Contrib-11066ebbd353a4a4c0e1add129b9d60202a9803e.tar.bz2
ChibiOS-Contrib-11066ebbd353a4a4c0e1add129b9d60202a9803e.zip
Merge pull request #143 from qmk/fix_kinesis_usb_data_sync
Fix Kinetis usb databank synchronization problems
-rw-r--r--os/common/ext/CMSIS/KINETIS/k20xx.h2
-rw-r--r--os/hal/ports/KINETIS/LLD/hal_usb_lld.c57
2 files changed, 42 insertions, 17 deletions
diff --git a/os/common/ext/CMSIS/KINETIS/k20xx.h b/os/common/ext/CMSIS/KINETIS/k20xx.h
index 38855aa..8218b3c 100644
--- a/os/common/ext/CMSIS/KINETIS/k20xx.h
+++ b/os/common/ext/CMSIS/KINETIS/k20xx.h
@@ -2242,7 +2242,7 @@ typedef struct
/******** Bits definition for USBx_CTL register *****************/
#define USBx_CTL_JSTATE ((uint8_t)0x80) /*!< Live USB differential receiver JSTATE signal */
#define USBx_CTL_SE0 ((uint8_t)0x40) /*!< Live USB single ended zero signal */
-#define USBx_CTL_TXSUSPENDTOKENBUS ((uint8_t)0x20) /*!< */
+#define USBx_CTL_TXSUSPENDTOKENBUSY ((uint8_t)0x20) /*!< */
#define USBx_CTL_RESET ((uint8_t)0x10) /*!< Generates an USB reset signal (host mode) */
#define USBx_CTL_HOSTMODEEN ((uint8_t)0x08) /*!< Operate in Host mode */
#define USBx_CTL_RESUME ((uint8_t)0x04) /*!< Executes resume signaling */
diff --git a/os/hal/ports/KINETIS/LLD/hal_usb_lld.c b/os/hal/ports/KINETIS/LLD/hal_usb_lld.c
index e8d9778..ba91d24 100644
--- a/os/hal/ports/KINETIS/LLD/hal_usb_lld.c
+++ b/os/hal/ports/KINETIS/LLD/hal_usb_lld.c
@@ -158,7 +158,7 @@ void usb_packet_transmit(USBDriver *usbp, usbep_t ep, size_t n)
USBInEndpointState *isp = epc->in_state;
bd_t *bd = (bd_t *)&_bdt[BDT_INDEX(ep, TX, isp->odd_even)];
-
+
if (n > (size_t)epc->in_maxsize)
n = (size_t)epc->in_maxsize;
@@ -244,19 +244,16 @@ OSAL_IRQ_HANDLER(KINETIS_USB_IRQ_VECTOR) {
{
case BDT_PID_SETUP: // SETUP
{
- /* Clear any pending IN stuff */
- _bdt[BDT_INDEX(ep, TX, EVEN)].desc = 0;
- _bdt[BDT_INDEX(ep, TX, ODD)].desc = 0;
- /* Also in the chibios state machine */
+ /* Clear receiving in the chibios state machine */
(usbp)->receiving &= ~1;
- /* After a SETUP, IN is always DATA1 */
- usbp->epc[ep]->in_state->data_bank = DATA1;
-
- /* Call SETUP function (ChibiOS core), which sends back stuff */
+ /* Call SETUP function (ChibiOS core), which prepares
+ * for send or receive and releases the buffer
+ */
_usb_isr_invoke_setup_cb(usbp, ep);
- /* Buffer is released by the above callback. */
- /* from Paul: "unfreeze the USB, now that we're ready" */
- USB0->CTL = USBx_CTL_USBENSOFEN;
+ /* When a setup packet is received, tx is suspended,
+ * so it needs to be resumed here.
+ */
+ USB0->CTL &= ~USBx_CTL_TXSUSPENDTOKENBUSY;
} break;
case BDT_PID_IN: // IN
{
@@ -728,9 +725,23 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
}
/* Release the buffer
* Setup packet is always DATA0
- * Initialize buffers so current expects DATA0 & opposite DATA1 */
+ * Release the current DATA0 buffer
+ */
bd->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA0);
- _bdt[BDT_INDEX(ep, RX, os->odd_even^ODD)].desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA1);
+ /* If DATA1 was expected, then the states are out of sync.
+ * So reset the other buffer too, and set it as DATA1.
+ * This should not happen in normal cases, but is possible in
+ * error situations. NOTE: it's possible that this is too late
+ * and the next packet has already been received and dropped, but
+ * there's nothing that we can do about that anymore at this point.
+ */
+ if (os->data_bank == DATA1)
+ {
+ bd_t *bd_next = (bd_t*)&_bdt[BDT_INDEX(ep, RX, os->odd_even^ODD)];
+ bd_next->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA1);
+ }
+ /* After a SETUP, both in and out are always DATA1 */
+ usbp->epc[ep]->in_state->data_bank = DATA1;
os->data_bank = DATA1;
}
@@ -762,8 +773,22 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
* @notapi
*/
void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
- (void)usbp;
- (void)ep;
+ if (ep == 0 && usbp->ep0state == USB_EP0_IN_SENDING_STS) {
+ /* When a status packet is about to be sent on endpoint 0 the
+ * next packet will be a setup packet, which means that the
+ * buffer we expect after this should be DATA0, and the following
+ * DATA1. Since no out packets should be in flight at this time
+ * it's safe to initialize the buffers according to the expectations
+ * here.
+ */
+ const USBEndpointConfig* epc = usbp->epc[ep];
+ bd_t * bd = (bd_t*)&_bdt[BDT_INDEX(ep, RX, epc->out_state->odd_even)];
+ bd_t *bd_next = (bd_t*)&_bdt[BDT_INDEX(ep, RX, epc->out_state->odd_even^ODD)];
+
+ bd->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA1);
+ bd_next->desc = BDT_DESC(usbp->epc[ep]->out_maxsize,DATA0);
+ epc->out_state->data_bank = DATA0;
+ }
usb_packet_transmit(usbp,ep,usbp->epc[ep]->in_state->txsize);
}