diff options
| author | Clemens Ladisch <clemens@ladisch.de> | 2011-03-15 02:53:21 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-03-15 03:42:22 -0400 |
| commit | 31ef9134eb52636d383a7d0626cbbd345cb94f2f (patch) | |
| tree | 5d994932a8773e844190cbea43ef31d67f605cf8 | |
| parent | a5abba989deceb731047425812d268daf7536575 (diff) | |
ALSA: add LaCie FireWire Speakers/Griffin FireWave Surround driver
Add a driver for two playback-only FireWire devices based on the OXFW970
chip.
v2: better AMDTP API abstraction; fix fw_unit leak; small fixes
v3: cache the iPCR value
v4: FireWave constraints; fix fw_device reference counting;
fix PCR caching; small changes and fixes
v5: volume/mute support; fix crashing due to pcm stop races
v6: fix build; one-channel volume for LaCie
v7: use signed values to make volume (range checks) work; fix function
block IDs for volume/mute; always use channel 0 for LaCie volume
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Tested-by: Jay Fenlason <fenlason@redhat.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | drivers/firewire/core-iso.c | 1 | ||||
| -rw-r--r-- | drivers/firewire/core.h | 3 | ||||
| -rw-r--r-- | include/linux/firewire.h | 7 | ||||
| -rw-r--r-- | sound/Kconfig | 2 | ||||
| -rw-r--r-- | sound/Makefile | 2 | ||||
| -rw-r--r-- | sound/firewire/Kconfig | 25 | ||||
| -rw-r--r-- | sound/firewire/Makefile | 6 | ||||
| -rw-r--r-- | sound/firewire/amdtp.c | 549 | ||||
| -rw-r--r-- | sound/firewire/amdtp.h | 157 | ||||
| -rw-r--r-- | sound/firewire/cmp.c | 305 | ||||
| -rw-r--r-- | sound/firewire/cmp.h | 41 | ||||
| -rw-r--r-- | sound/firewire/fcp.c | 223 | ||||
| -rw-r--r-- | sound/firewire/fcp.h | 12 | ||||
| -rw-r--r-- | sound/firewire/iso-resources.c | 224 | ||||
| -rw-r--r-- | sound/firewire/iso-resources.h | 39 | ||||
| -rw-r--r-- | sound/firewire/lib.c | 85 | ||||
| -rw-r--r-- | sound/firewire/lib.h | 19 | ||||
| -rw-r--r-- | sound/firewire/packets-buffer.c | 74 | ||||
| -rw-r--r-- | sound/firewire/packets-buffer.h | 26 | ||||
| -rw-r--r-- | sound/firewire/speakers.c | 855 |
20 files changed, 2651 insertions, 4 deletions
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index c003fa4e2db1..c8658888e67b 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c | |||
| @@ -362,3 +362,4 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, | |||
| 362 | *channel = ret; | 362 | *channel = ret; |
| 363 | } | 363 | } |
| 364 | } | 364 | } |
| 365 | EXPORT_SYMBOL(fw_iso_resource_manage); | ||
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index f8dfcf1c6cbe..25e729cde2f7 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h | |||
| @@ -147,9 +147,6 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event); | |||
| 147 | /* -iso */ | 147 | /* -iso */ |
| 148 | 148 | ||
| 149 | int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma); | 149 | int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma); |
| 150 | void fw_iso_resource_manage(struct fw_card *card, int generation, | ||
| 151 | u64 channels_mask, int *channel, int *bandwidth, | ||
| 152 | bool allocate, __be32 buffer[2]); | ||
| 153 | 150 | ||
| 154 | 151 | ||
| 155 | /* -topology */ | 152 | /* -topology */ |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 9a3f5f9383f6..fc023d67676f 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
| @@ -42,6 +42,10 @@ | |||
| 42 | #define CSR_BROADCAST_CHANNEL 0x234 | 42 | #define CSR_BROADCAST_CHANNEL 0x234 |
| 43 | #define CSR_CONFIG_ROM 0x400 | 43 | #define CSR_CONFIG_ROM 0x400 |
| 44 | #define CSR_CONFIG_ROM_END 0x800 | 44 | #define CSR_CONFIG_ROM_END 0x800 |
| 45 | #define CSR_OMPR 0x900 | ||
| 46 | #define CSR_OPCR(i) (0x904 + (i) * 4) | ||
| 47 | #define CSR_IMPR 0x980 | ||
| 48 | #define CSR_IPCR(i) (0x984 + (i) * 4) | ||
| 45 | #define CSR_FCP_COMMAND 0xB00 | 49 | #define CSR_FCP_COMMAND 0xB00 |
| 46 | #define CSR_FCP_RESPONSE 0xD00 | 50 | #define CSR_FCP_RESPONSE 0xD00 |
| 47 | #define CSR_FCP_END 0xF00 | 51 | #define CSR_FCP_END 0xF00 |
| @@ -441,5 +445,8 @@ int fw_iso_context_start(struct fw_iso_context *ctx, | |||
| 441 | int cycle, int sync, int tags); | 445 | int cycle, int sync, int tags); |
| 442 | int fw_iso_context_stop(struct fw_iso_context *ctx); | 446 | int fw_iso_context_stop(struct fw_iso_context *ctx); |
| 443 | void fw_iso_context_destroy(struct fw_iso_context *ctx); | 447 | void fw_iso_context_destroy(struct fw_iso_context *ctx); |
| 448 | void fw_iso_resource_manage(struct fw_card *card, int generation, | ||
| 449 | u64 channels_mask, int *channel, int *bandwidth, | ||
| 450 | bool allocate, __be32 buffer[2]); | ||
| 444 | 451 | ||
| 445 | #endif /* _LINUX_FIREWIRE_H */ | 452 | #endif /* _LINUX_FIREWIRE_H */ |
diff --git a/sound/Kconfig b/sound/Kconfig index fcad760f5691..1fef141ef8e7 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
| @@ -97,6 +97,8 @@ source "sound/sh/Kconfig" | |||
| 97 | # here assuming USB is defined before ALSA | 97 | # here assuming USB is defined before ALSA |
| 98 | source "sound/usb/Kconfig" | 98 | source "sound/usb/Kconfig" |
| 99 | 99 | ||
| 100 | source "sound/firewire/Kconfig" | ||
| 101 | |||
| 100 | # the following will depend on the order of config. | 102 | # the following will depend on the order of config. |
| 101 | # here assuming PCMCIA is defined before ALSA | 103 | # here assuming PCMCIA is defined before ALSA |
| 102 | source "sound/pcmcia/Kconfig" | 104 | source "sound/pcmcia/Kconfig" |
diff --git a/sound/Makefile b/sound/Makefile index ec467decfa79..ce9132b1c395 100644 --- a/sound/Makefile +++ b/sound/Makefile | |||
| @@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o | |||
| 6 | obj-$(CONFIG_SOUND_PRIME) += oss/ | 6 | obj-$(CONFIG_SOUND_PRIME) += oss/ |
| 7 | obj-$(CONFIG_DMASOUND) += oss/ | 7 | obj-$(CONFIG_DMASOUND) += oss/ |
| 8 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ | 8 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ |
| 9 | sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ | 9 | firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ |
| 10 | obj-$(CONFIG_SND_AOA) += aoa/ | 10 | obj-$(CONFIG_SND_AOA) += aoa/ |
| 11 | 11 | ||
| 12 | # This one must be compilable even if sound is configured out | 12 | # This one must be compilable even if sound is configured out |
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig new file mode 100644 index 000000000000..e486f48660fb --- /dev/null +++ b/sound/firewire/Kconfig | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | menuconfig SND_FIREWIRE | ||
| 2 | bool "FireWire sound devices" | ||
| 3 | depends on FIREWIRE | ||
| 4 | default y | ||
| 5 | help | ||
| 6 | Support for IEEE-1394/FireWire/iLink sound devices. | ||
| 7 | |||
| 8 | if SND_FIREWIRE && FIREWIRE | ||
| 9 | |||
| 10 | config SND_FIREWIRE_LIB | ||
| 11 | tristate | ||
| 12 | depends on SND_PCM | ||
| 13 | |||
| 14 | config SND_FIREWIRE_SPEAKERS | ||
| 15 | tristate "FireWire speakers" | ||
| 16 | select SND_PCM | ||
| 17 | select SND_FIREWIRE_LIB | ||
| 18 | help | ||
| 19 | Say Y here to include support for the Griffin FireWave Surround | ||
| 20 | and the LaCie FireWire Speakers. | ||
| 21 | |||
| 22 | To compile this driver as a module, choose M here: the module | ||
| 23 | will be called snd-firewire-speakers. | ||
| 24 | |||
| 25 | endif # SND_FIREWIRE | ||
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile new file mode 100644 index 000000000000..e5b1634d9ad4 --- /dev/null +++ b/sound/firewire/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ | ||
| 2 | fcp.o cmp.o amdtp.o | ||
| 3 | snd-firewire-speakers-objs := speakers.o | ||
| 4 | |||
| 5 | obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o | ||
| 6 | obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o | ||
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c new file mode 100644 index 000000000000..09f70ee4d04a --- /dev/null +++ b/sound/firewire/amdtp.c | |||
| @@ -0,0 +1,549 @@ | |||
| 1 | /* | ||
| 2 | * Audio and Music Data Transmission Protocol (IEC 61883-6) streams | ||
| 3 | * with Common Isochronous Packet (IEC 61883-1) headers | ||
| 4 | * | ||
| 5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/err.h> | ||
| 11 | #include <linux/firewire.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <sound/pcm.h> | ||
| 15 | #include "amdtp.h" | ||
| 16 | |||
| 17 | #define TICKS_PER_CYCLE 3072 | ||
| 18 | #define CYCLES_PER_SECOND 8000 | ||
| 19 | #define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) | ||
| 20 | |||
| 21 | #define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ | ||
| 22 | |||
| 23 | #define TAG_CIP 1 | ||
| 24 | |||
| 25 | #define CIP_EOH (1u << 31) | ||
| 26 | #define CIP_FMT_AM (0x10 << 24) | ||
| 27 | #define AMDTP_FDF_AM824 (0 << 19) | ||
| 28 | #define AMDTP_FDF_SFC_SHIFT 16 | ||
| 29 | |||
| 30 | /* TODO: make these configurable */ | ||
| 31 | #define INTERRUPT_INTERVAL 16 | ||
| 32 | #define QUEUE_LENGTH 48 | ||
| 33 | |||
| 34 | /** | ||
| 35 | * amdtp_out_stream_init - initialize an AMDTP output stream structure | ||
| 36 | * @s: the AMDTP output stream to initialize | ||
| 37 | * @unit: the target of the stream | ||
| 38 | * @flags: the packet transmission method to use | ||
| 39 | */ | ||
| 40 | int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, | ||
| 41 | enum cip_out_flags flags) | ||
| 42 | { | ||
| 43 | if (flags != CIP_NONBLOCKING) | ||
| 44 | return -EINVAL; | ||
| 45 | |||
| 46 | s->unit = fw_unit_get(unit); | ||
| 47 | s->flags = flags; | ||
| 48 | s->context = ERR_PTR(-1); | ||
| 49 | mutex_init(&s->mutex); | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL(amdtp_out_stream_init); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * amdtp_out_stream_destroy - free stream resources | ||
| 57 | * @s: the AMDTP output stream to destroy | ||
| 58 | */ | ||
| 59 | void amdtp_out_stream_destroy(struct amdtp_out_stream *s) | ||
| 60 | { | ||
| 61 | WARN_ON(!IS_ERR(s->context)); | ||
| 62 | mutex_destroy(&s->mutex); | ||
| 63 | fw_unit_put(s->unit); | ||
| 64 | } | ||
| 65 | EXPORT_SYMBOL(amdtp_out_stream_destroy); | ||
| 66 | |||
| 67 | /** | ||
| 68 | * amdtp_out_stream_set_rate - set the sample rate | ||
| 69 | * @s: the AMDTP output stream to configure | ||
| 70 | * @rate: the sample rate | ||
| 71 | * | ||
| 72 | * The sample rate must be set before the stream is started, and must not be | ||
| 73 | * changed while the stream is running. | ||
| 74 | */ | ||
| 75 | void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) | ||
| 76 | { | ||
| 77 | static const struct { | ||
| 78 | unsigned int rate; | ||
| 79 | unsigned int syt_interval; | ||
| 80 | } rate_info[] = { | ||
| 81 | [CIP_SFC_32000] = { 32000, 8, }, | ||
| 82 | [CIP_SFC_44100] = { 44100, 8, }, | ||
| 83 | [CIP_SFC_48000] = { 48000, 8, }, | ||
| 84 | [CIP_SFC_88200] = { 88200, 16, }, | ||
| 85 | [CIP_SFC_96000] = { 96000, 16, }, | ||
| 86 | [CIP_SFC_176400] = { 176400, 32, }, | ||
| 87 | [CIP_SFC_192000] = { 192000, 32, }, | ||
| 88 | }; | ||
| 89 | unsigned int sfc; | ||
| 90 | |||
| 91 | if (WARN_ON(!IS_ERR(s->context))) | ||
| 92 | return; | ||
| 93 | |||
| 94 | for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) | ||
| 95 | if (rate_info[sfc].rate == rate) { | ||
| 96 | s->sfc = sfc; | ||
| 97 | s->syt_interval = rate_info[sfc].syt_interval; | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | WARN_ON(1); | ||
| 101 | } | ||
| 102 | EXPORT_SYMBOL(amdtp_out_stream_set_rate); | ||
| 103 | |||
| 104 | /** | ||
| 105 | * amdtp_out_stream_get_max_payload - get the stream's packet size | ||
| 106 | * @s: the AMDTP output stream | ||
| 107 | * | ||
| 108 | * This function must not be called before the stream has been configured | ||
| 109 | * with amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and | ||
| 110 | * amdtp_out_stream_set_midi(). | ||
| 111 | */ | ||
| 112 | unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) | ||
| 113 | { | ||
| 114 | static const unsigned int max_data_blocks[] = { | ||
| 115 | [CIP_SFC_32000] = 4, | ||
| 116 | [CIP_SFC_44100] = 6, | ||
| 117 | [CIP_SFC_48000] = 6, | ||
| 118 | [CIP_SFC_88200] = 12, | ||
| 119 | [CIP_SFC_96000] = 12, | ||
| 120 | [CIP_SFC_176400] = 23, | ||
| 121 | [CIP_SFC_192000] = 24, | ||
| 122 | }; | ||
| 123 | |||
| 124 | s->data_block_quadlets = s->pcm_channels; | ||
| 125 | s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); | ||
| 126 | |||
| 127 | return 8 + max_data_blocks[s->sfc] * 4 * s->data_block_quadlets; | ||
| 128 | } | ||
| 129 | EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); | ||
| 130 | |||
| 131 | static void amdtp_write_s16(struct amdtp_out_stream *s, | ||
| 132 | struct snd_pcm_substream *pcm, | ||
| 133 | __be32 *buffer, unsigned int frames); | ||
| 134 | static void amdtp_write_s32(struct amdtp_out_stream *s, | ||
| 135 | struct snd_pcm_substream *pcm, | ||
| 136 | __be32 *buffer, unsigned int frames); | ||
| 137 | |||
| 138 | /** | ||
| 139 | * amdtp_out_stream_set_pcm_format - set the PCM format | ||
| 140 | * @s: the AMDTP output stream to configure | ||
| 141 | * @format: the format of the ALSA PCM device | ||
| 142 | * | ||
| 143 | * The sample format must be set before the stream is started, and must not be | ||
| 144 | * changed while the stream is running. | ||
| 145 | */ | ||
| 146 | void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, | ||
| 147 | snd_pcm_format_t format) | ||
| 148 | { | ||
| 149 | if (WARN_ON(!IS_ERR(s->context))) | ||
| 150 | return; | ||
| 151 | |||
| 152 | switch (format) { | ||
| 153 | default: | ||
| 154 | WARN_ON(1); | ||
| 155 | /* fall through */ | ||
| 156 | case SNDRV_PCM_FORMAT_S16: | ||
| 157 | s->transfer_samples = amdtp_write_s16; | ||
| 158 | break; | ||
| 159 | case SNDRV_PCM_FORMAT_S32: | ||
| 160 | s->transfer_samples = amdtp_write_s32; | ||
| 161 | break; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format); | ||
| 165 | |||
| 166 | static unsigned int calculate_data_blocks(struct amdtp_out_stream *s) | ||
| 167 | { | ||
| 168 | unsigned int phase, data_blocks; | ||
| 169 | |||
| 170 | if (!cip_sfc_is_base_44100(s->sfc)) { | ||
| 171 | /* Sample_rate / 8000 is an integer, and precomputed. */ | ||
| 172 | data_blocks = s->data_block_state; | ||
| 173 | } else { | ||
| 174 | phase = s->data_block_state; | ||
| 175 | |||
| 176 | /* | ||
| 177 | * This calculates the number of data blocks per packet so that | ||
| 178 | * 1) the overall rate is correct and exactly synchronized to | ||
| 179 | * the bus clock, and | ||
| 180 | * 2) packets with a rounded-up number of blocks occur as early | ||
| 181 | * as possible in the sequence (to prevent underruns of the | ||
| 182 | * device's buffer). | ||
| 183 | */ | ||
| 184 | if (s->sfc == CIP_SFC_44100) | ||
| 185 | /* 6 6 5 6 5 6 5 ... */ | ||
| 186 | data_blocks = 5 + ((phase & 1) ^ | ||
| 187 | (phase == 0 || phase >= 40)); | ||
| 188 | else | ||
| 189 | /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */ | ||
| 190 | data_blocks = 11 * (s->sfc >> 1) + (phase == 0); | ||
| 191 | if (++phase >= (80 >> (s->sfc >> 1))) | ||
| 192 | phase = 0; | ||
| 193 | s->data_block_state = phase; | ||
| 194 | } | ||
| 195 | |||
| 196 | return data_blocks; | ||
| 197 | } | ||
| 198 | |||
| 199 | static unsigned int calculate_syt(struct amdtp_out_stream *s, | ||
| 200 | unsigned int cycle) | ||
| 201 | { | ||
| 202 | unsigned int syt_offset, phase, index, syt; | ||
| 203 | |||
| 204 | if (s->last_syt_offset < TICKS_PER_CYCLE) { | ||
| 205 | if (!cip_sfc_is_base_44100(s->sfc)) | ||
| 206 | syt_offset = s->last_syt_offset + s->syt_offset_state; | ||
| 207 | else { | ||
| 208 | /* | ||
| 209 | * The time, in ticks, of the n'th SYT_INTERVAL sample is: | ||
| 210 | * n * SYT_INTERVAL * 24576000 / sample_rate | ||
| 211 | * Modulo TICKS_PER_CYCLE, the difference between successive | ||
| 212 | * elements is about 1386.23. Rounding the results of this | ||
| 213 | * formula to the SYT precision results in a sequence of | ||
| 214 | * differences that begins with: | ||
| 215 | * 1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ... | ||
| 216 | * This code generates _exactly_ the same sequence. | ||
| 217 | */ | ||
| 218 | phase = s->syt_offset_state; | ||
| 219 | index = phase % 13; | ||
| 220 | syt_offset = s->last_syt_offset; | ||
| 221 | syt_offset += 1386 + ((index && !(index & 3)) || | ||
| 222 | phase == 146); | ||
| 223 | if (++phase >= 147) | ||
| 224 | phase = 0; | ||
| 225 | s->syt_offset_state = phase; | ||
| 226 | } | ||
| 227 | } else | ||
| 228 | syt_offset = s->last_syt_offset - TICKS_PER_CYCLE; | ||
| 229 | s->last_syt_offset = syt_offset; | ||
| 230 | |||
| 231 | syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; | ||
| 232 | syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12; | ||
| 233 | syt += syt_offset % TICKS_PER_CYCLE; | ||
| 234 | |||
| 235 | return syt & 0xffff; | ||
| 236 | } | ||
| 237 | |||
| 238 | static void amdtp_write_s32(struct amdtp_out_stream *s, | ||
| 239 | struct snd_pcm_substream *pcm, | ||
| 240 | __be32 *buffer, unsigned int frames) | ||
| 241 | { | ||
| 242 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
| 243 | unsigned int channels, remaining_frames, frame_step, i, c; | ||
| 244 | const u32 *src; | ||
| 245 | |||
| 246 | channels = s->pcm_channels; | ||
| 247 | src = (void *)runtime->dma_area + | ||
| 248 | s->pcm_buffer_pointer * (runtime->frame_bits / 8); | ||
| 249 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
| 250 | frame_step = s->data_block_quadlets - channels; | ||
| 251 | |||
| 252 | for (i = 0; i < frames; ++i) { | ||
| 253 | for (c = 0; c < channels; ++c) { | ||
| 254 | *buffer = cpu_to_be32((*src >> 8) | 0x40000000); | ||
| 255 | src++; | ||
| 256 | buffer++; | ||
| 257 | } | ||
| 258 | buffer += frame_step; | ||
| 259 | if (--remaining_frames == 0) | ||
| 260 | src = (void *)runtime->dma_area; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | static void amdtp_write_s16(struct amdtp_out_stream *s, | ||
| 265 | struct snd_pcm_substream *pcm, | ||
| 266 | __be32 *buffer, unsigned int frames) | ||
| 267 | { | ||
| 268 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
| 269 | unsigned int channels, remaining_frames, frame_step, i, c; | ||
| 270 | const u16 *src; | ||
| 271 | |||
| 272 | channels = s->pcm_channels; | ||
| 273 | src = (void *)runtime->dma_area + | ||
| 274 | s->pcm_buffer_pointer * (runtime->frame_bits / 8); | ||
| 275 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
| 276 | frame_step = s->data_block_quadlets - channels; | ||
| 277 | |||
| 278 | for (i = 0; i < frames; ++i) { | ||
| 279 | for (c = 0; c < channels; ++c) { | ||
| 280 | *buffer = cpu_to_be32((*src << 8) | 0x40000000); | ||
| 281 | src++; | ||
| 282 | buffer++; | ||
| 283 | } | ||
| 284 | buffer += frame_step; | ||
| 285 | if (--remaining_frames == 0) | ||
| 286 | src = (void *)runtime->dma_area; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s, | ||
| 291 | __be32 *buffer, unsigned int frames) | ||
| 292 | { | ||
| 293 | unsigned int i, c; | ||
| 294 | |||
| 295 | for (i = 0; i < frames; ++i) { | ||
| 296 | for (c = 0; c < s->pcm_channels; ++c) | ||
| 297 | buffer[c] = cpu_to_be32(0x40000000); | ||
| 298 | buffer += s->data_block_quadlets; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | static void amdtp_fill_midi(struct amdtp_out_stream *s, | ||
| 303 | __be32 *buffer, unsigned int frames) | ||
| 304 | { | ||
| 305 | unsigned int i; | ||
| 306 | |||
| 307 | for (i = 0; i < frames; ++i) | ||
| 308 | buffer[s->pcm_channels + i * s->data_block_quadlets] = | ||
| 309 | cpu_to_be32(0x80000000); | ||
| 310 | } | ||
| 311 | |||
| 312 | static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) | ||
| 313 | { | ||
| 314 | __be32 *buffer; | ||
| 315 | unsigned int data_blocks, syt, ptr; | ||
| 316 | struct snd_pcm_substream *pcm; | ||
| 317 | struct fw_iso_packet packet; | ||
| 318 | int err; | ||
| 319 | |||
| 320 | data_blocks = calculate_data_blocks(s); | ||
| 321 | syt = calculate_syt(s, cycle); | ||
| 322 | |||
| 323 | buffer = s->buffer.packets[s->packet_counter].buffer; | ||
| 324 | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | | ||
| 325 | (s->data_block_quadlets << 16) | | ||
| 326 | s->data_block_counter); | ||
| 327 | buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 | | ||
| 328 | (s->sfc << AMDTP_FDF_SFC_SHIFT) | syt); | ||
| 329 | buffer += 2; | ||
| 330 | |||
| 331 | pcm = ACCESS_ONCE(s->pcm); | ||
| 332 | if (pcm) | ||
| 333 | s->transfer_samples(s, pcm, buffer, data_blocks); | ||
| 334 | else | ||
| 335 | amdtp_fill_pcm_silence(s, buffer, data_blocks); | ||
| 336 | if (s->midi_ports) | ||
| 337 | amdtp_fill_midi(s, buffer, data_blocks); | ||
| 338 | |||
| 339 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | ||
| 340 | |||
| 341 | packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; | ||
| 342 | packet.interrupt = IS_ALIGNED(s->packet_counter + 1, | ||
| 343 | INTERRUPT_INTERVAL); | ||
| 344 | packet.skip = 0; | ||
| 345 | packet.tag = TAG_CIP; | ||
| 346 | packet.sy = 0; | ||
| 347 | packet.header_length = 0; | ||
| 348 | |||
| 349 | err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer, | ||
| 350 | s->buffer.packets[s->packet_counter].offset); | ||
| 351 | if (err < 0) | ||
| 352 | dev_err(&s->unit->device, "queueing error: %d\n", err); | ||
| 353 | |||
| 354 | if (++s->packet_counter >= QUEUE_LENGTH) | ||
| 355 | s->packet_counter = 0; | ||
| 356 | |||
| 357 | if (pcm) { | ||
| 358 | ptr = s->pcm_buffer_pointer + data_blocks; | ||
| 359 | if (ptr >= pcm->runtime->buffer_size) | ||
| 360 | ptr -= pcm->runtime->buffer_size; | ||
| 361 | ACCESS_ONCE(s->pcm_buffer_pointer) = ptr; | ||
| 362 | |||
| 363 | s->pcm_period_pointer += data_blocks; | ||
| 364 | if (s->pcm_period_pointer >= pcm->runtime->period_size) { | ||
| 365 | s->pcm_period_pointer -= pcm->runtime->period_size; | ||
| 366 | snd_pcm_period_elapsed(pcm); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | static void out_packet_callback(struct fw_iso_context *context, u32 cycle, | ||
| 372 | size_t header_length, void *header, void *data) | ||
| 373 | { | ||
| 374 | struct amdtp_out_stream *s = data; | ||
| 375 | unsigned int i, packets = header_length / 4; | ||
| 376 | |||
| 377 | /* | ||
| 378 | * Compute the cycle of the last queued packet. | ||
| 379 | * (We need only the four lowest bits for the SYT, so we can ignore | ||
| 380 | * that bits 0-11 must wrap around at 3072.) | ||
| 381 | */ | ||
| 382 | cycle += QUEUE_LENGTH - packets; | ||
| 383 | |||
| 384 | for (i = 0; i < packets; ++i) | ||
| 385 | queue_out_packet(s, ++cycle); | ||
| 386 | } | ||
| 387 | |||
| 388 | static int queue_initial_skip_packets(struct amdtp_out_stream *s) | ||
| 389 | { | ||
| 390 | struct fw_iso_packet skip_packet = { | ||
| 391 | .skip = 1, | ||
| 392 | }; | ||
| 393 | unsigned int i; | ||
| 394 | int err; | ||
| 395 | |||
| 396 | for (i = 0; i < QUEUE_LENGTH; ++i) { | ||
| 397 | skip_packet.interrupt = IS_ALIGNED(s->packet_counter + 1, | ||
| 398 | INTERRUPT_INTERVAL); | ||
| 399 | err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0); | ||
| 400 | if (err < 0) | ||
| 401 | return err; | ||
| 402 | if (++s->packet_counter >= QUEUE_LENGTH) | ||
| 403 | s->packet_counter = 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | /** | ||
| 410 | * amdtp_out_stream_start - start sending packets | ||
| 411 | * @s: the AMDTP output stream to start | ||
| 412 | * @channel: the isochronous channel on the bus | ||
| 413 | * @speed: firewire speed code | ||
| 414 | * | ||
| 415 | * The stream cannot be started until it has been configured with | ||
| 416 | * amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and | ||
| 417 | * amdtp_out_stream_set_midi(); and it must be started before any | ||
| 418 | * PCM or MIDI device can be started. | ||
| 419 | */ | ||
| 420 | int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) | ||
| 421 | { | ||
| 422 | static const struct { | ||
| 423 | unsigned int data_block; | ||
| 424 | unsigned int syt_offset; | ||
| 425 | } initial_state[] = { | ||
| 426 | [CIP_SFC_32000] = { 4, 3072 }, | ||
| 427 | [CIP_SFC_48000] = { 6, 1024 }, | ||
| 428 | [CIP_SFC_96000] = { 12, 1024 }, | ||
| 429 | [CIP_SFC_192000] = { 24, 1024 }, | ||
| 430 | [CIP_SFC_44100] = { 0, 67 }, | ||
| 431 | [CIP_SFC_88200] = { 0, 67 }, | ||
| 432 | [CIP_SFC_176400] = { 0, 67 }, | ||
| 433 | }; | ||
| 434 | int err; | ||
| 435 | |||
| 436 | mutex_lock(&s->mutex); | ||
| 437 | |||
| 438 | if (WARN_ON(!IS_ERR(s->context) || | ||
| 439 | (!s->pcm_channels && !s->midi_ports))) { | ||
| 440 | err = -EBADFD; | ||
| 441 | goto err_unlock; | ||
| 442 | } | ||
| 443 | |||
| 444 | s->data_block_state = initial_state[s->sfc].data_block; | ||
| 445 | s->syt_offset_state = initial_state[s->sfc].syt_offset; | ||
| 446 | s->last_syt_offset = TICKS_PER_CYCLE; | ||
| 447 | |||
| 448 | err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH, | ||
| 449 | amdtp_out_stream_get_max_payload(s), | ||
| 450 | DMA_TO_DEVICE); | ||
| 451 | if (err < 0) | ||
| 452 | goto err_unlock; | ||
| 453 | |||
| 454 | s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, | ||
| 455 | FW_ISO_CONTEXT_TRANSMIT, | ||
| 456 | channel, speed, 0, | ||
| 457 | out_packet_callback, s); | ||
| 458 | if (IS_ERR(s->context)) { | ||
| 459 | err = PTR_ERR(s->context); | ||
| 460 | if (err == -EBUSY) | ||
| 461 | dev_err(&s->unit->device, | ||
| 462 | "no free output stream on this controller\n"); | ||
| 463 | goto err_buffer; | ||
| 464 | } | ||
| 465 | |||
| 466 | amdtp_out_stream_update(s); | ||
| 467 | |||
| 468 | s->packet_counter = 0; | ||
| 469 | s->data_block_counter = 0; | ||
| 470 | err = queue_initial_skip_packets(s); | ||
| 471 | if (err < 0) | ||
| 472 | goto err_context; | ||
| 473 | |||
| 474 | err = fw_iso_context_start(s->context, -1, 0, 0); | ||
| 475 | if (err < 0) | ||
| 476 | goto err_context; | ||
| 477 | |||
| 478 | mutex_unlock(&s->mutex); | ||
| 479 | |||
| 480 | return 0; | ||
| 481 | |||
| 482 | err_context: | ||
| 483 | fw_iso_context_destroy(s->context); | ||
| 484 | s->context = ERR_PTR(-1); | ||
| 485 | err_buffer: | ||
| 486 | iso_packets_buffer_destroy(&s->buffer, s->unit); | ||
| 487 | err_unlock: | ||
| 488 | mutex_unlock(&s->mutex); | ||
| 489 | |||
| 490 | return err; | ||
| 491 | } | ||
| 492 | EXPORT_SYMBOL(amdtp_out_stream_start); | ||
| 493 | |||
| 494 | /** | ||
| 495 | * amdtp_out_stream_update - update the stream after a bus reset | ||
| 496 | * @s: the AMDTP output stream | ||
| 497 | */ | ||
| 498 | void amdtp_out_stream_update(struct amdtp_out_stream *s) | ||
| 499 | { | ||
| 500 | ACCESS_ONCE(s->source_node_id_field) = | ||
| 501 | (fw_parent_device(s->unit)->card->node_id & 0x3f) << 24; | ||
| 502 | } | ||
| 503 | EXPORT_SYMBOL(amdtp_out_stream_update); | ||
| 504 | |||
| 505 | /** | ||
| 506 | * amdtp_out_stream_stop - stop sending packets | ||
| 507 | * @s: the AMDTP output stream to stop | ||
| 508 | * | ||
| 509 | * All PCM and MIDI devices of the stream must be stopped before the stream | ||
| 510 | * itself can be stopped. | ||
| 511 | */ | ||
| 512 | void amdtp_out_stream_stop(struct amdtp_out_stream *s) | ||
| 513 | { | ||
| 514 | mutex_lock(&s->mutex); | ||
| 515 | |||
| 516 | if (IS_ERR(s->context)) { | ||
| 517 | mutex_unlock(&s->mutex); | ||
| 518 | return; | ||
| 519 | } | ||
| 520 | |||
| 521 | fw_iso_context_stop(s->context); | ||
| 522 | fw_iso_context_destroy(s->context); | ||
| 523 | s->context = ERR_PTR(-1); | ||
| 524 | iso_packets_buffer_destroy(&s->buffer, s->unit); | ||
| 525 | |||
| 526 | mutex_unlock(&s->mutex); | ||
| 527 | } | ||
| 528 | EXPORT_SYMBOL(amdtp_out_stream_stop); | ||
| 529 | |||
| 530 | /** | ||
| 531 | * amdtp_out_stream_pcm_abort - abort the running PCM device | ||
| 532 | * @s: the AMDTP stream about to be stopped | ||
| 533 | * | ||
| 534 | * If the isochronous stream needs to be stopped asynchronously, call this | ||
| 535 | * function first to stop the PCM device. | ||
| 536 | */ | ||
| 537 | void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s) | ||
| 538 | { | ||
| 539 | struct snd_pcm_substream *pcm; | ||
| 540 | |||
| 541 | pcm = ACCESS_ONCE(s->pcm); | ||
| 542 | if (pcm) { | ||
| 543 | snd_pcm_stream_lock_irq(pcm); | ||
| 544 | if (snd_pcm_running(pcm)) | ||
| 545 | snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN); | ||
| 546 | snd_pcm_stream_unlock_irq(pcm); | ||
| 547 | } | ||
| 548 | } | ||
| 549 | EXPORT_SYMBOL(amdtp_out_stream_pcm_abort); | ||
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h new file mode 100644 index 000000000000..02dc1a664b55 --- /dev/null +++ b/sound/firewire/amdtp.h | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | #ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED | ||
| 2 | #define SOUND_FIREWIRE_AMDTP_H_INCLUDED | ||
| 3 | |||
| 4 | #include <linux/mutex.h> | ||
| 5 | #include <linux/spinlock.h> | ||
| 6 | #include "packets-buffer.h" | ||
| 7 | |||
| 8 | /** | ||
| 9 | * enum cip_out_flags - describes details of the streaming protocol | ||
| 10 | * @CIP_NONBLOCKING: In non-blocking mode, each packet contains | ||
| 11 | * sample_rate/8000 samples, with rounding up or down to adjust | ||
| 12 | * for clock skew and left-over fractional samples. This should | ||
| 13 | * be used if supported by the device. | ||
| 14 | */ | ||
| 15 | enum cip_out_flags { | ||
| 16 | CIP_NONBLOCKING = 0, | ||
| 17 | }; | ||
| 18 | |||
| 19 | /** | ||
| 20 | * enum cip_sfc - a stream's sample rate | ||
| 21 | */ | ||
| 22 | enum cip_sfc { | ||
| 23 | CIP_SFC_32000 = 0, | ||
| 24 | CIP_SFC_44100 = 1, | ||
| 25 | CIP_SFC_48000 = 2, | ||
| 26 | CIP_SFC_88200 = 3, | ||
| 27 | CIP_SFC_96000 = 4, | ||
| 28 | CIP_SFC_176400 = 5, | ||
| 29 | CIP_SFC_192000 = 6, | ||
| 30 | }; | ||
| 31 | |||
| 32 | #define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ | ||
| 33 | SNDRV_PCM_FMTBIT_S32) | ||
| 34 | |||
| 35 | struct fw_unit; | ||
| 36 | struct fw_iso_context; | ||
| 37 | struct snd_pcm_substream; | ||
| 38 | |||
| 39 | struct amdtp_out_stream { | ||
| 40 | struct fw_unit *unit; | ||
| 41 | enum cip_out_flags flags; | ||
| 42 | struct fw_iso_context *context; | ||
| 43 | struct mutex mutex; | ||
| 44 | |||
| 45 | enum cip_sfc sfc; | ||
| 46 | unsigned int data_block_quadlets; | ||
| 47 | unsigned int pcm_channels; | ||
| 48 | unsigned int midi_ports; | ||
| 49 | void (*transfer_samples)(struct amdtp_out_stream *s, | ||
| 50 | struct snd_pcm_substream *pcm, | ||
| 51 | __be32 *buffer, unsigned int frames); | ||
| 52 | |||
| 53 | unsigned int syt_interval; | ||
| 54 | unsigned int source_node_id_field; | ||
| 55 | struct iso_packets_buffer buffer; | ||
| 56 | |||
| 57 | struct snd_pcm_substream *pcm; | ||
| 58 | |||
| 59 | unsigned int packet_counter; | ||
| 60 | unsigned int data_block_counter; | ||
| 61 | |||
| 62 | unsigned int data_block_state; | ||
| 63 | |||
| 64 | unsigned int last_syt_offset; | ||
| 65 | unsigned int syt_offset_state; | ||
| 66 | |||
| 67 | unsigned int pcm_buffer_pointer; | ||
| 68 | unsigned int pcm_period_pointer; | ||
| 69 | }; | ||
| 70 | |||
| 71 | int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, | ||
| 72 | enum cip_out_flags flags); | ||
| 73 | void amdtp_out_stream_destroy(struct amdtp_out_stream *s); | ||
| 74 | |||
| 75 | void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate); | ||
| 76 | unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s); | ||
| 77 | |||
| 78 | int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed); | ||
| 79 | void amdtp_out_stream_update(struct amdtp_out_stream *s); | ||
| 80 | void amdtp_out_stream_stop(struct amdtp_out_stream *s); | ||
| 81 | |||
| 82 | void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, | ||
| 83 | snd_pcm_format_t format); | ||
| 84 | void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * amdtp_out_stream_set_pcm - configure format of PCM samples | ||
| 88 | * @s: the AMDTP output stream to be configured | ||
| 89 | * @pcm_channels: the number of PCM samples in each data block, to be encoded | ||
| 90 | * as AM824 multi-bit linear audio | ||
| 91 | * | ||
| 92 | * This function must not be called while the stream is running. | ||
| 93 | */ | ||
| 94 | static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s, | ||
| 95 | unsigned int pcm_channels) | ||
| 96 | { | ||
| 97 | s->pcm_channels = pcm_channels; | ||
| 98 | } | ||
| 99 | |||
| 100 | /** | ||
| 101 | * amdtp_out_stream_set_midi - configure format of MIDI data | ||
| 102 | * @s: the AMDTP output stream to be configured | ||
| 103 | * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) | ||
| 104 | * | ||
| 105 | * This function must not be called while the stream is running. | ||
| 106 | */ | ||
| 107 | static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s, | ||
| 108 | unsigned int midi_ports) | ||
| 109 | { | ||
| 110 | s->midi_ports = midi_ports; | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * amdtp_out_stream_pcm_prepare - prepare PCM device for running | ||
| 115 | * @s: the AMDTP output stream | ||
| 116 | * | ||
| 117 | * This function should be called from the PCM device's .prepare callback. | ||
| 118 | */ | ||
| 119 | static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s) | ||
| 120 | { | ||
| 121 | s->pcm_buffer_pointer = 0; | ||
| 122 | s->pcm_period_pointer = 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device | ||
| 127 | * @s: the AMDTP output stream | ||
| 128 | * @pcm: the PCM device to be started, or %NULL to stop the current device | ||
| 129 | * | ||
| 130 | * Call this function on a running isochronous stream to enable the actual | ||
| 131 | * transmission of PCM data. This function should be called from the PCM | ||
| 132 | * device's .trigger callback. | ||
| 133 | */ | ||
| 134 | static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s, | ||
| 135 | struct snd_pcm_substream *pcm) | ||
| 136 | { | ||
| 137 | ACCESS_ONCE(s->pcm) = pcm; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * amdtp_out_stream_pcm_pointer - get the PCM buffer position | ||
| 142 | * @s: the AMDTP output stream that transports the PCM data | ||
| 143 | * | ||
| 144 | * Returns the current buffer position, in frames. | ||
| 145 | */ | ||
| 146 | static inline unsigned long | ||
| 147 | amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s) | ||
| 148 | { | ||
| 149 | return ACCESS_ONCE(s->pcm_buffer_pointer); | ||
| 150 | } | ||
| 151 | |||
| 152 | static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) | ||
| 153 | { | ||
| 154 | return sfc & 1; | ||
| 155 | } | ||
| 156 | |||
| 157 | #endif | ||
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c new file mode 100644 index 000000000000..c992dab4bb95 --- /dev/null +++ b/sound/firewire/cmp.c | |||
| @@ -0,0 +1,305 @@ | |||
| 1 | /* | ||
| 2 | * Connection Management Procedures (IEC 61883-1) helper functions | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/firewire.h> | ||
| 10 | #include <linux/firewire-constants.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/sched.h> | ||
| 13 | #include "lib.h" | ||
| 14 | #include "iso-resources.h" | ||
| 15 | #include "cmp.h" | ||
| 16 | |||
| 17 | #define IMPR_SPEED_MASK 0xc0000000 | ||
| 18 | #define IMPR_SPEED_SHIFT 30 | ||
| 19 | #define IMPR_XSPEED_MASK 0x00000060 | ||
| 20 | #define IMPR_XSPEED_SHIFT 5 | ||
| 21 | #define IMPR_PLUGS_MASK 0x0000001f | ||
| 22 | |||
| 23 | #define IPCR_ONLINE 0x80000000 | ||
| 24 | #define IPCR_BCAST_CONN 0x40000000 | ||
| 25 | #define IPCR_P2P_CONN_MASK 0x3f000000 | ||
| 26 | #define IPCR_P2P_CONN_SHIFT 24 | ||
| 27 | #define IPCR_CHANNEL_MASK 0x003f0000 | ||
| 28 | #define IPCR_CHANNEL_SHIFT 16 | ||
| 29 | |||
| 30 | enum bus_reset_handling { | ||
| 31 | ABORT_ON_BUS_RESET, | ||
| 32 | SUCCEED_ON_BUS_RESET, | ||
| 33 | }; | ||
| 34 | |||
| 35 | static __attribute__((format(printf, 2, 3))) | ||
| 36 | void cmp_error(struct cmp_connection *c, const char *fmt, ...) | ||
| 37 | { | ||
| 38 | va_list va; | ||
| 39 | |||
| 40 | va_start(va, fmt); | ||
| 41 | dev_err(&c->resources.unit->device, "%cPCR%u: %pV", | ||
| 42 | 'i', c->pcr_index, &(struct va_format){ fmt, &va }); | ||
| 43 | va_end(va); | ||
| 44 | } | ||
| 45 | |||
| 46 | static int pcr_modify(struct cmp_connection *c, | ||
| 47 | __be32 (*modify)(struct cmp_connection *c, __be32 old), | ||
| 48 | int (*check)(struct cmp_connection *c, __be32 pcr), | ||
| 49 | enum bus_reset_handling bus_reset_handling) | ||
| 50 | { | ||
| 51 | struct fw_device *device = fw_parent_device(c->resources.unit); | ||
| 52 | __be32 *buffer = c->resources.buffer; | ||
| 53 | int generation = c->resources.generation; | ||
| 54 | int rcode, errors = 0; | ||
| 55 | __be32 old_arg; | ||
| 56 | int err; | ||
| 57 | |||
| 58 | buffer[0] = c->last_pcr_value; | ||
| 59 | for (;;) { | ||
| 60 | old_arg = buffer[0]; | ||
| 61 | buffer[1] = modify(c, buffer[0]); | ||
| 62 | |||
| 63 | rcode = fw_run_transaction( | ||
| 64 | device->card, TCODE_LOCK_COMPARE_SWAP, | ||
| 65 | device->node_id, generation, device->max_speed, | ||
| 66 | CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index), | ||
| 67 | buffer, 8); | ||
| 68 | |||
| 69 | if (rcode == RCODE_COMPLETE) { | ||
| 70 | if (buffer[0] == old_arg) /* success? */ | ||
| 71 | break; | ||
| 72 | |||
| 73 | if (check) { | ||
| 74 | err = check(c, buffer[0]); | ||
| 75 | if (err < 0) | ||
| 76 | return err; | ||
| 77 | } | ||
| 78 | } else if (rcode == RCODE_GENERATION) | ||
| 79 | goto bus_reset; | ||
| 80 | else if (rcode_is_permanent_error(rcode) || ++errors >= 3) | ||
| 81 | goto io_error; | ||
| 82 | } | ||
| 83 | c->last_pcr_value = buffer[1]; | ||
| 84 | |||
| 85 | return 0; | ||
| 86 | |||
| 87 | io_error: | ||
| 88 | cmp_error(c, "transaction failed: %s\n", rcode_string(rcode)); | ||
| 89 | return -EIO; | ||
| 90 | |||
| 91 | bus_reset: | ||
| 92 | return bus_reset_handling == ABORT_ON_BUS_RESET ? -EAGAIN : 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | /** | ||
| 97 | * cmp_connection_init - initializes a connection manager | ||
| 98 | * @c: the connection manager to initialize | ||
| 99 | * @unit: a unit of the target device | ||
| 100 | * @ipcr_index: the index of the iPCR on the target device | ||
| 101 | */ | ||
| 102 | int cmp_connection_init(struct cmp_connection *c, | ||
| 103 | struct fw_unit *unit, | ||
| 104 | unsigned int ipcr_index) | ||
| 105 | { | ||
| 106 | __be32 impr_be; | ||
| 107 | u32 impr; | ||
| 108 | int err; | ||
| 109 | |||
| 110 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, | ||
| 111 | CSR_REGISTER_BASE + CSR_IMPR, | ||
| 112 | &impr_be, 4); | ||
| 113 | if (err < 0) | ||
| 114 | return err; | ||
| 115 | impr = be32_to_cpu(impr_be); | ||
| 116 | |||
| 117 | if (ipcr_index >= (impr & IMPR_PLUGS_MASK)) | ||
| 118 | return -EINVAL; | ||
| 119 | |||
| 120 | c->connected = false; | ||
| 121 | mutex_init(&c->mutex); | ||
| 122 | fw_iso_resources_init(&c->resources, unit); | ||
| 123 | c->last_pcr_value = cpu_to_be32(0x80000000); | ||
| 124 | c->pcr_index = ipcr_index; | ||
| 125 | c->max_speed = (impr & IMPR_SPEED_MASK) >> IMPR_SPEED_SHIFT; | ||
| 126 | if (c->max_speed == SCODE_BETA) | ||
| 127 | c->max_speed += (impr & IMPR_XSPEED_MASK) >> IMPR_XSPEED_SHIFT; | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL(cmp_connection_init); | ||
| 132 | |||
| 133 | /** | ||
| 134 | * cmp_connection_destroy - free connection manager resources | ||
| 135 | * @c: the connection manager | ||
| 136 | */ | ||
| 137 | void cmp_connection_destroy(struct cmp_connection *c) | ||
| 138 | { | ||
| 139 | WARN_ON(c->connected); | ||
| 140 | mutex_destroy(&c->mutex); | ||
| 141 | fw_iso_resources_destroy(&c->resources); | ||
| 142 | } | ||
| 143 | EXPORT_SYMBOL(cmp_connection_destroy); | ||
| 144 | |||
| 145 | |||
| 146 | static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) | ||
| 147 | { | ||
| 148 | ipcr &= ~cpu_to_be32(IPCR_BCAST_CONN | | ||
| 149 | IPCR_P2P_CONN_MASK | | ||
| 150 | IPCR_CHANNEL_MASK); | ||
| 151 | ipcr |= cpu_to_be32(1 << IPCR_P2P_CONN_SHIFT); | ||
| 152 | ipcr |= cpu_to_be32(c->resources.channel << IPCR_CHANNEL_SHIFT); | ||
| 153 | |||
| 154 | return ipcr; | ||
| 155 | } | ||
| 156 | |||
| 157 | static int ipcr_set_check(struct cmp_connection *c, __be32 ipcr) | ||
| 158 | { | ||
| 159 | if (ipcr & cpu_to_be32(IPCR_BCAST_CONN | | ||
| 160 | IPCR_P2P_CONN_MASK)) { | ||
| 161 | cmp_error(c, "plug is already in use\n"); | ||
| 162 | return -EBUSY; | ||
| 163 | } | ||
| 164 | if (!(ipcr & cpu_to_be32(IPCR_ONLINE))) { | ||
| 165 | cmp_error(c, "plug is not on-line\n"); | ||
| 166 | return -ECONNREFUSED; | ||
| 167 | } | ||
| 168 | |||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | /** | ||
| 173 | * cmp_connection_establish - establish a connection to the target | ||
| 174 | * @c: the connection manager | ||
| 175 | * @max_payload_bytes: the amount of data (including CIP headers) per packet | ||
| 176 | * | ||
| 177 | * This function establishes a point-to-point connection from the local | ||
| 178 | * computer to the target by allocating isochronous resources (channel and | ||
| 179 | * bandwidth) and setting the target's input plug control register. When this | ||
| 180 | * function succeeds, the caller is responsible for starting transmitting | ||
| 181 | * packets. | ||
| 182 | */ | ||
| 183 | int cmp_connection_establish(struct cmp_connection *c, | ||
| 184 | unsigned int max_payload_bytes) | ||
| 185 | { | ||
| 186 | int err; | ||
| 187 | |||
| 188 | if (WARN_ON(c->connected)) | ||
| 189 | return -EISCONN; | ||
| 190 | |||
| 191 | c->speed = min(c->max_speed, | ||
| 192 | fw_parent_device(c->resources.unit)->max_speed); | ||
| 193 | |||
| 194 | mutex_lock(&c->mutex); | ||
| 195 | |||
| 196 | retry_after_bus_reset: | ||
| 197 | err = fw_iso_resources_allocate(&c->resources, | ||
| 198 | max_payload_bytes, c->speed); | ||
| 199 | if (err < 0) | ||
| 200 | goto err_mutex; | ||
| 201 | |||
| 202 | err = pcr_modify(c, ipcr_set_modify, ipcr_set_check, | ||
| 203 | ABORT_ON_BUS_RESET); | ||
| 204 | if (err == -EAGAIN) { | ||
| 205 | fw_iso_resources_free(&c->resources); | ||
| 206 | goto retry_after_bus_reset; | ||
| 207 | } | ||
| 208 | if (err < 0) | ||
| 209 | goto err_resources; | ||
| 210 | |||
| 211 | c->connected = true; | ||
| 212 | |||
| 213 | mutex_unlock(&c->mutex); | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | |||
| 217 | err_resources: | ||
| 218 | fw_iso_resources_free(&c->resources); | ||
| 219 | err_mutex: | ||
| 220 | mutex_unlock(&c->mutex); | ||
| 221 | |||
| 222 | return err; | ||
| 223 | } | ||
| 224 | EXPORT_SYMBOL(cmp_connection_establish); | ||
| 225 | |||
| 226 | /** | ||
| 227 | * cmp_connection_update - update the connection after a bus reset | ||
| 228 | * @c: the connection manager | ||
| 229 | * | ||
| 230 | * This function must be called from the driver's .update handler to reestablish | ||
| 231 | * any connection that might have been active. | ||
| 232 | * | ||
| 233 | * Returns zero on success, or a negative error code. On an error, the | ||
| 234 | * connection is broken and the caller must stop transmitting iso packets. | ||
| 235 | */ | ||
| 236 | int cmp_connection_update(struct cmp_connection *c) | ||
| 237 | { | ||
| 238 | int err; | ||
| 239 | |||
| 240 | mutex_lock(&c->mutex); | ||
| 241 | |||
| 242 | if (!c->connected) { | ||
| 243 | mutex_unlock(&c->mutex); | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 247 | err = fw_iso_resources_update(&c->resources); | ||
| 248 | if (err < 0) | ||
| 249 | goto err_unconnect; | ||
| 250 | |||
| 251 | err = pcr_modify(c, ipcr_set_modify, ipcr_set_check, | ||
| 252 | SUCCEED_ON_BUS_RESET); | ||
| 253 | if (err < 0) | ||
| 254 | goto err_resources; | ||
| 255 | |||
| 256 | mutex_unlock(&c->mutex); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | |||
| 260 | err_resources: | ||
| 261 | fw_iso_resources_free(&c->resources); | ||
| 262 | err_unconnect: | ||
| 263 | c->connected = false; | ||
| 264 | mutex_unlock(&c->mutex); | ||
| 265 | |||
| 266 | return err; | ||
| 267 | } | ||
| 268 | EXPORT_SYMBOL(cmp_connection_update); | ||
| 269 | |||
| 270 | |||
| 271 | static __be32 ipcr_break_modify(struct cmp_connection *c, __be32 ipcr) | ||
| 272 | { | ||
| 273 | return ipcr & ~cpu_to_be32(IPCR_BCAST_CONN | IPCR_P2P_CONN_MASK); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * cmp_connection_break - break the connection to the target | ||
| 278 | * @c: the connection manager | ||
| 279 | * | ||
| 280 | * This function deactives the connection in the target's input plug control | ||
| 281 | * register, and frees the isochronous resources of the connection. Before | ||
| 282 | * calling this function, the caller should cease transmitting packets. | ||
| 283 | */ | ||
| 284 | void cmp_connection_break(struct cmp_connection *c) | ||
| 285 | { | ||
| 286 | int err; | ||
| 287 | |||
| 288 | mutex_lock(&c->mutex); | ||
| 289 | |||
| 290 | if (!c->connected) { | ||
| 291 | mutex_unlock(&c->mutex); | ||
| 292 | return; | ||
| 293 | } | ||
| 294 | |||
| 295 | err = pcr_modify(c, ipcr_break_modify, NULL, SUCCEED_ON_BUS_RESET); | ||
| 296 | if (err < 0) | ||
| 297 | cmp_error(c, "plug is still connected\n"); | ||
| 298 | |||
| 299 | fw_iso_resources_free(&c->resources); | ||
| 300 | |||
| 301 | c->connected = false; | ||
| 302 | |||
| 303 | mutex_unlock(&c->mutex); | ||
| 304 | } | ||
| 305 | EXPORT_SYMBOL(cmp_connection_break); | ||
diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h new file mode 100644 index 000000000000..f47de08feb12 --- /dev/null +++ b/sound/firewire/cmp.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef SOUND_FIREWIRE_CMP_H_INCLUDED | ||
| 2 | #define SOUND_FIREWIRE_CMP_H_INCLUDED | ||
| 3 | |||
| 4 | #include <linux/mutex.h> | ||
| 5 | #include <linux/types.h> | ||
| 6 | #include "iso-resources.h" | ||
| 7 | |||
| 8 | struct fw_unit; | ||
| 9 | |||
| 10 | /** | ||
| 11 | * struct cmp_connection - manages an isochronous connection to a device | ||
| 12 | * @speed: the connection's actual speed | ||
| 13 | * | ||
| 14 | * This structure manages (using CMP) an isochronous stream from the local | ||
| 15 | * computer to a device's input plug (iPCR). | ||
| 16 | * | ||
| 17 | * There is no corresponding oPCR created on the local computer, so it is not | ||
| 18 | * possible to overlay connections on top of this one. | ||
| 19 | */ | ||
| 20 | struct cmp_connection { | ||
| 21 | int speed; | ||
| 22 | /* private: */ | ||
| 23 | bool connected; | ||
| 24 | struct mutex mutex; | ||
| 25 | struct fw_iso_resources resources; | ||
| 26 | __be32 last_pcr_value; | ||
| 27 | unsigned int pcr_index; | ||
| 28 | unsigned int max_speed; | ||
| 29 | }; | ||
| 30 | |||
| 31 | int cmp_connection_init(struct cmp_connection *connection, | ||
| 32 | struct fw_unit *unit, | ||
| 33 | unsigned int ipcr_index); | ||
| 34 | void cmp_connection_destroy(struct cmp_connection *connection); | ||
| 35 | |||
| 36 | int cmp_connection_establish(struct cmp_connection *connection, | ||
| 37 | unsigned int max_payload); | ||
| 38 | int cmp_connection_update(struct cmp_connection *connection); | ||
| 39 | void cmp_connection_break(struct cmp_connection *connection); | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c new file mode 100644 index 000000000000..c20bd9c8f5ab --- /dev/null +++ b/sound/firewire/fcp.c | |||
| @@ -0,0 +1,223 @@ | |||
| 1 | /* | ||
| 2 | * Function Control Protocol (IEC 61883-1) helper functions | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/firewire.h> | ||
| 10 | #include <linux/firewire-constants.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/sched.h> | ||
| 14 | #include <linux/spinlock.h> | ||
| 15 | #include <linux/wait.h> | ||
| 16 | #include "fcp.h" | ||
| 17 | #include "lib.h" | ||
| 18 | |||
| 19 | #define CTS_AVC 0x00 | ||
| 20 | |||
| 21 | #define ERROR_RETRIES 3 | ||
| 22 | #define ERROR_DELAY_MS 5 | ||
| 23 | #define FCP_TIMEOUT_MS 125 | ||
| 24 | |||
| 25 | static DEFINE_SPINLOCK(transactions_lock); | ||
| 26 | static LIST_HEAD(transactions); | ||
| 27 | |||
| 28 | enum fcp_state { | ||
| 29 | STATE_PENDING, | ||
| 30 | STATE_BUS_RESET, | ||
| 31 | STATE_COMPLETE, | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct fcp_transaction { | ||
| 35 | struct list_head list; | ||
| 36 | struct fw_unit *unit; | ||
| 37 | void *response_buffer; | ||
| 38 | unsigned int response_size; | ||
| 39 | unsigned int response_match_bytes; | ||
| 40 | enum fcp_state state; | ||
| 41 | wait_queue_head_t wait; | ||
| 42 | }; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * fcp_avc_transaction - send an AV/C command and wait for its response | ||
| 46 | * @unit: a unit on the target device | ||
| 47 | * @command: a buffer containing the command frame; must be DMA-able | ||
| 48 | * @command_size: the size of @command | ||
| 49 | * @response: a buffer for the response frame | ||
| 50 | * @response_size: the maximum size of @response | ||
| 51 | * @response_match_bytes: a bitmap specifying the bytes used to detect the | ||
| 52 | * correct response frame | ||
| 53 | * | ||
| 54 | * This function sends a FCP command frame to the target and waits for the | ||
| 55 | * corresponding response frame to be returned. | ||
| 56 | * | ||
| 57 | * Because it is possible for multiple FCP transactions to be active at the | ||
| 58 | * same time, the correct response frame is detected by the value of certain | ||
| 59 | * bytes. These bytes must be set in @response before calling this function, | ||
| 60 | * and the corresponding bits must be set in @response_match_bytes. | ||
| 61 | * | ||
| 62 | * @command and @response can point to the same buffer. | ||
| 63 | * | ||
| 64 | * Asynchronous operation (INTERIM, NOTIFY) is not supported at the moment. | ||
| 65 | * | ||
| 66 | * Returns the actual size of the response frame, or a negative error code. | ||
| 67 | */ | ||
| 68 | int fcp_avc_transaction(struct fw_unit *unit, | ||
| 69 | const void *command, unsigned int command_size, | ||
| 70 | void *response, unsigned int response_size, | ||
| 71 | unsigned int response_match_bytes) | ||
| 72 | { | ||
| 73 | struct fcp_transaction t; | ||
| 74 | int tcode, ret, tries = 0; | ||
| 75 | |||
| 76 | t.unit = unit; | ||
| 77 | t.response_buffer = response; | ||
| 78 | t.response_size = response_size; | ||
| 79 | t.response_match_bytes = response_match_bytes; | ||
| 80 | t.state = STATE_PENDING; | ||
| 81 | init_waitqueue_head(&t.wait); | ||
| 82 | |||
| 83 | spin_lock_irq(&transactions_lock); | ||
| 84 | list_add_tail(&t.list, &transactions); | ||
| 85 | spin_unlock_irq(&transactions_lock); | ||
| 86 | |||
| 87 | for (;;) { | ||
| 88 | tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST | ||
| 89 | : TCODE_WRITE_BLOCK_REQUEST; | ||
| 90 | ret = snd_fw_transaction(t.unit, tcode, | ||
| 91 | CSR_REGISTER_BASE + CSR_FCP_COMMAND, | ||
| 92 | (void *)command, command_size); | ||
| 93 | if (ret < 0) | ||
| 94 | break; | ||
| 95 | |||
| 96 | wait_event_timeout(t.wait, t.state != STATE_PENDING, | ||
| 97 | msecs_to_jiffies(FCP_TIMEOUT_MS)); | ||
| 98 | |||
| 99 | if (t.state == STATE_COMPLETE) { | ||
| 100 | ret = t.response_size; | ||
| 101 | break; | ||
| 102 | } else if (t.state == STATE_BUS_RESET) { | ||
| 103 | msleep(ERROR_DELAY_MS); | ||
| 104 | } else if (++tries >= ERROR_RETRIES) { | ||
| 105 | dev_err(&t.unit->device, "FCP command timed out\n"); | ||
| 106 | ret = -EIO; | ||
| 107 | break; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | spin_lock_irq(&transactions_lock); | ||
| 112 | list_del(&t.list); | ||
| 113 | spin_unlock_irq(&transactions_lock); | ||
| 114 | |||
| 115 | return ret; | ||
| 116 | } | ||
| 117 | EXPORT_SYMBOL(fcp_avc_transaction); | ||
| 118 | |||
| 119 | /** | ||
| 120 | * fcp_bus_reset - inform the target handler about a bus reset | ||
| 121 | * @unit: the unit that might be used by fcp_avc_transaction() | ||
| 122 | * | ||
| 123 | * This function must be called from the driver's .update handler to inform | ||
| 124 | * the FCP transaction handler that a bus reset has happened. Any pending FCP | ||
| 125 | * transactions are retried. | ||
| 126 | */ | ||
| 127 | void fcp_bus_reset(struct fw_unit *unit) | ||
| 128 | { | ||
| 129 | struct fcp_transaction *t; | ||
| 130 | |||
| 131 | spin_lock_irq(&transactions_lock); | ||
| 132 | list_for_each_entry(t, &transactions, list) { | ||
| 133 | if (t->unit == unit && | ||
| 134 | t->state == STATE_PENDING) { | ||
| 135 | t->state = STATE_BUS_RESET; | ||
| 136 | wake_up(&t->wait); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | spin_unlock_irq(&transactions_lock); | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL(fcp_bus_reset); | ||
| 142 | |||
| 143 | /* checks whether the response matches the masked bytes in response_buffer */ | ||
| 144 | static bool is_matching_response(struct fcp_transaction *transaction, | ||
| 145 | const void *response, size_t length) | ||
| 146 | { | ||
| 147 | const u8 *p1, *p2; | ||
| 148 | unsigned int mask, i; | ||
| 149 | |||
| 150 | p1 = response; | ||
| 151 | p2 = transaction->response_buffer; | ||
| 152 | mask = transaction->response_match_bytes; | ||
| 153 | |||
| 154 | for (i = 0; ; ++i) { | ||
| 155 | if ((mask & 1) && p1[i] != p2[i]) | ||
| 156 | return false; | ||
| 157 | mask >>= 1; | ||
| 158 | if (!mask) | ||
| 159 | return true; | ||
| 160 | if (--length == 0) | ||
| 161 | return false; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | static void fcp_response(struct fw_card *card, struct fw_request *request, | ||
| 166 | int tcode, int destination, int source, | ||
| 167 | int generation, unsigned long long offset, | ||
| 168 | void *data, size_t length, void *callback_data) | ||
| 169 | { | ||
| 170 | struct fcp_transaction *t; | ||
| 171 | unsigned long flags; | ||
| 172 | |||
| 173 | if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC) | ||
| 174 | return; | ||
| 175 | |||
| 176 | spin_lock_irqsave(&transactions_lock, flags); | ||
| 177 | list_for_each_entry(t, &transactions, list) { | ||
| 178 | struct fw_device *device = fw_parent_device(t->unit); | ||
| 179 | if (device->card != card || | ||
| 180 | device->generation != generation) | ||
| 181 | continue; | ||
| 182 | smp_rmb(); /* node_id vs. generation */ | ||
| 183 | if (device->node_id != source) | ||
| 184 | continue; | ||
| 185 | |||
| 186 | if (t->state == STATE_PENDING && | ||
| 187 | is_matching_response(t, data, length)) { | ||
| 188 | t->state = STATE_COMPLETE; | ||
| 189 | t->response_size = min((unsigned int)length, | ||
| 190 | t->response_size); | ||
| 191 | memcpy(t->response_buffer, data, t->response_size); | ||
| 192 | wake_up(&t->wait); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | spin_unlock_irqrestore(&transactions_lock, flags); | ||
| 196 | } | ||
| 197 | |||
| 198 | static struct fw_address_handler response_register_handler = { | ||
| 199 | .length = 0x200, | ||
| 200 | .address_callback = fcp_response, | ||
| 201 | }; | ||
| 202 | |||
| 203 | static int __init fcp_module_init(void) | ||
| 204 | { | ||
| 205 | static const struct fw_address_region response_register_region = { | ||
| 206 | .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, | ||
| 207 | .end = CSR_REGISTER_BASE + CSR_FCP_END, | ||
| 208 | }; | ||
| 209 | |||
| 210 | fw_core_add_address_handler(&response_register_handler, | ||
| 211 | &response_register_region); | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static void __exit fcp_module_exit(void) | ||
| 217 | { | ||
| 218 | WARN_ON(!list_empty(&transactions)); | ||
| 219 | fw_core_remove_address_handler(&response_register_handler); | ||
| 220 | } | ||
| 221 | |||
| 222 | module_init(fcp_module_init); | ||
| 223 | module_exit(fcp_module_exit); | ||
diff --git a/sound/firewire/fcp.h b/sound/firewire/fcp.h new file mode 100644 index 000000000000..86595688bd91 --- /dev/null +++ b/sound/firewire/fcp.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef SOUND_FIREWIRE_FCP_H_INCLUDED | ||
| 2 | #define SOUND_FIREWIRE_FCP_H_INCLUDED | ||
| 3 | |||
| 4 | struct fw_unit; | ||
| 5 | |||
| 6 | int fcp_avc_transaction(struct fw_unit *unit, | ||
| 7 | const void *command, unsigned int command_size, | ||
| 8 | void *response, unsigned int response_size, | ||
| 9 | unsigned int response_match_bytes); | ||
| 10 | void fcp_bus_reset(struct fw_unit *unit); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c new file mode 100644 index 000000000000..6f2b5f8651fd --- /dev/null +++ b/sound/firewire/iso-resources.c | |||
| @@ -0,0 +1,224 @@ | |||
| 1 | /* | ||
| 2 | * isochronous resources helper functions | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/firewire.h> | ||
| 10 | #include <linux/firewire-constants.h> | ||
| 11 | #include <linux/jiffies.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/sched.h> | ||
| 14 | #include <linux/spinlock.h> | ||
| 15 | #include "iso-resources.h" | ||
| 16 | |||
| 17 | /** | ||
| 18 | * fw_iso_resources_init - initializes a &struct fw_iso_resources | ||
| 19 | * @r: the resource manager to initialize | ||
| 20 | * @unit: the device unit for which the resources will be needed | ||
| 21 | * | ||
| 22 | * If the device does not support all channel numbers, change @r->channels_mask | ||
| 23 | * after calling this function. | ||
| 24 | */ | ||
| 25 | void fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) | ||
| 26 | { | ||
| 27 | r->channels_mask = ~0uLL; | ||
| 28 | r->unit = fw_unit_get(unit); | ||
| 29 | mutex_init(&r->mutex); | ||
| 30 | r->allocated = false; | ||
| 31 | } | ||
| 32 | |||
| 33 | /** | ||
| 34 | * fw_iso_resources_destroy - destroy a resource manager | ||
| 35 | * @r: the resource manager that is no longer needed | ||
| 36 | */ | ||
| 37 | void fw_iso_resources_destroy(struct fw_iso_resources *r) | ||
| 38 | { | ||
| 39 | WARN_ON(r->allocated); | ||
| 40 | mutex_destroy(&r->mutex); | ||
| 41 | fw_unit_put(r->unit); | ||
| 42 | } | ||
| 43 | |||
| 44 | static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed) | ||
| 45 | { | ||
| 46 | unsigned int bytes, s400_bytes; | ||
| 47 | |||
| 48 | /* iso packets have three header quadlets and quadlet-aligned payload */ | ||
| 49 | bytes = 3 * 4 + ALIGN(max_payload_bytes, 4); | ||
| 50 | |||
| 51 | /* convert to bandwidth units (quadlets at S1600 = bytes at S400) */ | ||
| 52 | if (speed <= SCODE_400) | ||
| 53 | s400_bytes = bytes * (1 << (SCODE_400 - speed)); | ||
| 54 | else | ||
| 55 | s400_bytes = DIV_ROUND_UP(bytes, 1 << (speed - SCODE_400)); | ||
| 56 | |||
| 57 | return s400_bytes; | ||
| 58 | } | ||
| 59 | |||
| 60 | static int current_bandwidth_overhead(struct fw_card *card) | ||
| 61 | { | ||
| 62 | /* | ||
| 63 | * Under the usual pessimistic assumption (cable length 4.5 m), the | ||
| 64 | * isochronous overhead for N cables is 1.797 µs + N * 0.494 µs, or | ||
| 65 | * 88.3 + N * 24.3 in bandwidth units. | ||
| 66 | * | ||
| 67 | * The calculation below tries to deduce N from the current gap count. | ||
| 68 | * If the gap count has been optimized by measuring the actual packet | ||
| 69 | * transmission time, this derived overhead should be near the actual | ||
| 70 | * overhead as well. | ||
| 71 | */ | ||
| 72 | return card->gap_count < 63 ? card->gap_count * 97 / 10 + 89 : 512; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int wait_isoch_resource_delay_after_bus_reset(struct fw_card *card) | ||
| 76 | { | ||
| 77 | for (;;) { | ||
| 78 | s64 delay = (card->reset_jiffies + HZ) - get_jiffies_64(); | ||
| 79 | if (delay <= 0) | ||
| 80 | return 0; | ||
| 81 | if (schedule_timeout_interruptible(delay) > 0) | ||
| 82 | return -ERESTARTSYS; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | /** | ||
| 87 | * fw_iso_resources_allocate - allocate isochronous channel and bandwidth | ||
| 88 | * @r: the resource manager | ||
| 89 | * @max_payload_bytes: the amount of data (including CIP headers) per packet | ||
| 90 | * @speed: the speed (e.g., SCODE_400) at which the packets will be sent | ||
| 91 | * | ||
| 92 | * This function allocates one isochronous channel and enough bandwidth for the | ||
| 93 | * specified packet size. | ||
| 94 | * | ||
| 95 | * Returns the channel number that the caller must use for streaming, or | ||
| 96 | * a negative error code. Due to potentionally long delays, this function is | ||
| 97 | * interruptible and can return -ERESTARTSYS. On success, the caller is | ||
| 98 | * responsible for calling fw_iso_resources_update() on bus resets, and | ||
| 99 | * fw_iso_resources_free() when the resources are not longer needed. | ||
| 100 | */ | ||
| 101 | int fw_iso_resources_allocate(struct fw_iso_resources *r, | ||
| 102 | unsigned int max_payload_bytes, int speed) | ||
| 103 | { | ||
| 104 | struct fw_card *card = fw_parent_device(r->unit)->card; | ||
| 105 | int bandwidth, channel, err; | ||
| 106 | |||
| 107 | if (WARN_ON(r->allocated)) | ||
| 108 | return -EBADFD; | ||
| 109 | |||
| 110 | r->bandwidth = packet_bandwidth(max_payload_bytes, speed); | ||
| 111 | |||
| 112 | retry_after_bus_reset: | ||
| 113 | spin_lock_irq(&card->lock); | ||
| 114 | r->generation = card->generation; | ||
| 115 | r->bandwidth_overhead = current_bandwidth_overhead(card); | ||
| 116 | spin_unlock_irq(&card->lock); | ||
| 117 | |||
| 118 | err = wait_isoch_resource_delay_after_bus_reset(card); | ||
| 119 | if (err < 0) | ||
| 120 | return err; | ||
| 121 | |||
| 122 | mutex_lock(&r->mutex); | ||
| 123 | |||
| 124 | bandwidth = r->bandwidth + r->bandwidth_overhead; | ||
| 125 | fw_iso_resource_manage(card, r->generation, r->channels_mask, | ||
| 126 | &channel, &bandwidth, true, r->buffer); | ||
| 127 | if (channel == -EAGAIN) { | ||
| 128 | mutex_unlock(&r->mutex); | ||
| 129 | goto retry_after_bus_reset; | ||
| 130 | } | ||
| 131 | if (channel >= 0) { | ||
| 132 | r->channel = channel; | ||
| 133 | r->allocated = true; | ||
| 134 | } else { | ||
| 135 | if (channel == -EBUSY) | ||
| 136 | dev_err(&r->unit->device, | ||
| 137 | "isochronous resources exhausted\n"); | ||
| 138 | else | ||
| 139 | dev_err(&r->unit->device, | ||
| 140 | "isochronous resource allocation failed\n"); | ||
| 141 | } | ||
| 142 | |||
| 143 | mutex_unlock(&r->mutex); | ||
| 144 | |||
| 145 | return channel; | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * fw_iso_resources_update - update resource allocations after a bus reset | ||
| 150 | * @r: the resource manager | ||
| 151 | * | ||
| 152 | * This function must be called from the driver's .update handler to reallocate | ||
| 153 | * any resources that were allocated before the bus reset. It is safe to call | ||
| 154 | * this function if no resources are currently allocated. | ||
| 155 | * | ||
| 156 | * Returns a negative error code on failure. If this happens, the caller must | ||
| 157 | * stop streaming. | ||
| 158 | */ | ||
| 159 | int fw_iso_resources_update(struct fw_iso_resources *r) | ||
| 160 | { | ||
| 161 | struct fw_card *card = fw_parent_device(r->unit)->card; | ||
| 162 | int bandwidth, channel; | ||
| 163 | |||
| 164 | mutex_lock(&r->mutex); | ||
| 165 | |||
| 166 | if (!r->allocated) { | ||
| 167 | mutex_unlock(&r->mutex); | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | spin_lock_irq(&card->lock); | ||
| 172 | r->generation = card->generation; | ||
| 173 | r->bandwidth_overhead = current_bandwidth_overhead(card); | ||
| 174 | spin_unlock_irq(&card->lock); | ||
| 175 | |||
| 176 | bandwidth = r->bandwidth + r->bandwidth_overhead; | ||
| 177 | |||
| 178 | fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, | ||
| 179 | &channel, &bandwidth, true, r->buffer); | ||
| 180 | /* | ||
| 181 | * When another bus reset happens, pretend that the allocation | ||
| 182 | * succeeded; we will try again for the new generation later. | ||
| 183 | */ | ||
| 184 | if (channel < 0 && channel != -EAGAIN) { | ||
| 185 | r->allocated = false; | ||
| 186 | if (channel == -EBUSY) | ||
| 187 | dev_err(&r->unit->device, | ||
| 188 | "isochronous resources exhausted\n"); | ||
| 189 | else | ||
| 190 | dev_err(&r->unit->device, | ||
| 191 | "isochronous resource allocation failed\n"); | ||
| 192 | } | ||
| 193 | |||
| 194 | mutex_unlock(&r->mutex); | ||
| 195 | |||
| 196 | return channel; | ||
| 197 | } | ||
| 198 | |||
| 199 | /** | ||
| 200 | * fw_iso_resources_free - frees allocated resources | ||
| 201 | * @r: the resource manager | ||
| 202 | * | ||
| 203 | * This function deallocates the channel and bandwidth, if allocated. | ||
| 204 | */ | ||
| 205 | void fw_iso_resources_free(struct fw_iso_resources *r) | ||
| 206 | { | ||
| 207 | struct fw_card *card = fw_parent_device(r->unit)->card; | ||
| 208 | int bandwidth, channel; | ||
| 209 | |||
| 210 | mutex_lock(&r->mutex); | ||
| 211 | |||
| 212 | if (r->allocated) { | ||
| 213 | bandwidth = r->bandwidth + r->bandwidth_overhead; | ||
| 214 | fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, | ||
| 215 | &channel, &bandwidth, false, r->buffer); | ||
| 216 | if (channel < 0) | ||
| 217 | dev_err(&r->unit->device, | ||
| 218 | "isochronous resource deallocation failed\n"); | ||
| 219 | |||
| 220 | r->allocated = false; | ||
| 221 | } | ||
| 222 | |||
| 223 | mutex_unlock(&r->mutex); | ||
| 224 | } | ||
diff --git a/sound/firewire/iso-resources.h b/sound/firewire/iso-resources.h new file mode 100644 index 000000000000..9feb9f8d4745 --- /dev/null +++ b/sound/firewire/iso-resources.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #ifndef SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED | ||
| 2 | #define SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED | ||
| 3 | |||
| 4 | #include <linux/mutex.h> | ||
| 5 | #include <linux/types.h> | ||
| 6 | |||
| 7 | struct fw_unit; | ||
| 8 | |||
| 9 | /** | ||
| 10 | * struct fw_iso_resources - manages channel/bandwidth allocation | ||
| 11 | * @channels_mask: if the device does not support all channel numbers, set this | ||
| 12 | * bit mask to something else than the default (all ones) | ||
| 13 | * | ||
| 14 | * This structure manages (de)allocation of isochronous resources (channel and | ||
| 15 | * bandwidth) for one isochronous stream. | ||
| 16 | */ | ||
| 17 | struct fw_iso_resources { | ||
| 18 | u64 channels_mask; | ||
| 19 | /* private: */ | ||
| 20 | struct fw_unit *unit; | ||
| 21 | struct mutex mutex; | ||
| 22 | unsigned int channel; | ||
| 23 | unsigned int bandwidth; /* in bandwidth units, without overhead */ | ||
| 24 | unsigned int bandwidth_overhead; | ||
| 25 | int generation; /* in which allocation is valid */ | ||
| 26 | bool allocated; | ||
| 27 | __be32 buffer[2]; | ||
| 28 | }; | ||
| 29 | |||
| 30 | void fw_iso_resources_init(struct fw_iso_resources *r, | ||
| 31 | struct fw_unit *unit); | ||
| 32 | void fw_iso_resources_destroy(struct fw_iso_resources *r); | ||
| 33 | |||
| 34 | int fw_iso_resources_allocate(struct fw_iso_resources *r, | ||
| 35 | unsigned int max_payload_bytes, int speed); | ||
| 36 | int fw_iso_resources_update(struct fw_iso_resources *r); | ||
| 37 | void fw_iso_resources_free(struct fw_iso_resources *r); | ||
| 38 | |||
| 39 | #endif | ||
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c new file mode 100644 index 000000000000..4750cea2210e --- /dev/null +++ b/sound/firewire/lib.c | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | * miscellaneous helper functions | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/delay.h> | ||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/firewire.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include "lib.h" | ||
| 13 | |||
| 14 | #define ERROR_RETRY_DELAY_MS 5 | ||
| 15 | |||
| 16 | /** | ||
| 17 | * rcode_string - convert a firewire result code to a string | ||
| 18 | * @rcode: the result | ||
| 19 | */ | ||
| 20 | const char *rcode_string(unsigned int rcode) | ||
| 21 | { | ||
| 22 | static const char *const names[] = { | ||
| 23 | [RCODE_COMPLETE] = "complete", | ||
| 24 | [RCODE_CONFLICT_ERROR] = "conflict error", | ||
| 25 | [RCODE_DATA_ERROR] = "data error", | ||
| 26 | [RCODE_TYPE_ERROR] = "type error", | ||
| 27 | [RCODE_ADDRESS_ERROR] = "address error", | ||
| 28 | [RCODE_SEND_ERROR] = "send error", | ||
| 29 | [RCODE_CANCELLED] = "cancelled", | ||
| 30 | [RCODE_BUSY] = "busy", | ||
| 31 | [RCODE_GENERATION] = "generation", | ||
| 32 | [RCODE_NO_ACK] = "no ack", | ||
| 33 | }; | ||
| 34 | |||
| 35 | if (rcode < ARRAY_SIZE(names) && names[rcode]) | ||
| 36 | return names[rcode]; | ||
| 37 | else | ||
| 38 | return "unknown"; | ||
| 39 | } | ||
| 40 | EXPORT_SYMBOL(rcode_string); | ||
| 41 | |||
| 42 | /** | ||
| 43 | * snd_fw_transaction - send a request and wait for its completion | ||
| 44 | * @unit: the driver's unit on the target device | ||
| 45 | * @tcode: the transaction code | ||
| 46 | * @offset: the address in the target's address space | ||
| 47 | * @buffer: input/output data | ||
| 48 | * @length: length of @buffer | ||
| 49 | * | ||
| 50 | * Submits an asynchronous request to the target device, and waits for the | ||
| 51 | * response. The node ID and the current generation are derived from @unit. | ||
| 52 | * On a bus reset or an error, the transaction is retried a few times. | ||
| 53 | * Returns zero on success, or a negative error code. | ||
| 54 | */ | ||
| 55 | int snd_fw_transaction(struct fw_unit *unit, int tcode, | ||
| 56 | u64 offset, void *buffer, size_t length) | ||
| 57 | { | ||
| 58 | struct fw_device *device = fw_parent_device(unit); | ||
| 59 | int generation, rcode, tries = 0; | ||
| 60 | |||
| 61 | for (;;) { | ||
| 62 | generation = device->generation; | ||
| 63 | smp_rmb(); /* node_id vs. generation */ | ||
| 64 | rcode = fw_run_transaction(device->card, tcode, | ||
| 65 | device->node_id, generation, | ||
| 66 | device->max_speed, offset, | ||
| 67 | buffer, length); | ||
| 68 | |||
| 69 | if (rcode == RCODE_COMPLETE) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (rcode_is_permanent_error(rcode) || ++tries >= 3) { | ||
| 73 | dev_err(&unit->device, "transaction failed: %s\n", | ||
| 74 | rcode_string(rcode)); | ||
| 75 | return -EIO; | ||
| 76 | } | ||
| 77 | |||
| 78 | msleep(ERROR_RETRY_DELAY_MS); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | EXPORT_SYMBOL(snd_fw_transaction); | ||
| 82 | |||
| 83 | MODULE_DESCRIPTION("FireWire audio helper functions"); | ||
| 84 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
| 85 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h new file mode 100644 index 000000000000..064f3fd9ab06 --- /dev/null +++ b/sound/firewire/lib.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #ifndef SOUND_FIREWIRE_LIB_H_INCLUDED | ||
| 2 | #define SOUND_FIREWIRE_LIB_H_INCLUDED | ||
| 3 | |||
| 4 | #include <linux/firewire-constants.h> | ||
| 5 | #include <linux/types.h> | ||
| 6 | |||
| 7 | struct fw_unit; | ||
| 8 | |||
| 9 | int snd_fw_transaction(struct fw_unit *unit, int tcode, | ||
| 10 | u64 offset, void *buffer, size_t length); | ||
| 11 | const char *rcode_string(unsigned int rcode); | ||
| 12 | |||
| 13 | /* returns true if retrying the transaction would not make sense */ | ||
| 14 | static inline bool rcode_is_permanent_error(int rcode) | ||
| 15 | { | ||
| 16 | return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR; | ||
| 17 | } | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c new file mode 100644 index 000000000000..1e20e60ba6a6 --- /dev/null +++ b/sound/firewire/packets-buffer.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | /* | ||
| 2 | * helpers for managing a buffer for many packets | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/firewire.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include "packets-buffer.h" | ||
| 11 | |||
| 12 | /** | ||
| 13 | * iso_packets_buffer_init - allocates the memory for packets | ||
| 14 | * @b: the buffer structure to initialize | ||
| 15 | * @unit: the device at the other end of the stream | ||
| 16 | * @count: the number of packets | ||
| 17 | * @packet_size: the (maximum) size of a packet, in bytes | ||
| 18 | * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE | ||
| 19 | */ | ||
| 20 | int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, | ||
| 21 | unsigned int count, unsigned int packet_size, | ||
| 22 | enum dma_data_direction direction) | ||
| 23 | { | ||
| 24 | unsigned int packets_per_page, pages; | ||
| 25 | unsigned int i, page_index, offset_in_page; | ||
| 26 | void *p; | ||
| 27 | int err; | ||
| 28 | |||
| 29 | b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL); | ||
| 30 | if (!b->packets) { | ||
| 31 | err = -ENOMEM; | ||
| 32 | goto error; | ||
| 33 | } | ||
| 34 | |||
| 35 | packet_size = L1_CACHE_ALIGN(packet_size); | ||
| 36 | packets_per_page = PAGE_SIZE / packet_size; | ||
| 37 | if (WARN_ON(!packets_per_page)) { | ||
| 38 | err = -EINVAL; | ||
| 39 | goto error; | ||
| 40 | } | ||
| 41 | pages = DIV_ROUND_UP(count, packets_per_page); | ||
| 42 | |||
| 43 | err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, | ||
| 44 | pages, direction); | ||
| 45 | if (err < 0) | ||
| 46 | goto err_packets; | ||
| 47 | |||
| 48 | for (i = 0; i < count; ++i) { | ||
| 49 | page_index = i / packets_per_page; | ||
| 50 | p = page_address(b->iso_buffer.pages[page_index]); | ||
| 51 | offset_in_page = (i % packets_per_page) * packet_size; | ||
| 52 | b->packets[i].buffer = p + offset_in_page; | ||
| 53 | b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; | ||
| 54 | } | ||
| 55 | |||
| 56 | return 0; | ||
| 57 | |||
| 58 | err_packets: | ||
| 59 | kfree(b->packets); | ||
| 60 | error: | ||
| 61 | return err; | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * iso_packets_buffer_destroy - frees packet buffer resources | ||
| 66 | * @b: the buffer structure to free | ||
| 67 | * @unit: the device at the other end of the stream | ||
| 68 | */ | ||
| 69 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | ||
| 70 | struct fw_unit *unit) | ||
| 71 | { | ||
| 72 | fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); | ||
| 73 | kfree(b->packets); | ||
| 74 | } | ||
diff --git a/sound/firewire/packets-buffer.h b/sound/firewire/packets-buffer.h new file mode 100644 index 000000000000..6513c5cb6ea9 --- /dev/null +++ b/sound/firewire/packets-buffer.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #ifndef SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED | ||
| 2 | #define SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED | ||
| 3 | |||
| 4 | #include <linux/dma-mapping.h> | ||
| 5 | #include <linux/firewire.h> | ||
| 6 | |||
| 7 | /** | ||
| 8 | * struct iso_packets_buffer - manages a buffer for many packets | ||
| 9 | * @iso_buffer: the memory containing the packets | ||
| 10 | * @packets: an array, with each element pointing to one packet | ||
| 11 | */ | ||
| 12 | struct iso_packets_buffer { | ||
| 13 | struct fw_iso_buffer iso_buffer; | ||
| 14 | struct { | ||
| 15 | void *buffer; | ||
| 16 | unsigned int offset; | ||
| 17 | } *packets; | ||
| 18 | }; | ||
| 19 | |||
| 20 | int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, | ||
| 21 | unsigned int count, unsigned int packet_size, | ||
| 22 | enum dma_data_direction direction); | ||
| 23 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | ||
| 24 | struct fw_unit *unit); | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c new file mode 100644 index 000000000000..f6b095ef075a --- /dev/null +++ b/sound/firewire/speakers.c | |||
| @@ -0,0 +1,855 @@ | |||
| 1 | /* | ||
| 2 | * OXFW970-based speakers driver | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/firewire.h> | ||
| 10 | #include <linux/firewire-constants.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/mod_devicetable.h> | ||
| 13 | #include <linux/mutex.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <sound/control.h> | ||
| 16 | #include <sound/core.h> | ||
| 17 | #include <sound/initval.h> | ||
| 18 | #include <sound/pcm.h> | ||
| 19 | #include <sound/pcm_params.h> | ||
| 20 | #include "cmp.h" | ||
| 21 | #include "fcp.h" | ||
| 22 | #include "amdtp.h" | ||
| 23 | #include "lib.h" | ||
| 24 | |||
| 25 | #define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) | ||
| 26 | /* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ | ||
| 27 | |||
| 28 | #define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) | ||
| 29 | #define OXFORD_HARDWARE_ID_OXFW970 0x39443841 | ||
| 30 | #define OXFORD_HARDWARE_ID_OXFW971 0x39373100 | ||
| 31 | |||
| 32 | #define VENDOR_GRIFFIN 0x001292 | ||
| 33 | #define VENDOR_LACIE 0x00d04b | ||
| 34 | |||
| 35 | #define SPECIFIER_1394TA 0x00a02d | ||
| 36 | #define VERSION_AVC 0x010001 | ||
| 37 | |||
| 38 | struct device_info { | ||
| 39 | const char *driver_name; | ||
| 40 | const char *short_name; | ||
| 41 | const char *long_name; | ||
| 42 | int (*pcm_constraints)(struct snd_pcm_runtime *runtime); | ||
| 43 | unsigned int mixer_channels; | ||
| 44 | u8 mute_fb_id; | ||
| 45 | u8 volume_fb_id; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct fwspk { | ||
| 49 | struct snd_card *card; | ||
| 50 | struct fw_unit *unit; | ||
| 51 | const struct device_info *device_info; | ||
| 52 | struct snd_pcm_substream *pcm; | ||
| 53 | struct mutex mutex; | ||
| 54 | struct cmp_connection connection; | ||
| 55 | struct amdtp_out_stream stream; | ||
| 56 | bool stream_running; | ||
| 57 | bool mute; | ||
| 58 | s16 volume[6]; | ||
| 59 | s16 volume_min; | ||
| 60 | s16 volume_max; | ||
| 61 | }; | ||
| 62 | |||
| 63 | MODULE_DESCRIPTION("FireWire speakers driver"); | ||
| 64 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
| 65 | MODULE_LICENSE("GPL v2"); | ||
| 66 | |||
| 67 | static int firewave_rate_constraint(struct snd_pcm_hw_params *params, | ||
| 68 | struct snd_pcm_hw_rule *rule) | ||
| 69 | { | ||
| 70 | static unsigned int stereo_rates[] = { 48000, 96000 }; | ||
| 71 | struct snd_interval *channels = | ||
| 72 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 73 | struct snd_interval *rate = | ||
| 74 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
| 75 | |||
| 76 | /* two channels work only at 48/96 kHz */ | ||
| 77 | if (snd_interval_max(channels) < 6) | ||
| 78 | return snd_interval_list(rate, 2, stereo_rates, 0); | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int firewave_channels_constraint(struct snd_pcm_hw_params *params, | ||
| 83 | struct snd_pcm_hw_rule *rule) | ||
| 84 | { | ||
| 85 | static const struct snd_interval all_channels = { .min = 6, .max = 6 }; | ||
| 86 | struct snd_interval *rate = | ||
| 87 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
| 88 | struct snd_interval *channels = | ||
| 89 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 90 | |||
| 91 | /* 32/44.1 kHz work only with all six channels */ | ||
| 92 | if (snd_interval_max(rate) < 48000) | ||
| 93 | return snd_interval_refine(channels, &all_channels); | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int firewave_constraints(struct snd_pcm_runtime *runtime) | ||
| 98 | { | ||
| 99 | static unsigned int channels_list[] = { 2, 6 }; | ||
| 100 | static struct snd_pcm_hw_constraint_list channels_list_constraint = { | ||
| 101 | .count = 2, | ||
| 102 | .list = channels_list, | ||
| 103 | }; | ||
| 104 | int err; | ||
| 105 | |||
| 106 | runtime->hw.rates = SNDRV_PCM_RATE_32000 | | ||
| 107 | SNDRV_PCM_RATE_44100 | | ||
| 108 | SNDRV_PCM_RATE_48000 | | ||
| 109 | SNDRV_PCM_RATE_96000; | ||
| 110 | runtime->hw.channels_max = 6; | ||
| 111 | |||
| 112 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
| 113 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
| 114 | &channels_list_constraint); | ||
| 115 | if (err < 0) | ||
| 116 | return err; | ||
| 117 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
| 118 | firewave_rate_constraint, NULL, | ||
| 119 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
| 120 | if (err < 0) | ||
| 121 | return err; | ||
| 122 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
| 123 | firewave_channels_constraint, NULL, | ||
| 124 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
| 125 | if (err < 0) | ||
| 126 | return err; | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) | ||
| 132 | { | ||
| 133 | runtime->hw.rates = SNDRV_PCM_RATE_32000 | | ||
| 134 | SNDRV_PCM_RATE_44100 | | ||
| 135 | SNDRV_PCM_RATE_48000 | | ||
| 136 | SNDRV_PCM_RATE_88200 | | ||
| 137 | SNDRV_PCM_RATE_96000; | ||
| 138 | |||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int fwspk_open(struct snd_pcm_substream *substream) | ||
| 143 | { | ||
| 144 | static const struct snd_pcm_hardware hardware = { | ||
| 145 | .info = SNDRV_PCM_INFO_MMAP | | ||
| 146 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 147 | SNDRV_PCM_INFO_BATCH | | ||
| 148 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 149 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
| 150 | .formats = AMDTP_OUT_PCM_FORMAT_BITS, | ||
| 151 | .channels_min = 2, | ||
| 152 | .channels_max = 2, | ||
| 153 | .buffer_bytes_max = 4 * 1024 * 1024, | ||
| 154 | .period_bytes_min = 1, | ||
| 155 | .period_bytes_max = UINT_MAX, | ||
| 156 | .periods_min = 1, | ||
| 157 | .periods_max = UINT_MAX, | ||
| 158 | }; | ||
| 159 | struct fwspk *fwspk = substream->private_data; | ||
| 160 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 161 | int err; | ||
| 162 | |||
| 163 | runtime->hw = hardware; | ||
| 164 | |||
| 165 | err = fwspk->device_info->pcm_constraints(runtime); | ||
| 166 | if (err < 0) | ||
| 167 | return err; | ||
| 168 | err = snd_pcm_limit_hw_rates(runtime); | ||
| 169 | if (err < 0) | ||
| 170 | return err; | ||
| 171 | |||
| 172 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
| 173 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
| 174 | 5000, 8192000); | ||
| 175 | if (err < 0) | ||
| 176 | return err; | ||
| 177 | |||
| 178 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
| 179 | if (err < 0) | ||
| 180 | return err; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int fwspk_close(struct snd_pcm_substream *substream) | ||
| 186 | { | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void fwspk_stop_stream(struct fwspk *fwspk) | ||
| 191 | { | ||
| 192 | if (fwspk->stream_running) { | ||
| 193 | amdtp_out_stream_stop(&fwspk->stream); | ||
| 194 | cmp_connection_break(&fwspk->connection); | ||
| 195 | fwspk->stream_running = false; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | static int fwspk_set_rate(struct fwspk *fwspk, unsigned int sfc) | ||
| 200 | { | ||
| 201 | u8 *buf; | ||
| 202 | int err; | ||
| 203 | |||
| 204 | buf = kmalloc(8, GFP_KERNEL); | ||
| 205 | if (!buf) | ||
| 206 | return -ENOMEM; | ||
| 207 | |||
| 208 | buf[0] = 0x00; /* AV/C, CONTROL */ | ||
| 209 | buf[1] = 0xff; /* unit */ | ||
| 210 | buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */ | ||
| 211 | buf[3] = 0x00; /* plug 0 */ | ||
| 212 | buf[4] = 0x90; /* format: audio */ | ||
| 213 | buf[5] = 0x00 | sfc; /* AM824, frequency */ | ||
| 214 | buf[6] = 0xff; /* SYT (not used) */ | ||
| 215 | buf[7] = 0xff; | ||
| 216 | |||
| 217 | err = fcp_avc_transaction(fwspk->unit, buf, 8, buf, 8, | ||
| 218 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); | ||
| 219 | if (err < 0) | ||
| 220 | goto error; | ||
| 221 | if (err < 6 || buf[0] != 0x09 /* ACCEPTED */) { | ||
| 222 | dev_err(&fwspk->unit->device, "failed to set sample rate\n"); | ||
| 223 | err = -EIO; | ||
| 224 | goto error; | ||
| 225 | } | ||
| 226 | |||
| 227 | err = 0; | ||
| 228 | |||
| 229 | error: | ||
| 230 | kfree(buf); | ||
| 231 | |||
| 232 | return err; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int fwspk_hw_params(struct snd_pcm_substream *substream, | ||
| 236 | struct snd_pcm_hw_params *hw_params) | ||
| 237 | { | ||
| 238 | struct fwspk *fwspk = substream->private_data; | ||
| 239 | int err; | ||
| 240 | |||
| 241 | mutex_lock(&fwspk->mutex); | ||
| 242 | fwspk_stop_stream(fwspk); | ||
| 243 | mutex_unlock(&fwspk->mutex); | ||
| 244 | |||
| 245 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 246 | params_buffer_bytes(hw_params)); | ||
| 247 | if (err < 0) | ||
| 248 | goto error; | ||
| 249 | |||
| 250 | amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params)); | ||
| 251 | amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params)); | ||
| 252 | |||
| 253 | amdtp_out_stream_set_pcm_format(&fwspk->stream, | ||
| 254 | params_format(hw_params)); | ||
| 255 | |||
| 256 | err = fwspk_set_rate(fwspk, fwspk->stream.sfc); | ||
| 257 | if (err < 0) | ||
| 258 | goto err_buffer; | ||
| 259 | |||
| 260 | return 0; | ||
| 261 | |||
| 262 | err_buffer: | ||
| 263 | snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 264 | error: | ||
| 265 | return err; | ||
| 266 | } | ||
| 267 | |||
| 268 | static int fwspk_hw_free(struct snd_pcm_substream *substream) | ||
| 269 | { | ||
| 270 | struct fwspk *fwspk = substream->private_data; | ||
| 271 | |||
| 272 | mutex_lock(&fwspk->mutex); | ||
| 273 | fwspk_stop_stream(fwspk); | ||
| 274 | mutex_unlock(&fwspk->mutex); | ||
| 275 | |||
| 276 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 277 | } | ||
| 278 | |||
| 279 | static int fwspk_prepare(struct snd_pcm_substream *substream) | ||
| 280 | { | ||
| 281 | struct fwspk *fwspk = substream->private_data; | ||
| 282 | int err; | ||
| 283 | |||
| 284 | mutex_lock(&fwspk->mutex); | ||
| 285 | |||
| 286 | if (!fwspk->stream_running) { | ||
| 287 | err = cmp_connection_establish(&fwspk->connection, | ||
| 288 | amdtp_out_stream_get_max_payload(&fwspk->stream)); | ||
| 289 | if (err < 0) | ||
| 290 | goto err_mutex; | ||
| 291 | |||
| 292 | err = amdtp_out_stream_start(&fwspk->stream, | ||
| 293 | fwspk->connection.resources.channel, | ||
| 294 | fwspk->connection.speed); | ||
| 295 | if (err < 0) | ||
| 296 | goto err_connection; | ||
| 297 | |||
| 298 | fwspk->stream_running = true; | ||
| 299 | } | ||
| 300 | |||
| 301 | mutex_unlock(&fwspk->mutex); | ||
| 302 | |||
| 303 | amdtp_out_stream_pcm_prepare(&fwspk->stream); | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | |||
| 307 | err_connection: | ||
| 308 | cmp_connection_break(&fwspk->connection); | ||
| 309 | err_mutex: | ||
| 310 | mutex_unlock(&fwspk->mutex); | ||
| 311 | |||
| 312 | return err; | ||
| 313 | } | ||
| 314 | |||
| 315 | static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 316 | { | ||
| 317 | struct fwspk *fwspk = substream->private_data; | ||
| 318 | struct snd_pcm_substream *pcm; | ||
| 319 | |||
| 320 | switch (cmd) { | ||
| 321 | case SNDRV_PCM_TRIGGER_START: | ||
| 322 | pcm = substream; | ||
| 323 | break; | ||
| 324 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 325 | pcm = NULL; | ||
| 326 | break; | ||
| 327 | default: | ||
| 328 | return -EINVAL; | ||
| 329 | } | ||
| 330 | amdtp_out_stream_pcm_trigger(&fwspk->stream, pcm); | ||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream) | ||
| 335 | { | ||
| 336 | struct fwspk *fwspk = substream->private_data; | ||
| 337 | |||
| 338 | return amdtp_out_stream_pcm_pointer(&fwspk->stream); | ||
| 339 | } | ||
| 340 | |||
| 341 | static int fwspk_create_pcm(struct fwspk *fwspk) | ||
| 342 | { | ||
| 343 | static struct snd_pcm_ops ops = { | ||
| 344 | .open = fwspk_open, | ||
| 345 | .close = fwspk_close, | ||
| 346 | .ioctl = snd_pcm_lib_ioctl, | ||
| 347 | .hw_params = fwspk_hw_params, | ||
| 348 | .hw_free = fwspk_hw_free, | ||
| 349 | .prepare = fwspk_prepare, | ||
| 350 | .trigger = fwspk_trigger, | ||
| 351 | .pointer = fwspk_pointer, | ||
| 352 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 353 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 354 | }; | ||
| 355 | struct snd_pcm *pcm; | ||
| 356 | int err; | ||
| 357 | |||
| 358 | err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm); | ||
| 359 | if (err < 0) | ||
| 360 | return err; | ||
| 361 | pcm->private_data = fwspk; | ||
| 362 | strcpy(pcm->name, fwspk->device_info->short_name); | ||
| 363 | fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | ||
| 364 | fwspk->pcm->ops = &ops; | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | enum control_action { CTL_READ, CTL_WRITE }; | ||
| 369 | enum control_attribute { | ||
| 370 | CTL_MIN = 0x02, | ||
| 371 | CTL_MAX = 0x03, | ||
| 372 | CTL_CURRENT = 0x10, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static int fwspk_mute_command(struct fwspk *fwspk, bool *value, | ||
| 376 | enum control_action action) | ||
| 377 | { | ||
| 378 | u8 *buf; | ||
| 379 | u8 response_ok; | ||
| 380 | int err; | ||
| 381 | |||
| 382 | buf = kmalloc(11, GFP_KERNEL); | ||
| 383 | if (!buf) | ||
| 384 | return -ENOMEM; | ||
| 385 | |||
| 386 | if (action == CTL_READ) { | ||
| 387 | buf[0] = 0x01; /* AV/C, STATUS */ | ||
| 388 | response_ok = 0x0c; /* STABLE */ | ||
| 389 | } else { | ||
| 390 | buf[0] = 0x00; /* AV/C, CONTROL */ | ||
| 391 | response_ok = 0x09; /* ACCEPTED */ | ||
| 392 | } | ||
| 393 | buf[1] = 0x08; /* audio unit 0 */ | ||
| 394 | buf[2] = 0xb8; /* FUNCTION BLOCK */ | ||
| 395 | buf[3] = 0x81; /* function block type: feature */ | ||
| 396 | buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */ | ||
| 397 | buf[5] = 0x10; /* control attribute: current */ | ||
| 398 | buf[6] = 0x02; /* selector length */ | ||
| 399 | buf[7] = 0x00; /* audio channel number */ | ||
| 400 | buf[8] = 0x01; /* control selector: mute */ | ||
| 401 | buf[9] = 0x01; /* control data length */ | ||
| 402 | if (action == CTL_READ) | ||
| 403 | buf[10] = 0xff; | ||
| 404 | else | ||
| 405 | buf[10] = *value ? 0x70 : 0x60; | ||
| 406 | |||
| 407 | err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe); | ||
| 408 | if (err < 0) | ||
| 409 | goto error; | ||
| 410 | if (err < 11) { | ||
| 411 | dev_err(&fwspk->unit->device, "short FCP response\n"); | ||
| 412 | err = -EIO; | ||
| 413 | goto error; | ||
| 414 | } | ||
| 415 | if (buf[0] != response_ok) { | ||
| 416 | dev_err(&fwspk->unit->device, "mute command failed\n"); | ||
| 417 | err = -EIO; | ||
| 418 | goto error; | ||
| 419 | } | ||
| 420 | if (action == CTL_READ) | ||
| 421 | *value = buf[10] == 0x70; | ||
| 422 | |||
| 423 | err = 0; | ||
| 424 | |||
| 425 | error: | ||
| 426 | kfree(buf); | ||
| 427 | |||
| 428 | return err; | ||
| 429 | } | ||
| 430 | |||
| 431 | static int fwspk_volume_command(struct fwspk *fwspk, s16 *value, | ||
| 432 | unsigned int channel, | ||
| 433 | enum control_attribute attribute, | ||
| 434 | enum control_action action) | ||
| 435 | { | ||
| 436 | u8 *buf; | ||
| 437 | u8 response_ok; | ||
| 438 | int err; | ||
| 439 | |||
| 440 | buf = kmalloc(12, GFP_KERNEL); | ||
| 441 | if (!buf) | ||
| 442 | return -ENOMEM; | ||
| 443 | |||
| 444 | if (action == CTL_READ) { | ||
| 445 | buf[0] = 0x01; /* AV/C, STATUS */ | ||
| 446 | response_ok = 0x0c; /* STABLE */ | ||
| 447 | } else { | ||
| 448 | buf[0] = 0x00; /* AV/C, CONTROL */ | ||
| 449 | response_ok = 0x09; /* ACCEPTED */ | ||
| 450 | } | ||
| 451 | buf[1] = 0x08; /* audio unit 0 */ | ||
| 452 | buf[2] = 0xb8; /* FUNCTION BLOCK */ | ||
| 453 | buf[3] = 0x81; /* function block type: feature */ | ||
| 454 | buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */ | ||
| 455 | buf[5] = attribute; /* control attribute */ | ||
| 456 | buf[6] = 0x02; /* selector length */ | ||
| 457 | buf[7] = channel; /* audio channel number */ | ||
| 458 | buf[8] = 0x02; /* control selector: volume */ | ||
| 459 | buf[9] = 0x02; /* control data length */ | ||
| 460 | if (action == CTL_READ) { | ||
| 461 | buf[10] = 0xff; | ||
| 462 | buf[11] = 0xff; | ||
| 463 | } else { | ||
| 464 | buf[10] = *value >> 8; | ||
| 465 | buf[11] = *value; | ||
| 466 | } | ||
| 467 | |||
| 468 | err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe); | ||
| 469 | if (err < 0) | ||
| 470 | goto error; | ||
| 471 | if (err < 12) { | ||
| 472 | dev_err(&fwspk->unit->device, "short FCP response\n"); | ||
| 473 | err = -EIO; | ||
| 474 | goto error; | ||
| 475 | } | ||
| 476 | if (buf[0] != response_ok) { | ||
| 477 | dev_err(&fwspk->unit->device, "volume command failed\n"); | ||
| 478 | err = -EIO; | ||
| 479 | goto error; | ||
| 480 | } | ||
| 481 | if (action == CTL_READ) | ||
| 482 | *value = (buf[10] << 8) | buf[11]; | ||
| 483 | |||
| 484 | err = 0; | ||
| 485 | |||
| 486 | error: | ||
| 487 | kfree(buf); | ||
| 488 | |||
| 489 | return err; | ||
| 490 | } | ||
| 491 | |||
| 492 | static int fwspk_mute_get(struct snd_kcontrol *control, | ||
| 493 | struct snd_ctl_elem_value *value) | ||
| 494 | { | ||
| 495 | struct fwspk *fwspk = control->private_data; | ||
| 496 | |||
| 497 | value->value.integer.value[0] = !fwspk->mute; | ||
| 498 | |||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | static int fwspk_mute_put(struct snd_kcontrol *control, | ||
| 503 | struct snd_ctl_elem_value *value) | ||
| 504 | { | ||
| 505 | struct fwspk *fwspk = control->private_data; | ||
| 506 | bool mute; | ||
| 507 | int err; | ||
| 508 | |||
| 509 | mute = !value->value.integer.value[0]; | ||
| 510 | |||
| 511 | if (mute == fwspk->mute) | ||
| 512 | return 0; | ||
| 513 | |||
| 514 | err = fwspk_mute_command(fwspk, &mute, CTL_WRITE); | ||
| 515 | if (err < 0) | ||
| 516 | return err; | ||
| 517 | fwspk->mute = mute; | ||
| 518 | |||
| 519 | return 1; | ||
| 520 | } | ||
| 521 | |||
| 522 | static int fwspk_volume_info(struct snd_kcontrol *control, | ||
| 523 | struct snd_ctl_elem_info *info) | ||
| 524 | { | ||
| 525 | struct fwspk *fwspk = control->private_data; | ||
| 526 | |||
| 527 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 528 | info->count = fwspk->device_info->mixer_channels; | ||
| 529 | info->value.integer.min = fwspk->volume_min; | ||
| 530 | info->value.integer.max = fwspk->volume_max; | ||
| 531 | |||
| 532 | return 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; | ||
| 536 | |||
| 537 | static int fwspk_volume_get(struct snd_kcontrol *control, | ||
| 538 | struct snd_ctl_elem_value *value) | ||
| 539 | { | ||
| 540 | struct fwspk *fwspk = control->private_data; | ||
| 541 | unsigned int i; | ||
| 542 | |||
| 543 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) | ||
| 544 | value->value.integer.value[channel_map[i]] = fwspk->volume[i]; | ||
| 545 | |||
| 546 | return 0; | ||
| 547 | } | ||
| 548 | |||
| 549 | static int fwspk_volume_put(struct snd_kcontrol *control, | ||
| 550 | struct snd_ctl_elem_value *value) | ||
| 551 | { | ||
| 552 | struct fwspk *fwspk = control->private_data; | ||
| 553 | unsigned int i, changed_channels; | ||
| 554 | bool equal_values = true; | ||
| 555 | s16 volume; | ||
| 556 | int err; | ||
| 557 | |||
| 558 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { | ||
| 559 | if (value->value.integer.value[i] < fwspk->volume_min || | ||
| 560 | value->value.integer.value[i] > fwspk->volume_max) | ||
| 561 | return -EINVAL; | ||
| 562 | if (value->value.integer.value[i] != | ||
| 563 | value->value.integer.value[0]) | ||
| 564 | equal_values = false; | ||
| 565 | } | ||
| 566 | |||
| 567 | changed_channels = 0; | ||
| 568 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) | ||
| 569 | if (value->value.integer.value[channel_map[i]] != | ||
| 570 | fwspk->volume[i]) | ||
| 571 | changed_channels |= 1 << (i + 1); | ||
| 572 | |||
| 573 | if (equal_values && changed_channels != 0) | ||
| 574 | changed_channels = 1 << 0; | ||
| 575 | |||
| 576 | for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) { | ||
| 577 | volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; | ||
| 578 | if (changed_channels & (1 << i)) { | ||
| 579 | err = fwspk_volume_command(fwspk, &volume, i, | ||
| 580 | CTL_CURRENT, CTL_WRITE); | ||
| 581 | if (err < 0) | ||
| 582 | return err; | ||
| 583 | } | ||
| 584 | if (i > 0) | ||
| 585 | fwspk->volume[i - 1] = volume; | ||
| 586 | } | ||
| 587 | |||
| 588 | return changed_channels != 0; | ||
| 589 | } | ||
| 590 | |||
| 591 | static int fwspk_create_mixer(struct fwspk *fwspk) | ||
| 592 | { | ||
| 593 | static const struct snd_kcontrol_new controls[] = { | ||
| 594 | { | ||
| 595 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 596 | .name = "PCM Playback Switch", | ||
| 597 | .info = snd_ctl_boolean_mono_info, | ||
| 598 | .get = fwspk_mute_get, | ||
| 599 | .put = fwspk_mute_put, | ||
| 600 | }, | ||
| 601 | { | ||
| 602 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 603 | .name = "PCM Playback Volume", | ||
| 604 | .info = fwspk_volume_info, | ||
| 605 | .get = fwspk_volume_get, | ||
| 606 | .put = fwspk_volume_put, | ||
| 607 | }, | ||
| 608 | }; | ||
| 609 | unsigned int i, first_ch; | ||
| 610 | int err; | ||
| 611 | |||
| 612 | err = fwspk_volume_command(fwspk, &fwspk->volume_min, | ||
| 613 | 0, CTL_MIN, CTL_READ); | ||
| 614 | if (err < 0) | ||
| 615 | return err; | ||
| 616 | err = fwspk_volume_command(fwspk, &fwspk->volume_max, | ||
| 617 | 0, CTL_MAX, CTL_READ); | ||
| 618 | if (err < 0) | ||
| 619 | return err; | ||
| 620 | |||
| 621 | err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ); | ||
| 622 | if (err < 0) | ||
| 623 | return err; | ||
| 624 | |||
| 625 | first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1; | ||
| 626 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { | ||
| 627 | err = fwspk_volume_command(fwspk, &fwspk->volume[i], | ||
| 628 | first_ch + i, CTL_CURRENT, CTL_READ); | ||
| 629 | if (err < 0) | ||
| 630 | return err; | ||
| 631 | } | ||
| 632 | |||
| 633 | for (i = 0; i < ARRAY_SIZE(controls); ++i) { | ||
| 634 | err = snd_ctl_add(fwspk->card, | ||
| 635 | snd_ctl_new1(&controls[i], fwspk)); | ||
| 636 | if (err < 0) | ||
| 637 | return err; | ||
| 638 | } | ||
| 639 | |||
| 640 | return 0; | ||
| 641 | } | ||
| 642 | |||
| 643 | static u32 fwspk_read_firmware_version(struct fw_unit *unit) | ||
| 644 | { | ||
| 645 | __be32 data; | ||
| 646 | int err; | ||
| 647 | |||
| 648 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, | ||
| 649 | OXFORD_FIRMWARE_ID_ADDRESS, &data, 4); | ||
| 650 | return err >= 0 ? be32_to_cpu(data) : 0; | ||
| 651 | } | ||
| 652 | |||
| 653 | static void fwspk_card_free(struct snd_card *card) | ||
| 654 | { | ||
| 655 | struct fwspk *fwspk = card->private_data; | ||
| 656 | struct fw_device *dev = fw_parent_device(fwspk->unit); | ||
| 657 | |||
| 658 | amdtp_out_stream_destroy(&fwspk->stream); | ||
| 659 | cmp_connection_destroy(&fwspk->connection); | ||
| 660 | fw_unit_put(fwspk->unit); | ||
| 661 | fw_device_put(dev); | ||
| 662 | mutex_destroy(&fwspk->mutex); | ||
| 663 | } | ||
| 664 | |||
| 665 | static const struct device_info *__devinit fwspk_detect(struct fw_device *dev) | ||
| 666 | { | ||
| 667 | static const struct device_info griffin_firewave = { | ||
| 668 | .driver_name = "FireWave", | ||
| 669 | .short_name = "FireWave", | ||
| 670 | .long_name = "Griffin FireWave Surround", | ||
| 671 | .pcm_constraints = firewave_constraints, | ||
| 672 | .mixer_channels = 6, | ||
| 673 | .mute_fb_id = 0x01, | ||
| 674 | .volume_fb_id = 0x02, | ||
| 675 | }; | ||
| 676 | static const struct device_info lacie_speakers = { | ||
| 677 | .driver_name = "FWSpeakers", | ||
| 678 | .short_name = "FireWire Speakers", | ||
| 679 | .long_name = "LaCie FireWire Speakers", | ||
| 680 | .pcm_constraints = lacie_speakers_constraints, | ||
| 681 | .mixer_channels = 1, | ||
| 682 | .mute_fb_id = 0x01, | ||
| 683 | .volume_fb_id = 0x01, | ||
| 684 | }; | ||
| 685 | struct fw_csr_iterator i; | ||
| 686 | int key, value; | ||
| 687 | |||
| 688 | fw_csr_iterator_init(&i, dev->config_rom); | ||
| 689 | while (fw_csr_iterator_next(&i, &key, &value)) | ||
| 690 | if (key == CSR_VENDOR) | ||
| 691 | switch (value) { | ||
| 692 | case VENDOR_GRIFFIN: | ||
| 693 | return &griffin_firewave; | ||
| 694 | case VENDOR_LACIE: | ||
| 695 | return &lacie_speakers; | ||
| 696 | } | ||
| 697 | |||
| 698 | return NULL; | ||
| 699 | } | ||
| 700 | |||
| 701 | static int __devinit fwspk_probe(struct device *unit_dev) | ||
| 702 | { | ||
| 703 | struct fw_unit *unit = fw_unit(unit_dev); | ||
| 704 | struct fw_device *fw_dev = fw_parent_device(unit); | ||
| 705 | struct snd_card *card; | ||
| 706 | struct fwspk *fwspk; | ||
| 707 | u32 firmware; | ||
| 708 | int err; | ||
| 709 | |||
| 710 | err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card); | ||
| 711 | if (err < 0) | ||
| 712 | return err; | ||
| 713 | snd_card_set_dev(card, unit_dev); | ||
| 714 | |||
| 715 | fwspk = card->private_data; | ||
| 716 | fwspk->card = card; | ||
| 717 | mutex_init(&fwspk->mutex); | ||
| 718 | fw_device_get(fw_dev); | ||
| 719 | fwspk->unit = fw_unit_get(unit); | ||
| 720 | fwspk->device_info = fwspk_detect(fw_dev); | ||
| 721 | if (!fwspk->device_info) { | ||
| 722 | err = -ENODEV; | ||
| 723 | goto err_unit; | ||
| 724 | } | ||
| 725 | |||
| 726 | err = cmp_connection_init(&fwspk->connection, unit, 0); | ||
| 727 | if (err < 0) | ||
| 728 | goto err_unit; | ||
| 729 | |||
| 730 | err = amdtp_out_stream_init(&fwspk->stream, unit, CIP_NONBLOCKING); | ||
| 731 | if (err < 0) | ||
| 732 | goto err_connection; | ||
| 733 | |||
| 734 | card->private_free = fwspk_card_free; | ||
| 735 | |||
| 736 | strcpy(card->driver, fwspk->device_info->driver_name); | ||
| 737 | strcpy(card->shortname, fwspk->device_info->short_name); | ||
| 738 | firmware = fwspk_read_firmware_version(unit); | ||
| 739 | snprintf(card->longname, sizeof(card->longname), | ||
| 740 | "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", | ||
| 741 | fwspk->device_info->long_name, | ||
| 742 | firmware >> 20, firmware & 0xffff, | ||
| 743 | fw_dev->config_rom[3], fw_dev->config_rom[4], | ||
| 744 | dev_name(&unit->device), 100 << fw_dev->max_speed); | ||
| 745 | strcpy(card->mixername, "OXFW970"); | ||
| 746 | |||
| 747 | err = fwspk_create_pcm(fwspk); | ||
| 748 | if (err < 0) | ||
| 749 | goto error; | ||
| 750 | |||
| 751 | err = fwspk_create_mixer(fwspk); | ||
| 752 | if (err < 0) | ||
| 753 | goto error; | ||
| 754 | |||
| 755 | err = snd_card_register(card); | ||
| 756 | if (err < 0) | ||
| 757 | goto error; | ||
| 758 | |||
| 759 | dev_set_drvdata(unit_dev, fwspk); | ||
| 760 | |||
| 761 | return 0; | ||
| 762 | |||
| 763 | err_connection: | ||
| 764 | cmp_connection_destroy(&fwspk->connection); | ||
| 765 | err_unit: | ||
| 766 | fw_unit_put(fwspk->unit); | ||
| 767 | fw_device_put(fw_dev); | ||
| 768 | mutex_destroy(&fwspk->mutex); | ||
| 769 | error: | ||
| 770 | snd_card_free(card); | ||
| 771 | return err; | ||
| 772 | } | ||
| 773 | |||
| 774 | static int __devexit fwspk_remove(struct device *dev) | ||
| 775 | { | ||
| 776 | struct fwspk *fwspk = dev_get_drvdata(dev); | ||
| 777 | |||
| 778 | snd_card_disconnect(fwspk->card); | ||
| 779 | |||
| 780 | mutex_lock(&fwspk->mutex); | ||
| 781 | amdtp_out_stream_pcm_abort(&fwspk->stream); | ||
| 782 | fwspk_stop_stream(fwspk); | ||
| 783 | mutex_unlock(&fwspk->mutex); | ||
| 784 | |||
| 785 | snd_card_free_when_closed(fwspk->card); | ||
| 786 | |||
| 787 | return 0; | ||
| 788 | } | ||
| 789 | |||
| 790 | static void fwspk_bus_reset(struct fw_unit *unit) | ||
| 791 | { | ||
| 792 | struct fwspk *fwspk = dev_get_drvdata(&unit->device); | ||
| 793 | |||
| 794 | fcp_bus_reset(fwspk->unit); | ||
| 795 | |||
| 796 | if (cmp_connection_update(&fwspk->connection) < 0) { | ||
| 797 | mutex_lock(&fwspk->mutex); | ||
| 798 | amdtp_out_stream_pcm_abort(&fwspk->stream); | ||
| 799 | fwspk_stop_stream(fwspk); | ||
| 800 | mutex_unlock(&fwspk->mutex); | ||
| 801 | return; | ||
| 802 | } | ||
| 803 | |||
| 804 | amdtp_out_stream_update(&fwspk->stream); | ||
| 805 | } | ||
| 806 | |||
| 807 | static const struct ieee1394_device_id fwspk_id_table[] = { | ||
| 808 | { | ||
| 809 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
| 810 | IEEE1394_MATCH_MODEL_ID | | ||
| 811 | IEEE1394_MATCH_SPECIFIER_ID | | ||
| 812 | IEEE1394_MATCH_VERSION, | ||
| 813 | .vendor_id = VENDOR_GRIFFIN, | ||
| 814 | .model_id = 0x00f970, | ||
| 815 | .specifier_id = SPECIFIER_1394TA, | ||
| 816 | .version = VERSION_AVC, | ||
| 817 | }, | ||
| 818 | { | ||
| 819 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
| 820 | IEEE1394_MATCH_MODEL_ID | | ||
| 821 | IEEE1394_MATCH_SPECIFIER_ID | | ||
| 822 | IEEE1394_MATCH_VERSION, | ||
| 823 | .vendor_id = VENDOR_LACIE, | ||
| 824 | .model_id = 0x00f970, | ||
| 825 | .specifier_id = SPECIFIER_1394TA, | ||
| 826 | .version = VERSION_AVC, | ||
| 827 | }, | ||
| 828 | { } | ||
| 829 | }; | ||
| 830 | MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table); | ||
| 831 | |||
| 832 | static struct fw_driver fwspk_driver = { | ||
| 833 | .driver = { | ||
| 834 | .owner = THIS_MODULE, | ||
| 835 | .name = KBUILD_MODNAME, | ||
| 836 | .bus = &fw_bus_type, | ||
| 837 | .probe = fwspk_probe, | ||
| 838 | .remove = __devexit_p(fwspk_remove), | ||
| 839 | }, | ||
| 840 | .update = fwspk_bus_reset, | ||
| 841 | .id_table = fwspk_id_table, | ||
| 842 | }; | ||
| 843 | |||
| 844 | static int __init alsa_fwspk_init(void) | ||
| 845 | { | ||
| 846 | return driver_register(&fwspk_driver.driver); | ||
| 847 | } | ||
| 848 | |||
| 849 | static void __exit alsa_fwspk_exit(void) | ||
| 850 | { | ||
| 851 | driver_unregister(&fwspk_driver.driver); | ||
| 852 | } | ||
| 853 | |||
| 854 | module_init(alsa_fwspk_init); | ||
| 855 | module_exit(alsa_fwspk_exit); | ||
