aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/src
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/src')
-rw-r--r--os/hal/src/adc.c7
-rw-r--r--os/hal/src/ext.c167
-rw-r--r--os/hal/src/gpt.c1
-rw-r--r--os/hal/src/hal.c6
-rw-r--r--os/hal/src/mac.c63
-rw-r--r--os/hal/src/rtc.c158
-rw-r--r--os/hal/src/serial_usb.c91
-rw-r--r--os/hal/src/usb.c107
8 files changed, 468 insertions, 132 deletions
diff --git a/os/hal/src/adc.c b/os/hal/src/adc.c
index c375818a6..08aa830f0 100644
--- a/os/hal/src/adc.c
+++ b/os/hal/src/adc.c
@@ -162,6 +162,8 @@ void adcStartConversion(ADCDriver *adcp,
/**
* @brief Starts an ADC conversion.
* @details Starts an asynchronous conversion operation.
+ * @post The callbacks associated to the conversion group will be invoked
+ * on buffer fill and error events.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
@@ -185,7 +187,8 @@ void adcStartConversionI(ADCDriver *adcp,
((depth == 1) || ((depth & 1) == 0)),
"adcStartConversionI");
chDbgAssert((adcp->state == ADC_READY) ||
- (adcp->state == ADC_COMPLETE),
+ (adcp->state == ADC_COMPLETE) ||
+ (adcp->state == ADC_ERROR),
"adcStartConversionI(), #1", "not ready");
adcp->samples = samples;
@@ -268,6 +271,8 @@ void adcStopConversionI(ADCDriver *adcp) {
* @retval RDY_RESET The conversion has been stopped using
* @p acdStopConversion() or @p acdStopConversionI(),
* the result buffer may contain incorrect data.
+ * @retval RDY_TIMEOUT The conversion has been stopped because an hardware
+ * error.
*
* @api
*/
diff --git a/os/hal/src/ext.c b/os/hal/src/ext.c
new file mode 100644
index 000000000..1c83cd2e6
--- /dev/null
+++ b/os/hal/src/ext.c
@@ -0,0 +1,167 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file ext.c
+ * @brief EXT Driver code.
+ *
+ * @addtogroup EXT
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_EXT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief EXT Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void extInit(void) {
+
+ ext_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p EXTDriver structure.
+ *
+ * @param[out] extp pointer to the @p EXTDriver object
+ *
+ * @init
+ */
+void extObjectInit(EXTDriver *extp) {
+
+ extp->state = EXT_STOP;
+ extp->config = NULL;
+}
+
+/**
+ * @brief Configures and activates the EXT peripheral.
+ * @post After activation all EXT channels are in the disabled state,
+ * use @p extChannelEnable() in order to activate them.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] config pointer to the @p EXTConfig object
+ *
+ * @api
+ */
+void extStart(EXTDriver *extp, const EXTConfig *config) {
+
+ chDbgCheck((extp != NULL) && (config != NULL), "extStart");
+
+ chSysLock();
+ chDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE),
+ "extStart(), #1", "invalid state");
+ extp->config = config;
+ ext_lld_start(extp);
+ extp->state = EXT_ACTIVE;
+ chSysUnlock();
+}
+
+/**
+ * @brief Deactivates the EXT peripheral.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ *
+ * @api
+ */
+void extStop(EXTDriver *extp) {
+
+ chDbgCheck(extp != NULL, "extStop");
+
+ chSysLock();
+ chDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE),
+ "extStop(), #1", "invalid state");
+ ext_lld_stop(extp);
+ extp->state = EXT_STOP;
+ chSysUnlock();
+}
+
+/**
+ * @brief Enables an EXT channel.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] channel channel to be enabled
+ *
+ * @api
+ */
+void extChannelEnable(EXTDriver *extp, expchannel_t channel) {
+
+ chDbgCheck((extp != NULL) &&
+ (channel < EXT_MAX_CHANNELS) &&
+ (extp->config->channels[channel].mode != EXT_CH_MODE_DISABLED),
+ "extChannelEnable");
+
+ chSysLock();
+ chDbgAssert(extp->state == EXT_ACTIVE,
+ "extChannelEnable(), #1", "invalid state");
+ extChannelEnableI(extp, channel);
+ chSysUnlock();
+}
+
+/**
+ * @brief Disables an EXT channel.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] channel channel to be disabled
+ *
+ * @api
+ */
+void extChannelDisable(EXTDriver *extp, expchannel_t channel) {
+
+ chDbgCheck((extp != NULL) &&
+ (channel < EXT_MAX_CHANNELS) &&
+ (extp->config->channels[channel].mode != EXT_CH_MODE_DISABLED),
+ "extChannelDisable");
+
+ chSysLock();
+ chDbgAssert(extp->state == EXT_ACTIVE,
+ "extChannelDisable(), #1", "invalid state");
+ extChannelDisableI(extp, channel);
+ chSysUnlock();
+}
+
+#endif /* HAL_USE_EXT */
+
+/** @} */
diff --git a/os/hal/src/gpt.c b/os/hal/src/gpt.c
index c677f5284..726936ca8 100644
--- a/os/hal/src/gpt.c
+++ b/os/hal/src/gpt.c
@@ -236,6 +236,7 @@ void gptPolledDelay(GPTDriver *gptp, gptcnt_t interval) {
gptp->state = GPT_ONESHOT;
gpt_lld_polled_delay(gptp, interval);
+ gptp->state = GPT_READY;
}
#endif /* HAL_USE_GPT */
diff --git a/os/hal/src/hal.c b/os/hal/src/hal.c
index ef7d7af8b..d5a8082e9 100644
--- a/os/hal/src/hal.c
+++ b/os/hal/src/hal.c
@@ -71,6 +71,9 @@ void halInit(void) {
#if HAL_USE_CAN || defined(__DOXYGEN__)
canInit();
#endif
+#if HAL_USE_EXT || defined(__DOXYGEN__)
+ extInit();
+#endif
#if HAL_USE_GPT || defined(__DOXYGEN__)
gptInit();
#endif
@@ -107,6 +110,9 @@ void halInit(void) {
#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
sduInit();
#endif
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+ rtcInit();
+#endif
/* Board specific initialization.*/
boardInit();
}
diff --git a/os/hal/src/mac.c b/os/hal/src/mac.c
index 0f1c47576..edd15d087 100644
--- a/os/hal/src/mac.c
+++ b/os/hal/src/mac.c
@@ -21,8 +21,6 @@
/**
* @file mac.c
* @brief MAC Driver code.
- * @note This function is implicitly invoked by @p halInit(), there is
- * no need to explicitly initialize the driver.
*
* @addtogroup MAC
* @{
@@ -59,6 +57,8 @@
/**
* @brief MAC Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
*
* @init
*/
@@ -76,28 +76,53 @@ void macInit(void) {
*/
void macObjectInit(MACDriver *macp) {
+ macp->state = MAC_STOP;
+ macp->config = NULL;
chSemInit(&macp->tdsem, 0);
chSemInit(&macp->rdsem, 0);
-#if CH_USE_EVENTS
+#if MAC_USE_EVENTS
chEvtInit(&macp->rdevent);
#endif
}
/**
- * @brief MAC address setup.
- * @pre This function must be invoked with the driver in the stopped
- * state. If invoked on an active interface then it is ignored.
+ * @brief Configures and activates the MAC peripheral.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ * @param[in] config pointer to the @p MACConfig object
+ *
+ * @api
+ */
+void macStart(MACDriver *macp, const MACConfig *config) {
+
+ chDbgCheck((macp != NULL) && (config != NULL), "macStart");
+
+ chSysLock();
+ chDbgAssert(macp->state == MAC_STOP,
+ "macStart(), #1", "invalid state");
+ macp->config = config;
+ mac_lld_start(macp);
+ macp->state = MAC_ACTIVE;
+ chSysUnlock();
+}
+
+/**
+ * @brief Deactivates the MAC peripheral.
*
* @param[in] macp pointer to the @p MACDriver object
- * @param[in] p pointer to a six bytes buffer containing the MAC
- * address. If this parameter is set to @p NULL then MAC
- * a system default is used.
*
* @api
*/
-void macSetAddress(MACDriver *macp, const uint8_t *p) {
+void macStop(MACDriver *macp) {
+
+ chDbgCheck(macp != NULL, "macStop");
- mac_lld_set_address(macp, p);
+ chSysLock();
+ chDbgAssert((macp->state == MAC_STOP) || (macp->state == MAC_ACTIVE),
+ "macStop(), #1", "invalid state");
+ mac_lld_stop(macp);
+ macp->state = MAC_STOP;
+ chSysUnlock();
}
/**
@@ -124,6 +149,10 @@ msg_t macWaitTransmitDescriptor(MACDriver *macp,
systime_t time) {
msg_t msg;
+ chDbgCheck((macp != NULL) && (tdp != NULL), "macWaitTransmitDescriptor");
+ chDbgAssert(macp->state == MAC_ACTIVE, "macWaitTransmitDescriptor(), #1",
+ "not active");
+
while (((msg = max_lld_get_transmit_descriptor(macp, tdp)) != RDY_OK) &&
(time > 0)) {
chSysLock();
@@ -149,6 +178,8 @@ msg_t macWaitTransmitDescriptor(MACDriver *macp,
*/
void macReleaseTransmitDescriptor(MACTransmitDescriptor *tdp) {
+ chDbgCheck((tdp != NULL), "macReleaseTransmitDescriptor");
+
mac_lld_release_transmit_descriptor(tdp);
}
@@ -176,6 +207,10 @@ msg_t macWaitReceiveDescriptor(MACDriver *macp,
systime_t time) {
msg_t msg;
+ chDbgCheck((macp != NULL) && (rdp != NULL), "macWaitReceiveDescriptor");
+ chDbgAssert(macp->state == MAC_ACTIVE, "macWaitReceiveDescriptor(), #1",
+ "not active");
+
while (((msg = max_lld_get_receive_descriptor(macp, rdp)) != RDY_OK) &&
(time > 0)) {
chSysLock();
@@ -202,6 +237,8 @@ msg_t macWaitReceiveDescriptor(MACDriver *macp,
*/
void macReleaseReceiveDescriptor(MACReceiveDescriptor *rdp) {
+ chDbgCheck((rdp != NULL), "macReleaseReceiveDescriptor");
+
mac_lld_release_receive_descriptor(rdp);
}
@@ -217,6 +254,10 @@ void macReleaseReceiveDescriptor(MACReceiveDescriptor *rdp) {
*/
bool_t macPollLinkStatus(MACDriver *macp) {
+ chDbgCheck((macp != NULL), "macPollLinkStatus");
+ chDbgAssert(macp->state == MAC_ACTIVE, "macPollLinkStatus(), #1",
+ "not active");
+
return mac_lld_poll_link_status(macp);
}
diff --git a/os/hal/src/rtc.c b/os/hal/src/rtc.c
new file mode 100644
index 000000000..dda5a9c95
--- /dev/null
+++ b/os/hal/src/rtc.c
@@ -0,0 +1,158 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file rtc.c
+ * @brief RTC Driver code.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void rtcInit(void) {
+
+ rtc_lld_init();
+}
+
+/**
+ * @brief Set current time.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCTime structure
+ *
+ * @api
+ */
+void rtcSetTime(RTCDriver *rtcp, const RTCTime *timespec) {
+
+ chDbgCheck((rtcp != NULL) && (timespec != NULL), "rtcSetTime");
+
+ rtc_lld_set_time(rtcp, timespec);
+}
+
+/**
+ * @brief Get current time.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] timespec pointer to a @p RTCTime structure
+ *
+ * @api
+ */
+void rtcGetTime(RTCDriver *rtcp, RTCTime *timespec) {
+
+ chDbgCheck((rtcp != NULL) && (timespec != NULL), "rtcGetTime");
+
+ rtc_lld_get_time(rtcp, timespec);
+}
+
+#if (RTC_ALARMS > 0) || defined(__DOXYGEN__)
+/**
+ * @brief Set alarm time.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[in] alarmspec pointer to a @p RTCAlarm structure or @p NULL
+ *
+ * @api
+ */
+void rtcSetAlarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec) {
+
+ chDbgCheck((rtcp != NULL) && (alarm < RTC_ALARMS), "rtcSetAlarm");
+
+ rtc_lld_set_alarm(rtcp, alarm, alarmspec);
+}
+
+/**
+ * @brief Get current alarm.
+ * @note If an alarm has not been set then the returned alarm specification
+ * is not meaningful.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[out] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @api
+ */
+void rtcGetAlarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec) {
+
+ chDbgCheck((rtcp != NULL) && (alarm < RTC_ALARMS) && (alarmspec != NULL),
+ "rtcGetAlarm");
+
+ rtc_lld_get_alarm(rtcp, alarm, alarmspec);
+}
+#endif /* RTC_ALARMS > 0 */
+
+#if RTC_SUPPORTS_CALLBACKS || defined(__DOXYGEN__)
+/**
+ * @brief Enables or disables RTC callbacks.
+ * @details This function enables or disables callbacks, use a @p NULL pointer
+ * in order to disable a callback.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] callback callback function pointer or @p NULL
+ *
+ * @api
+ */
+void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback) {
+
+ chDbgCheck((rtcp != NULL), "rtcSetCallback");
+
+ rtc_lld_set_callback(rtcp, callback);
+}
+#endif /* RTC_SUPPORTS_CALLBACKS */
+
+#endif /* HAL_USE_RTC */
+
+/** @} */
diff --git a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c
index 16822502a..ea434b197 100644
--- a/os/hal/src/serial_usb.c
+++ b/os/hal/src/serial_usb.c
@@ -118,21 +118,26 @@ static const struct SerialUSBDriverVMT vmt = {
*/
static void inotify(GenericQueue *qp) {
SerialUSBDriver *sdup = (SerialUSBDriver *)qp->q_wrptr;
- size_t n;
/* 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)) {
-
- n = usbReadPacketI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP,
- sdup->iqueue.q_buffer, SERIAL_USB_BUFFERS_SIZE);
- if (n != USB_ENDPOINT_BUSY) {
- chIOAddFlagsI(sdup, IO_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;
- }
+ if (!usbGetReceiveStatusI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP) &&
+ chIQIsEmptyI(&sdup->iqueue)) {
+ 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);
+
+ chSysLock();
+ usbStartReceiveI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP);
+ chIOAddFlagsI(sdup, IO_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;
}
}
@@ -141,14 +146,20 @@ static void inotify(GenericQueue *qp) {
*/
static void onotify(GenericQueue *qp) {
SerialUSBDriver *sdup = (SerialUSBDriver *)qp->q_rdptr;
- size_t w, n;
+ size_t n;
/* 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);
- w = usbWritePacketI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP,
- sdup->oqueue.q_buffer, n);
- if (w != USB_ENDPOINT_BUSY) {
+ if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP)) {
+ chSysUnlock();
+
+ /* Unlocked to make the potentially long write operation preemptable.*/
+ usbWritePacketBuffer(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP,
+ sdup->oqueue.q_buffer, n);
+
+ chSysLock();
+ usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP);
chIOAddFlagsI(sdup, IO_OUTPUT_EMPTY);
sdup->oqueue.q_wrptr = sdup->oqueue.q_buffer;
sdup->oqueue.q_counter = chQSizeI(&sdup->oqueue);
@@ -285,21 +296,27 @@ bool_t sduRequestsHook(USBDriver *usbp) {
*/
void sduDataTransmitted(USBDriver *usbp, usbep_t ep) {
SerialUSBDriver *sdup = usbp->param;
- size_t n, w;
+ size_t n;
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) {
- w = usbWritePacketI(usbp, ep, sdup->oqueue.q_buffer, n);
- if (w != USB_ENDPOINT_BUSY) {
- chIOAddFlagsI(sdup, IO_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;
- }
+ /* 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);
+
+ chSysLockFromIsr();
+ usbStartTransmitI(usbp, ep);
+ chIOAddFlagsI(sdup, IO_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;
}
chSysUnlockFromIsr();
}
@@ -319,17 +336,23 @@ void sduDataReceived(USBDriver *usbp, usbep_t ep) {
/* 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)) {
+ /* 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;
- n = usbReadPacketI(usbp, ep, sdup->iqueue.q_buffer,
- SERIAL_USB_BUFFERS_SIZE);
- if (n != USB_ENDPOINT_BUSY) {
- chIOAddFlagsI(sdup, IO_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;
- }
+ chSysUnlockFromIsr();
+
+ /* Unlocked to make the potentially long write operation preemptable.*/
+ n = usbReadPacketBuffer(usbp, ep, sdup->iqueue.q_buffer,
+ SERIAL_USB_BUFFERS_SIZE);
+
+ chSysLockFromIsr();
+ usbStartReceiveI(usbp, ep);
+ chIOAddFlagsI(sdup, IO_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;
}
chSysUnlockFromIsr();
}
diff --git a/os/hal/src/usb.c b/os/hal/src/usb.c
index 44a772ab1..30919580c 100644
--- a/os/hal/src/usb.c
+++ b/os/hal/src/usb.c
@@ -309,7 +309,7 @@ void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
chDbgCheck((usbp != NULL) && (epcp != NULL), "usbInitEndpointI");
chDbgAssert(usbp->state == USB_ACTIVE,
"usbEnableEndpointI(), #1", "invalid state");
- chDbgAssert(usbp->epc[ep] != NULL,
+ chDbgAssert(usbp->epc[ep] == NULL,
"usbEnableEndpointI(), #2", "already initialized");
/* Logically enabling the endpoint in the USBDriver structure.*/
@@ -352,126 +352,54 @@ void usbDisableEndpointsI(USBDriver *usbp) {
}
/**
- * @brief Reads a packet from the dedicated packet buffer.
- * @pre In order to use this function he endpoint must have been
- * initialized in packet mode.
- * @post The endpoint is ready to accept another packet.
- *
- * @param[in] usbp pointer to the @p USBDriver object
- * @param[in] ep endpoint number
- * @param[out] buf buffer where to copy the packet data
- * @param[in] n maximum number of bytes to copy. This value must
- * not exceed the maximum packet size for this endpoint.
- * @return The received packet size regardless the specified
- * @p n parameter.
- * @retval USB_ENDPOINT_BUSY Endpoint busy receiving.
- * @retval 0 Zero size packet received.
- *
- * @iclass
- */
-size_t usbReadPacketI(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n) {
-
- chDbgCheckClassI();
- chDbgCheck((usbp != NULL) && (buf != NULL), "usbReadPacketI");
-
- if (usbGetReceiveStatusI(usbp, ep))
- return USB_ENDPOINT_BUSY;
-
- usbp->receiving |= (1 << ep);
- return usb_lld_read_packet(usbp, ep, buf, n);;
-}
-
-/**
- * @brief Writes a packet to the dedicated packet buffer.
- * @pre In order to use this function he endpoint must have been
- * initialized in packet mode.
- * @post The endpoint is ready to transmit the packet.
- *
- * @param[in] usbp pointer to the @p USBDriver object
- * @param[in] ep endpoint number
- * @param[in] buf buffer where to fetch the packet data
- * @param[in] n maximum number of bytes to copy. This value must
- * not exceed the maximum packet size for this endpoint.
- * @return The operation status.
- * @retval USB_ENDPOINT_BUSY Endpoint busy transmitting.
- * @retval 0 Operation complete.
- *
- * @iclass
- */
-size_t usbWritePacketI(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n) {
-
- chDbgCheckClassI();
- chDbgCheck((usbp != NULL) && (buf != NULL), "usbWritePacketI");
-
- if (usbGetTransmitStatusI(usbp, ep))
- return USB_ENDPOINT_BUSY;
-
- usbp->transmitting |= (1 << ep);
- usb_lld_write_packet(usbp, ep, buf, n);
- return 0;
-}
-
-/**
* @brief Starts a receive transaction on an OUT endpoint.
- * @pre In order to use this function he endpoint must have been
- * initialized in transaction mode.
* @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
- * @param[out] buf buffer where to copy the received data
- * @param[in] n maximum number of bytes to copy
* @return The operation status.
* @retval FALSE Operation started successfully.
* @retval TRUE Endpoint busy, operation not started.
*
* @iclass
*/
-bool_t usbStartReceiveI(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n) {
+bool_t usbStartReceiveI(USBDriver *usbp, usbep_t ep) {
chDbgCheckClassI();
- chDbgCheck((usbp != NULL) && (buf != NULL), "usbStartReceiveI");
+ chDbgCheck(usbp != NULL, "usbStartReceiveI");
if (usbGetReceiveStatusI(usbp, ep))
return TRUE;
usbp->receiving |= (1 << ep);
- usb_lld_start_out(usbp, ep, buf, n);
+ usb_lld_start_out(usbp, ep);
return FALSE;
}
/**
* @brief Starts a transmit transaction on an IN endpoint.
- * @pre In order to use this function he endpoint must have been
- * initialized in transaction mode.
* @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
- * @param[in] buf buffer where to fetch the data to be transmitted
- * @param[in] n maximum number of bytes to copy
* @return The operation status.
* @retval FALSE Operation started successfully.
* @retval TRUE Endpoint busy, operation not started.
*
* @iclass
*/
-bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n) {
+bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep) {
chDbgCheckClassI();
- chDbgCheck((usbp != NULL) && (buf != NULL), "usbStartTransmitI");
+ chDbgCheck(usbp != NULL, "usbStartTransmitI");
if (usbGetTransmitStatusI(usbp, ep))
return TRUE;
usbp->transmitting |= (1 << ep);
- usb_lld_start_in(usbp, ep, buf, n);
+ usb_lld_start_in(usbp, ep);
return FALSE;
}
@@ -597,13 +525,15 @@ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
if (usbp->ep0n > 0) {
/* Starts the transmit phase.*/
usbp->ep0state = USB_EP0_TX;
- usb_lld_start_in(usbp, 0, usbp->ep0next, usbp->ep0n);
+ usb_lld_prepare_transmit(usbp, 0, usbp->ep0next, usbp->ep0n);
+ usb_lld_start_in(usbp, 0);
}
else {
/* No transmission phase, directly receiving the zero sized status
packet.*/
usbp->ep0state = USB_EP0_WAITING_STS;
- usb_lld_start_out(usbp, 0, NULL, 0);
+ usb_lld_prepare_receive(usbp, 0, NULL, 0);
+ usb_lld_start_out(usbp, 0);
}
}
else {
@@ -611,13 +541,15 @@ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
if (usbp->ep0n > 0) {
/* Starts the receive phase.*/
usbp->ep0state = USB_EP0_RX;
- usb_lld_start_out(usbp, 0, usbp->ep0next, usbp->ep0n);
+ usb_lld_prepare_receive(usbp, 0, usbp->ep0next, usbp->ep0n);
+ usb_lld_start_out(usbp, 0);
}
else {
/* No receive phase, directly sending the zero sized status
packet.*/
usbp->ep0state = USB_EP0_SENDING_STS;
- usb_lld_start_in(usbp, 0, NULL, 0);
+ usb_lld_prepare_transmit(usbp, 0, NULL, 0);
+ usb_lld_start_in(usbp, 0);
}
}
}
@@ -644,13 +576,15 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
transmitted.*/
if ((usbp->ep0n < max) &&
((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0)) {
- usb_lld_start_in(usbp, 0, NULL, 0);
+ usb_lld_prepare_transmit(usbp, 0, NULL, 0);
+ usb_lld_start_in(usbp, 0);
return;
}
/* Transmit phase over, receiving the zero sized status packet.*/
usbp->ep0state = USB_EP0_WAITING_STS;
- usb_lld_start_out(usbp, 0, NULL, 0);
+ usb_lld_prepare_receive(usbp, 0, NULL, 0);
+ usb_lld_start_out(usbp, 0);
return;
case USB_EP0_SENDING_STS:
/* Status packet sent, invoking the callback if defined.*/
@@ -687,7 +621,8 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
case USB_EP0_RX:
/* Receive phase over, sending the zero sized status packet.*/
usbp->ep0state = USB_EP0_SENDING_STS;
- usb_lld_start_in(usbp, 0, NULL, 0);
+ usb_lld_prepare_transmit(usbp, 0, NULL, 0);
+ usb_lld_start_in(usbp, 0);
return;
case USB_EP0_WAITING_STS:
/* Status packet received, it must be zero sized, invoking the callback