New USB API finalized, updated OTGv1, USBv1 not yet updated.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8653 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
Giovanni Di Sirio 2015-12-28 11:16:40 +00:00
parent d93fdcd424
commit de202dd376
7 changed files with 158 additions and 218 deletions

View File

@ -412,9 +412,9 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
* @param[in] usbp pointer to the @p USBDriver object * @param[in] usbp pointer to the @p USBDriver object
* @return The current frame number. * @return The current frame number.
* *
* @api * @xclass
*/ */
#define usbGetFrameNumber(usbp) usb_lld_get_frame_number(usbp) #define usbGetFrameNumberX(usbp) usb_lld_get_frame_number(usbp)
/** /**
* @brief Returns the status of an IN endpoint. * @brief Returns the status of an IN endpoint.
@ -454,9 +454,9 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
* @param[in] ep endpoint number * @param[in] ep endpoint number
* @return Received data size. * @return Received data size.
* *
* @iclass * @xclass
*/ */
#define usbGetReceiveTransactionSizeI(usbp, ep) \ #define usbGetReceiveTransactionSizeX(usbp, ep) \
usb_lld_get_transaction_size(usbp, ep) usb_lld_get_transaction_size(usbp, ep)
/** /**
@ -469,7 +469,7 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
* @param[in] n number of bytes to be transferred * @param[in] n number of bytes to be transferred
* @param[in] endcb callback to be invoked after the transfer or @p NULL * @param[in] endcb callback to be invoked after the transfer or @p NULL
* *
* @api * @special
*/ */
#define usbSetupTransfer(usbp, buf, n, endcb) { \ #define usbSetupTransfer(usbp, buf, n, endcb) { \
(usbp)->ep0next = (buf); \ (usbp)->ep0next = (buf); \
@ -580,7 +580,7 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
} \ } \
osalSysLockFromISR(); \ osalSysLockFromISR(); \
osalThreadResumeI(&(usbp)->epc[ep]->out_state->thread, \ osalThreadResumeI(&(usbp)->epc[ep]->out_state->thread, \
usbGetReceiveTransactionSizeI(usbp, ep)); \ usbGetReceiveTransactionSizeX(usbp, ep)); \
osalSysUnlockFromISR(); \ osalSysUnlockFromISR(); \
} }
#else #else
@ -608,12 +608,10 @@ extern "C" {
const USBEndpointConfig *epcp); const USBEndpointConfig *epcp);
void usbDisableEndpointsI(USBDriver *usbp); void usbDisableEndpointsI(USBDriver *usbp);
void usbReadSetupI(USBDriver *usbp, usbep_t ep, uint8_t *buf); void usbReadSetupI(USBDriver *usbp, usbep_t ep, uint8_t *buf);
void usbPrepareReceive(USBDriver *usbp, usbep_t ep, void usbStartReceiveI(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n); uint8_t *buf, size_t n);
void usbPrepareTransmit(USBDriver *usbp, usbep_t ep, void usbStartTransmitI(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n); const uint8_t *buf, size_t n);
bool usbStartReceiveI(USBDriver *usbp, usbep_t ep);
bool usbStartTransmitI(USBDriver *usbp, usbep_t ep);
#if USB_USE_WAIT == TRUE #if USB_USE_WAIT == TRUE
msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n); msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n);
msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n); msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n);

View File

