|
|
|
@ -211,27 +211,40 @@ static int uart_putxmitchar(FAR uart_dev_t *dev, int ch)
@@ -211,27 +211,40 @@ static int uart_putxmitchar(FAR uart_dev_t *dev, int ch)
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
flags = irqsave(); |
|
|
|
|
dev->xmitwaiting = true; |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* Check if the removable device is no longer connected while we
|
|
|
|
|
* have interrupts off. We do not want the transition to occur |
|
|
|
|
* as a race condition before we begin the wait. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
irqrestore(flags); |
|
|
|
|
return -ENOTCONN; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
/* Wait for some characters to be sent from the buffer with the TX
|
|
|
|
|
* interrupt enabled. When the TX interrupt is enabled, uart_xmitchars |
|
|
|
|
* should execute and remove some of the data from the TX buffer. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
dev->xmitwaiting = true; |
|
|
|
|
uart_enabletxint(dev); |
|
|
|
|
ret = uart_takesem(&dev->xmitsem, true); |
|
|
|
|
uart_disabletxint(dev); |
|
|
|
|
irqrestore(flags); |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* Check if the removable device is no longer connected */ |
|
|
|
|
/* Check if the removable device was disconnected while we were
|
|
|
|
|
* waiting. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
return -ENOTCONN; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Check if we were awakened by signal. */ |
|
|
|
|
|
|
|
|
|
if (ret < 0) |
|
|
|
@ -342,7 +355,9 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
@@ -342,7 +355,9 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* If the removable device is no longer connected, refuse to write to the
|
|
|
|
|
* device. |
|
|
|
|
* device. This check occurs after taking the xmit.sem because the |
|
|
|
|
* disconnection event might have occurred while we were waiting for |
|
|
|
|
* access to the transmit buffers. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
@ -377,8 +392,12 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
@@ -377,8 +392,12 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
|
|
|
|
|
ret = uart_putxmitchar(dev, ch); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Were we awakened by a signal? That should be the only condition that
|
|
|
|
|
* uart_putxmitchar() should return an error. |
|
|
|
|
/* uart_putxmitchar() might return an error under one of two
|
|
|
|
|
* conditions: (1) The wait for buffer space might have been |
|
|
|
|
* interrupted by a signal (ret should be -EINTR), or (2) if |
|
|
|
|
* CONFIG_SERIAL_REMOVABLE is defined, then uart_putxmitchar() |
|
|
|
|
* might also return if the serial device was disconnected |
|
|
|
|
* (wtih -ENOTCONN). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (ret < 0) |
|
|
|
@ -402,7 +421,7 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
@@ -402,7 +421,7 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
|
|
|
|
|
* set the errno value appropriately). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
nread = -EINTR; |
|
|
|
|
nread = ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
@ -444,16 +463,6 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
@@ -444,16 +463,6 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* If the removable device is no longer connected, refuse to read from the device */ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
uart_givesem(&dev->recv.sem); |
|
|
|
|
return -ENOTCONN; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Loop while we still have data to copy to the receive buffer.
|
|
|
|
|
* we add data to the head of the buffer; uart_xmitchars takes the |
|
|
|
|
* data from the end of the buffer. |
|
|
|
@ -461,6 +470,22 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
@@ -461,6 +470,22 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|
|
|
|
|
|
|
|
|
while (recvd < buflen) |
|
|
|
|
{ |
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* If the removable device is no longer connected, refuse to read any
|
|
|
|
|
* further from the device. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
if (recvd == 0) |
|
|
|
|
{ |
|
|
|
|
recvd = -ENOTCONN; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Check if there is more data to return in the circular buffer.
|
|
|
|
|
* NOTE: Rx interrupt handling logic may aynchronously increment |
|
|
|
|
* the head index but must not modify the tail index. The tail |
|
|
|
@ -509,6 +534,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
@@ -509,6 +534,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|
|
|
|
{ |
|
|
|
|
recvd = -EAGAIN; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
@ -560,19 +586,34 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
@@ -560,19 +586,34 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
flags = irqsave(); |
|
|
|
|
dev->recvwaiting = true; |
|
|
|
|
uart_enablerxint(dev); |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* Check if the removable device is no longer connected while
|
|
|
|
|
* we have interrupts off. We do not want the transition to |
|
|
|
|
* occur as a race condition before we begin the wait. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
uart_enablerxint(dev); |
|
|
|
|
irqrestore(flags); |
|
|
|
|
ret = -ENOTCONN; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
/* Now wait with the Rx interrupt re-enabled. NuttX will
|
|
|
|
|
* automatically re-enable global interrupts when this thread |
|
|
|
|
* goes to sleep. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
dev->recvwaiting = true; |
|
|
|
|
uart_enablerxint(dev); |
|
|
|
|
ret = uart_takesem(&dev->recvsem, true); |
|
|
|
|
irqrestore(flags); |
|
|
|
|
|
|
|
|
|
/* Was a signal received while waiting for data to be
|
|
|
|
|
* received? Was a removable device disconnected? |
|
|
|
|
* received? Was a removable device disconnected while |
|
|
|
|
* we were waiting? |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
@ -840,6 +881,7 @@ static int uart_close(FAR struct file *filep)
@@ -840,6 +881,7 @@ static int uart_close(FAR struct file *filep)
|
|
|
|
|
{ |
|
|
|
|
uart_shutdown(dev); /* Disable the UART */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
irqrestore(flags); |
|
|
|
|
|
|
|
|
|
uart_givesem(&dev->closesem); |
|
|
|
@ -861,15 +903,6 @@ static int uart_open(FAR struct file *filep)
@@ -861,15 +903,6 @@ static int uart_open(FAR struct file *filep)
|
|
|
|
|
uint8_t tmp; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* If the removable device is no longer connected, refuse to open the device */ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
return -ENOTCONN; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* If the port is the middle of closing, wait until the close is finished.
|
|
|
|
|
* If a signal is received while we are waiting, then return EINTR. |
|
|
|
|
*/ |
|
|
|
@ -882,6 +915,19 @@ static int uart_open(FAR struct file *filep)
@@ -882,6 +915,19 @@ static int uart_open(FAR struct file *filep)
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_REMOVABLE |
|
|
|
|
/* If the removable device is no longer connected, refuse to open the
|
|
|
|
|
* device. We check this after obtaining the close semaphore because |
|
|
|
|
* we might have been waiting when the device was disconnected. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->disconnected) |
|
|
|
|
{ |
|
|
|
|
ret = -ENOTCONN; |
|
|
|
|
goto errout_with_sem; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Start up serial port */ |
|
|
|
|
/* Increment the count of references to the device. */ |
|
|
|
|
|
|
|
|
|