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:
parent
06edc37521
commit
c114627853
1 changed files with 42 additions and 16 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue