1 From 5f3557a2e88b324e026d44f8fb7eb3ea37bba16b Mon Sep 17 00:00:00 2001
2 From: Giedrius Trainavicius <giedrius@blokas.io>
3 Date: Tue, 25 Oct 2016 01:47:20 +0300
4 Subject: [PATCH 138/454] Updates for Pisound module code:
6 * Merged 'Fix a warning in DEBUG builds' (1c8b82b).
7 * Updating some strings and copyright information.
8 * Fix for handling high load of MIDI input and output.
9 * Use dual rate oversampling ratio for 96kHz instead of single
12 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
14 .../arm/boot/dts/overlays/pisound-overlay.dts | 4 +-
15 sound/soc/bcm/pisound.c | 209 ++++++++++++------
16 2 files changed, 146 insertions(+), 67 deletions(-)
18 --- a/arch/arm/boot/dts/overlays/pisound-overlay.dts
19 +++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts
22 - * pisound Linux kernel module.
23 - * Copyright (C) 2016 Vilniaus Blokas UAB, http://blokas.io/pisound
24 + * Pisound Linux kernel module.
25 + * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
27 * This program is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU General Public License
29 --- a/sound/soc/bcm/pisound.c
30 +++ b/sound/soc/bcm/pisound.c
33 - * pisound Linux kernel module.
34 - * Copyright (C) 2016 Vilniaus Blokas UAB, http://blokas.io/pisound
35 + * Pisound Linux kernel module.
36 + * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
38 * This program is free software; you can redistribute it and/or
39 * modify it under the terms of the GNU General Public License
41 #include <linux/spi/spi.h>
42 #include <linux/interrupt.h>
43 #include <linux/kfifo.h>
44 +#include <linux/jiffies.h>
46 #include <sound/core.h>
47 #include <sound/pcm.h>
49 static int pisnd_spi_init(struct device *dev);
50 static void pisnd_spi_uninit(void);
52 -static void pisnd_spi_send(uint8_t val);
53 +static void pisnd_spi_flush(void);
54 +static void pisnd_spi_start(void);
55 static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
57 typedef void (*pisnd_spi_recv_cb)(void *data);
58 @@ -56,7 +58,7 @@ static void pisnd_midi_uninit(void);
60 #define PISOUND_LOG_PREFIX "pisound: "
64 # define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
66 # define printd(...) do {} while (0)
67 @@ -65,13 +67,18 @@ static void pisnd_midi_uninit(void);
68 #define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
69 #define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
71 +static struct snd_rawmidi *g_rmidi;
72 +static struct snd_rawmidi_substream *g_midi_output_substream;
74 static int pisnd_output_open(struct snd_rawmidi_substream *substream)
76 + g_midi_output_substream = substream;
80 static int pisnd_output_close(struct snd_rawmidi_substream *substream)
82 + g_midi_output_substream = NULL;
86 @@ -80,26 +87,20 @@ static void pisnd_output_trigger(
91 + if (substream != g_midi_output_substream) {
92 + printe("MIDI output trigger called for an unexpected stream!");
99 - while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
100 - pisnd_spi_send(data);
101 - snd_rawmidi_transmit_ack(substream, 1);
106 static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
110 - while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
111 - pisnd_spi_send(data);
113 - snd_rawmidi_transmit_ack(substream, 1);
118 static int pisnd_input_open(struct snd_rawmidi_substream *substream)
119 @@ -120,7 +121,7 @@ static void pisnd_midi_recv_callback(voi
120 while ((n = pisnd_spi_recv(data, sizeof(data)))) {
121 int res = snd_rawmidi_receive(substream, data, n);
123 - printd("midi recv 0x%02x, res = %d\n", data, res);
124 + printd("midi recv %u bytes, res = %d\n", n, res);
128 @@ -134,8 +135,6 @@ static void pisnd_input_trigger(struct s
132 -static struct snd_rawmidi *g_rmidi;
134 static struct snd_rawmidi_ops pisnd_output_ops = {
135 .open = pisnd_output_open,
136 .close = pisnd_output_close,
137 @@ -168,7 +167,11 @@ static struct snd_rawmidi_global_ops pis
139 static int pisnd_midi_init(struct snd_card *card)
141 - int err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
144 + g_midi_output_substream = NULL;
146 + err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
149 printe("snd_rawmidi_new failed: %d\n", err);
150 @@ -209,7 +212,7 @@ static void pisnd_midi_uninit(void)
151 static void *g_recvData;
152 static pisnd_spi_recv_cb g_recvCallback;
154 -#define FIFO_SIZE 512
155 +#define FIFO_SIZE 4096
157 static char g_serial_num[11];
158 static char g_id[25];
159 @@ -231,6 +234,7 @@ static struct work_struct pisnd_work_pro
161 static void pisnd_work_handler(struct work_struct *work);
163 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
164 static uint16_t spi_transfer16(uint16_t val);
166 static int pisnd_init_workqueues(void)
167 @@ -285,9 +289,6 @@ static unsigned long spilockflags;
169 static uint16_t spi_transfer16(uint16_t val)
172 - struct spi_transfer transfer;
173 - struct spi_message msg;
177 @@ -296,19 +297,38 @@ static uint16_t spi_transfer16(uint16_t
181 + txbuf[0] = val >> 8;
182 + txbuf[1] = val & 0xff;
184 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
186 + printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
188 + return (rxbuf[0] << 8) | rxbuf[1];
191 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
194 + struct spi_transfer transfer;
195 + struct spi_message msg;
197 + memset(rxbuf, 0, sizeof(txbuf));
199 + if (!pisnd_spi_device) {
200 + printe("pisnd_spi_device null, returning\n");
204 spi_message_init(&msg);
206 memset(&transfer, 0, sizeof(transfer));
207 - memset(&rxbuf, 0, sizeof(rxbuf));
209 - txbuf[0] = val >> 8;
210 - txbuf[1] = val & 0xff;
212 - transfer.tx_buf = &txbuf;
213 - transfer.rx_buf = &rxbuf;
214 - transfer.len = sizeof(txbuf);
215 - transfer.speed_hz = 125000;
216 - transfer.delay_usecs = 100;
217 + transfer.tx_buf = txbuf;
218 + transfer.rx_buf = rxbuf;
219 + transfer.len = len;
220 + transfer.speed_hz = 100000;
221 + transfer.delay_usecs = 10;
222 spi_message_add_tail(&transfer, &msg);
224 spin_lock_irqsave(&spilock, spilockflags);
225 @@ -317,13 +337,10 @@ static uint16_t spi_transfer16(uint16_t
228 printe("spi_sync error %d\n", err);
233 - printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
234 printd("hasMore %d\n", pisnd_spi_has_more());
236 - return (rxbuf[0] << 8) | rxbuf[1];
239 static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
240 @@ -335,7 +352,7 @@ static int spi_read_bytes(char *dst, siz
241 memset(dst, 0, length);
244 - rx = spi_transfer16(0);
245 + rx = spi_transfer16(0);
249 @@ -388,35 +405,90 @@ static struct spi_device *pisnd_spi_find
251 static void pisnd_work_handler(struct work_struct *work)
255 + enum { TRANSFER_SIZE = 4 };
256 + enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
257 + enum { MIDI_BYTES_PER_SECOND = 3125 };
258 + int out_buffer_used = 0;
261 + uint8_t txbuf[TRANSFER_SIZE];
262 + uint8_t rxbuf[TRANSFER_SIZE];
263 + uint8_t midibuf[TRANSFER_SIZE];
267 + unsigned long last_transfer_at = jiffies;
269 if (work == &pisnd_work_process) {
270 if (pisnd_spi_device == NULL)
276 + if (g_midi_output_substream &&
277 + kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
279 - if (g_ledFlashDurationChanged) {
280 - tx = 0xf000 | g_ledFlashDuration;
281 - g_ledFlashDuration = 0;
282 - g_ledFlashDurationChanged = false;
283 - } else if (kfifo_get(&spi_fifo_out, &val)) {
285 + n = snd_rawmidi_transmit_peek(
286 + g_midi_output_substream,
287 + midibuf, sizeof(midibuf)
291 + for (i = 0; i < n; ++i)
296 + snd_rawmidi_transmit_ack(
297 + g_midi_output_substream,
303 - rx = spi_transfer16(tx);
305 + memset(txbuf, 0, sizeof(txbuf));
306 + for (i = 0; i < sizeof(txbuf) &&
307 + out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
312 + if (g_ledFlashDurationChanged) {
314 + txbuf[i+1] = g_ledFlashDuration;
315 + g_ledFlashDuration = 0;
316 + g_ledFlashDurationChanged = false;
317 + } else if (kfifo_get(&spi_fifo_out, &val)) {
325 - kfifo_put(&spi_fifo_in, rx & 0xff);
326 - if (kfifo_len(&spi_fifo_in) > 16
328 - g_recvCallback(g_recvData);
329 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
330 + /* Estimate the Pisound's MIDI output buffer usage, so
331 + * that we don't overflow it. Space in the buffer should
332 + * be becoming available at the UART MIDI byte transfer
337 + (MIDI_BYTES_PER_SECOND / HZ) /
338 + (now - last_transfer_at);
339 + if (out_buffer_used < 0)
340 + out_buffer_used = 0;
341 + last_transfer_at = now;
343 + for (i = 0; i < sizeof(rxbuf); i += 2) {
345 + kfifo_put(&spi_fifo_in, rxbuf[i+1]);
346 + if (kfifo_len(&spi_fifo_in) > 16 &&
348 + g_recvCallback(g_recvData);
354 || !kfifo_is_empty(&spi_fifo_out)
355 || pisnd_spi_has_more()
356 || g_ledFlashDurationChanged
357 @@ -492,7 +564,7 @@ static int spi_read_info(void)
361 - count = tmp & 0xff;
362 + count = tmp & 0xff;
364 for (i = 0; i < count; ++i) {
365 memset(buffer, 0, sizeof(buffer));
366 @@ -628,10 +700,17 @@ static void pisnd_spi_flash_leds(uint8_t
367 pisnd_schedule_process(TASK_PROCESS);
370 -static void pisnd_spi_send(uint8_t val)
371 +static void pisnd_spi_flush(void)
373 + while (!kfifo_is_empty(&spi_fifo_out)) {
375 + flush_workqueue(pisnd_workqueue);
379 +static void pisnd_spi_start(void)
381 - kfifo_put(&spi_fifo_out, val);
382 - printd("schedule from spi_send\n");
383 + printd("schedule from spi_start\n");
384 pisnd_schedule_process(TASK_PROCESS);
387 @@ -765,7 +844,7 @@ static int pisnd_hw_params(
388 struct snd_soc_pcm_runtime *rtd = substream->private_data;
389 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
391 - /* pisound runs on fixed 32 clock counts per channel,
392 + /* Pisound runs on fixed 32 clock counts per channel,
393 * as generated by the master ADC.
395 snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
396 @@ -786,8 +865,8 @@ static int pisnd_hw_params(
399 gpiod_set_value(osr0, true);
400 - gpiod_set_value(osr1, true);
401 - gpiod_set_value(osr2, false);
402 + gpiod_set_value(osr1, false);
403 + gpiod_set_value(osr2, true);
406 gpiod_set_value(osr0, true);
407 @@ -1030,7 +1109,7 @@ static int pisnd_probe(struct platform_d
411 - printi("Detected pisound card:\n");
412 + printi("Detected Pisound card:\n");
413 printi("\tSerial: %s\n", pisnd_spi_get_serial());
414 printi("\tVersion: %s\n", pisnd_spi_get_version());
415 printi("\tId: %s\n", pisnd_spi_get_id());
416 @@ -1119,5 +1198,5 @@ static struct platform_driver pisnd_driv
417 module_platform_driver(pisnd_driver);
419 MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
420 -MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound");
421 +MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
422 MODULE_LICENSE("GPL v2");