@ -369,7 +369,6 @@ static void otg_epin_handler(USBDriver *usbp, usbep_t ep) {
cover the remaining.*/ cover the remaining.*/
isp->txsize = isp->totsize - isp->txsize; isp->txsize = isp->totsize - isp->txsize;
isp->txcnt = 0; isp->txcnt = 0;
usb_lld_prepare_transmit(usbp, ep);
osalSysLockFromISR(); osalSysLockFromISR();
usb_lld_start_in(usbp, ep); usb_lld_start_in(usbp, ep);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
@ -415,13 +414,14 @@ static void otg_epout_handler(USBDriver *usbp, usbep_t ep) {
/* Receive transfer complete.*/ /* Receive transfer complete.*/
USBOutEndpointState *osp = usbp->epc[ep]->out_state; USBOutEndpointState *osp = usbp->epc[ep]->out_state;
if (osp->rxsize < osp->totsize) { /* A short packet always terminates a transaction.*/
if (((osp->rxcnt % usbp->epc[ep]->out_maxsize) == 0) &&
(osp->rxsize < osp->totsize)) {
/* In case the transaction covered only part of the total transfer /* In case the transaction covered only part of the total transfer
then another transaction is immediately started in order to then another transaction is immediately started in order to
cover the remaining.*/ cover the remaining.*/
osp->rxsize = osp->totsize - osp->rxsize; osp->rxsize = osp->totsize - osp->rxsize;
osp->rxcnt = 0; osp->rxcnt = 0;
usb_lld_prepare_receive(usbp, ep);
osalSysLockFromISR(); osalSysLockFromISR();
usb_lld_start_out(usbp, ep); usb_lld_start_out(usbp, ep);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
@ -476,7 +476,6 @@ static void otg_isoc_in_failed_handler(USBDriver *usbp) {
* *
* @notapi * @notapi
*/ */
static void otg_isoc_out_failed_handler(USBDriver *usbp) { static void otg_isoc_out_failed_handler(USBDriver *usbp) {
usbep_t ep; usbep_t ep;
stm32_otg_t *otgp = usbp->otg; stm32_otg_t *otgp = usbp->otg;
@ -1134,60 +1133,6 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
memcpy(buf, usbp->epc[ep]->setup_buf, 8); memcpy(buf, usbp->epc[ep]->setup_buf, 8);
} }
/**
* @brief Prepares for a receive operation.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep) {
uint32_t pcnt;
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
/* Transfer initialization.*/
osp->totsize = osp->rxsize;
if ((ep == 0) && (osp->rxsize > EP0_MAX_OUTSIZE))
osp->rxsize = EP0_MAX_OUTSIZE;
pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1) /
usbp->epc[ep]->out_maxsize;
usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) |
DOEPTSIZ_XFRSIZ(osp->rxsize);
}
/**
* @brief Prepares for a transmit operation.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) {
USBInEndpointState *isp = usbp->epc[ep]->in_state;
/* Transfer initialization.*/
isp->totsize = isp->txsize;
if (isp->txsize == 0) {
/* Special case, sending zero size packet.*/
usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
}
else {
if ((ep == 0) && (isp->txsize > EP0_MAX_INSIZE))
isp->txsize = EP0_MAX_INSIZE;
/* Normal case.*/
uint32_t pcnt = (isp->txsize + usbp->epc[ep]->in_maxsize - 1) /
usbp->epc[ep]->in_maxsize;
/* TODO: Support more than one packet per frame for isochronous transfers.*/
usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_MCNT(1) | DIEPTSIZ_PKTCNT(pcnt) |
DIEPTSIZ_XFRSIZ(isp->txsize);
}
}
/** /**
* @brief Starts a receive operation on an OUT endpoint. * @brief Starts a receive operation on an OUT endpoint.
* *
@ -1197,7 +1142,28 @@ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) {
* @notapi * @notapi
*/ */
void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
uint32_t pcnt, rxsize;
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
/* Transfer initialization.*/
osp->totsize = osp->rxsize;
if ((ep == 0) && (osp->rxsize > EP0_MAX_OUTSIZE))
osp->rxsize = EP0_MAX_OUTSIZE;
/* Transaction size is rounded to a multiple of packet size because the
following requirement in the RM:
"For OUT transfers, the transfer size field in the endpoint's transfer
size register must be a multiple of the maximum packet size of the
endpoint, adjusted to the Word boundary".*/
pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1U) /
usbp->epc[ep]->out_maxsize;
rxsize = (pcnt * usbp->epc[ep]->out_maxsize + 3U) & 0xFFFFFFFCU;
/*Setting up transaction parameters in DOEPTSIZ.*/
usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) |
DOEPTSIZ_XFRSIZ(rxsize);
/* Special case of isochronous endpoint.*/
if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) { if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) {
/* Odd/even bit toggling for isochronous endpoint.*/ /* Odd/even bit toggling for isochronous endpoint.*/
if (usbp->otg->DSTS & DSTS_FNSOF_ODD) if (usbp->otg->DSTS & DSTS_FNSOF_ODD)
@ -1206,6 +1172,7 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SODDFRM; usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SODDFRM;
} }
/* Starting operation.*/
usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_EPENA | DOEPCTL_CNAK; usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_EPENA | DOEPCTL_CNAK;
} }
@ -1218,7 +1185,27 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
* @notapi * @notapi
*/ */
void usb_lld_start_in(USBDriver *usbp, usbep_t ep) { void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
USBInEndpointState *isp = usbp->epc[ep]->in_state;
/* Transfer initialization.*/
isp->totsize = isp->txsize;
if (isp->txsize == 0) {
/* Special case, sending zero size packet.*/
usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
}
else {
if ((ep == 0) && (isp->txsize > EP0_MAX_INSIZE))
isp->txsize = EP0_MAX_INSIZE;
/* Normal case.*/
uint32_t pcnt = (isp->txsize + usbp->epc[ep]->in_maxsize - 1) /
usbp->epc[ep]->in_maxsize;
/* TODO: Support more than one packet per frame for isochronous transfers.*/
usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_MCNT(1) | DIEPTSIZ_PKTCNT(pcnt) |
DIEPTSIZ_XFRSIZ(isp->txsize);
}
/* Special case of isochronous endpoint.*/
if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) { if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) {
/* Odd/even bit toggling.*/ /* Odd/even bit toggling.*/
if (usbp->otg->DSTS & DSTS_FNSOF_ODD) if (usbp->otg->DSTS & DSTS_FNSOF_ODD)
@ -1227,6 +1214,7 @@ void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_SODDFRM; usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_SODDFRM;
} }
/* Starting operation.*/
usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK; usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK;
usbp->otg->DIEPEMPMSK |= DIEPEMPMSK_INEPTXFEM(ep); usbp->otg->DIEPEMPMSK |= DIEPEMPMSK_INEPTXFEM(ep);
} }

