diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-01-27 09:39:34 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-01-27 09:39:34 -0200 |
commit | 4a8ba3319764f4a254c0aa97072da0a67636c64b (patch) | |
tree | ad59c5ab5c36f0606c79c7f43198c048cf765b1a /sound/firewire/amdtp.c | |
parent | e32b31ae45c18679c186e67aa41d0e2318cae487 (diff) | |
parent | 26bc420b59a38e4e6685a73345a0def461136dce (diff) | |
download | op-kernel-dev-4a8ba3319764f4a254c0aa97072da0a67636c64b.zip op-kernel-dev-4a8ba3319764f4a254c0aa97072da0a67636c64b.tar.gz |
Merge tag 'v3.19-rc6' into patchwork
This is needed in order to get the media fixes applied on -rc6.
Linux 3.19-rc6
* tag 'v3.19-rc6': (891 commits)
Linux 3.19-rc6
dm: fix handling of multiple internal suspends
hwmon: (i5500_temp) Convert to use ATTRIBUTE_GROUPS macro
hwmon: (i5500_temp) Convert to module_pci_driver
hwmon: (i5500_temp) Don't bind to disabled sensors
hwmon: (i5500_temp) Convert to devm_hwmon_device_register_with_groups
hwmon: (i5500_temp) New driver for the Intel 5500/5520/X58 chipsets
arm64: dts: add baud rate to Juno stdout-path
Revert "platform: x86: dell-laptop: Add support for keyboard backlight"
Revert "Documentation: Add entry for dell-laptop sysfs interface"
dm cache: fix problematic dual use of a single migration count variable
dm cache: share cache-metadata object across inactive and active DM tables
of/unittest: Overlays with sub-devices tests
KVM: x86: SYSENTER emulation is broken
KVM: x86: Fix of previously incomplete fix for CVE-2014-8480
arm64: dump: Fix implicit inclusion of definition for PCI_IOBASE
x86/tsc: Change Fast TSC calibration failed from error to info
x86/apic: Re-enable PCI_MSI support for non-SMP X86_32
x86, mm: Change cachemode exports to non-gpl
x86, tls: Interpret an all-zero struct user_desc as "no segment"
...
Conflicts:
drivers/media/pci/cx23885/cx23885.h
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r-- | sound/firewire/amdtp.c | 71 |
1 files changed, 62 insertions, 9 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 3badc70..0d58018 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -21,7 +21,19 @@ #define CYCLES_PER_SECOND 8000 #define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) -#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ +/* + * Nominally 3125 bytes/second, but the MIDI port's clock might be + * 1% too slow, and the bus clock 100 ppm too fast. + */ +#define MIDI_BYTES_PER_SECOND 3093 + +/* + * Several devices look only at the first eight data blocks. + * In any case, this is more than enough for the MIDI data rate. + */ +#define MAX_MIDI_RX_BLOCKS 8 + +#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ /* isochronous header parameters */ #define ISO_DATA_LENGTH_SHIFT 16 @@ -78,8 +90,6 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->callbacked = false; s->sync_slave = NULL; - s->rx_blocks_for_midi = UINT_MAX; - return 0; } EXPORT_SYMBOL(amdtp_stream_init); @@ -222,6 +232,14 @@ sfc_found: for (i = 0; i < pcm_channels; i++) s->pcm_positions[i] = i; s->midi_position = s->pcm_channels; + + /* + * We do not know the actual MIDI FIFO size of most devices. Just + * assume two bytes, i.e., one byte can be received over the bus while + * the previous one is transmitted over MIDI. + * (The value here is adjusted for midi_ratelimit_per_packet().) + */ + s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; } EXPORT_SYMBOL(amdtp_stream_set_parameters); @@ -463,6 +481,36 @@ static void amdtp_fill_pcm_silence(struct amdtp_stream *s, } } +/* + * To avoid sending MIDI bytes at too high a rate, assume that the receiving + * device has a FIFO, and track how much it is filled. This values increases + * by one whenever we send one byte in a packet, but the FIFO empties at + * a constant rate independent of our packet rate. One packet has syt_interval + * samples, so the number of bytes that empty out of the FIFO, per packet(!), + * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate. To avoid storing + * fractional values, the values in midi_fifo_used[] are measured in bytes + * multiplied by the sample rate. + */ +static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) +{ + int used; + + used = s->midi_fifo_used[port]; + if (used == 0) /* common shortcut */ + return true; + + used -= MIDI_BYTES_PER_SECOND * s->syt_interval; + used = max(used, 0); + s->midi_fifo_used[port] = used; + + return used < s->midi_fifo_limit; +} + +static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) +{ + s->midi_fifo_used[port] += amdtp_rate_table[s->sfc]; +} + static void amdtp_fill_midi(struct amdtp_stream *s, __be32 *buffer, unsigned int frames) { @@ -470,16 +518,21 @@ static void amdtp_fill_midi(struct amdtp_stream *s, u8 *b; for (f = 0; f < frames; f++) { - buffer[s->midi_position] = 0; b = (u8 *)&buffer[s->midi_position]; port = (s->data_block_counter + f) % 8; - if ((f >= s->rx_blocks_for_midi) || - (s->midi[port] == NULL) || - (snd_rawmidi_transmit(s->midi[port], b + 1, 1) <= 0)) - b[0] = 0x80; - else + if (f < MAX_MIDI_RX_BLOCKS && + midi_ratelimit_per_packet(s, port) && + s->midi[port] != NULL && + snd_rawmidi_transmit(s->midi[port], &b[1], 1) == 1) { + midi_rate_use_one_byte(s, port); b[0] = 0x81; + } else { + b[0] = 0x80; + b[1] = 0; + } + b[2] = 0; + b[3] = 0; buffer += s->data_block_quadlets; } |