diff options
Diffstat (limited to 'sound/firewire/lib.c')
-rw-r--r-- | sound/firewire/lib.c | 141 |
1 files changed, 0 insertions, 141 deletions
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c index 7683238283b6..39dfa74906ef 100644 --- a/sound/firewire/lib.c +++ b/sound/firewire/lib.c | |||
@@ -99,147 +99,6 @@ void snd_fw_schedule_registration(struct fw_unit *unit, | |||
99 | } | 99 | } |
100 | EXPORT_SYMBOL(snd_fw_schedule_registration); | 100 | EXPORT_SYMBOL(snd_fw_schedule_registration); |
101 | 101 | ||
102 | static void async_midi_port_callback(struct fw_card *card, int rcode, | ||
103 | void *data, size_t length, | ||
104 | void *callback_data) | ||
105 | { | ||
106 | struct snd_fw_async_midi_port *port = callback_data; | ||
107 | struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); | ||
108 | |||
109 | /* This port is closed. */ | ||
110 | if (substream == NULL) | ||
111 | return; | ||
112 | |||
113 | if (rcode == RCODE_COMPLETE) | ||
114 | snd_rawmidi_transmit_ack(substream, port->consume_bytes); | ||
115 | else if (!rcode_is_permanent_error(rcode)) | ||
116 | /* To start next transaction immediately for recovery. */ | ||
117 | port->next_ktime = 0; | ||
118 | else | ||
119 | /* Don't continue processing. */ | ||
120 | port->error = true; | ||
121 | |||
122 | port->idling = true; | ||
123 | |||
124 | if (!snd_rawmidi_transmit_empty(substream)) | ||
125 | schedule_work(&port->work); | ||
126 | } | ||
127 | |||
128 | static void midi_port_work(struct work_struct *work) | ||
129 | { | ||
130 | struct snd_fw_async_midi_port *port = | ||
131 | container_of(work, struct snd_fw_async_midi_port, work); | ||
132 | struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); | ||
133 | int generation; | ||
134 | int type; | ||
135 | |||
136 | /* Under transacting or error state. */ | ||
137 | if (!port->idling || port->error) | ||
138 | return; | ||
139 | |||
140 | /* Nothing to do. */ | ||
141 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) | ||
142 | return; | ||
143 | |||
144 | /* Do it in next chance. */ | ||
145 | if (ktime_after(port->next_ktime, ktime_get())) { | ||
146 | schedule_work(&port->work); | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * Fill the buffer. The callee must use snd_rawmidi_transmit_peek(). | ||
152 | * Later, snd_rawmidi_transmit_ack() is called. | ||
153 | */ | ||
154 | memset(port->buf, 0, port->len); | ||
155 | port->consume_bytes = port->fill(substream, port->buf); | ||
156 | if (port->consume_bytes <= 0) { | ||
157 | /* Do it in next chance, immediately. */ | ||
158 | if (port->consume_bytes == 0) { | ||
159 | port->next_ktime = 0; | ||
160 | schedule_work(&port->work); | ||
161 | } else { | ||
162 | /* Fatal error. */ | ||
163 | port->error = true; | ||
164 | } | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | /* Calculate type of transaction. */ | ||
169 | if (port->len == 4) | ||
170 | type = TCODE_WRITE_QUADLET_REQUEST; | ||
171 | else | ||
172 | type = TCODE_WRITE_BLOCK_REQUEST; | ||
173 | |||
174 | /* Set interval to next transaction. */ | ||
175 | port->next_ktime = ktime_add_ns(ktime_get(), | ||
176 | port->consume_bytes * 8 * NSEC_PER_SEC / 31250); | ||
177 | |||
178 | /* Start this transaction. */ | ||
179 | port->idling = false; | ||
180 | |||
181 | /* | ||
182 | * In Linux FireWire core, when generation is updated with memory | ||
183 | * barrier, node id has already been updated. In this module, After | ||
184 | * this smp_rmb(), load/store instructions to memory are completed. | ||
185 | * Thus, both of generation and node id are available with recent | ||
186 | * values. This is a light-serialization solution to handle bus reset | ||
187 | * events on IEEE 1394 bus. | ||
188 | */ | ||
189 | generation = port->parent->generation; | ||
190 | smp_rmb(); | ||
191 | |||
192 | fw_send_request(port->parent->card, &port->transaction, type, | ||
193 | port->parent->node_id, generation, | ||
194 | port->parent->max_speed, port->addr, | ||
195 | port->buf, port->len, async_midi_port_callback, | ||
196 | port); | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * snd_fw_async_midi_port_init - initialize asynchronous MIDI port structure | ||
201 | * @port: the asynchronous MIDI port to initialize | ||
202 | * @unit: the target of the asynchronous transaction | ||
203 | * @addr: the address to which transactions are transferred | ||
204 | * @len: the length of transaction | ||
205 | * @fill: the callback function to fill given buffer, and returns the | ||
206 | * number of consumed bytes for MIDI message. | ||
207 | * | ||
208 | */ | ||
209 | int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, | ||
210 | struct fw_unit *unit, u64 addr, unsigned int len, | ||
211 | snd_fw_async_midi_port_fill fill) | ||
212 | { | ||
213 | port->len = DIV_ROUND_UP(len, 4) * 4; | ||
214 | port->buf = kzalloc(port->len, GFP_KERNEL); | ||
215 | if (port->buf == NULL) | ||
216 | return -ENOMEM; | ||
217 | |||
218 | port->parent = fw_parent_device(unit); | ||
219 | port->addr = addr; | ||
220 | port->fill = fill; | ||
221 | port->idling = true; | ||
222 | port->next_ktime = 0; | ||
223 | port->error = false; | ||
224 | |||
225 | INIT_WORK(&port->work, midi_port_work); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | EXPORT_SYMBOL(snd_fw_async_midi_port_init); | ||
230 | |||
231 | /** | ||
232 | * snd_fw_async_midi_port_destroy - free asynchronous MIDI port structure | ||
233 | * @port: the asynchronous MIDI port structure | ||
234 | */ | ||
235 | void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port) | ||
236 | { | ||
237 | snd_fw_async_midi_port_finish(port); | ||
238 | cancel_work_sync(&port->work); | ||
239 | kfree(port->buf); | ||
240 | } | ||
241 | EXPORT_SYMBOL(snd_fw_async_midi_port_destroy); | ||
242 | |||
243 | MODULE_DESCRIPTION("FireWire audio helper functions"); | 102 | MODULE_DESCRIPTION("FireWire audio helper functions"); |
244 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 103 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
245 | MODULE_LICENSE("GPL v2"); | 104 | MODULE_LICENSE("GPL v2"); |