diff options
-rw-r--r-- | sound/firewire/lib.c | 18 | ||||
-rw-r--r-- | sound/firewire/lib.h | 1 |
2 files changed, 18 insertions, 1 deletions
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c index 3e9afd7d402c..9a98c7cd8744 100644 --- a/sound/firewire/lib.c +++ b/sound/firewire/lib.c | |||
@@ -76,6 +76,9 @@ static void async_midi_port_callback(struct fw_card *card, int rcode, | |||
76 | 76 | ||
77 | if (rcode == RCODE_COMPLETE && substream != NULL) | 77 | if (rcode == RCODE_COMPLETE && substream != NULL) |
78 | snd_rawmidi_transmit_ack(substream, port->consume_bytes); | 78 | snd_rawmidi_transmit_ack(substream, port->consume_bytes); |
79 | else if (!rcode_is_permanent_error(rcode)) | ||
80 | /* To start next transaction immediately for recovery. */ | ||
81 | port->next_ktime = ktime_set(0, 0); | ||
79 | 82 | ||
80 | port->idling = true; | 83 | port->idling = true; |
81 | 84 | ||
@@ -99,6 +102,12 @@ static void midi_port_work(struct work_struct *work) | |||
99 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) | 102 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) |
100 | return; | 103 | return; |
101 | 104 | ||
105 | /* Do it in next chance. */ | ||
106 | if (ktime_after(port->next_ktime, ktime_get())) { | ||
107 | schedule_work(&port->work); | ||
108 | return; | ||
109 | } | ||
110 | |||
102 | /* | 111 | /* |
103 | * Fill the buffer. The callee must use snd_rawmidi_transmit_peek(). | 112 | * Fill the buffer. The callee must use snd_rawmidi_transmit_peek(). |
104 | * Later, snd_rawmidi_transmit_ack() is called. | 113 | * Later, snd_rawmidi_transmit_ack() is called. |
@@ -107,8 +116,10 @@ static void midi_port_work(struct work_struct *work) | |||
107 | port->consume_bytes = port->fill(substream, port->buf); | 116 | port->consume_bytes = port->fill(substream, port->buf); |
108 | if (port->consume_bytes <= 0) { | 117 | if (port->consume_bytes <= 0) { |
109 | /* Do it in next chance, immediately. */ | 118 | /* Do it in next chance, immediately. */ |
110 | if (port->consume_bytes == 0) | 119 | if (port->consume_bytes == 0) { |
120 | port->next_ktime = ktime_set(0, 0); | ||
111 | schedule_work(&port->work); | 121 | schedule_work(&port->work); |
122 | } | ||
112 | return; | 123 | return; |
113 | } | 124 | } |
114 | 125 | ||
@@ -118,6 +129,10 @@ static void midi_port_work(struct work_struct *work) | |||
118 | else | 129 | else |
119 | type = TCODE_WRITE_BLOCK_REQUEST; | 130 | type = TCODE_WRITE_BLOCK_REQUEST; |
120 | 131 | ||
132 | /* Set interval to next transaction. */ | ||
133 | port->next_ktime = ktime_add_ns(ktime_get(), | ||
134 | port->consume_bytes * 8 * NSEC_PER_SEC / 31250); | ||
135 | |||
121 | /* Start this transaction. */ | 136 | /* Start this transaction. */ |
122 | port->idling = false; | 137 | port->idling = false; |
123 | 138 | ||
@@ -162,6 +177,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, | |||
162 | port->addr = addr; | 177 | port->addr = addr; |
163 | port->fill = fill; | 178 | port->fill = fill; |
164 | port->idling = true; | 179 | port->idling = true; |
180 | port->next_ktime = ktime_set(0, 0); | ||
165 | 181 | ||
166 | INIT_WORK(&port->work, midi_port_work); | 182 | INIT_WORK(&port->work, midi_port_work); |
167 | 183 | ||
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index 0af06f44e8c2..59e086587212 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h | |||
@@ -31,6 +31,7 @@ struct snd_fw_async_midi_port { | |||
31 | struct fw_device *parent; | 31 | struct fw_device *parent; |
32 | struct work_struct work; | 32 | struct work_struct work; |
33 | bool idling; | 33 | bool idling; |
34 | ktime_t next_ktime; | ||
34 | 35 | ||
35 | u64 addr; | 36 | u64 addr; |
36 | struct fw_transaction transaction; | 37 | struct fw_transaction transaction; |