View File

@ -540,8 +540,6 @@ extern "C" {
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep); usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep); usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf); void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep);
void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep);
void usb_lld_start_out(USBDriver *usbp, usbep_t ep); void usb_lld_start_out(USBDriver *usbp, usbep_t ep);
void usb_lld_start_in(USBDriver *usbp, usbep_t ep); void usb_lld_start_in(USBDriver *usbp, usbep_t ep);
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep); void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);

View File

@ -146,13 +146,8 @@ static void ibnotify(io_buffers_queue_t *bqp) {
uint8_t *buf = ibqGetEmptyBufferI(&sdup->ibqueue); uint8_t *buf = ibqGetEmptyBufferI(&sdup->ibqueue);
if (buf != NULL) { if (buf != NULL) {
/* Buffer found, starting a new transaction.*/ /* Buffer found, starting a new transaction.*/
osalSysUnlock(); usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out,
buf, SERIAL_USB_BUFFERS_SIZE);
usbPrepareReceive(sdup->config->usbp, sdup->config->bulk_out,
buf, SERIAL_USB_BUFFERS_SIZE);
osalSysLock();
(void) usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out);
} }
} }
} }
@ -179,12 +174,7 @@ static void obnotify(io_buffers_queue_t *bqp) {
uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n);
if (buf != NULL) { if (buf != NULL) {
/* Buffer found, starting a new transaction.*/ /* Buffer found, starting a new transaction.*/
osalSysUnlock(); usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n);
usbPrepareTransmit(sdup->config->usbp, sdup->config->bulk_in, buf, n);
osalSysLock();
(void) usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in);
} }
} }
} }
@ -319,9 +309,8 @@ void sduConfigureHookI(SerialUSBDriver *sdup) {
osalDbgAssert(buf != NULL, "no free buffer"); osalDbgAssert(buf != NULL, "no free buffer");
usbPrepareReceive(sdup->config->usbp, sdup->config->bulk_out, usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out,
buf, SERIAL_USB_BUFFERS_SIZE); buf, SERIAL_USB_BUFFERS_SIZE);
(void) usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out);
} }
/** /**
@ -392,12 +381,7 @@ void sduSOFHookI(SerialUSBDriver *sdup) {
osalDbgAssert(buf != NULL, "queue is empty"); osalDbgAssert(buf != NULL, "queue is empty");
osalSysUnlockFromISR(); usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n);
usbPrepareTransmit(sdup->config->usbp, sdup->config->bulk_in, buf, n);
osalSysLockFromISR();
(void) usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in);
} }
} }
@ -431,13 +415,10 @@ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) {
/* Checking if there is a buffer ready for transmission.*/ /* Checking if there is a buffer ready for transmission.*/
buf = obqGetFullBufferI(&sdup->obqueue, &n); buf = obqGetFullBufferI(&sdup->obqueue, &n);
/* Unlocking the critical zone.*/
osalSysUnlockFromISR();
if (buf != NULL) { if (buf != NULL) {
/* The endpoint cannot be busy, we are in the context of the callback, /* The endpoint cannot be busy, we are in the context of the callback,
so it is safe to transmit without a check.*/ so it is safe to transmit without a check.*/
usbPrepareTransmit(usbp, ep, buf, n); usbStartTransmitI(usbp, ep, buf, n);
} }
else if ((usbp->epc[ep]->in_state->txsize > 0U) && else if ((usbp->epc[ep]->in_state->txsize > 0U) &&
((usbp->epc[ep]->in_state->txsize & ((usbp->epc[ep]->in_state->txsize &
@ -446,17 +427,13 @@ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) {
size. Otherwise the recipient may expect more data coming soon and size. Otherwise the recipient may expect more data coming soon and
not return buffered data to app. See section 5.8.3 Bulk Transfer not return buffered data to app. See section 5.8.3 Bulk Transfer
Packet Size Constraints of the USB Specification document.*/ Packet Size Constraints of the USB Specification document.*/
usbPrepareTransmit(usbp, ep, usbp->setup, 0); usbStartTransmitI(usbp, ep, usbp->setup, 0);
} }
else { else {
/* Nothing to transmit.*/ /* Nothing to transmit.*/
return;
} }
/* Locking again and starting transmission.*/
osalSysLockFromISR();
(void) usbStartTransmitI(usbp, ep);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
} }
@ -483,7 +460,7 @@ void sduDataReceived(USBDriver *usbp, usbep_t ep) {
/* Posting the filled buffer in the queue.*/ /* Posting the filled buffer in the queue.*/
ibqPostFullBufferI(&sdup->ibqueue, ibqPostFullBufferI(&sdup->ibqueue,
usbGetReceiveTransactionSizeI(sdup->config->usbp, usbGetReceiveTransactionSizeX(sdup->config->usbp,
sdup->config->bulk_out)); sdup->config->bulk_out));
/* The endpoint cannot be busy, we are in the context of the callback, /* The endpoint cannot be busy, we are in the context of the callback,
@ -492,11 +469,8 @@ void sduDataReceived(USBDriver *usbp, usbep_t ep) {
buf = ibqGetEmptyBufferI(&sdup->ibqueue); buf = ibqGetEmptyBufferI(&sdup->ibqueue);
if (buf != NULL) { if (buf != NULL) {
/* Buffer found, starting a new transaction.*/ /* Buffer found, starting a new transaction.*/
osalSysUnlockFromISR(); usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out,
usbPrepareReceive(sdup->config->usbp, sdup->config->bulk_out, buf, SERIAL_USB_BUFFERS_SIZE);
buf, SERIAL_USB_BUFFERS_SIZE);
osalSysLockFromISR();
(void) usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out);
} }
osalSysUnlockFromISR(); osalSysUnlockFromISR();
} }

