Fixed bug 3530043.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4244 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
gdisirio 2012-05-27 14:50:05 +00:00
parent 2b01d72e42
commit c0cbc2411e
3 changed files with 23 additions and 21 deletions

View File

@ -102,7 +102,7 @@ typedef enum {
*/ */
#define i2cMasterTransmit(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes) \ #define i2cMasterTransmit(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes) \
(i2cMasterTransmitTimeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, \ (i2cMasterTransmitTimeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, \
TIME_INFINITE)) TIME_INFINITE))
/** /**
* @brief Wrap i2cMasterReceiveTimeout function with TIME_INFINITE timeout. * @brief Wrap i2cMasterReceiveTimeout function with TIME_INFINITE timeout.

View File

@ -165,13 +165,15 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
static void i2c_lld_safety_timeout(void *p) { static void i2c_lld_safety_timeout(void *p) {
I2CDriver *i2cp = (I2CDriver *)p; I2CDriver *i2cp = (I2CDriver *)p;
chSysLockFromIsr();
if (i2cp->thread) { if (i2cp->thread) {
Thread *tp = i2cp->thread;
i2c_lld_abort_operation(i2cp); i2c_lld_abort_operation(i2cp);
chSysLockFromIsr(); i2cp->thread = NULL;
i2cp->thread->p_u.rdymsg = RDY_TIMEOUT; tp->p_u.rdymsg = RDY_TIMEOUT;
chSchReadyI(i2cp->thread); chSchReadyI(tp);
chSysUnlockFromIsr();
} }
chSysUnlockFromIsr();
} }
/** /**
@ -768,12 +770,12 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
systime_t timeout) { systime_t timeout) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
VirtualTimer vt; VirtualTimer vt;
msg_t rdymsg;
chDbgCheck((rxbytes > 1), "i2c_lld_master_receive_timeout"); chDbgCheck((rxbytes > 1), "i2c_lld_master_receive_timeout");
/* Global timeout for the whole operation.*/ /* Global timeout for the whole operation.*/
chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); if (timeout != TIME_INFINITE)
chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp);
/* Releases the lock from high level driver.*/ /* Releases the lock from high level driver.*/
chSysUnlock(); chSysUnlock();
@ -789,10 +791,10 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Waits until BUSY flag is reset and the STOP from the previous operation /* Waits until BUSY flag is reset and the STOP from the previous operation
is completed, alternatively for a timeout condition.*/ is completed, alternatively for a timeout condition.*/
while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) { while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) {
if (!chVTIsArmedI(&vt)) { chSysLock();
chSysLock(); if (!chVTIsArmedI(&vt))
return RDY_TIMEOUT; return RDY_TIMEOUT;
} chSysUnlock();
} }
/* This lock will be released in high level driver.*/ /* This lock will be released in high level driver.*/
@ -810,11 +812,10 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Waits for the operation completion or a timeout.*/ /* Waits for the operation completion or a timeout.*/
i2cp->thread = chThdSelf(); i2cp->thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED); chSchGoSleepS(THD_STATE_SUSPENDED);
rdymsg = chThdSelf()->p_u.rdymsg; if (chVTIsArmedI(&vt))
if (rdymsg != RDY_TIMEOUT)
chVTResetI(&vt); chVTResetI(&vt);
return rdymsg; return chThdSelf()->p_u.rdymsg;
} }
/** /**
@ -848,13 +849,13 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
systime_t timeout) { systime_t timeout) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
VirtualTimer vt; VirtualTimer vt;
msg_t rdymsg;
chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))), chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))),
"i2c_lld_master_transmit_timeout"); "i2c_lld_master_transmit_timeout");
/* Global timeout for the whole operation.*/ /* Global timeout for the whole operation.*/
chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); if (timeout != TIME_INFINITE)
chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp);
/* Releases the lock from high level driver.*/ /* Releases the lock from high level driver.*/
chSysUnlock(); chSysUnlock();
@ -874,10 +875,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Waits until BUSY flag is reset and the STOP from the previous operation /* Waits until BUSY flag is reset and the STOP from the previous operation
is completed, alternatively for a timeout condition.*/ is completed, alternatively for a timeout condition.*/
while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) { while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) {
if (!chVTIsArmedI(&vt)) { chSysLock();
chSysLock(); if (!chVTIsArmedI(&vt))
return RDY_TIMEOUT; return RDY_TIMEOUT;
} chSysUnlock();
} }
/* This lock will be released in high level driver.*/ /* This lock will be released in high level driver.*/
@ -895,11 +896,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Waits for the operation completion or a timeout.*/ /* Waits for the operation completion or a timeout.*/
i2cp->thread = chThdSelf(); i2cp->thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED); chSchGoSleepS(THD_STATE_SUSPENDED);
rdymsg = chThdSelf()->p_u.rdymsg; if (chVTIsArmedI(&vt))
if (rdymsg != RDY_TIMEOUT)
chVTResetI(&vt); chVTResetI(&vt);
return rdymsg; return chThdSelf()->p_u.rdymsg;
} }
#endif /* HAL_USE_I2C */ #endif /* HAL_USE_I2C */

View File

@ -81,6 +81,8 @@
***************************************************************************** *****************************************************************************
*** 2.5.0 *** *** 2.5.0 ***
- FIX: Fixed timeout related race condition in STM32 I2C driver (bug 3530043)
(backported to 2.4.2).
- FIX: Fixed wrong macro check in STM32 MAC driver (bug 3527179)(backported - FIX: Fixed wrong macro check in STM32 MAC driver (bug 3527179)(backported
to 2.4.2). to 2.4.2).
- FIX: Fixed error in STM32L-Discovery board.h file (bug 3526918)(backported - FIX: Fixed error in STM32L-Discovery board.h file (bug 3526918)(backported