git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4273 35acf78f-673a-0410-8e92-d51de3d6d3f4

master
gdisirio 2012-06-13 16:13:00 +00:00
parent 93ed653e57
commit f620f29e0a
8 changed files with 226 additions and 120 deletions

View File

@ -275,7 +275,7 @@ typedef struct {
/** @brief No pending conditions.*/
#define CHN_NO_ERROR 0
/** @brief Connection happened.*/
#define ICHN_CONNECTED 1
#define CHN_CONNECTED 1
/** @brief Disconnection happened.*/
#define CHN_DISCONNECTED 2
/** @brief Data available in the input queue.*/

View File

@ -160,6 +160,7 @@ extern "C" {
void sduObjectInit(SerialUSBDriver *sdp);
void sduStart(SerialUSBDriver *sdup, const SerialUSBConfig *config);
void sduStop(SerialUSBDriver *sdup);
void sduConfigureHookI(USBDriver *usbp);
bool_t sduRequestsHook(USBDriver *usbp);
void sduDataTransmitted(USBDriver *usbp, usbep_t ep);
void sduDataReceived(USBDriver *usbp, usbep_t ep);

View File

@ -321,9 +321,21 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
* @name Macro Functions
* @{
*/
/**
* @brief Returns the sriver state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The driver state.
*
* @iclass
*/
#define usbGetDriverStateI(usbp) ((usbp)->state)
/**
* @brief Connects the USB device.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
#define usbConnectBus(usbp) usb_lld_connect_bus(usbp)
@ -331,6 +343,8 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
/**
* @brief Disconnect the USB device.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
#define usbDisconnectBus(usbp) usb_lld_disconnect_bus(usbp)

View File

@ -144,7 +144,7 @@ static void otg_rxfifo_flush(void) {
OTG->GRSTCTL = GRSTCTL_RXFFLSH;
while ((OTG->GRSTCTL & GRSTCTL_RXFFLSH) != 0)
;
/* Wait for 3 PHY Clocks*/
/* Wait for 3 PHY Clocks.*/
halPolledDelay(12);
}
@ -153,7 +153,7 @@ static void otg_txfifo_flush(uint32_t fifo) {
OTG->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH;
while ((OTG->GRSTCTL & GRSTCTL_TXFFLSH) != 0)
;
/* Wait for 3 PHY Clocks*/
/* Wait for 3 PHY Clocks.*/
halPolledDelay(12);
}
@ -186,6 +186,84 @@ static uint32_t otg_ram_alloc(USBDriver *usbp, size_t size) {
"otg_fifo_alloc(), #1", "FIFO memory overflow");
return next;
}
/**
* @brief Prepares for a transmit transaction on an IN endpoint.
* @post The endpoint is ready for @p usbStartTransmitI().
* @note The transmit transaction size is equal to the data contained
* in the queue.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[in] n maximum number of bytes to copy
*
* @special
*/
static void otg_prepare_transmit(USBDriver *usbp, usbep_t ep, size_t n) {
uint32_t pcnt;
USBInEndpointState *isp = usbp->epc[ep]->in_state;
isp->txsize = n;
isp->txcnt = 0;
/* Transfer initialization.*/
if (n == 0) {
/* Special case, sending zero size packet.*/
OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
}
else {
/* Normal case.*/
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);
}
}
/**
* @brief Prepares for a receive transaction on an OUT endpoint.
* @post The endpoint is ready for @p usbStartReceiveI().
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[in] n maximum number of bytes to copy
*
* @special
*/
static void otg_prepare_receive(USBDriver *usbp, usbep_t ep, size_t n) {
uint32_t pcnt;
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
osp->rxsize = n;
osp->rxcnt = 0;
/* 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);
}
/**
* @brief Pushes a series of words into a FIFO.
*
* @param[in] fifop pointer to the FIFO register
* @param[in] buf pointer to the words buffer, not necessarily word
* aligned
* @param[in] n number of words to push
*
* @return A pointer after the last word pushed.
*
* @notapi
*/
static uint8_t *otg_do_push(volatile uint32_t *fifop, uint8_t *buf, size_t n) {
while (n > 0) {
/* Note, this line relies on the Cortex-M3/M4 ability to perform
unaligned word accesses and on the LSB-first memory organization.*/
*fifop = *((uint32_t *)buf);
buf += 4;
n--;
}
return buf;
}
/**
* @brief Writes to a TX FIFO.
@ -199,19 +277,8 @@ static uint32_t otg_ram_alloc(USBDriver *usbp, size_t size) {
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);
n = (n + 3) / 4;
while (n) {
uint32_t dw = (uint32_t)buf[0] |
((uint32_t)buf[1] << 8) |
((uint32_t)buf[2] << 16) |
((uint32_t)buf[3] << 24);
*fifop = dw;
n--;
buf += 4;
}
otg_do_push(OTG_FIFO(ep), (uint8_t *)buf, (n + 3) / 4);
}
/**
@ -226,43 +293,75 @@ static void otg_fifo_write_from_buffer(usbep_t ep,
static void otg_fifo_write_from_queue(usbep_t ep,
OutputQueue *oqp,
size_t n) {
size_t nw;
uint8_t *bp;
size_t ntogo;
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;
ntogo = n;
while (ntogo > 0) {
uint32_t dw, i;
size_t streak, nw = ntogo / 4;
uint32_t nw2end = (oqp->q_top - oqp->q_rdptr) / 4;
ntogo -= (streak = nw <= nw2end ? nw : nw2end) * 4;
oqp->q_rdptr = otg_do_push(fifop, oqp->q_rdptr, streak);
if (oqp->q_rdptr >= oqp->q_top) {
oqp->q_rdptr = oqp->q_buffer;
continue;
}
/* If this condition is not satisfied then there is a word lying across
queue circular buffer boundary.*/
if (ntogo <= 0)
break;
/* One byte at time.*/
dw = 0;
i = 0;
while ((ntogo > 0) && (i < 4)) {
dw |= (uint32_t)*oqp->q_rdptr++ << (i * 8);
if (oqp->q_rdptr >= oqp->q_top)
oqp->q_rdptr = oqp->q_buffer;
ntogo--;
i++;
}
*fifop = dw;
} while (--nw > 0);
}
/* Updating queue.*/
chSysLockFromIsr();
oqp->q_rdptr += n;
if (oqp->q_rdptr >= oqp->q_top)
oqp->q_rdptr -= chQSizeI(oqp);
oqp->q_counter += n;
while (notempty(&oqp->q_waiting))
chSchReadyI(fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_OK;
chSysUnlockFromIsr();
}
/**
* @brief Pops a series of words from a FIFO.
*
* @param[in] fifop pointer to the FIFO register
* @param[in] buf pointer to the words buffer, not necessarily word
* aligned
* @param[in] n number of words to push
*
* @return A pointer after the last word pushed.
*
* @notapi
*/
static uint8_t *otg_do_pop(volatile uint32_t *fifop, uint8_t *buf, size_t n) {
while (n > 0) {
uint32_t dw = *fifop;
/* Note, this line relies on the Cortex-M3/M4 ability to perform
unaligned word accesses and on the LSB-first memory organization.*/
*((uint32_t *)buf) = dw;
buf += 4;
n--;
}
return buf;
}
/**
* @brief Reads a packet from the RXFIFO.
*
@ -281,10 +380,10 @@ static void otg_fifo_read_to_buffer(uint8_t *buf, size_t n, size_t max) {
while (n) {
uint32_t dw = *fifop;
if (max) {
*buf++ = (uint8_t)dw;
*buf++ = (uint8_t)(dw >> 8);
*buf++ = (uint8_t)(dw >> 16);
*buf++ = (uint8_t)(dw >> 24);
/* Note, this line relies on the Cortex-M3/M4 ability to perform
unaligned word accesses and on the LSB-first memory organization.*/
*((uint32_t *)buf) = dw;
buf += 4;
max--;
}
n--;
@ -300,37 +399,40 @@ static void otg_fifo_read_to_buffer(uint8_t *buf, size_t n, size_t max) {
* @notapi
*/
static void otg_fifo_read_to_queue(InputQueue *iqp, size_t n) {
size_t nw, nb;
size_t ntogo;
volatile uint32_t *fifop;
fifop = OTG_FIFO(0);
nb = n;
nw = (n + 3) / 4;
do {
uint32_t dw = *fifop;
*iqp->q_wrptr++ = (uint8_t)dw;
if (iqp->q_wrptr >= iqp->q_top)
ntogo = n;
while (ntogo > 0) {
uint32_t dw, i;
size_t streak, nw = ntogo / 4;
uint32_t nw2end = (iqp->q_wrptr - iqp->q_wrptr) / 4;
ntogo -= (streak = nw <= nw2end ? nw : nw2end) * 4;
iqp->q_wrptr = otg_do_pop(fifop, iqp->q_wrptr, streak);
if (iqp->q_wrptr >= iqp->q_top) {
iqp->q_wrptr = iqp->q_buffer;
if (--nb > 0) {
*iqp->q_wrptr++ = (uint8_t)(dw >> 8);
continue;
}
/* If this condition is not satisfied then there is a word lying across
queue circular buffer boundary.*/
if (ntogo <= 0)
break;
/* One byte at time.*/
dw = *fifop;
i = 0;
while ((ntogo > 0) && (i < 4)) {
*iqp->q_wrptr++ = (uint8_t)dw >> (i * 8);
if (iqp->q_wrptr >= iqp->q_top)
iqp->q_wrptr = iqp->q_buffer;
if (--nb > 0) {
*iqp->q_wrptr++ = (uint8_t)(dw >> 16);
if (iqp->q_wrptr >= iqp->q_top)
iqp->q_wrptr = iqp->q_buffer;
if (--nb > 0) {
*iqp->q_wrptr++ = (uint8_t)(dw >> 24);
if (iqp->q_wrptr >= iqp->q_top)
iqp->q_wrptr = iqp->q_buffer;
--nb;
}
}
ntogo--;
i++;
}
} while (--nw > 0);
}
/* Updating queue.*/
chSysLockFromIsr();
@ -846,18 +948,11 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
*/
void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n) {
uint32_t pcnt;
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
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);
otg_prepare_receive(usbp, ep, n);
}
/**
@ -872,30 +967,15 @@ void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep,
*/
void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n) {
uint32_t pcnt;
USBInEndpointState *isp = usbp->epc[ep]->in_state;
isp->txqueued = FALSE;
isp->txsize = n;
isp->txcnt = 0;
isp->mode.linear.txbuf = buf;
if (n == 0) {
/* Special case, sending zero size packet.*/
OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
}
else {
/* 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);
}
otg_prepare_transmit(usbp, ep, n);
}
/**
* @brief Prepares for a receive transaction on an OUT endpoint.
* @pre In order to use this function the endpoint must have been
* initialized in transaction mode.
* @post The endpoint is ready for @p usbStartReceiveI().
* @note The receive transaction size is equal to the space in the queue
* rounded to the lower multiple of a packet size. So make sure there
@ -911,24 +991,15 @@ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep,
*/
void usb_lld_prepare_queued_receive(USBDriver *usbp, usbep_t ep,
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);
otg_prepare_receive(usbp, ep, n);
}
/**
* @brief Prepares for a transmit transaction on an IN endpoint.
* @pre In order to use this function the endpoint must have been
* initialized in transaction mode.
* @post The endpoint is ready for @p usbStartTransmitI().
* @note The transmit transaction size is equal to the data contained
* in the queue.
@ -942,18 +1013,11 @@ void usb_lld_prepare_queued_receive(USBDriver *usbp, usbep_t ep,
*/
void usb_lld_prepare_queued_transmit(USBDriver *usbp, usbep_t ep,
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);
otg_prepare_transmit(usbp, ep, n);
}
/**

View File

@ -126,7 +126,7 @@ typedef struct {
union {
struct {
/**
* @brief Pointer to the transmission buffer.
* @brief Pointer to the transmission linear buffer.
*/
const uint8_t *txbuf;
} linear;
@ -158,7 +158,7 @@ typedef struct {
union {
struct {
/**
* @brief Pointer to the receive buffer.
* @brief Pointer to the receive linear buffer.
*/
uint8_t *rxbuf;
} linear;
@ -217,16 +217,12 @@ typedef struct {
uint16_t out_maxsize;
/**
* @brief @p USBEndpointState associated to the IN endpoint.
* @details This structure maintains the state of the IN endpoint when
* the endpoint is not in packet mode. Endpoints configured in
* packet mode must set this field to @p NULL.
* @details This structure maintains the state of the IN endpoint.
*/
USBInEndpointState *in_state;
/**
* @brief @p USBEndpointState associated to the OUT endpoint.
* @details This structure maintains the state of the OUT endpoint when
* the endpoint is not in packet mode. Endpoints configured in
* packet mode must set this field to @p NULL.
* @details This structure maintains the state of the OUT endpoint.
*/
USBOutEndpointState *out_state;
/* End of the mandatory fields.*/

View File

@ -120,6 +120,11 @@ static void inotify(GenericQueue *qp) {
size_t n, maxsize;
SerialUSBDriver *sdup = chQGetLink(qp);
/* If the USB driver is not in the appropriate state then transactions
must not be started.*/
if (usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE)
return;
/* 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.*/
@ -145,6 +150,11 @@ static void onotify(GenericQueue *qp) {
size_t n;
SerialUSBDriver *sdup = chQGetLink(qp);
/* If the USB driver is not in the appropriate state then transactions
must not be started.*/
if (usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE)
return;
/* 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) &&
@ -238,6 +248,22 @@ void sduStop(SerialUSBDriver *sdup) {
usbStop(sdup->config->usbp);
}
/**
* @brief USB device configured handler.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @iclass
*/
void sduConfigureHookI(USBDriver *usbp) {
SerialUSBDriver *sdup = usbp->param;
sdup->flags = CHN_NO_ERROR;
chIQResetI(&sdup->iqueue);
chOQResetI(&sdup->oqueue);
chnAddFlagsI(sdup, CHN_CONNECTED);
}
/**
* @brief Default requests hook.
* @details Applications wanting to use the Serial over USB driver can use

View File

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

View File

@ -296,13 +296,18 @@ static void usb_event(USBDriver *usbp, usbevent_t event) {
case USB_EVENT_ADDRESS:
return;
case USB_EVENT_CONFIGURED:
chSysLockFromIsr();
/* Enables the endpoints specified into the configuration.
Note, this callback is invoked from an ISR so I-Class functions
must be used.*/
chSysLockFromIsr();
usbInitEndpointI(usbp, USB_CDC_DATA_REQUEST_EP, &ep1config);
usbInitEndpointI(usbp, USB_CDC_INTERRUPT_REQUEST_EP, &ep2config);
usbInitEndpointI(usbp, USB_CDC_DATA_AVAILABLE_EP, &ep3config);
/* Resetting the state of the CDC subsystem.*/
sduConfigureHookI(usbp);
chSysUnlockFromIsr();
return;
case USB_EVENT_SUSPEND:
@ -437,10 +442,10 @@ int main(void) {
/*
* Activates the USB driver and then the USB bus pull-up on D+.
*/
usbDisconnectBus(serusbcfg.usbp);
chThdSleepMilliseconds(1000);
sduObjectInit(&SDU1);
sduStart(&SDU1, &serusbcfg);
usbDisconnectBus(serusbcfg.usbp);
chThdSleepMilliseconds(100);
usbConnectBus(serusbcfg.usbp);
/*