From d094e348c5d1a3785289c69c5185bbaca1257de8 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Mon, 11 Jun 2012 16:54:35 +0000 Subject: [PATCH] git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4266 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/usb.h | 10 +- os/hal/platforms/STM32/OTGv1/usb_lld.c | 163 +++++++++++++++++++++---- os/hal/platforms/STM32/OTGv1/usb_lld.h | 44 +++++-- os/hal/src/serial.c | 4 +- os/hal/src/serial_usb.c | 115 +++++++---------- os/kernel/include/chqueues.h | 40 ++++-- os/kernel/src/chqueues.c | 10 +- readme.txt | 1 + test/testbmk.c | 2 +- test/testqueues.c | 8 +- 10 files changed, 276 insertions(+), 121 deletions(-) diff --git a/os/hal/include/usb.h b/os/hal/include/usb.h index 89871ffe6..d2a154949 100644 --- a/os/hal/include/usb.h +++ b/os/hal/include/usb.h @@ -416,11 +416,12 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp, * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * @param[in] iq input queue to be filled with incoming data + * @param[in] n maximum number of bytes to copy * * @special */ -#define usbPrepareQueuedReceive(usbp, ep, iq) \ - usb_lld_prepare_queued_receive(usbp, ep, iq) +#define usbPrepareQueuedReceive(usbp, ep, iq, n) \ + usb_lld_prepare_queued_receive(usbp, ep, iq, n) /** * @brief Prepares for a transmit transaction on an IN endpoint. @@ -433,11 +434,12 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp, * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * @param[in] oq output queue to be fetched for outgoing data + * @param[in] n maximum number of bytes to copy * * @special */ -#define usbPrepareQueuedTransmit(usbp, ep, oq) \ - usb_lld_prepare_queued_transmit(usbp, ep, oq) +#define usbPrepareQueuedTransmit(usbp, ep, oq, n) \ + usb_lld_prepare_queued_transmit(usbp, ep, oq, n) /** * @brief Returns the exact size of a receive transaction. diff --git a/os/hal/platforms/STM32/OTGv1/usb_lld.c b/os/hal/platforms/STM32/OTGv1/usb_lld.c index 44d292b8b..fae5f500f 100644 --- a/os/hal/platforms/STM32/OTGv1/usb_lld.c +++ b/os/hal/platforms/STM32/OTGv1/usb_lld.c @@ -193,11 +193,12 @@ static uint32_t otg_ram_alloc(USBDriver *usbp, size_t size) { * @param[in] ep endpoint number * @param[in] buf buffer where to copy the endpoint data * @param[in] n maximum number of bytes to copy - * @return the number of bytes that were effectively written * * @notapi */ -static void otg_fifo_write(usbep_t ep, const uint8_t *buf, size_t n) { +static void otg_fifo_write_from_buffer(usbep_t ep, + const uint8_t *buf, + size_t n) { volatile uint32_t *fifop; fifop = OTG_FIFO(ep); @@ -213,6 +214,55 @@ static void otg_fifo_write(usbep_t ep, const uint8_t *buf, size_t n) { } } +/** + * @brief Writes to a TX FIFO fetching data from a queue. + * + * @param[in] ep endpoint number + * @param[in] oqp pointer to an @p OutputQueue object + * @param[in] n maximum number of bytes to copy + * + * @notapi + */ +static void otg_fifo_write_from_queue(usbep_t ep, + OutputQueue *oqp, + size_t n) { + size_t nw; + uint8_t *bp; + volatile uint32_t *fifop; + + fifop = OTG_FIFO(ep); + + /* Fetching data from the queue buffer directly.*/ + bp = oqp->q_rdptr; + nw = (n + 3) / 4; + do { + uint32_t dw; + dw = (uint32_t)*bp++; + if (bp >= oqp->q_top) + bp = oqp->q_buffer; + dw |= (uint32_t)*bp++ << 8; + if (bp >= oqp->q_top) + bp = oqp->q_buffer; + dw |= (uint32_t)*bp++ << 16; + if (bp >= oqp->q_top) + bp = oqp->q_buffer; + dw |= (uint32_t)*bp++ << 24; + if (bp >= oqp->q_top) + bp = oqp->q_buffer; + *fifop = dw; + } while (--nw > 0); + + /* Updating queue.*/ + chSysLockFromIsr(); + oqp->q_rdptr += n; + if (oqp->q_rdptr >= oqp->q_top) + oqp->q_rdptr = oqp->q_buffer; + oqp->q_counter += n; + while (notempty(&oqp->q_waiting)) + chSchReadyI(fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_OK; + chSysUnlockFromIsr(); +} + /** * @brief Reads a packet from the RXFIFO. * @@ -222,7 +272,7 @@ static void otg_fifo_write(usbep_t ep, const uint8_t *buf, size_t n) { * * @notapi */ -static void otg_fifo_read(uint8_t *buf, size_t n, size_t max) { +static void otg_fifo_read_to_buffer(uint8_t *buf, size_t n, size_t max) { volatile uint32_t *fifop; fifop = OTG_FIFO(0); @@ -241,6 +291,25 @@ static void otg_fifo_read(uint8_t *buf, size_t n, size_t max) { } } +/** + * @brief Reads a packet from the RXFIFO. + * + * @param[in] oqp pointer to an @p InputQueue object + * @param[in] n number of bytes to pull from the FIFO + * + * @notapi + */ +static void otg_fifo_read_to_queue(InputQueue *iqp, size_t n) { + size_t nw; + volatile uint32_t *fifop; + + fifop = OTG_FIFO(0); + nw = (n + 3) / 4; + do { + uint32_t dw = *fifop; + } while (--n > 0); +} + /** * @brief Incoming packets handler. * @@ -258,15 +327,21 @@ static void otg_rxfifo_handler(USBDriver *usbp) { case GRXSTSP_SETUP_DATA: cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF; - otg_fifo_read(usbp->epc[ep]->setup_buf, cnt, 8); + otg_fifo_read_to_buffer(usbp->epc[ep]->setup_buf, cnt, 8); break; case GRXSTSP_OUT_DATA: cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF; - otg_fifo_read(usbp->epc[ep]->out_state->rxbuf, cnt, - usbp->epc[ep]->out_state->rxsize - - usbp->epc[ep]->out_state->rxcnt); - usbp->epc[ep]->out_state->rxbuf += cnt; + if (usbp->epc[ep]->out_state->rxqueued) { + /* Queue associated.*/ + } + else { + otg_fifo_read_to_buffer(usbp->epc[ep]->out_state->mode.linear.rxbuf, + cnt, + usbp->epc[ep]->out_state->rxsize - + usbp->epc[ep]->out_state->rxcnt); + usbp->epc[ep]->out_state->mode.linear.rxbuf += cnt; + } usbp->epc[ep]->out_state->rxcnt += cnt; break; case GRXSTSP_OUT_GLOBAL_NAK: @@ -287,12 +362,28 @@ static void otg_rxfifo_handler(USBDriver *usbp) { static void otg_txfifo_handler(USBDriver *usbp, usbep_t ep) { uint32_t n; + /* Number of bytes remaining in current transaction.*/ n = usbp->epc[ep]->in_state->txsize - usbp->epc[ep]->in_state->txcnt; if (n > usbp->epc[ep]->in_maxsize) n = usbp->epc[ep]->in_maxsize; - otg_fifo_write(ep, usbp->epc[ep]->in_state->txbuf, n); - usbp->epc[ep]->in_state->txbuf += n; + + if (usbp->epc[ep]->in_state->txqueued) { + /* Queue associated.*/ + otg_fifo_write_from_queue(ep, + usbp->epc[ep]->in_state->mode.queue.txqueue, + n); + } + else { + /* Linear buffer associated.*/ + otg_fifo_write_from_buffer(ep, + usbp->epc[ep]->in_state->mode.linear.txbuf, + n); + usbp->epc[ep]->in_state->mode.linear.txbuf += n; + } usbp->epc[ep]->in_state->txcnt += n; + /* TODO: Potential issue, txcnt can be less than txsize after the planned + number of packets have been received, better disable the interrupt + at the end of the transaction in otg_epin_handler().*/ if (usbp->epc[ep]->in_state->txcnt >= usbp->epc[ep]->in_state->txsize) { /* Transfer finished.*/ OTG->DIEPEMPMSK &= ~DIEPEMPMSK_INEPTXFEM(ep); @@ -313,14 +404,14 @@ static void otg_epin_handler(USBDriver *usbp, usbep_t ep) { /* Resets all EP IRQ sources.*/ OTG->ie[ep].DIEPINT = 0xFFFFFFFF; - if (epint & DIEPINT_TXFE) { - /* TX FIFO empty or emptying.*/ - otg_txfifo_handler(usbp, ep); - } if (epint & DIEPINT_XFRC) { /* Transmit transfer complete.*/ _usb_isr_invoke_in_cb(usbp, ep); } + if (epint & DIEPINT_TXFE) { + /* TX FIFO empty or emptying.*/ + otg_txfifo_handler(usbp, ep); + } if (epint & DIEPINT_TOC) { /* Timeouts not handled yet, not sure how to handle.*/ } @@ -730,9 +821,12 @@ void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep, uint32_t pcnt; USBOutEndpointState *osp = usbp->epc[ep]->out_state; - osp->rxbuf = buf; - osp->rxsize = n; - osp->rxcnt = 0; + osp->rxqueued = FALSE; + osp->rxsize = n; + osp->rxcnt = 0; + osp->mode.linear.rxbuf = buf; + + /* Transfer initialization.*/ pcnt = (n + usbp->epc[ep]->out_maxsize - 1) / usbp->epc[ep]->out_maxsize; OTG->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) | DOEPTSIZ_XFRSIZ(usbp->epc[ep]->out_maxsize); @@ -753,9 +847,10 @@ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep, uint32_t pcnt; USBInEndpointState *isp = usbp->epc[ep]->in_state; - isp->txbuf = buf; - isp->txsize = n; - isp->txcnt = 0; + isp->txqueued = FALSE; + isp->txsize = n; + isp->txcnt = 0; + isp->mode.linear.txbuf = buf; if (n == 0) { /* Special case, sending zero size packet.*/ @@ -782,12 +877,24 @@ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep, * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * @param[in] iq input queue to be filled with incoming data + * @param[in] n maximum number of bytes to copy * * @special */ void usb_lld_prepare_queued_receive(USBDriver *usbp, usbep_t ep, - InputQueue *iq) { + InputQueue *iq, size_t n) { + uint32_t pcnt; + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + osp->rxqueued = TRUE; + osp->rxsize = n; + osp->rxcnt = 0; + osp->mode.queue.rxqueue = iq; + + /* Transfer initialization.*/ + pcnt = (n + usbp->epc[ep]->out_maxsize - 1) / usbp->epc[ep]->out_maxsize; + OTG->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) | + DOEPTSIZ_XFRSIZ(usbp->epc[ep]->out_maxsize); } /** @@ -801,12 +908,24 @@ void usb_lld_prepare_queued_receive(USBDriver *usbp, usbep_t ep, * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * @param[in] oq output queue to be fetched for outgoing data + * @param[in] n maximum number of bytes to copy * * @special */ void usb_lld_prepare_queued_transmit(USBDriver *usbp, usbep_t ep, - OutputQueue *oq) { + OutputQueue *oq, size_t n) { + uint32_t pcnt; + USBInEndpointState *isp = usbp->epc[ep]->in_state; + isp->txqueued = TRUE; + isp->txsize = n; + isp->txcnt = 0; + isp->mode.queue.txqueue = oq; + + /* Transfer initialization.*/ + pcnt = (n + usbp->epc[ep]->in_maxsize - 1) / usbp->epc[ep]->in_maxsize; + OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(pcnt) | + DIEPTSIZ_XFRSIZ(usbp->epc[ep]->in_state->txsize); } /** diff --git a/os/hal/platforms/STM32/OTGv1/usb_lld.h b/os/hal/platforms/STM32/OTGv1/usb_lld.h index 687d788ff..ea0def924 100644 --- a/os/hal/platforms/STM32/OTGv1/usb_lld.h +++ b/os/hal/platforms/STM32/OTGv1/usb_lld.h @@ -108,13 +108,13 @@ /*===========================================================================*/ /** - * @brief Type of an endpoint state structure. + * @brief Type of an IN endpoint state structure. */ typedef struct { /** - * @brief Pointer to the transmission buffer. + * @brief Buffer mode, queue or linear. */ - const uint8_t *txbuf; + bool_t txqueued; /** * @brief Requested transmit transfer size. */ @@ -123,16 +123,30 @@ typedef struct { * @brief Transmitted bytes so far. */ size_t txcnt; + union { + struct { + /** + * @brief Pointer to the transmission buffer. + */ + const uint8_t *txbuf; + } linear; + struct { + /** + * @brief Pointer to the output queue. + */ + OutputQueue *txqueue; + } queue; + } mode; } USBInEndpointState; /** - * @brief Type of an endpoint state structure. + * @brief Type of an OUT endpoint state structure. */ typedef struct { /** - * @brief Pointer to the receive buffer. + * @brief Buffer mode, queue or linear. */ - uint8_t *rxbuf; + bool_t rxqueued; /** * @brief Requested receive transfer size. */ @@ -141,6 +155,20 @@ typedef struct { * @brief Received bytes so far. */ size_t rxcnt; + union { + struct { + /** + * @brief Pointer to the receive buffer. + */ + uint8_t *rxbuf; + } linear; + struct { + /** + * @brief Pointer to the input queue. + */ + InputQueue *rxqueue; + } queue; + } mode; } USBOutEndpointState; /** @@ -378,9 +406,9 @@ extern "C" { void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n); void usb_lld_prepare_queued_receive(USBDriver *usbp, usbep_t ep, - InputQueue *iq); + InputQueue *iq, size_t n); void usb_lld_prepare_queued_transmit(USBDriver *usbp, usbep_t ep, - OutputQueue *oq); + OutputQueue *oq, size_t n); void usb_lld_start_out(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); diff --git a/os/hal/src/serial.c b/os/hal/src/serial.c index 3f06025c6..5b883e16a 100644 --- a/os/hal/src/serial.c +++ b/os/hal/src/serial.c @@ -149,8 +149,8 @@ void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) { chEvtInit(&sdp->event); sdp->flags = CHN_NO_ERROR; sdp->state = SD_STOP; - chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify); - chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify); + chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp); + chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp); } /** diff --git a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c index 7f1658812..5fec52a68 100644 --- a/os/hal/src/serial_usb.c +++ b/os/hal/src/serial_usb.c @@ -117,59 +117,47 @@ static const struct SerialUSBDriverVMT vmt = { * @brief Notification of data removed from the input queue. */ static void inotify(GenericQueue *qp) { - SerialUSBDriver *sdup = (SerialUSBDriver *)qp->q_wrptr; + size_t n, maxsize; + SerialUSBDriver *sdup = chQGetLink(qp); -#if 0 - /* Writes to the input queue can only happen when the queue has been - emptied, then a whole packet is loaded in the queue.*/ + /* If there is in the queue enough space to hold at least one packet and + a transaction is not yet started then a new transaction is started for + the available space.*/ + maxsize = sdup->config->usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize; if (!usbGetReceiveStatusI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP) && - chIQIsEmptyI(&sdup->iqueue)) { + ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize)) { chSysUnlock(); - /* Unlocked to make the potentially long read operation preemptable.*/ - size_t n = usbReadPacketBuffer(sdup->config->usbp, - USB_CDC_DATA_AVAILABLE_EP, - sdup->iqueue.q_buffer, - SERIAL_USB_BUFFERS_SIZE); + n = (n / maxsize) * maxsize; + usbPrepareQueuedReceive(sdup->config->usbp, + USB_CDC_DATA_AVAILABLE_EP, + &sdup->iqueue, n); chSysLock(); usbStartReceiveI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP); - chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); - sdup->iqueue.q_rdptr = sdup->iqueue.q_buffer; - sdup->iqueue.q_counter = n; - while (notempty(&sdup->iqueue.q_waiting)) - chSchReadyI(fifo_remove(&sdup->iqueue.q_waiting))->p_u.rdymsg = Q_OK; } -#endif } /** * @brief Notification of data inserted into the output queue. */ static void onotify(GenericQueue *qp) { - SerialUSBDriver *sdup = (SerialUSBDriver *)qp->q_rdptr; size_t n; + SerialUSBDriver *sdup = chQGetLink(qp); -#if 0 - /* If there is any data in the output queue then it is sent within a - single packet and the queue is emptied.*/ - n = chOQGetFullI(&sdup->oqueue); - if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP)) { + /* If there is not an ongoing transaction and the output queue contains + data then a new transaction is started.*/ + if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP) && + ((n = chOQGetFullI(&sdup->oqueue)) > 0)) { chSysUnlock(); - /* Unlocked to make the potentially long write operation preemptable.*/ - usbWritePacketBuffer(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP, - sdup->oqueue.q_buffer, n); + usbPrepareQueuedTransmit(sdup->config->usbp, + USB_CDC_DATA_REQUEST_EP, + &sdup->oqueue, n); chSysLock(); usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP); - chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); - sdup->oqueue.q_wrptr = sdup->oqueue.q_buffer; - sdup->oqueue.q_counter = chQSizeI(&sdup->oqueue); - while (notempty(&sdup->oqueue.q_waiting)) - chSchReadyI(fifo_remove(&sdup->oqueue.q_waiting))->p_u.rdymsg = Q_OK; } -#endif } /*===========================================================================*/ @@ -201,12 +189,8 @@ void sduObjectInit(SerialUSBDriver *sdup) { chEvtInit(&sdup->event); sdup->flags = CHN_NO_ERROR; sdup->state = SDU_STOP; - chIQInit(&sdup->iqueue, sdup->ib, SERIAL_USB_BUFFERS_SIZE, inotify); - chOQInit(&sdup->oqueue, sdup->ob, SERIAL_USB_BUFFERS_SIZE, onotify); - /* This is a dirty trick but those pointers are never used because queues - are accessed in block mode from the low level.*/ - sdup->iqueue.q_wrptr = (uint8_t *)sdup; - sdup->oqueue.q_rdptr = (uint8_t *)sdup; + chIQInit(&sdup->iqueue, sdup->ib, SERIAL_USB_BUFFERS_SIZE, inotify, sdup); + chOQInit(&sdup->oqueue, sdup->ob, SERIAL_USB_BUFFERS_SIZE, onotify, sdup); } /** @@ -299,32 +283,28 @@ bool_t sduRequestsHook(USBDriver *usbp) { * @param[in] ep endpoint number */ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { - SerialUSBDriver *sdup = usbp->param; size_t n; + SerialUSBDriver *sdup = usbp->param; -#if 0 + (void)ep; + + chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); chSysLockFromIsr(); - /* If there is any data in the output queue then it is sent within a - single packet and the queue is emptied.*/ - n = chOQGetFullI(&sdup->oqueue); - if (n > 0) { + + if ((n = chOQGetFullI(&sdup->oqueue)) > 0) { /* The endpoint cannot be busy, we are in the context of the callback, so it is safe to transmit without a check.*/ chSysUnlockFromIsr(); - /* Unlocked to make the potentially long write operation preemptable.*/ - usbWritePacketBuffer(usbp, ep, sdup->oqueue.q_buffer, n); + usbPrepareQueuedTransmit(sdup->config->usbp, + USB_CDC_DATA_REQUEST_EP, + &sdup->oqueue, n); chSysLockFromIsr(); - usbStartTransmitI(usbp, ep); - chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); - sdup->oqueue.q_wrptr = sdup->oqueue.q_buffer; - sdup->oqueue.q_counter = chQSizeI(&sdup->oqueue); - while (notempty(&sdup->oqueue.q_waiting)) - chSchReadyI(fifo_remove(&sdup->oqueue.q_waiting))->p_u.rdymsg = Q_OK; + usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP); } + chSysUnlockFromIsr(); -#endif } /** @@ -336,33 +316,32 @@ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { * @param[in] ep endpoint number */ void sduDataReceived(USBDriver *usbp, usbep_t ep) { + size_t n, maxsize; SerialUSBDriver *sdup = usbp->param; -#if 0 + (void)ep; + + chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); chSysLockFromIsr(); - /* Writes to the input queue can only happen when the queue has been - emptied, then a whole packet is loaded in the queue.*/ - if (chIQIsEmptyI(&sdup->iqueue)) { + + /* Writes to the input queue can only happen when there is enough space + to hold at least one packet.*/ + maxsize = sdup->config->usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize; + if ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize) { /* The endpoint cannot be busy, we are in the context of the callback, so a packet is in the buffer for sure.*/ - size_t n; - chSysUnlockFromIsr(); - /* Unlocked to make the potentially long write operation preemptable.*/ - n = usbReadPacketBuffer(usbp, ep, sdup->iqueue.q_buffer, - SERIAL_USB_BUFFERS_SIZE); + n = (n / maxsize) * maxsize; + usbPrepareQueuedReceive(sdup->config->usbp, + USB_CDC_DATA_AVAILABLE_EP, + &sdup->iqueue, n); chSysLockFromIsr(); - usbStartReceiveI(usbp, ep); - chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); - sdup->iqueue.q_rdptr = sdup->iqueue.q_buffer; - sdup->iqueue.q_counter = n; - while (notempty(&sdup->iqueue.q_waiting)) - chSchReadyI(fifo_remove(&sdup->iqueue.q_waiting))->p_u.rdymsg = Q_OK; + usbStartReceiveI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP); } + chSysUnlockFromIsr(); -#endif } /** diff --git a/os/kernel/include/chqueues.h b/os/kernel/include/chqueues.h index b15cd70b0..b16a19609 100644 --- a/os/kernel/include/chqueues.h +++ b/os/kernel/include/chqueues.h @@ -68,6 +68,7 @@ struct GenericQueue { uint8_t *q_wrptr; /**< @brief Write pointer. */ uint8_t *q_rdptr; /**< @brief Read pointer. */ qnotify_t q_notify; /**< @brief Data notification callback. */ + void *q_link; /**< @brief Application defined field. */ }; /** @@ -95,6 +96,17 @@ struct GenericQueue { * @iclass */ #define chQSpaceI(qp) ((qp)->q_counter) + +/** + * @brief Returns the queue application-defined link. + * @note This function can be called in any context. + * + * @param[in] qp pointer to a @p GenericQueue structure. + * @return The application-defined link. + * + * @special + */ +#define chQGetLink(qp) ((qp)->q_link) /** @} */ /** @@ -185,15 +197,17 @@ typedef GenericQueue InputQueue; * @param[in] buffer pointer to the queue buffer area * @param[in] size size of the queue buffer area * @param[in] inotify input notification callback pointer + * @param[in] link application defined pointer */ -#define _INPUTQUEUE_DATA(name, buffer, size, inotify) { \ +#define _INPUTQUEUE_DATA(name, buffer, size, inotify, link) { \ _THREADSQUEUE_DATA(name), \ 0, \ (uint8_t *)(buffer), \ (uint8_t *)(buffer) + (size), \ (uint8_t *)(buffer), \ (uint8_t *)(buffer), \ - inotify \ + (inotify), \ + (link) \ } /** @@ -205,9 +219,10 @@ typedef GenericQueue InputQueue; * @param[in] buffer pointer to the queue buffer area * @param[in] size size of the queue buffer area * @param[in] inotify input notification callback pointer + * @param[in] link application defined pointer */ -#define INPUTQUEUE_DECL(name, buffer, size, inotify) \ - InputQueue name = _INPUTQUEUE_DATA(name, buffer, size, inotify) +#define INPUTQUEUE_DECL(name, buffer, size, inotify, link) \ + InputQueue name = _INPUTQUEUE_DATA(name, buffer, size, inotify, link) /** * @extends GenericQueue @@ -299,15 +314,17 @@ typedef GenericQueue OutputQueue; * @param[in] buffer pointer to the queue buffer area * @param[in] size size of the queue buffer area * @param[in] onotify output notification callback pointer + * @param[in] link application defined pointer */ -#define _OUTPUTQUEUE_DATA(name, buffer, size, onotify) { \ +#define _OUTPUTQUEUE_DATA(name, buffer, size, onotify, link) { \ _THREADSQUEUE_DATA(name), \ (size), \ (uint8_t *)(buffer), \ (uint8_t *)(buffer) + (size), \ (uint8_t *)(buffer), \ (uint8_t *)(buffer), \ - onotify \ + (onotify), \ + (link) \ } /** @@ -319,21 +336,24 @@ typedef GenericQueue OutputQueue; * @param[in] buffer pointer to the queue buffer area * @param[in] size size of the queue buffer area * @param[in] onotify output notification callback pointer + * @param[in] link application defined pointer */ -#define OUTPUTQUEUE_DECL(name, buffer, size, onotify) \ - OutputQueue name = _OUTPUTQUEUE_DATA(name, buffer, size, onotify) +#define OUTPUTQUEUE_DECL(name, buffer, size, onotify, link) \ + OutputQueue name = _OUTPUTQUEUE_DATA(name, buffer, size, onotify, link) #ifdef __cplusplus extern "C" { #endif - void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy); + void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy, + void *link); void chIQResetI(InputQueue *iqp); msg_t chIQPutI(InputQueue *iqp, uint8_t b); msg_t chIQGetTimeout(InputQueue *iqp, systime_t time); size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp, size_t n, systime_t time); - void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy); + void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy, + void *link); void chOQResetI(OutputQueue *oqp); msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time); msg_t chOQGetI(OutputQueue *oqp); diff --git a/os/kernel/src/chqueues.c b/os/kernel/src/chqueues.c index adb5dd807..79bf409cb 100644 --- a/os/kernel/src/chqueues.c +++ b/os/kernel/src/chqueues.c @@ -83,16 +83,19 @@ static msg_t qwait(GenericQueue *qp, systime_t time) { * @param[in] size size of the queue buffer * @param[in] infy pointer to a callback function that is invoked when * data is read from the queue. The value can be @p NULL. + * @param[in] link application defined pointer * * @init */ -void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy) { +void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy, + void *link) { queue_init(&iqp->q_waiting); iqp->q_counter = 0; iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = bp; iqp->q_top = bp + size; iqp->q_notify = infy; + iqp->q_link = link; } /** @@ -260,16 +263,19 @@ size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp, * @param[in] size size of the queue buffer * @param[in] onfy pointer to a callback function that is invoked when * data is written to the queue. The value can be @p NULL. + * @param[in] link application defined pointer * * @init */ -void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy) { +void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy, + void *link) { queue_init(&oqp->q_waiting); oqp->q_counter = size; oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = bp; oqp->q_top = bp + size; oqp->q_notify = onfy; + oqp->q_link = link; } /** diff --git a/readme.txt b/readme.txt index 95d3e6bdb..33f5f152e 100644 --- a/readme.txt +++ b/readme.txt @@ -144,6 +144,7 @@ 3484947)(backported to 2.4.1). - FIX: Fixed various minor documentation errors (bug 3484942)(backported to 2.4.1). +- NEW: Added an application-defined field to I/O queues (a void pointer). - NEW: Added board files for Maple Mini STM32F103, contributed by Wagner Sartori Junior. - NEW: Added SSP1 capability to the LPC13xx SPI driver. diff --git a/test/testbmk.c b/test/testbmk.c index b8031f190..5e5b11e7d 100644 --- a/test/testbmk.c +++ b/test/testbmk.c @@ -460,7 +460,7 @@ static void bmk9_execute(void) { static uint8_t ib[16]; static InputQueue iq; - chIQInit(&iq, ib, sizeof(ib), NULL); + chIQInit(&iq, ib, sizeof(ib), NULL, NULL); n = 0; test_wait_tick(); test_start_timer(1000); diff --git a/test/testqueues.c b/test/testqueues.c index 86cb2e1e5..1dc669af7 100644 --- a/test/testqueues.c +++ b/test/testqueues.c @@ -67,8 +67,8 @@ static void notify(GenericQueue *qp) { * variables are explicitly initialized in each test case. It is done in order * to test the macros. */ -static INPUTQUEUE_DECL(iq, test.wa.T0, TEST_QUEUES_SIZE, notify); -static OUTPUTQUEUE_DECL(oq, test.wa.T1, TEST_QUEUES_SIZE, notify); +static INPUTQUEUE_DECL(iq, test.wa.T0, TEST_QUEUES_SIZE, notify, NULL); +static OUTPUTQUEUE_DECL(oq, test.wa.T1, TEST_QUEUES_SIZE, notify, NULL); /** * @page test_queues_001 Input Queues functionality and APIs @@ -81,7 +81,7 @@ static OUTPUTQUEUE_DECL(oq, test.wa.T1, TEST_QUEUES_SIZE, notify); static void queues1_setup(void) { - chIQInit(&iq, wa[0], TEST_QUEUES_SIZE, notify); + chIQInit(&iq, wa[0], TEST_QUEUES_SIZE, notify, NULL); } static msg_t thread1(void *p) { @@ -168,7 +168,7 @@ ROMCONST struct testcase testqueues1 = { static void queues2_setup(void) { - chOQInit(&oq, wa[0], TEST_QUEUES_SIZE, notify); + chOQInit(&oq, wa[0], TEST_QUEUES_SIZE, notify, NULL); } static msg_t thread2(void *p) {