modem: cmux: Implement TRANSMIT_IDLE event

Implement transmit idle event both for transmitting data to the
bus, and for the individual DLCI channels.

Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
Bjarki Arge Andreasen 2023-11-24 14:47:59 +01:00 committed by David Leach
parent 06edc37521
commit c114627853

View file

@ -197,8 +197,17 @@ static void modem_cmux_bus_callback(struct modem_pipe *pipe, enum modem_pipe_eve
{
struct modem_cmux *cmux = (struct modem_cmux *)user_data;
if (event == MODEM_PIPE_EVENT_RECEIVE_READY) {
switch (event) {
case MODEM_PIPE_EVENT_RECEIVE_READY:
k_work_schedule(&cmux->receive_work, K_NO_WAIT);
break;
case MODEM_PIPE_EVENT_TRANSMIT_IDLE:
k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
break;
default:
break;
}
}
@ -833,6 +842,17 @@ static void modem_cmux_receive_handler(struct k_work *item)
k_work_schedule(&cmux->receive_work, K_NO_WAIT);
}
static void modem_cmux_dlci_notify_transmit_idle(struct modem_cmux *cmux)
{
sys_snode_t *node;
struct modem_cmux_dlci *dlci;
SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) {
dlci = (struct modem_cmux_dlci *)node;
modem_pipe_notify_transmit_idle(&dlci->pipe);
}
}
static void modem_cmux_transmit_handler(struct k_work *item)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(item);
@ -840,31 +860,37 @@ static void modem_cmux_transmit_handler(struct k_work *item)
uint8_t *reserved;
uint32_t reserved_size;
int ret;
bool transmit_rb_empty;
k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
/* Reserve data to transmit from transmit ring buffer */
reserved_size = ring_buf_get_claim(&cmux->transmit_rb, &reserved, UINT32_MAX);
while (true) {
transmit_rb_empty = ring_buf_is_empty(&cmux->transmit_rb);
/* Transmit reserved data */
ret = modem_pipe_transmit(cmux->pipe, reserved, reserved_size);
if (ret < 1) {
ring_buf_get_finish(&cmux->transmit_rb, 0);
k_mutex_unlock(&cmux->transmit_rb_lock);
k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
if (transmit_rb_empty) {
break;
}
return;
}
reserved_size = ring_buf_get_claim(&cmux->transmit_rb, &reserved, UINT32_MAX);
/* Release remaining reserved data */
ring_buf_get_finish(&cmux->transmit_rb, ret);
ret = modem_pipe_transmit(cmux->pipe, reserved, reserved_size);
if (ret < 0) {
ring_buf_get_finish(&cmux->transmit_rb, 0);
break;
}
/* Resubmit transmit work if data remains */
if (ring_buf_is_empty(&cmux->transmit_rb) == false) {
k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
ring_buf_get_finish(&cmux->transmit_rb, (uint32_t)ret);
if (ret == 0) {
break;
}
}
k_mutex_unlock(&cmux->transmit_rb_lock);
if (transmit_rb_empty) {
modem_cmux_dlci_notify_transmit_idle(cmux);
}
}
static void modem_cmux_connect_handler(struct k_work *item)