View File

@ -401,22 +401,31 @@ void usbDisableEndpointsI(USBDriver *usbp) {
} }
/** /**
* @brief Prepares for a receive transaction on an OUT endpoint. * @brief Starts a receive transaction on an OUT endpoint.
* @post The endpoint is ready for @p usbStartReceiveI(). * @note This function is meant to be called from ISR context outside
* @note This function can be called both in ISR and thread context. * critical zones because there is a potentially slow operation
* inside.
* *
* @param[in] usbp pointer to the @p USBDriver object * @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number * @param[in] ep endpoint number
* @param[out] buf buffer where to copy the received data * @param[out] buf buffer where to copy the received data
* @param[in] n transaction size * @param[in] n transaction size. It is recommended a multiple of
* the packet size because the excess is discarded.
* *
* @special * @iclass
*/ */
void usbPrepareReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { void usbStartReceiveI(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n) {
USBOutEndpointState *osp; USBOutEndpointState *osp;
osalDbgCheckClassI();
osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS)); osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS));
osalDbgAssert(!usbGetReceiveStatusI(usbp, ep), "already receiving");
/* Marking the endpoint as active.*/
usbp->receiving |= (uint16_t)((unsigned)1U << (unsigned)ep);
/* Setting up the transfer.*/
osp = usbp->epc[ep]->out_state; osp = usbp->epc[ep]->out_state;
osp->rxbuf = buf; osp->rxbuf = buf;
osp->rxsize = n; osp->rxsize = n;
@ -425,29 +434,35 @@ void usbPrepareReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) {
osp->thread = NULL; osp->thread = NULL;
#endif #endif
usb_lld_prepare_receive(usbp, ep); /* Starting transfer.*/
usb_lld_start_out(usbp, ep);
} }
/** /**
* @brief Prepares for a transmit transaction on an IN endpoint. * @brief Starts a transmit transaction on an IN endpoint.
* @post The endpoint is ready for @p usbStartTransmitI(). * @note This function is meant to be called from ISR context outside
* @note This function can be called both in ISR and thread context. * critical zones because there is a potentially slow operation
* @note The queue must contain at least the amount of data specified * inside.
* as transaction size.
* *
* @param[in] usbp pointer to the @p USBDriver object * @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number * @param[in] ep endpoint number
* @param[in] buf buffer where to fetch the data to be transmitted * @param[in] buf buffer where to fetch the data to be transmitted
* @param[in] n transaction size * @param[in] n transaction size
* *
* @special * @iclass
*/ */
void usbPrepareTransmit(USBDriver *usbp, usbep_t ep, void usbStartTransmitI(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n) { const uint8_t *buf, size_t n) {
USBInEndpointState *isp; USBInEndpointState *isp;
osalDbgCheckClassI();
osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS)); osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS));
osalDbgAssert(!usbGetTransmitStatusI(usbp, ep), "already transmitting");
/* Marking the endpoint as active.*/
usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep);
/* Setting up the transfer.*/
isp = usbp->epc[ep]->in_state; isp = usbp->epc[ep]->in_state;
isp->txbuf = buf; isp->txbuf = buf;
isp->txsize = n; isp->txsize = n;
@ -456,63 +471,8 @@ void usbPrepareTransmit(USBDriver *usbp, usbep_t ep,
isp->thread = NULL; isp->thread = NULL;
#endif #endif
usb_lld_prepare_transmit(usbp, ep); /* Starting transfer.*/
}
/**
* @brief Starts a receive transaction on an OUT endpoint.
* @post The endpoint callback is invoked when the transfer has been
* completed.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @return The operation status.
* @retval false Operation started successfully.
* @retval true Endpoint busy, operation not started.
*
* @iclass
*/
bool usbStartReceiveI(USBDriver *usbp, usbep_t ep) {
osalDbgCheckClassI();
osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS));
if (usbGetReceiveStatusI(usbp, ep)) {
return true;
}
usbp->receiving |= (uint16_t)((unsigned)1U << (unsigned)ep);
usb_lld_start_out(usbp, ep);
return false;
}
/**
* @brief Starts a transmit transaction on an IN endpoint.
* @post The endpoint callback is invoked when the transfer has been
* completed.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @return The operation status.
* @retval false Operation started successfully.
* @retval true Endpoint busy, operation not started.
*
* @iclass
*/
bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) {
osalDbgCheckClassI();
osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS));
if (usbGetTransmitStatusI(usbp, ep)) {
return true;
}
usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep);
usb_lld_start_in(usbp, ep); usb_lld_start_in(usbp, ep);
return false;
} }
#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) #if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
@ -527,18 +487,23 @@ bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) {
* *
* @return The received effective data size, it can be less than * @return The received effective data size, it can be less than
* the amount specified. * the amount specified.
* @retval MSG_RESET operation aborted by a reset. * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation
* @retval MSG_TIMEOUT operation aborted by a suspend. * has been aborted by an USB reset or a transition to
* the @p USB_SUSPENDED state.
* *
* @api * @api
*/ */
msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) {
msg_t msg; msg_t msg;
usbPrepareReceive(usbp, ep, buf, n);
osalSysLock(); osalSysLock();
usbStartReceiveI(usbp, ep);
if (usbGetDriverStateI(usbp) != USB_ACTIVE) {
osalSysUnlock();
return MSG_RESET;
}
usbStartReceiveI(usbp, ep, buf, n);
msg = osalThreadSuspendS(&usbp->epc[ep]->out_state->thread); msg = osalThreadSuspendS(&usbp->epc[ep]->out_state->thread);
osalSysUnlock(); osalSysUnlock();
@ -555,18 +520,23 @@ msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) {
* *
* @return The operation status. * @return The operation status.
* @retval MSG_OK operation performed successfully. * @retval MSG_OK operation performed successfully.
* @retval MSG_RESET operation aborted by a reset. * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation
* @retval MSG_TIMEOUT operation aborted by a suspend. * has been aborted by an USB reset or a transition to
* the @p USB_SUSPENDED state.
* *
* @api * @api
*/ */
msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) {
msg_t msg; msg_t msg;
usbPrepareTransmit(usbp, ep, buf, n);
osalSysLock(); osalSysLock();
usbStartTransmitI(usbp, ep);
if (usbGetDriverStateI(usbp) != USB_ACTIVE) {
osalSysUnlock();
return MSG_RESET;
}
usbStartTransmitI(usbp, ep, buf, n);
msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread); msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread);
osalSysUnlock(); osalSysUnlock();
@ -700,10 +670,10 @@ void _usb_suspend(USBDriver *usbp) {
if (usbp->epc[i] != NULL) { if (usbp->epc[i] != NULL) {
osalSysLockFromISR(); osalSysLockFromISR();
if (usbp->epc[i]->in_state != NULL) { if (usbp->epc[i]->in_state != NULL) {
osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_TIMEOUT); osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET);
} }
if (usbp->epc[i]->out_state != NULL) { if (usbp->epc[i]->out_state != NULL) {
osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_TIMEOUT); osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET);
} }
osalSysUnlockFromISR(); osalSysUnlockFromISR();
} }
@ -787,9 +757,8 @@ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
if (usbp->ep0n != 0U) { if (usbp->ep0n != 0U) {
/* Starts the transmit phase.*/ /* Starts the transmit phase.*/
usbp->ep0state = USB_EP0_TX; usbp->ep0state = USB_EP0_TX;
usbPrepareTransmit(usbp, 0, usbp->ep0next, usbp->ep0n);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartTransmitI(usbp, 0); usbStartTransmitI(usbp, 0, usbp->ep0next, usbp->ep0n);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
} }
else { else {
@ -797,9 +766,8 @@ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
packet.*/ packet.*/
usbp->ep0state = USB_EP0_WAITING_STS; usbp->ep0state = USB_EP0_WAITING_STS;
#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
usbPrepareReceive(usbp, 0, NULL, 0);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartReceiveI(usbp, 0); usbStartReceiveI(usbp, 0, NULL, 0);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
#else #else
usb_lld_end_setup(usbp, ep); usb_lld_end_setup(usbp, ep);
@ -811,9 +779,8 @@ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
if (usbp->ep0n != 0U) { if (usbp->ep0n != 0U) {
/* Starts the receive phase.*/ /* Starts the receive phase.*/
usbp->ep0state = USB_EP0_RX; usbp->ep0state = USB_EP0_RX;
usbPrepareReceive(usbp, 0, usbp->ep0next, usbp->ep0n);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartReceiveI(usbp, 0); usbStartReceiveI(usbp, 0, usbp->ep0next, usbp->ep0n);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
} }
else { else {
@ -821,9 +788,8 @@ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
packet.*/ packet.*/
usbp->ep0state = USB_EP0_SENDING_STS; usbp->ep0state = USB_EP0_SENDING_STS;
#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
usbPrepareTransmit(usbp, 0, NULL, 0);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartTransmitI(usbp, 0); usbStartTransmitI(usbp, 0, NULL, 0);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
#else #else
usb_lld_end_setup(usbp, ep); usb_lld_end_setup(usbp, ep);
@ -854,9 +820,8 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
transmitted.*/ transmitted.*/
if ((usbp->ep0n < max) && if ((usbp->ep0n < max) &&
((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0U)) { ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0U)) {
usbPrepareTransmit(usbp, 0, NULL, 0);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartTransmitI(usbp, 0); usbStartTransmitI(usbp, 0, NULL, 0);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
usbp->ep0state = USB_EP0_WAITING_TX0; usbp->ep0state = USB_EP0_WAITING_TX0;
return; return;
@ -866,9 +831,8 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
/* Transmit phase over, receiving the zero sized status packet.*/ /* Transmit phase over, receiving the zero sized status packet.*/
usbp->ep0state = USB_EP0_WAITING_STS; usbp->ep0state = USB_EP0_WAITING_STS;
#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
usbPrepareReceive(usbp, 0, NULL, 0);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartReceiveI(usbp, 0); usbStartReceiveI(usbp, 0, NULL, 0);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
#else #else
usb_lld_end_setup(usbp, ep); usb_lld_end_setup(usbp, ep);
@ -919,9 +883,8 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
/* Receive phase over, sending the zero sized status packet.*/ /* Receive phase over, sending the zero sized status packet.*/
usbp->ep0state = USB_EP0_SENDING_STS; usbp->ep0state = USB_EP0_SENDING_STS;
#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
usbPrepareTransmit(usbp, 0, NULL, 0);
osalSysLockFromISR(); osalSysLockFromISR();
(void) usbStartTransmitI(usbp, 0); usbStartTransmitI(usbp, 0, NULL, 0);
osalSysUnlockFromISR(); osalSysUnlockFromISR();
#else #else
usb_lld_end_setup(usbp, ep); usb_lld_end_setup(usbp, ep);
@ -931,7 +894,7 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
/* Status packet received, it must be zero sized, invoking the callback /* Status packet received, it must be zero sized, invoking the callback
if defined.*/ if defined.*/
#if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW)
if (usbGetReceiveTransactionSizeI(usbp, 0) != 0U) { if (usbGetReceiveTransactionSizeX(usbp, 0) != 0U) {
break; break;
} }
#endif #endif

View File

@ -5,7 +5,7 @@
# Compiler options here. # Compiler options here.
ifeq ($(USE_OPT),) ifeq ($(USE_OPT),)
USE_OPT = -O0 -ggdb -fomit-frame-pointer -falign-functions=16 USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
endif endif
# C specific options here (added to USE_OPT). # C specific options here (added to USE_OPT).

View File

@ -23,8 +23,7 @@
#include "usbcfg.h" #include "usbcfg.h"
/* Can be measured using dd if=/dev/xxxx of=/dev/null bs=512 count=10000.*/ static const uint8_t txbuf[] =
static uint8_t buf[] =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
@ -42,8 +41,12 @@ static uint8_t buf[] =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
static uint8_t rxbuf[1024];
/* /*
* Red LED blinker thread, times are in milliseconds. * USB writer. This thread writes data to the USB at maximum rate.
* Can be measured using:
* dd if=/dev/xxxx of=/dev/null bs=512 count=10000
*/ */
static THD_WORKING_AREA(waWriter, 128); static THD_WORKING_AREA(waWriter, 128);
static THD_FUNCTION(Writer, arg) { static THD_FUNCTION(Writer, arg) {
@ -51,13 +54,28 @@ static THD_FUNCTION(Writer, arg) {
(void)arg; (void)arg;
chRegSetThreadName("writer"); chRegSetThreadName("writer");
while (true) { while (true) {
if (USBD2.state == USB_ACTIVE) { msg_t msg = usbTransmit(&USBD2, USBD2_DATA_REQUEST_EP,
msg_t msg = usbTransmit(&USBD2, USBD2_DATA_REQUEST_EP, txbuf, sizeof (txbuf) - 1);
buf, sizeof (buf) - 1); if (msg == MSG_RESET)
if (msg == MSG_OK) chThdSleepMilliseconds(500);
continue; }
} }
chThdSleepMilliseconds(500);
/*
* USB reader. This thread reads data from the USB at maximum rate.
* Can be measured using:
* dd if=bigfile of=/dev/xxx bs=512 count=10000
*/
static THD_WORKING_AREA(waReader, 128);
static THD_FUNCTION(Reader, arg) {
(void)arg;
chRegSetThreadName("reader");
while (true) {
msg_t msg = usbReceive(&USBD2, USBD2_DATA_AVAILABLE_EP,
rxbuf, sizeof (rxbuf) - 1);
if (msg == MSG_RESET)
chThdSleepMilliseconds(500);
} }
} }
@ -116,6 +134,7 @@ int main(void) {
*/ */
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
chThdCreateStatic(waWriter, sizeof(waWriter), NORMALPRIO, Writer, NULL); chThdCreateStatic(waWriter, sizeof(waWriter), NORMALPRIO, Writer, NULL);
chThdCreateStatic(waReader, sizeof(waReader), NORMALPRIO, Reader, NULL);
/* /*
* Normal main() thread activity, in this demo it does nothing except * Normal main() thread activity, in this demo it does nothing except