cuart_driver_tty: Work around linux kernel bug ignoring CREAD
Almost all linux USB serial drivers are ignoring CREAD and hence
cannot disable the receiver hardware, see https://bugzilla.kernel.org/show_bug.cgi?id=205033
We therefore have to receive every byte we transmit before notifying the
user of transmit completion.
Change-Id: Id3cca29f78ee5469a1142aaa1ff754cc0427ec93
diff --git a/ccid_common/cuart.c b/ccid_common/cuart.c
index 2c0428e..393bf55 100644
--- a/ccid_common/cuart.c
+++ b/ccid_common/cuart.c
@@ -113,7 +113,6 @@
case CUART_E_TX_COMPLETE:
cuart->tx_busy = false;
/* re-enable receiver if we're done with transmit */
- sleep(1);
card_uart_ctrl(cuart, CUART_CTL_RX, true);
break;
default:
diff --git a/ccid_common/cuart.h b/ccid_common/cuart.h
index 7e217db..c28209f 100644
--- a/ccid_common/cuart.h
+++ b/ccid_common/cuart.h
@@ -77,6 +77,8 @@
size_t tx_buf_len;
/* index: offset of next to be transmitted byte in tx_buf */
size_t tx_index;
+ /* number of bytes we have received echoed back during transmit */
+ uint32_t rx_count_during_tx;
struct osmo_fd ofd;
unsigned int baudrate;
@@ -104,4 +106,3 @@
void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data);
int card_uart_driver_register(struct card_uart_driver *drv);
-
diff --git a/ccid_host/cuart_driver_tty.c b/ccid_host/cuart_driver_tty.c
index 6bd2b52..7fc8d3a 100644
--- a/ccid_host/cuart_driver_tty.c
+++ b/ccid_host/cuart_driver_tty.c
@@ -125,7 +125,21 @@
rc = read(ofd->fd, buf, sizeof(buf));
OSMO_ASSERT(rc > 0);
for (i = 0; i < rc; i++) {
+#ifndef CREAD_ACTUALLY_WORKS
/* work-around for https://bugzilla.kernel.org/show_bug.cgi?id=205033 */
+ if (cuart->tx_busy) {
+ if (cuart->u.tty.rx_count_during_tx < cuart->u.tty.tx_buf_len) {
+ /* FIXME: compare! */
+ cuart->u.tty.rx_count_during_tx += 1;
+ if (cuart->u.tty.rx_count_during_tx == cuart->u.tty.tx_buf_len) {
+ cuart->tx_busy = false;
+ card_uart_notification(cuart, CUART_E_TX_COMPLETE,
+ (void *)cuart->u.tty.tx_buf);
+ }
+ continue;
+ }
+ }
+#endif
if (!cuart->rx_enabled)
continue;
@@ -152,12 +166,15 @@
/* if no more bytes to transmit, disable OSMO_FD_WRITE */
if (cuart->u.tty.tx_index >= cuart->u.tty.tx_buf_len) {
ofd->when &= ~BSC_FD_WRITE;
+#ifndef CREAD_ACTUALLY_WORKS
+ /* don't immediately notify user; first wait for characters to be received */
+#else
/* ensure everything is written (tx queue/fifo drained) */
tcdrain(cuart->u.tty.ofd.fd);
- osmo_select_main(true);
cuart->tx_busy = false;
/* notify */
card_uart_notification(cuart, CUART_E_TX_COMPLETE, (void *)cuart->u.tty.tx_buf);
+#endif
}
}
return 0;
@@ -209,7 +226,8 @@
cuart->u.tty.tx_buf = data;
cuart->u.tty.tx_buf_len = len;
- cuart->u.tty.tx_buf_len = len;
+ cuart->u.tty.tx_index = 0;
+ cuart->u.tty.rx_count_during_tx = 0;
cuart->tx_busy = true;
cuart->u.tty.ofd.when |= OSMO_FD_WRITE;
diff --git a/ccid_host/cuart_test.c b/ccid_host/cuart_test.c
index aff9de7..0ed6614 100644
--- a/ccid_host/cuart_test.c
+++ b/ccid_host/cuart_test.c
@@ -47,6 +47,8 @@
card_uart_tx(&g_cuart, select_mf, 5, true);
osmo_select_main(true);
+ sleep(1);
+ osmo_select_main(true);
/* we should get an RX_SINGLE event here */
}