diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/sound/firewire | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/sound/firewire')
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/Kconfig | 36 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/Makefile | 8 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/amdtp.c | 563 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/amdtp.h | 169 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/cmp.c | 307 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/cmp.h | 41 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/fcp.c | 224 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/fcp.h | 12 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/isight.c | 753 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/iso-resources.c | 232 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/iso-resources.h | 38 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/lib.c | 85 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/lib.h | 19 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/packets-buffer.c | 77 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/packets-buffer.h | 26 | ||||
-rw-r--r-- | ANDROID_3.4.5/sound/firewire/speakers.c | 854 |
16 files changed, 0 insertions, 3444 deletions
diff --git a/ANDROID_3.4.5/sound/firewire/Kconfig b/ANDROID_3.4.5/sound/firewire/Kconfig deleted file mode 100644 index 26071489..00000000 --- a/ANDROID_3.4.5/sound/firewire/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -menuconfig SND_FIREWIRE - bool "FireWire sound devices" - depends on FIREWIRE - default y - help - Support for IEEE-1394/FireWire/iLink sound devices. - -if SND_FIREWIRE && FIREWIRE - -config SND_FIREWIRE_LIB - tristate - depends on SND_PCM - -config SND_FIREWIRE_SPEAKERS - tristate "FireWire speakers" - select SND_PCM - select SND_FIREWIRE_LIB - help - Say Y here to include support for the Griffin FireWave Surround - and the LaCie FireWire Speakers. - - To compile this driver as a module, choose M here: the module - will be called snd-firewire-speakers. - -config SND_ISIGHT - tristate "Apple iSight microphone" - select SND_PCM - select SND_FIREWIRE_LIB - help - Say Y here to include support for the front and rear microphones - of the Apple iSight web camera. - - To compile this driver as a module, choose M here: the module - will be called snd-isight. - -endif # SND_FIREWIRE diff --git a/ANDROID_3.4.5/sound/firewire/Makefile b/ANDROID_3.4.5/sound/firewire/Makefile deleted file mode 100644 index d71ed893..00000000 --- a/ANDROID_3.4.5/sound/firewire/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ - fcp.o cmp.o amdtp.o -snd-firewire-speakers-objs := speakers.o -snd-isight-objs := isight.o - -obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o -obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o -obj-$(CONFIG_SND_ISIGHT) += snd-isight.o diff --git a/ANDROID_3.4.5/sound/firewire/amdtp.c b/ANDROID_3.4.5/sound/firewire/amdtp.c deleted file mode 100644 index 87657dd7..00000000 --- a/ANDROID_3.4.5/sound/firewire/amdtp.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Audio and Music Data Transmission Protocol (IEC 61883-6) streams - * with Common Isochronous Packet (IEC 61883-1) headers - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/device.h> -#include <linux/err.h> -#include <linux/firewire.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <sound/pcm.h> -#include "amdtp.h" - -#define TICKS_PER_CYCLE 3072 -#define CYCLES_PER_SECOND 8000 -#define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) - -#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ - -#define TAG_CIP 1 - -#define CIP_EOH (1u << 31) -#define CIP_FMT_AM (0x10 << 24) -#define AMDTP_FDF_AM824 (0 << 19) -#define AMDTP_FDF_SFC_SHIFT 16 - -/* TODO: make these configurable */ -#define INTERRUPT_INTERVAL 16 -#define QUEUE_LENGTH 48 - -/** - * amdtp_out_stream_init - initialize an AMDTP output stream structure - * @s: the AMDTP output stream to initialize - * @unit: the target of the stream - * @flags: the packet transmission method to use - */ -int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, - enum cip_out_flags flags) -{ - if (flags != CIP_NONBLOCKING) - return -EINVAL; - - s->unit = fw_unit_get(unit); - s->flags = flags; - s->context = ERR_PTR(-1); - mutex_init(&s->mutex); - s->packet_index = 0; - - return 0; -} -EXPORT_SYMBOL(amdtp_out_stream_init); - -/** - * amdtp_out_stream_destroy - free stream resources - * @s: the AMDTP output stream to destroy - */ -void amdtp_out_stream_destroy(struct amdtp_out_stream *s) -{ - WARN_ON(!IS_ERR(s->context)); - mutex_destroy(&s->mutex); - fw_unit_put(s->unit); -} -EXPORT_SYMBOL(amdtp_out_stream_destroy); - -/** - * amdtp_out_stream_set_rate - set the sample rate - * @s: the AMDTP output stream to configure - * @rate: the sample rate - * - * The sample rate must be set before the stream is started, and must not be - * changed while the stream is running. - */ -void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) -{ - static const struct { - unsigned int rate; - unsigned int syt_interval; - } rate_info[] = { - [CIP_SFC_32000] = { 32000, 8, }, - [CIP_SFC_44100] = { 44100, 8, }, - [CIP_SFC_48000] = { 48000, 8, }, - [CIP_SFC_88200] = { 88200, 16, }, - [CIP_SFC_96000] = { 96000, 16, }, - [CIP_SFC_176400] = { 176400, 32, }, - [CIP_SFC_192000] = { 192000, 32, }, - }; - unsigned int sfc; - - if (WARN_ON(!IS_ERR(s->context))) - return; - - for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) - if (rate_info[sfc].rate == rate) { - s->sfc = sfc; - s->syt_interval = rate_info[sfc].syt_interval; - return; - } - WARN_ON(1); -} -EXPORT_SYMBOL(amdtp_out_stream_set_rate); - -/** - * amdtp_out_stream_get_max_payload - get the stream's packet size - * @s: the AMDTP output stream - * - * This function must not be called before the stream has been configured - * with amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and - * amdtp_out_stream_set_midi(). - */ -unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) -{ - static const unsigned int max_data_blocks[] = { - [CIP_SFC_32000] = 4, - [CIP_SFC_44100] = 6, - [CIP_SFC_48000] = 6, - [CIP_SFC_88200] = 12, - [CIP_SFC_96000] = 12, - [CIP_SFC_176400] = 23, - [CIP_SFC_192000] = 24, - }; - - s->data_block_quadlets = s->pcm_channels; - s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); - - return 8 + max_data_blocks[s->sfc] * 4 * s->data_block_quadlets; -} -EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); - -static void amdtp_write_s16(struct amdtp_out_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); -static void amdtp_write_s32(struct amdtp_out_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); - -/** - * amdtp_out_stream_set_pcm_format - set the PCM format - * @s: the AMDTP output stream to configure - * @format: the format of the ALSA PCM device - * - * The sample format must be set before the stream is started, and must not be - * changed while the stream is running. - */ -void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, - snd_pcm_format_t format) -{ - if (WARN_ON(!IS_ERR(s->context))) - return; - - switch (format) { - default: - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S16: - s->transfer_samples = amdtp_write_s16; - break; - case SNDRV_PCM_FORMAT_S32: - s->transfer_samples = amdtp_write_s32; - break; - } -} -EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format); - -static unsigned int calculate_data_blocks(struct amdtp_out_stream *s) -{ - unsigned int phase, data_blocks; - - if (!cip_sfc_is_base_44100(s->sfc)) { - /* Sample_rate / 8000 is an integer, and precomputed. */ - data_blocks = s->data_block_state; - } else { - phase = s->data_block_state; - - /* - * This calculates the number of data blocks per packet so that - * 1) the overall rate is correct and exactly synchronized to - * the bus clock, and - * 2) packets with a rounded-up number of blocks occur as early - * as possible in the sequence (to prevent underruns of the - * device's buffer). - */ - if (s->sfc == CIP_SFC_44100) - /* 6 6 5 6 5 6 5 ... */ - data_blocks = 5 + ((phase & 1) ^ - (phase == 0 || phase >= 40)); - else - /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */ - data_blocks = 11 * (s->sfc >> 1) + (phase == 0); - if (++phase >= (80 >> (s->sfc >> 1))) - phase = 0; - s->data_block_state = phase; - } - - return data_blocks; -} - -static unsigned int calculate_syt(struct amdtp_out_stream *s, - unsigned int cycle) -{ - unsigned int syt_offset, phase, index, syt; - - if (s->last_syt_offset < TICKS_PER_CYCLE) { - if (!cip_sfc_is_base_44100(s->sfc)) - syt_offset = s->last_syt_offset + s->syt_offset_state; - else { - /* - * The time, in ticks, of the n'th SYT_INTERVAL sample is: - * n * SYT_INTERVAL * 24576000 / sample_rate - * Modulo TICKS_PER_CYCLE, the difference between successive - * elements is about 1386.23. Rounding the results of this - * formula to the SYT precision results in a sequence of - * differences that begins with: - * 1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ... - * This code generates _exactly_ the same sequence. - */ - phase = s->syt_offset_state; - index = phase % 13; - syt_offset = s->last_syt_offset; - syt_offset += 1386 + ((index && !(index & 3)) || - phase == 146); - if (++phase >= 147) - phase = 0; - s->syt_offset_state = phase; - } - } else - syt_offset = s->last_syt_offset - TICKS_PER_CYCLE; - s->last_syt_offset = syt_offset; - - if (syt_offset < TICKS_PER_CYCLE) { - syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; - syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12; - syt += syt_offset % TICKS_PER_CYCLE; - - return syt & 0xffff; - } else { - return 0xffff; /* no info */ - } -} - -static void amdtp_write_s32(struct amdtp_out_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, frame_step, i, c; - const u32 *src; - - channels = s->pcm_channels; - src = (void *)runtime->dma_area + - s->pcm_buffer_pointer * (runtime->frame_bits / 8); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - frame_step = s->data_block_quadlets - channels; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - *buffer = cpu_to_be32((*src >> 8) | 0x40000000); - src++; - buffer++; - } - buffer += frame_step; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - -static void amdtp_write_s16(struct amdtp_out_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, frame_step, i, c; - const u16 *src; - - channels = s->pcm_channels; - src = (void *)runtime->dma_area + - s->pcm_buffer_pointer * (runtime->frame_bits / 8); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - frame_step = s->data_block_quadlets - channels; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - *buffer = cpu_to_be32((*src << 8) | 0x40000000); - src++; - buffer++; - } - buffer += frame_step; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - -static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s, - __be32 *buffer, unsigned int frames) -{ - unsigned int i, c; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < s->pcm_channels; ++c) - buffer[c] = cpu_to_be32(0x40000000); - buffer += s->data_block_quadlets; - } -} - -static void amdtp_fill_midi(struct amdtp_out_stream *s, - __be32 *buffer, unsigned int frames) -{ - unsigned int i; - - for (i = 0; i < frames; ++i) - buffer[s->pcm_channels + i * s->data_block_quadlets] = - cpu_to_be32(0x80000000); -} - -static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) -{ - __be32 *buffer; - unsigned int index, data_blocks, syt, ptr; - struct snd_pcm_substream *pcm; - struct fw_iso_packet packet; - int err; - - if (s->packet_index < 0) - return; - index = s->packet_index; - - data_blocks = calculate_data_blocks(s); - syt = calculate_syt(s, cycle); - - buffer = s->buffer.packets[index].buffer; - buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | - (s->data_block_quadlets << 16) | - s->data_block_counter); - buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 | - (s->sfc << AMDTP_FDF_SFC_SHIFT) | syt); - buffer += 2; - - pcm = ACCESS_ONCE(s->pcm); - if (pcm) - s->transfer_samples(s, pcm, buffer, data_blocks); - else - amdtp_fill_pcm_silence(s, buffer, data_blocks); - if (s->midi_ports) - amdtp_fill_midi(s, buffer, data_blocks); - - s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; - - packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; - packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL); - packet.skip = 0; - packet.tag = TAG_CIP; - packet.sy = 0; - packet.header_length = 0; - - err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer, - s->buffer.packets[index].offset); - if (err < 0) { - dev_err(&s->unit->device, "queueing error: %d\n", err); - s->packet_index = -1; - amdtp_out_stream_pcm_abort(s); - return; - } - - if (++index >= QUEUE_LENGTH) - index = 0; - s->packet_index = index; - - if (pcm) { - ptr = s->pcm_buffer_pointer + data_blocks; - if (ptr >= pcm->runtime->buffer_size) - ptr -= pcm->runtime->buffer_size; - ACCESS_ONCE(s->pcm_buffer_pointer) = ptr; - - s->pcm_period_pointer += data_blocks; - if (s->pcm_period_pointer >= pcm->runtime->period_size) { - s->pcm_period_pointer -= pcm->runtime->period_size; - snd_pcm_period_elapsed(pcm); - } - } -} - -static void out_packet_callback(struct fw_iso_context *context, u32 cycle, - size_t header_length, void *header, void *data) -{ - struct amdtp_out_stream *s = data; - unsigned int i, packets = header_length / 4; - - /* - * Compute the cycle of the last queued packet. - * (We need only the four lowest bits for the SYT, so we can ignore - * that bits 0-11 must wrap around at 3072.) - */ - cycle += QUEUE_LENGTH - packets; - - for (i = 0; i < packets; ++i) - queue_out_packet(s, ++cycle); - fw_iso_context_queue_flush(s->context); -} - -static int queue_initial_skip_packets(struct amdtp_out_stream *s) -{ - struct fw_iso_packet skip_packet = { - .skip = 1, - }; - unsigned int i; - int err; - - for (i = 0; i < QUEUE_LENGTH; ++i) { - skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1, - INTERRUPT_INTERVAL); - err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0); - if (err < 0) - return err; - if (++s->packet_index >= QUEUE_LENGTH) - s->packet_index = 0; - } - - return 0; -} - -/** - * amdtp_out_stream_start - start sending packets - * @s: the AMDTP output stream to start - * @channel: the isochronous channel on the bus - * @speed: firewire speed code - * - * The stream cannot be started until it has been configured with - * amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and - * amdtp_out_stream_set_midi(); and it must be started before any - * PCM or MIDI device can be started. - */ -int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) -{ - static const struct { - unsigned int data_block; - unsigned int syt_offset; - } initial_state[] = { - [CIP_SFC_32000] = { 4, 3072 }, - [CIP_SFC_48000] = { 6, 1024 }, - [CIP_SFC_96000] = { 12, 1024 }, - [CIP_SFC_192000] = { 24, 1024 }, - [CIP_SFC_44100] = { 0, 67 }, - [CIP_SFC_88200] = { 0, 67 }, - [CIP_SFC_176400] = { 0, 67 }, - }; - int err; - - mutex_lock(&s->mutex); - - if (WARN_ON(!IS_ERR(s->context) || - (!s->pcm_channels && !s->midi_ports))) { - err = -EBADFD; - goto err_unlock; - } - - s->data_block_state = initial_state[s->sfc].data_block; - s->syt_offset_state = initial_state[s->sfc].syt_offset; - s->last_syt_offset = TICKS_PER_CYCLE; - - err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH, - amdtp_out_stream_get_max_payload(s), - DMA_TO_DEVICE); - if (err < 0) - goto err_unlock; - - s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, - FW_ISO_CONTEXT_TRANSMIT, - channel, speed, 0, - out_packet_callback, s); - if (IS_ERR(s->context)) { - err = PTR_ERR(s->context); - if (err == -EBUSY) - dev_err(&s->unit->device, - "no free output stream on this controller\n"); - goto err_buffer; - } - - amdtp_out_stream_update(s); - - s->packet_index = 0; - s->data_block_counter = 0; - err = queue_initial_skip_packets(s); - if (err < 0) - goto err_context; - - err = fw_iso_context_start(s->context, -1, 0, 0); - if (err < 0) - goto err_context; - - mutex_unlock(&s->mutex); - - return 0; - -err_context: - fw_iso_context_destroy(s->context); - s->context = ERR_PTR(-1); -err_buffer: - iso_packets_buffer_destroy(&s->buffer, s->unit); -err_unlock: - mutex_unlock(&s->mutex); - - return err; -} -EXPORT_SYMBOL(amdtp_out_stream_start); - -/** - * amdtp_out_stream_update - update the stream after a bus reset - * @s: the AMDTP output stream - */ -void amdtp_out_stream_update(struct amdtp_out_stream *s) -{ - ACCESS_ONCE(s->source_node_id_field) = - (fw_parent_device(s->unit)->card->node_id & 0x3f) << 24; -} -EXPORT_SYMBOL(amdtp_out_stream_update); - -/** - * amdtp_out_stream_stop - stop sending packets - * @s: the AMDTP output stream to stop - * - * All PCM and MIDI devices of the stream must be stopped before the stream - * itself can be stopped. - */ -void amdtp_out_stream_stop(struct amdtp_out_stream *s) -{ - mutex_lock(&s->mutex); - - if (IS_ERR(s->context)) { - mutex_unlock(&s->mutex); - return; - } - - fw_iso_context_stop(s->context); - fw_iso_context_destroy(s->context); - s->context = ERR_PTR(-1); - iso_packets_buffer_destroy(&s->buffer, s->unit); - - mutex_unlock(&s->mutex); -} -EXPORT_SYMBOL(amdtp_out_stream_stop); - -/** - * amdtp_out_stream_pcm_abort - abort the running PCM device - * @s: the AMDTP stream about to be stopped - * - * If the isochronous stream needs to be stopped asynchronously, call this - * function first to stop the PCM device. - */ -void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s) -{ - struct snd_pcm_substream *pcm; - - pcm = ACCESS_ONCE(s->pcm); - if (pcm) { - snd_pcm_stream_lock_irq(pcm); - if (snd_pcm_running(pcm)) - snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irq(pcm); - } -} -EXPORT_SYMBOL(amdtp_out_stream_pcm_abort); diff --git a/ANDROID_3.4.5/sound/firewire/amdtp.h b/ANDROID_3.4.5/sound/firewire/amdtp.h deleted file mode 100644 index 537a9cb8..00000000 --- a/ANDROID_3.4.5/sound/firewire/amdtp.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED -#define SOUND_FIREWIRE_AMDTP_H_INCLUDED - -#include <linux/mutex.h> -#include <linux/spinlock.h> -#include "packets-buffer.h" - -/** - * enum cip_out_flags - describes details of the streaming protocol - * @CIP_NONBLOCKING: In non-blocking mode, each packet contains - * sample_rate/8000 samples, with rounding up or down to adjust - * for clock skew and left-over fractional samples. This should - * be used if supported by the device. - */ -enum cip_out_flags { - CIP_NONBLOCKING = 0, -}; - -/** - * enum cip_sfc - a stream's sample rate - */ -enum cip_sfc { - CIP_SFC_32000 = 0, - CIP_SFC_44100 = 1, - CIP_SFC_48000 = 2, - CIP_SFC_88200 = 3, - CIP_SFC_96000 = 4, - CIP_SFC_176400 = 5, - CIP_SFC_192000 = 6, -}; - -#define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ - SNDRV_PCM_FMTBIT_S32) - -struct fw_unit; -struct fw_iso_context; -struct snd_pcm_substream; - -struct amdtp_out_stream { - struct fw_unit *unit; - enum cip_out_flags flags; - struct fw_iso_context *context; - struct mutex mutex; - - enum cip_sfc sfc; - unsigned int data_block_quadlets; - unsigned int pcm_channels; - unsigned int midi_ports; - void (*transfer_samples)(struct amdtp_out_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); - - unsigned int syt_interval; - unsigned int source_node_id_field; - struct iso_packets_buffer buffer; - - struct snd_pcm_substream *pcm; - - int packet_index; - unsigned int data_block_counter; - - unsigned int data_block_state; - - unsigned int last_syt_offset; - unsigned int syt_offset_state; - - unsigned int pcm_buffer_pointer; - unsigned int pcm_period_pointer; -}; - -int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, - enum cip_out_flags flags); -void amdtp_out_stream_destroy(struct amdtp_out_stream *s); - -void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate); -unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s); - -int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed); -void amdtp_out_stream_update(struct amdtp_out_stream *s); -void amdtp_out_stream_stop(struct amdtp_out_stream *s); - -void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, - snd_pcm_format_t format); -void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s); - -/** - * amdtp_out_stream_set_pcm - configure format of PCM samples - * @s: the AMDTP output stream to be configured - * @pcm_channels: the number of PCM samples in each data block, to be encoded - * as AM824 multi-bit linear audio - * - * This function must not be called while the stream is running. - */ -static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s, - unsigned int pcm_channels) -{ - s->pcm_channels = pcm_channels; -} - -/** - * amdtp_out_stream_set_midi - configure format of MIDI data - * @s: the AMDTP output stream to be configured - * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) - * - * This function must not be called while the stream is running. - */ -static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s, - unsigned int midi_ports) -{ - s->midi_ports = midi_ports; -} - -/** - * amdtp_out_streaming_error - check for streaming error - * @s: the AMDTP output stream - * - * If this function returns true, the stream's packet queue has stopped due to - * an asynchronous error. - */ -static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s) -{ - return s->packet_index < 0; -} - -/** - * amdtp_out_stream_pcm_prepare - prepare PCM device for running - * @s: the AMDTP output stream - * - * This function should be called from the PCM device's .prepare callback. - */ -static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s) -{ - s->pcm_buffer_pointer = 0; - s->pcm_period_pointer = 0; -} - -/** - * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device - * @s: the AMDTP output stream - * @pcm: the PCM device to be started, or %NULL to stop the current device - * - * Call this function on a running isochronous stream to enable the actual - * transmission of PCM data. This function should be called from the PCM - * device's .trigger callback. - */ -static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s, - struct snd_pcm_substream *pcm) -{ - ACCESS_ONCE(s->pcm) = pcm; -} - -/** - * amdtp_out_stream_pcm_pointer - get the PCM buffer position - * @s: the AMDTP output stream that transports the PCM data - * - * Returns the current buffer position, in frames. - */ -static inline unsigned long -amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s) -{ - return ACCESS_ONCE(s->pcm_buffer_pointer); -} - -static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) -{ - return sfc & 1; -} - -#endif diff --git a/ANDROID_3.4.5/sound/firewire/cmp.c b/ANDROID_3.4.5/sound/firewire/cmp.c deleted file mode 100644 index 76294f2a..00000000 --- a/ANDROID_3.4.5/sound/firewire/cmp.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Connection Management Procedures (IEC 61883-1) helper functions - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/firewire-constants.h> -#include <linux/module.h> -#include <linux/sched.h> -#include "lib.h" -#include "iso-resources.h" -#include "cmp.h" - -#define IMPR_SPEED_MASK 0xc0000000 -#define IMPR_SPEED_SHIFT 30 -#define IMPR_XSPEED_MASK 0x00000060 -#define IMPR_XSPEED_SHIFT 5 -#define IMPR_PLUGS_MASK 0x0000001f - -#define IPCR_ONLINE 0x80000000 -#define IPCR_BCAST_CONN 0x40000000 -#define IPCR_P2P_CONN_MASK 0x3f000000 -#define IPCR_P2P_CONN_SHIFT 24 -#define IPCR_CHANNEL_MASK 0x003f0000 -#define IPCR_CHANNEL_SHIFT 16 - -enum bus_reset_handling { - ABORT_ON_BUS_RESET, - SUCCEED_ON_BUS_RESET, -}; - -static __printf(2, 3) -void cmp_error(struct cmp_connection *c, const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - dev_err(&c->resources.unit->device, "%cPCR%u: %pV", - 'i', c->pcr_index, &(struct va_format){ fmt, &va }); - va_end(va); -} - -static int pcr_modify(struct cmp_connection *c, - __be32 (*modify)(struct cmp_connection *c, __be32 old), - int (*check)(struct cmp_connection *c, __be32 pcr), - enum bus_reset_handling bus_reset_handling) -{ - struct fw_device *device = fw_parent_device(c->resources.unit); - int generation = c->resources.generation; - int rcode, errors = 0; - __be32 old_arg, buffer[2]; - int err; - - buffer[0] = c->last_pcr_value; - for (;;) { - old_arg = buffer[0]; - buffer[1] = modify(c, buffer[0]); - - rcode = fw_run_transaction( - device->card, TCODE_LOCK_COMPARE_SWAP, - device->node_id, generation, device->max_speed, - CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index), - buffer, 8); - - if (rcode == RCODE_COMPLETE) { - if (buffer[0] == old_arg) /* success? */ - break; - - if (check) { - err = check(c, buffer[0]); - if (err < 0) - return err; - } - } else if (rcode == RCODE_GENERATION) - goto bus_reset; - else if (rcode_is_permanent_error(rcode) || ++errors >= 3) - goto io_error; - } - c->last_pcr_value = buffer[1]; - - return 0; - -io_error: - cmp_error(c, "transaction failed: %s\n", rcode_string(rcode)); - return -EIO; - -bus_reset: - return bus_reset_handling == ABORT_ON_BUS_RESET ? -EAGAIN : 0; -} - - -/** - * cmp_connection_init - initializes a connection manager - * @c: the connection manager to initialize - * @unit: a unit of the target device - * @ipcr_index: the index of the iPCR on the target device - */ -int cmp_connection_init(struct cmp_connection *c, - struct fw_unit *unit, - unsigned int ipcr_index) -{ - __be32 impr_be; - u32 impr; - int err; - - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - CSR_REGISTER_BASE + CSR_IMPR, - &impr_be, 4); - if (err < 0) - return err; - impr = be32_to_cpu(impr_be); - - if (ipcr_index >= (impr & IMPR_PLUGS_MASK)) - return -EINVAL; - - err = fw_iso_resources_init(&c->resources, unit); - if (err < 0) - return err; - - c->connected = false; - mutex_init(&c->mutex); - c->last_pcr_value = cpu_to_be32(0x80000000); - c->pcr_index = ipcr_index; - c->max_speed = (impr & IMPR_SPEED_MASK) >> IMPR_SPEED_SHIFT; - if (c->max_speed == SCODE_BETA) - c->max_speed += (impr & IMPR_XSPEED_MASK) >> IMPR_XSPEED_SHIFT; - - return 0; -} -EXPORT_SYMBOL(cmp_connection_init); - -/** - * cmp_connection_destroy - free connection manager resources - * @c: the connection manager - */ -void cmp_connection_destroy(struct cmp_connection *c) -{ - WARN_ON(c->connected); - mutex_destroy(&c->mutex); - fw_iso_resources_destroy(&c->resources); -} -EXPORT_SYMBOL(cmp_connection_destroy); - - -static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) -{ - ipcr &= ~cpu_to_be32(IPCR_BCAST_CONN | - IPCR_P2P_CONN_MASK | - IPCR_CHANNEL_MASK); - ipcr |= cpu_to_be32(1 << IPCR_P2P_CONN_SHIFT); - ipcr |= cpu_to_be32(c->resources.channel << IPCR_CHANNEL_SHIFT); - - return ipcr; -} - -static int ipcr_set_check(struct cmp_connection *c, __be32 ipcr) -{ - if (ipcr & cpu_to_be32(IPCR_BCAST_CONN | - IPCR_P2P_CONN_MASK)) { - cmp_error(c, "plug is already in use\n"); - return -EBUSY; - } - if (!(ipcr & cpu_to_be32(IPCR_ONLINE))) { - cmp_error(c, "plug is not on-line\n"); - return -ECONNREFUSED; - } - - return 0; -} - -/** - * cmp_connection_establish - establish a connection to the target - * @c: the connection manager - * @max_payload_bytes: the amount of data (including CIP headers) per packet - * - * This function establishes a point-to-point connection from the local - * computer to the target by allocating isochronous resources (channel and - * bandwidth) and setting the target's input plug control register. When this - * function succeeds, the caller is responsible for starting transmitting - * packets. - */ -int cmp_connection_establish(struct cmp_connection *c, - unsigned int max_payload_bytes) -{ - int err; - - if (WARN_ON(c->connected)) - return -EISCONN; - - c->speed = min(c->max_speed, - fw_parent_device(c->resources.unit)->max_speed); - - mutex_lock(&c->mutex); - -retry_after_bus_reset: - err = fw_iso_resources_allocate(&c->resources, - max_payload_bytes, c->speed); - if (err < 0) - goto err_mutex; - - err = pcr_modify(c, ipcr_set_modify, ipcr_set_check, - ABORT_ON_BUS_RESET); - if (err == -EAGAIN) { - fw_iso_resources_free(&c->resources); - goto retry_after_bus_reset; - } - if (err < 0) - goto err_resources; - - c->connected = true; - - mutex_unlock(&c->mutex); - - return 0; - -err_resources: - fw_iso_resources_free(&c->resources); -err_mutex: - mutex_unlock(&c->mutex); - - return err; -} -EXPORT_SYMBOL(cmp_connection_establish); - -/** - * cmp_connection_update - update the connection after a bus reset - * @c: the connection manager - * - * This function must be called from the driver's .update handler to reestablish - * any connection that might have been active. - * - * Returns zero on success, or a negative error code. On an error, the - * connection is broken and the caller must stop transmitting iso packets. - */ -int cmp_connection_update(struct cmp_connection *c) -{ - int err; - - mutex_lock(&c->mutex); - - if (!c->connected) { - mutex_unlock(&c->mutex); - return 0; - } - - err = fw_iso_resources_update(&c->resources); - if (err < 0) - goto err_unconnect; - - err = pcr_modify(c, ipcr_set_modify, ipcr_set_check, - SUCCEED_ON_BUS_RESET); - if (err < 0) - goto err_resources; - - mutex_unlock(&c->mutex); - - return 0; - -err_resources: - fw_iso_resources_free(&c->resources); -err_unconnect: - c->connected = false; - mutex_unlock(&c->mutex); - - return err; -} -EXPORT_SYMBOL(cmp_connection_update); - - -static __be32 ipcr_break_modify(struct cmp_connection *c, __be32 ipcr) -{ - return ipcr & ~cpu_to_be32(IPCR_BCAST_CONN | IPCR_P2P_CONN_MASK); -} - -/** - * cmp_connection_break - break the connection to the target - * @c: the connection manager - * - * This function deactives the connection in the target's input plug control - * register, and frees the isochronous resources of the connection. Before - * calling this function, the caller should cease transmitting packets. - */ -void cmp_connection_break(struct cmp_connection *c) -{ - int err; - - mutex_lock(&c->mutex); - - if (!c->connected) { - mutex_unlock(&c->mutex); - return; - } - - err = pcr_modify(c, ipcr_break_modify, NULL, SUCCEED_ON_BUS_RESET); - if (err < 0) - cmp_error(c, "plug is still connected\n"); - - fw_iso_resources_free(&c->resources); - - c->connected = false; - - mutex_unlock(&c->mutex); -} -EXPORT_SYMBOL(cmp_connection_break); diff --git a/ANDROID_3.4.5/sound/firewire/cmp.h b/ANDROID_3.4.5/sound/firewire/cmp.h deleted file mode 100644 index f47de08f..00000000 --- a/ANDROID_3.4.5/sound/firewire/cmp.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef SOUND_FIREWIRE_CMP_H_INCLUDED -#define SOUND_FIREWIRE_CMP_H_INCLUDED - -#include <linux/mutex.h> -#include <linux/types.h> -#include "iso-resources.h" - -struct fw_unit; - -/** - * struct cmp_connection - manages an isochronous connection to a device - * @speed: the connection's actual speed - * - * This structure manages (using CMP) an isochronous stream from the local - * computer to a device's input plug (iPCR). - * - * There is no corresponding oPCR created on the local computer, so it is not - * possible to overlay connections on top of this one. - */ -struct cmp_connection { - int speed; - /* private: */ - bool connected; - struct mutex mutex; - struct fw_iso_resources resources; - __be32 last_pcr_value; - unsigned int pcr_index; - unsigned int max_speed; -}; - -int cmp_connection_init(struct cmp_connection *connection, - struct fw_unit *unit, - unsigned int ipcr_index); -void cmp_connection_destroy(struct cmp_connection *connection); - -int cmp_connection_establish(struct cmp_connection *connection, - unsigned int max_payload); -int cmp_connection_update(struct cmp_connection *connection); -void cmp_connection_break(struct cmp_connection *connection); - -#endif diff --git a/ANDROID_3.4.5/sound/firewire/fcp.c b/ANDROID_3.4.5/sound/firewire/fcp.c deleted file mode 100644 index ec578b5a..00000000 --- a/ANDROID_3.4.5/sound/firewire/fcp.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Function Control Protocol (IEC 61883-1) helper functions - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/firewire-constants.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/wait.h> -#include <linux/delay.h> -#include "fcp.h" -#include "lib.h" - -#define CTS_AVC 0x00 - -#define ERROR_RETRIES 3 -#define ERROR_DELAY_MS 5 -#define FCP_TIMEOUT_MS 125 - -static DEFINE_SPINLOCK(transactions_lock); -static LIST_HEAD(transactions); - -enum fcp_state { - STATE_PENDING, - STATE_BUS_RESET, - STATE_COMPLETE, -}; - -struct fcp_transaction { - struct list_head list; - struct fw_unit *unit; - void *response_buffer; - unsigned int response_size; - unsigned int response_match_bytes; - enum fcp_state state; - wait_queue_head_t wait; -}; - -/** - * fcp_avc_transaction - send an AV/C command and wait for its response - * @unit: a unit on the target device - * @command: a buffer containing the command frame; must be DMA-able - * @command_size: the size of @command - * @response: a buffer for the response frame - * @response_size: the maximum size of @response - * @response_match_bytes: a bitmap specifying the bytes used to detect the - * correct response frame - * - * This function sends a FCP command frame to the target and waits for the - * corresponding response frame to be returned. - * - * Because it is possible for multiple FCP transactions to be active at the - * same time, the correct response frame is detected by the value of certain - * bytes. These bytes must be set in @response before calling this function, - * and the corresponding bits must be set in @response_match_bytes. - * - * @command and @response can point to the same buffer. - * - * Asynchronous operation (INTERIM, NOTIFY) is not supported at the moment. - * - * Returns the actual size of the response frame, or a negative error code. - */ -int fcp_avc_transaction(struct fw_unit *unit, - const void *command, unsigned int command_size, - void *response, unsigned int response_size, - unsigned int response_match_bytes) -{ - struct fcp_transaction t; - int tcode, ret, tries = 0; - - t.unit = unit; - t.response_buffer = response; - t.response_size = response_size; - t.response_match_bytes = response_match_bytes; - t.state = STATE_PENDING; - init_waitqueue_head(&t.wait); - - spin_lock_irq(&transactions_lock); - list_add_tail(&t.list, &transactions); - spin_unlock_irq(&transactions_lock); - - for (;;) { - tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST - : TCODE_WRITE_BLOCK_REQUEST; - ret = snd_fw_transaction(t.unit, tcode, - CSR_REGISTER_BASE + CSR_FCP_COMMAND, - (void *)command, command_size); - if (ret < 0) - break; - - wait_event_timeout(t.wait, t.state != STATE_PENDING, - msecs_to_jiffies(FCP_TIMEOUT_MS)); - - if (t.state == STATE_COMPLETE) { - ret = t.response_size; - break; - } else if (t.state == STATE_BUS_RESET) { - msleep(ERROR_DELAY_MS); - } else if (++tries >= ERROR_RETRIES) { - dev_err(&t.unit->device, "FCP command timed out\n"); - ret = -EIO; - break; - } - } - - spin_lock_irq(&transactions_lock); - list_del(&t.list); - spin_unlock_irq(&transactions_lock); - - return ret; -} -EXPORT_SYMBOL(fcp_avc_transaction); - -/** - * fcp_bus_reset - inform the target handler about a bus reset - * @unit: the unit that might be used by fcp_avc_transaction() - * - * This function must be called from the driver's .update handler to inform - * the FCP transaction handler that a bus reset has happened. Any pending FCP - * transactions are retried. - */ -void fcp_bus_reset(struct fw_unit *unit) -{ - struct fcp_transaction *t; - - spin_lock_irq(&transactions_lock); - list_for_each_entry(t, &transactions, list) { - if (t->unit == unit && - t->state == STATE_PENDING) { - t->state = STATE_BUS_RESET; - wake_up(&t->wait); - } - } - spin_unlock_irq(&transactions_lock); -} -EXPORT_SYMBOL(fcp_bus_reset); - -/* checks whether the response matches the masked bytes in response_buffer */ -static bool is_matching_response(struct fcp_transaction *transaction, - const void *response, size_t length) -{ - const u8 *p1, *p2; - unsigned int mask, i; - - p1 = response; - p2 = transaction->response_buffer; - mask = transaction->response_match_bytes; - - for (i = 0; ; ++i) { - if ((mask & 1) && p1[i] != p2[i]) - return false; - mask >>= 1; - if (!mask) - return true; - if (--length == 0) - return false; - } -} - -static void fcp_response(struct fw_card *card, struct fw_request *request, - int tcode, int destination, int source, - int generation, unsigned long long offset, - void *data, size_t length, void *callback_data) -{ - struct fcp_transaction *t; - unsigned long flags; - - if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC) - return; - - spin_lock_irqsave(&transactions_lock, flags); - list_for_each_entry(t, &transactions, list) { - struct fw_device *device = fw_parent_device(t->unit); - if (device->card != card || - device->generation != generation) - continue; - smp_rmb(); /* node_id vs. generation */ - if (device->node_id != source) - continue; - - if (t->state == STATE_PENDING && - is_matching_response(t, data, length)) { - t->state = STATE_COMPLETE; - t->response_size = min((unsigned int)length, - t->response_size); - memcpy(t->response_buffer, data, t->response_size); - wake_up(&t->wait); - } - } - spin_unlock_irqrestore(&transactions_lock, flags); -} - -static struct fw_address_handler response_register_handler = { - .length = 0x200, - .address_callback = fcp_response, -}; - -static int __init fcp_module_init(void) -{ - static const struct fw_address_region response_register_region = { - .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, - .end = CSR_REGISTER_BASE + CSR_FCP_END, - }; - - fw_core_add_address_handler(&response_register_handler, - &response_register_region); - - return 0; -} - -static void __exit fcp_module_exit(void) -{ - WARN_ON(!list_empty(&transactions)); - fw_core_remove_address_handler(&response_register_handler); -} - -module_init(fcp_module_init); -module_exit(fcp_module_exit); diff --git a/ANDROID_3.4.5/sound/firewire/fcp.h b/ANDROID_3.4.5/sound/firewire/fcp.h deleted file mode 100644 index 86595688..00000000 --- a/ANDROID_3.4.5/sound/firewire/fcp.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SOUND_FIREWIRE_FCP_H_INCLUDED -#define SOUND_FIREWIRE_FCP_H_INCLUDED - -struct fw_unit; - -int fcp_avc_transaction(struct fw_unit *unit, - const void *command, unsigned int command_size, - void *response, unsigned int response_size, - unsigned int response_match_bytes); -void fcp_bus_reset(struct fw_unit *unit); - -#endif diff --git a/ANDROID_3.4.5/sound/firewire/isight.c b/ANDROID_3.4.5/sound/firewire/isight.c deleted file mode 100644 index d428ffed..00000000 --- a/ANDROID_3.4.5/sound/firewire/isight.c +++ /dev/null @@ -1,753 +0,0 @@ -/* - * Apple iSight audio driver - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <asm/byteorder.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/firewire-constants.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/mutex.h> -#include <linux/string.h> -#include <sound/control.h> -#include <sound/core.h> -#include <sound/initval.h> -#include <sound/pcm.h> -#include <sound/tlv.h> -#include "lib.h" -#include "iso-resources.h" -#include "packets-buffer.h" - -#define OUI_APPLE 0x000a27 -#define MODEL_APPLE_ISIGHT 0x000008 -#define SW_ISIGHT_AUDIO 0x000010 - -#define REG_AUDIO_ENABLE 0x000 -#define AUDIO_ENABLE 0x80000000 -#define REG_DEF_AUDIO_GAIN 0x204 -#define REG_GAIN_RAW_START 0x210 -#define REG_GAIN_RAW_END 0x214 -#define REG_GAIN_DB_START 0x218 -#define REG_GAIN_DB_END 0x21c -#define REG_SAMPLE_RATE_INQUIRY 0x280 -#define REG_ISO_TX_CONFIG 0x300 -#define SPEED_SHIFT 16 -#define REG_SAMPLE_RATE 0x400 -#define RATE_48000 0x80000000 -#define REG_GAIN 0x500 -#define REG_MUTE 0x504 - -#define MAX_FRAMES_PER_PACKET 475 - -#define QUEUE_LENGTH 20 - -struct isight { - struct snd_card *card; - struct fw_unit *unit; - struct fw_device *device; - u64 audio_base; - struct snd_pcm_substream *pcm; - struct mutex mutex; - struct iso_packets_buffer buffer; - struct fw_iso_resources resources; - struct fw_iso_context *context; - bool pcm_active; - bool pcm_running; - bool first_packet; - int packet_index; - u32 total_samples; - unsigned int buffer_pointer; - unsigned int period_counter; - s32 gain_min, gain_max; - unsigned int gain_tlv[4]; -}; - -struct audio_payload { - __be32 sample_count; - __be32 signature; - __be32 sample_total; - __be32 reserved; - __be16 samples[2 * MAX_FRAMES_PER_PACKET]; -}; - -MODULE_DESCRIPTION("iSight audio driver"); -MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); -MODULE_LICENSE("GPL v2"); - -static struct fw_iso_packet audio_packet = { - .payload_length = sizeof(struct audio_payload), - .interrupt = 1, - .header_length = 4, -}; - -static void isight_update_pointers(struct isight *isight, unsigned int count) -{ - struct snd_pcm_runtime *runtime = isight->pcm->runtime; - unsigned int ptr; - - smp_wmb(); /* update buffer data before buffer pointer */ - - ptr = isight->buffer_pointer; - ptr += count; - if (ptr >= runtime->buffer_size) - ptr -= runtime->buffer_size; - ACCESS_ONCE(isight->buffer_pointer) = ptr; - - isight->period_counter += count; - if (isight->period_counter >= runtime->period_size) { - isight->period_counter -= runtime->period_size; - snd_pcm_period_elapsed(isight->pcm); - } -} - -static void isight_samples(struct isight *isight, - const __be16 *samples, unsigned int count) -{ - struct snd_pcm_runtime *runtime; - unsigned int count1; - - if (!ACCESS_ONCE(isight->pcm_running)) - return; - - runtime = isight->pcm->runtime; - if (isight->buffer_pointer + count <= runtime->buffer_size) { - memcpy(runtime->dma_area + isight->buffer_pointer * 4, - samples, count * 4); - } else { - count1 = runtime->buffer_size - isight->buffer_pointer; - memcpy(runtime->dma_area + isight->buffer_pointer * 4, - samples, count1 * 4); - samples += count1 * 2; - memcpy(runtime->dma_area, samples, (count - count1) * 4); - } - - isight_update_pointers(isight, count); -} - -static void isight_pcm_abort(struct isight *isight) -{ - unsigned long flags; - - if (ACCESS_ONCE(isight->pcm_active)) { - snd_pcm_stream_lock_irqsave(isight->pcm, flags); - if (snd_pcm_running(isight->pcm)) - snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(isight->pcm, flags); - } -} - -static void isight_dropped_samples(struct isight *isight, unsigned int total) -{ - struct snd_pcm_runtime *runtime; - u32 dropped; - unsigned int count1; - - if (!ACCESS_ONCE(isight->pcm_running)) - return; - - runtime = isight->pcm->runtime; - dropped = total - isight->total_samples; - if (dropped < runtime->buffer_size) { - if (isight->buffer_pointer + dropped <= runtime->buffer_size) { - memset(runtime->dma_area + isight->buffer_pointer * 4, - 0, dropped * 4); - } else { - count1 = runtime->buffer_size - isight->buffer_pointer; - memset(runtime->dma_area + isight->buffer_pointer * 4, - 0, count1 * 4); - memset(runtime->dma_area, 0, (dropped - count1) * 4); - } - isight_update_pointers(isight, dropped); - } else { - isight_pcm_abort(isight); - } -} - -static void isight_packet(struct fw_iso_context *context, u32 cycle, - size_t header_length, void *header, void *data) -{ - struct isight *isight = data; - const struct audio_payload *payload; - unsigned int index, length, count, total; - int err; - - if (isight->packet_index < 0) - return; - index = isight->packet_index; - payload = isight->buffer.packets[index].buffer; - length = be32_to_cpup(header) >> 16; - - if (likely(length >= 16 && - payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) { - count = be32_to_cpu(payload->sample_count); - if (likely(count <= (length - 16) / 4)) { - total = be32_to_cpu(payload->sample_total); - if (unlikely(total != isight->total_samples)) { - if (!isight->first_packet) - isight_dropped_samples(isight, total); - isight->first_packet = false; - isight->total_samples = total; - } - - isight_samples(isight, payload->samples, count); - isight->total_samples += count; - } - } - - err = fw_iso_context_queue(isight->context, &audio_packet, - &isight->buffer.iso_buffer, - isight->buffer.packets[index].offset); - if (err < 0) { - dev_err(&isight->unit->device, "queueing error: %d\n", err); - isight_pcm_abort(isight); - isight->packet_index = -1; - return; - } - fw_iso_context_queue_flush(isight->context); - - if (++index >= QUEUE_LENGTH) - index = 0; - isight->packet_index = index; -} - -static int isight_connect(struct isight *isight) -{ - int ch, err, rcode, errors = 0; - __be32 value; - -retry_after_bus_reset: - ch = fw_iso_resources_allocate(&isight->resources, - sizeof(struct audio_payload), - isight->device->max_speed); - if (ch < 0) { - err = ch; - goto error; - } - - value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT)); - for (;;) { - rcode = fw_run_transaction( - isight->device->card, - TCODE_WRITE_QUADLET_REQUEST, - isight->device->node_id, - isight->resources.generation, - isight->device->max_speed, - isight->audio_base + REG_ISO_TX_CONFIG, - &value, 4); - if (rcode == RCODE_COMPLETE) { - return 0; - } else if (rcode == RCODE_GENERATION) { - fw_iso_resources_free(&isight->resources); - goto retry_after_bus_reset; - } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) { - err = -EIO; - goto err_resources; - } - msleep(5); - } - -err_resources: - fw_iso_resources_free(&isight->resources); -error: - return err; -} - -static int isight_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = SNDRV_PCM_FMTBIT_S16_BE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 4 * 1024 * 1024, - .period_bytes_min = MAX_FRAMES_PER_PACKET * 4, - .period_bytes_max = 1024 * 1024, - .periods_min = 2, - .periods_max = UINT_MAX, - }; - struct isight *isight = substream->private_data; - - substream->runtime->hw = hardware; - - return iso_packets_buffer_init(&isight->buffer, isight->unit, - QUEUE_LENGTH, - sizeof(struct audio_payload), - DMA_FROM_DEVICE); -} - -static int isight_close(struct snd_pcm_substream *substream) -{ - struct isight *isight = substream->private_data; - - iso_packets_buffer_destroy(&isight->buffer, isight->unit); - - return 0; -} - -static int isight_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct isight *isight = substream->private_data; - int err; - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - ACCESS_ONCE(isight->pcm_active) = true; - - return 0; -} - -static int reg_read(struct isight *isight, int offset, __be32 *value) -{ - return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST, - isight->audio_base + offset, value, 4); -} - -static int reg_write(struct isight *isight, int offset, __be32 value) -{ - return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST, - isight->audio_base + offset, &value, 4); -} - -static void isight_stop_streaming(struct isight *isight) -{ - if (!isight->context) - return; - - fw_iso_context_stop(isight->context); - fw_iso_context_destroy(isight->context); - isight->context = NULL; - fw_iso_resources_free(&isight->resources); - reg_write(isight, REG_AUDIO_ENABLE, 0); -} - -static int isight_hw_free(struct snd_pcm_substream *substream) -{ - struct isight *isight = substream->private_data; - - ACCESS_ONCE(isight->pcm_active) = false; - - mutex_lock(&isight->mutex); - isight_stop_streaming(isight); - mutex_unlock(&isight->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int isight_start_streaming(struct isight *isight) -{ - unsigned int i; - int err; - - if (isight->context) { - if (isight->packet_index < 0) - isight_stop_streaming(isight); - else - return 0; - } - - err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000)); - if (err < 0) - goto error; - - err = isight_connect(isight); - if (err < 0) - goto error; - - err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE)); - if (err < 0) - goto err_resources; - - isight->context = fw_iso_context_create(isight->device->card, - FW_ISO_CONTEXT_RECEIVE, - isight->resources.channel, - isight->device->max_speed, - 4, isight_packet, isight); - if (IS_ERR(isight->context)) { - err = PTR_ERR(isight->context); - isight->context = NULL; - goto err_resources; - } - - for (i = 0; i < QUEUE_LENGTH; ++i) { - err = fw_iso_context_queue(isight->context, &audio_packet, - &isight->buffer.iso_buffer, - isight->buffer.packets[i].offset); - if (err < 0) - goto err_context; - } - - isight->first_packet = true; - isight->packet_index = 0; - - err = fw_iso_context_start(isight->context, -1, 0, - FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/); - if (err < 0) - goto err_context; - - return 0; - -err_context: - fw_iso_context_destroy(isight->context); - isight->context = NULL; -err_resources: - fw_iso_resources_free(&isight->resources); - reg_write(isight, REG_AUDIO_ENABLE, 0); -error: - return err; -} - -static int isight_prepare(struct snd_pcm_substream *substream) -{ - struct isight *isight = substream->private_data; - int err; - - isight->buffer_pointer = 0; - isight->period_counter = 0; - - mutex_lock(&isight->mutex); - err = isight_start_streaming(isight); - mutex_unlock(&isight->mutex); - - return err; -} - -static int isight_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct isight *isight = substream->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - ACCESS_ONCE(isight->pcm_running) = true; - break; - case SNDRV_PCM_TRIGGER_STOP: - ACCESS_ONCE(isight->pcm_running) = false; - break; - default: - return -EINVAL; - } - return 0; -} - -static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream) -{ - struct isight *isight = substream->private_data; - - return ACCESS_ONCE(isight->buffer_pointer); -} - -static int isight_create_pcm(struct isight *isight) -{ - static struct snd_pcm_ops ops = { - .open = isight_open, - .close = isight_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = isight_hw_params, - .hw_free = isight_hw_free, - .prepare = isight_prepare, - .trigger = isight_trigger, - .pointer = isight_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm); - if (err < 0) - return err; - pcm->private_data = isight; - strcpy(pcm->name, "iSight"); - isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; - isight->pcm->ops = &ops; - - return 0; -} - -static int isight_gain_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - struct isight *isight = ctl->private_data; - - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; - info->value.integer.min = isight->gain_min; - info->value.integer.max = isight->gain_max; - - return 0; -} - -static int isight_gain_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct isight *isight = ctl->private_data; - __be32 gain; - int err; - - err = reg_read(isight, REG_GAIN, &gain); - if (err < 0) - return err; - - value->value.integer.value[0] = (s32)be32_to_cpu(gain); - - return 0; -} - -static int isight_gain_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct isight *isight = ctl->private_data; - - if (value->value.integer.value[0] < isight->gain_min || - value->value.integer.value[0] > isight->gain_max) - return -EINVAL; - - return reg_write(isight, REG_GAIN, - cpu_to_be32(value->value.integer.value[0])); -} - -static int isight_mute_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct isight *isight = ctl->private_data; - __be32 mute; - int err; - - err = reg_read(isight, REG_MUTE, &mute); - if (err < 0) - return err; - - value->value.integer.value[0] = !mute; - - return 0; -} - -static int isight_mute_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct isight *isight = ctl->private_data; - - return reg_write(isight, REG_MUTE, - (__force __be32)!value->value.integer.value[0]); -} - -static int isight_create_mixer(struct isight *isight) -{ - static const struct snd_kcontrol_new gain_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = isight_gain_info, - .get = isight_gain_get, - .put = isight_gain_put, - }; - static const struct snd_kcontrol_new mute_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Capture Switch", - .info = snd_ctl_boolean_mono_info, - .get = isight_mute_get, - .put = isight_mute_put, - }; - __be32 value; - struct snd_kcontrol *ctl; - int err; - - err = reg_read(isight, REG_GAIN_RAW_START, &value); - if (err < 0) - return err; - isight->gain_min = be32_to_cpu(value); - - err = reg_read(isight, REG_GAIN_RAW_END, &value); - if (err < 0) - return err; - isight->gain_max = be32_to_cpu(value); - - isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; - isight->gain_tlv[1] = 2 * sizeof(unsigned int); - - err = reg_read(isight, REG_GAIN_DB_START, &value); - if (err < 0) - return err; - isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100; - - err = reg_read(isight, REG_GAIN_DB_END, &value); - if (err < 0) - return err; - isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100; - - ctl = snd_ctl_new1(&gain_control, isight); - if (ctl) - ctl->tlv.p = isight->gain_tlv; - err = snd_ctl_add(isight->card, ctl); - if (err < 0) - return err; - - err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight)); - if (err < 0) - return err; - - return 0; -} - -static void isight_card_free(struct snd_card *card) -{ - struct isight *isight = card->private_data; - - fw_iso_resources_destroy(&isight->resources); - fw_unit_put(isight->unit); - mutex_destroy(&isight->mutex); -} - -static u64 get_unit_base(struct fw_unit *unit) -{ - struct fw_csr_iterator i; - int key, value; - - fw_csr_iterator_init(&i, unit->directory); - while (fw_csr_iterator_next(&i, &key, &value)) - if (key == CSR_OFFSET) - return CSR_REGISTER_BASE + value * 4; - return 0; -} - -static int isight_probe(struct device *unit_dev) -{ - struct fw_unit *unit = fw_unit(unit_dev); - struct fw_device *fw_dev = fw_parent_device(unit); - struct snd_card *card; - struct isight *isight; - int err; - - err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card); - if (err < 0) - return err; - snd_card_set_dev(card, unit_dev); - - isight = card->private_data; - isight->card = card; - mutex_init(&isight->mutex); - isight->unit = fw_unit_get(unit); - isight->device = fw_dev; - isight->audio_base = get_unit_base(unit); - if (!isight->audio_base) { - dev_err(&unit->device, "audio unit base not found\n"); - err = -ENXIO; - goto err_unit; - } - fw_iso_resources_init(&isight->resources, unit); - - card->private_free = isight_card_free; - - strcpy(card->driver, "iSight"); - strcpy(card->shortname, "Apple iSight"); - snprintf(card->longname, sizeof(card->longname), - "Apple iSight (GUID %08x%08x) at %s, S%d", - fw_dev->config_rom[3], fw_dev->config_rom[4], - dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, "iSight"); - - err = isight_create_pcm(isight); - if (err < 0) - goto error; - - err = isight_create_mixer(isight); - if (err < 0) - goto error; - - err = snd_card_register(card); - if (err < 0) - goto error; - - dev_set_drvdata(unit_dev, isight); - - return 0; - -err_unit: - fw_unit_put(isight->unit); - mutex_destroy(&isight->mutex); -error: - snd_card_free(card); - return err; -} - -static int isight_remove(struct device *dev) -{ - struct isight *isight = dev_get_drvdata(dev); - - isight_pcm_abort(isight); - - snd_card_disconnect(isight->card); - - mutex_lock(&isight->mutex); - isight_stop_streaming(isight); - mutex_unlock(&isight->mutex); - - snd_card_free_when_closed(isight->card); - - return 0; -} - -static void isight_bus_reset(struct fw_unit *unit) -{ - struct isight *isight = dev_get_drvdata(&unit->device); - - if (fw_iso_resources_update(&isight->resources) < 0) { - isight_pcm_abort(isight); - - mutex_lock(&isight->mutex); - isight_stop_streaming(isight); - mutex_unlock(&isight->mutex); - } -} - -static const struct ieee1394_device_id isight_id_table[] = { - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .specifier_id = OUI_APPLE, - .version = SW_ISIGHT_AUDIO, - }, - { } -}; -MODULE_DEVICE_TABLE(ieee1394, isight_id_table); - -static struct fw_driver isight_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - .probe = isight_probe, - .remove = isight_remove, - }, - .update = isight_bus_reset, - .id_table = isight_id_table, -}; - -static int __init alsa_isight_init(void) -{ - return driver_register(&isight_driver.driver); -} - -static void __exit alsa_isight_exit(void) -{ - driver_unregister(&isight_driver.driver); -} - -module_init(alsa_isight_init); -module_exit(alsa_isight_exit); diff --git a/ANDROID_3.4.5/sound/firewire/iso-resources.c b/ANDROID_3.4.5/sound/firewire/iso-resources.c deleted file mode 100644 index 5f17b77e..00000000 --- a/ANDROID_3.4.5/sound/firewire/iso-resources.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * isochronous resources helper functions - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/firewire-constants.h> -#include <linux/export.h> -#include <linux/jiffies.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include "iso-resources.h" - -/** - * fw_iso_resources_init - initializes a &struct fw_iso_resources - * @r: the resource manager to initialize - * @unit: the device unit for which the resources will be needed - * - * If the device does not support all channel numbers, change @r->channels_mask - * after calling this function. - */ -int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) -{ - r->channels_mask = ~0uLL; - r->unit = fw_unit_get(unit); - mutex_init(&r->mutex); - r->allocated = false; - - return 0; -} -EXPORT_SYMBOL(fw_iso_resources_init); - -/** - * fw_iso_resources_destroy - destroy a resource manager - * @r: the resource manager that is no longer needed - */ -void fw_iso_resources_destroy(struct fw_iso_resources *r) -{ - WARN_ON(r->allocated); - mutex_destroy(&r->mutex); - fw_unit_put(r->unit); -} -EXPORT_SYMBOL(fw_iso_resources_destroy); - -static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed) -{ - unsigned int bytes, s400_bytes; - - /* iso packets have three header quadlets and quadlet-aligned payload */ - bytes = 3 * 4 + ALIGN(max_payload_bytes, 4); - - /* convert to bandwidth units (quadlets at S1600 = bytes at S400) */ - if (speed <= SCODE_400) - s400_bytes = bytes * (1 << (SCODE_400 - speed)); - else - s400_bytes = DIV_ROUND_UP(bytes, 1 << (speed - SCODE_400)); - - return s400_bytes; -} - -static int current_bandwidth_overhead(struct fw_card *card) -{ - /* - * Under the usual pessimistic assumption (cable length 4.5 m), the - * isochronous overhead for N cables is 1.797 µs + N * 0.494 µs, or - * 88.3 + N * 24.3 in bandwidth units. - * - * The calculation below tries to deduce N from the current gap count. - * If the gap count has been optimized by measuring the actual packet - * transmission time, this derived overhead should be near the actual - * overhead as well. - */ - return card->gap_count < 63 ? card->gap_count * 97 / 10 + 89 : 512; -} - -static int wait_isoch_resource_delay_after_bus_reset(struct fw_card *card) -{ - for (;;) { - s64 delay = (card->reset_jiffies + HZ) - get_jiffies_64(); - if (delay <= 0) - return 0; - if (schedule_timeout_interruptible(delay) > 0) - return -ERESTARTSYS; - } -} - -/** - * fw_iso_resources_allocate - allocate isochronous channel and bandwidth - * @r: the resource manager - * @max_payload_bytes: the amount of data (including CIP headers) per packet - * @speed: the speed (e.g., SCODE_400) at which the packets will be sent - * - * This function allocates one isochronous channel and enough bandwidth for the - * specified packet size. - * - * Returns the channel number that the caller must use for streaming, or - * a negative error code. Due to potentionally long delays, this function is - * interruptible and can return -ERESTARTSYS. On success, the caller is - * responsible for calling fw_iso_resources_update() on bus resets, and - * fw_iso_resources_free() when the resources are not longer needed. - */ -int fw_iso_resources_allocate(struct fw_iso_resources *r, - unsigned int max_payload_bytes, int speed) -{ - struct fw_card *card = fw_parent_device(r->unit)->card; - int bandwidth, channel, err; - - if (WARN_ON(r->allocated)) - return -EBADFD; - - r->bandwidth = packet_bandwidth(max_payload_bytes, speed); - -retry_after_bus_reset: - spin_lock_irq(&card->lock); - r->generation = card->generation; - r->bandwidth_overhead = current_bandwidth_overhead(card); - spin_unlock_irq(&card->lock); - - err = wait_isoch_resource_delay_after_bus_reset(card); - if (err < 0) - return err; - - mutex_lock(&r->mutex); - - bandwidth = r->bandwidth + r->bandwidth_overhead; - fw_iso_resource_manage(card, r->generation, r->channels_mask, - &channel, &bandwidth, true); - if (channel == -EAGAIN) { - mutex_unlock(&r->mutex); - goto retry_after_bus_reset; - } - if (channel >= 0) { - r->channel = channel; - r->allocated = true; - } else { - if (channel == -EBUSY) - dev_err(&r->unit->device, - "isochronous resources exhausted\n"); - else - dev_err(&r->unit->device, - "isochronous resource allocation failed\n"); - } - - mutex_unlock(&r->mutex); - - return channel; -} -EXPORT_SYMBOL(fw_iso_resources_allocate); - -/** - * fw_iso_resources_update - update resource allocations after a bus reset - * @r: the resource manager - * - * This function must be called from the driver's .update handler to reallocate - * any resources that were allocated before the bus reset. It is safe to call - * this function if no resources are currently allocated. - * - * Returns a negative error code on failure. If this happens, the caller must - * stop streaming. - */ -int fw_iso_resources_update(struct fw_iso_resources *r) -{ - struct fw_card *card = fw_parent_device(r->unit)->card; - int bandwidth, channel; - - mutex_lock(&r->mutex); - - if (!r->allocated) { - mutex_unlock(&r->mutex); - return 0; - } - - spin_lock_irq(&card->lock); - r->generation = card->generation; - r->bandwidth_overhead = current_bandwidth_overhead(card); - spin_unlock_irq(&card->lock); - - bandwidth = r->bandwidth + r->bandwidth_overhead; - - fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, true); - /* - * When another bus reset happens, pretend that the allocation - * succeeded; we will try again for the new generation later. - */ - if (channel < 0 && channel != -EAGAIN) { - r->allocated = false; - if (channel == -EBUSY) - dev_err(&r->unit->device, - "isochronous resources exhausted\n"); - else - dev_err(&r->unit->device, - "isochronous resource allocation failed\n"); - } - - mutex_unlock(&r->mutex); - - return channel; -} -EXPORT_SYMBOL(fw_iso_resources_update); - -/** - * fw_iso_resources_free - frees allocated resources - * @r: the resource manager - * - * This function deallocates the channel and bandwidth, if allocated. - */ -void fw_iso_resources_free(struct fw_iso_resources *r) -{ - struct fw_card *card = fw_parent_device(r->unit)->card; - int bandwidth, channel; - - mutex_lock(&r->mutex); - - if (r->allocated) { - bandwidth = r->bandwidth + r->bandwidth_overhead; - fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, false); - if (channel < 0) - dev_err(&r->unit->device, - "isochronous resource deallocation failed\n"); - - r->allocated = false; - } - - mutex_unlock(&r->mutex); -} -EXPORT_SYMBOL(fw_iso_resources_free); diff --git a/ANDROID_3.4.5/sound/firewire/iso-resources.h b/ANDROID_3.4.5/sound/firewire/iso-resources.h deleted file mode 100644 index 5a9af7c6..00000000 --- a/ANDROID_3.4.5/sound/firewire/iso-resources.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED -#define SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED - -#include <linux/mutex.h> -#include <linux/types.h> - -struct fw_unit; - -/** - * struct fw_iso_resources - manages channel/bandwidth allocation - * @channels_mask: if the device does not support all channel numbers, set this - * bit mask to something else than the default (all ones) - * - * This structure manages (de)allocation of isochronous resources (channel and - * bandwidth) for one isochronous stream. - */ -struct fw_iso_resources { - u64 channels_mask; - /* private: */ - struct fw_unit *unit; - struct mutex mutex; - unsigned int channel; - unsigned int bandwidth; /* in bandwidth units, without overhead */ - unsigned int bandwidth_overhead; - int generation; /* in which allocation is valid */ - bool allocated; -}; - -int fw_iso_resources_init(struct fw_iso_resources *r, - struct fw_unit *unit); -void fw_iso_resources_destroy(struct fw_iso_resources *r); - -int fw_iso_resources_allocate(struct fw_iso_resources *r, - unsigned int max_payload_bytes, int speed); -int fw_iso_resources_update(struct fw_iso_resources *r); -void fw_iso_resources_free(struct fw_iso_resources *r); - -#endif diff --git a/ANDROID_3.4.5/sound/firewire/lib.c b/ANDROID_3.4.5/sound/firewire/lib.c deleted file mode 100644 index 4750cea2..00000000 --- a/ANDROID_3.4.5/sound/firewire/lib.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * miscellaneous helper functions - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/module.h> -#include "lib.h" - -#define ERROR_RETRY_DELAY_MS 5 - -/** - * rcode_string - convert a firewire result code to a string - * @rcode: the result - */ -const char *rcode_string(unsigned int rcode) -{ - static const char *const names[] = { - [RCODE_COMPLETE] = "complete", - [RCODE_CONFLICT_ERROR] = "conflict error", - [RCODE_DATA_ERROR] = "data error", - [RCODE_TYPE_ERROR] = "type error", - [RCODE_ADDRESS_ERROR] = "address error", - [RCODE_SEND_ERROR] = "send error", - [RCODE_CANCELLED] = "cancelled", - [RCODE_BUSY] = "busy", - [RCODE_GENERATION] = "generation", - [RCODE_NO_ACK] = "no ack", - }; - - if (rcode < ARRAY_SIZE(names) && names[rcode]) - return names[rcode]; - else - return "unknown"; -} -EXPORT_SYMBOL(rcode_string); - -/** - * snd_fw_transaction - send a request and wait for its completion - * @unit: the driver's unit on the target device - * @tcode: the transaction code - * @offset: the address in the target's address space - * @buffer: input/output data - * @length: length of @buffer - * - * Submits an asynchronous request to the target device, and waits for the - * response. The node ID and the current generation are derived from @unit. - * On a bus reset or an error, the transaction is retried a few times. - * Returns zero on success, or a negative error code. - */ -int snd_fw_transaction(struct fw_unit *unit, int tcode, - u64 offset, void *buffer, size_t length) -{ - struct fw_device *device = fw_parent_device(unit); - int generation, rcode, tries = 0; - - for (;;) { - generation = device->generation; - smp_rmb(); /* node_id vs. generation */ - rcode = fw_run_transaction(device->card, tcode, - device->node_id, generation, - device->max_speed, offset, - buffer, length); - - if (rcode == RCODE_COMPLETE) - return 0; - - if (rcode_is_permanent_error(rcode) || ++tries >= 3) { - dev_err(&unit->device, "transaction failed: %s\n", - rcode_string(rcode)); - return -EIO; - } - - msleep(ERROR_RETRY_DELAY_MS); - } -} -EXPORT_SYMBOL(snd_fw_transaction); - -MODULE_DESCRIPTION("FireWire audio helper functions"); -MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/sound/firewire/lib.h b/ANDROID_3.4.5/sound/firewire/lib.h deleted file mode 100644 index 064f3fd9..00000000 --- a/ANDROID_3.4.5/sound/firewire/lib.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SOUND_FIREWIRE_LIB_H_INCLUDED -#define SOUND_FIREWIRE_LIB_H_INCLUDED - -#include <linux/firewire-constants.h> -#include <linux/types.h> - -struct fw_unit; - -int snd_fw_transaction(struct fw_unit *unit, int tcode, - u64 offset, void *buffer, size_t length); -const char *rcode_string(unsigned int rcode); - -/* returns true if retrying the transaction would not make sense */ -static inline bool rcode_is_permanent_error(int rcode) -{ - return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR; -} - -#endif diff --git a/ANDROID_3.4.5/sound/firewire/packets-buffer.c b/ANDROID_3.4.5/sound/firewire/packets-buffer.c deleted file mode 100644 index ea150667..00000000 --- a/ANDROID_3.4.5/sound/firewire/packets-buffer.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * helpers for managing a buffer for many packets - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/firewire.h> -#include <linux/export.h> -#include <linux/slab.h> -#include "packets-buffer.h" - -/** - * iso_packets_buffer_init - allocates the memory for packets - * @b: the buffer structure to initialize - * @unit: the device at the other end of the stream - * @count: the number of packets - * @packet_size: the (maximum) size of a packet, in bytes - * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE - */ -int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, - unsigned int count, unsigned int packet_size, - enum dma_data_direction direction) -{ - unsigned int packets_per_page, pages; - unsigned int i, page_index, offset_in_page; - void *p; - int err; - - b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL); - if (!b->packets) { - err = -ENOMEM; - goto error; - } - - packet_size = L1_CACHE_ALIGN(packet_size); - packets_per_page = PAGE_SIZE / packet_size; - if (WARN_ON(!packets_per_page)) { - err = -EINVAL; - goto error; - } - pages = DIV_ROUND_UP(count, packets_per_page); - - err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, - pages, direction); - if (err < 0) - goto err_packets; - - for (i = 0; i < count; ++i) { - page_index = i / packets_per_page; - p = page_address(b->iso_buffer.pages[page_index]); - offset_in_page = (i % packets_per_page) * packet_size; - b->packets[i].buffer = p + offset_in_page; - b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; - } - - return 0; - -err_packets: - kfree(b->packets); -error: - return err; -} -EXPORT_SYMBOL(iso_packets_buffer_init); - -/** - * iso_packets_buffer_destroy - frees packet buffer resources - * @b: the buffer structure to free - * @unit: the device at the other end of the stream - */ -void iso_packets_buffer_destroy(struct iso_packets_buffer *b, - struct fw_unit *unit) -{ - fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); - kfree(b->packets); -} -EXPORT_SYMBOL(iso_packets_buffer_destroy); diff --git a/ANDROID_3.4.5/sound/firewire/packets-buffer.h b/ANDROID_3.4.5/sound/firewire/packets-buffer.h deleted file mode 100644 index 6513c5cb..00000000 --- a/ANDROID_3.4.5/sound/firewire/packets-buffer.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED -#define SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED - -#include <linux/dma-mapping.h> -#include <linux/firewire.h> - -/** - * struct iso_packets_buffer - manages a buffer for many packets - * @iso_buffer: the memory containing the packets - * @packets: an array, with each element pointing to one packet - */ -struct iso_packets_buffer { - struct fw_iso_buffer iso_buffer; - struct { - void *buffer; - unsigned int offset; - } *packets; -}; - -int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, - unsigned int count, unsigned int packet_size, - enum dma_data_direction direction); -void iso_packets_buffer_destroy(struct iso_packets_buffer *b, - struct fw_unit *unit); - -#endif diff --git a/ANDROID_3.4.5/sound/firewire/speakers.c b/ANDROID_3.4.5/sound/firewire/speakers.c deleted file mode 100644 index 297244e6..00000000 --- a/ANDROID_3.4.5/sound/firewire/speakers.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * OXFW970-based speakers driver - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/firewire-constants.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include <sound/control.h> -#include <sound/core.h> -#include <sound/initval.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include "cmp.h" -#include "fcp.h" -#include "amdtp.h" -#include "lib.h" - -#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) -/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ - -#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) -#define OXFORD_HARDWARE_ID_OXFW970 0x39443841 -#define OXFORD_HARDWARE_ID_OXFW971 0x39373100 - -#define VENDOR_GRIFFIN 0x001292 -#define VENDOR_LACIE 0x00d04b - -#define SPECIFIER_1394TA 0x00a02d -#define VERSION_AVC 0x010001 - -struct device_info { - const char *driver_name; - const char *short_name; - const char *long_name; - int (*pcm_constraints)(struct snd_pcm_runtime *runtime); - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; -}; - -struct fwspk { - struct snd_card *card; - struct fw_unit *unit; - const struct device_info *device_info; - struct snd_pcm_substream *pcm; - struct mutex mutex; - struct cmp_connection connection; - struct amdtp_out_stream stream; - bool stream_running; - bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; -}; - -MODULE_DESCRIPTION("FireWire speakers driver"); -MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); -MODULE_LICENSE("GPL v2"); - -static int firewave_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static unsigned int stereo_rates[] = { 48000, 96000 }; - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - - /* two channels work only at 48/96 kHz */ - if (snd_interval_max(channels) < 6) - return snd_interval_list(rate, 2, stereo_rates, 0); - return 0; -} - -static int firewave_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static const struct snd_interval all_channels = { .min = 6, .max = 6 }; - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - - /* 32/44.1 kHz work only with all six channels */ - if (snd_interval_max(rate) < 48000) - return snd_interval_refine(channels, &all_channels); - return 0; -} - -static int firewave_constraints(struct snd_pcm_runtime *runtime) -{ - static unsigned int channels_list[] = { 2, 6 }; - static struct snd_pcm_hw_constraint_list channels_list_constraint = { - .count = 2, - .list = channels_list, - }; - int err; - - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000; - runtime->hw.channels_max = 6; - - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &channels_list_constraint); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - firewave_rate_constraint, NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - firewave_channels_constraint, NULL, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - - return 0; -} - -static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) -{ - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000; - - return 0; -} - -static int fwspk_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 4 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct fwspk *fwspk = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - runtime->hw = hardware; - - err = fwspk->device_info->pcm_constraints(runtime); - if (err < 0) - return err; - err = snd_pcm_limit_hw_rates(runtime); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5000, UINT_MAX); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - if (err < 0) - return err; - - return 0; -} - -static int fwspk_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -static void fwspk_stop_stream(struct fwspk *fwspk) -{ - if (fwspk->stream_running) { - amdtp_out_stream_stop(&fwspk->stream); - cmp_connection_break(&fwspk->connection); - fwspk->stream_running = false; - } -} - -static int fwspk_set_rate(struct fwspk *fwspk, unsigned int sfc) -{ - u8 *buf; - int err; - - buf = kmalloc(8, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - buf[0] = 0x00; /* AV/C, CONTROL */ - buf[1] = 0xff; /* unit */ - buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */ - buf[3] = 0x00; /* plug 0 */ - buf[4] = 0x90; /* format: audio */ - buf[5] = 0x00 | sfc; /* AM824, frequency */ - buf[6] = 0xff; /* SYT (not used) */ - buf[7] = 0xff; - - err = fcp_avc_transaction(fwspk->unit, buf, 8, buf, 8, - BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); - if (err < 0) - goto error; - if (err < 6 || buf[0] != 0x09 /* ACCEPTED */) { - dev_err(&fwspk->unit->device, "failed to set sample rate\n"); - err = -EIO; - goto error; - } - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int fwspk_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct fwspk *fwspk = substream->private_data; - int err; - - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - goto error; - - amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params)); - amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params)); - - amdtp_out_stream_set_pcm_format(&fwspk->stream, - params_format(hw_params)); - - err = fwspk_set_rate(fwspk, fwspk->stream.sfc); - if (err < 0) - goto err_buffer; - - return 0; - -err_buffer: - snd_pcm_lib_free_vmalloc_buffer(substream); -error: - return err; -} - -static int fwspk_hw_free(struct snd_pcm_substream *substream) -{ - struct fwspk *fwspk = substream->private_data; - - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int fwspk_prepare(struct snd_pcm_substream *substream) -{ - struct fwspk *fwspk = substream->private_data; - int err; - - mutex_lock(&fwspk->mutex); - - if (amdtp_out_streaming_error(&fwspk->stream)) - fwspk_stop_stream(fwspk); - - if (!fwspk->stream_running) { - err = cmp_connection_establish(&fwspk->connection, - amdtp_out_stream_get_max_payload(&fwspk->stream)); - if (err < 0) - goto err_mutex; - - err = amdtp_out_stream_start(&fwspk->stream, - fwspk->connection.resources.channel, - fwspk->connection.speed); - if (err < 0) - goto err_connection; - - fwspk->stream_running = true; - } - - mutex_unlock(&fwspk->mutex); - - amdtp_out_stream_pcm_prepare(&fwspk->stream); - - return 0; - -err_connection: - cmp_connection_break(&fwspk->connection); -err_mutex: - mutex_unlock(&fwspk->mutex); - - return err; -} - -static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct fwspk *fwspk = substream->private_data; - struct snd_pcm_substream *pcm; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pcm = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pcm = NULL; - break; - default: - return -EINVAL; - } - amdtp_out_stream_pcm_trigger(&fwspk->stream, pcm); - return 0; -} - -static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream) -{ - struct fwspk *fwspk = substream->private_data; - - return amdtp_out_stream_pcm_pointer(&fwspk->stream); -} - -static int fwspk_create_pcm(struct fwspk *fwspk) -{ - static struct snd_pcm_ops ops = { - .open = fwspk_open, - .close = fwspk_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = fwspk_hw_params, - .hw_free = fwspk_hw_free, - .prepare = fwspk_prepare, - .trigger = fwspk_trigger, - .pointer = fwspk_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm); - if (err < 0) - return err; - pcm->private_data = fwspk; - strcpy(pcm->name, fwspk->device_info->short_name); - fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - fwspk->pcm->ops = &ops; - return 0; -} - -enum control_action { CTL_READ, CTL_WRITE }; -enum control_attribute { - CTL_MIN = 0x02, - CTL_MAX = 0x03, - CTL_CURRENT = 0x10, -}; - -static int fwspk_mute_command(struct fwspk *fwspk, bool *value, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(11, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */ - buf[5] = 0x10; /* control attribute: current */ - buf[6] = 0x02; /* selector length */ - buf[7] = 0x00; /* audio channel number */ - buf[8] = 0x01; /* control selector: mute */ - buf[9] = 0x01; /* control data length */ - if (action == CTL_READ) - buf[10] = 0xff; - else - buf[10] = *value ? 0x70 : 0x60; - - err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe); - if (err < 0) - goto error; - if (err < 11) { - dev_err(&fwspk->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&fwspk->unit->device, "mute command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = buf[10] == 0x70; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int fwspk_volume_command(struct fwspk *fwspk, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */ - buf[5] = attribute; /* control attribute */ - buf[6] = 0x02; /* selector length */ - buf[7] = channel; /* audio channel number */ - buf[8] = 0x02; /* control selector: volume */ - buf[9] = 0x02; /* control data length */ - if (action == CTL_READ) { - buf[10] = 0xff; - buf[11] = 0xff; - } else { - buf[10] = *value >> 8; - buf[11] = *value; - } - - err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe); - if (err < 0) - goto error; - if (err < 12) { - dev_err(&fwspk->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&fwspk->unit->device, "volume command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = (buf[10] << 8) | buf[11]; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int fwspk_mute_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - - value->value.integer.value[0] = !fwspk->mute; - - return 0; -} - -static int fwspk_mute_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - bool mute; - int err; - - mute = !value->value.integer.value[0]; - - if (mute == fwspk->mute) - return 0; - - err = fwspk_mute_command(fwspk, &mute, CTL_WRITE); - if (err < 0) - return err; - fwspk->mute = mute; - - return 1; -} - -static int fwspk_volume_info(struct snd_kcontrol *control, - struct snd_ctl_elem_info *info) -{ - struct fwspk *fwspk = control->private_data; - - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = fwspk->device_info->mixer_channels; - info->value.integer.min = fwspk->volume_min; - info->value.integer.max = fwspk->volume_max; - - return 0; -} - -static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; - -static int fwspk_volume_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - unsigned int i; - - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = fwspk->volume[i]; - - return 0; -} - -static int fwspk_volume_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - unsigned int i, changed_channels; - bool equal_values = true; - s16 volume; - int err; - - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < fwspk->volume_min || - value->value.integer.value[i] > fwspk->volume_max) - return -EINVAL; - if (value->value.integer.value[i] != - value->value.integer.value[0]) - equal_values = false; - } - - changed_channels = 0; - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) - if (value->value.integer.value[channel_map[i]] != - fwspk->volume[i]) - changed_channels |= 1 << (i + 1); - - if (equal_values && changed_channels != 0) - changed_channels = 1 << 0; - - for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) { - volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; - if (changed_channels & (1 << i)) { - err = fwspk_volume_command(fwspk, &volume, i, - CTL_CURRENT, CTL_WRITE); - if (err < 0) - return err; - } - if (i > 0) - fwspk->volume[i - 1] = volume; - } - - return changed_channels != 0; -} - -static int fwspk_create_mixer(struct fwspk *fwspk) -{ - static const struct snd_kcontrol_new controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = fwspk_mute_get, - .put = fwspk_mute_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .info = fwspk_volume_info, - .get = fwspk_volume_get, - .put = fwspk_volume_put, - }, - }; - unsigned int i, first_ch; - int err; - - err = fwspk_volume_command(fwspk, &fwspk->volume_min, - 0, CTL_MIN, CTL_READ); - if (err < 0) - return err; - err = fwspk_volume_command(fwspk, &fwspk->volume_max, - 0, CTL_MAX, CTL_READ); - if (err < 0) - return err; - - err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ); - if (err < 0) - return err; - - first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { - err = fwspk_volume_command(fwspk, &fwspk->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); - if (err < 0) - return err; - } - - for (i = 0; i < ARRAY_SIZE(controls); ++i) { - err = snd_ctl_add(fwspk->card, - snd_ctl_new1(&controls[i], fwspk)); - if (err < 0) - return err; - } - - return 0; -} - -static u32 fwspk_read_firmware_version(struct fw_unit *unit) -{ - __be32 data; - int err; - - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - OXFORD_FIRMWARE_ID_ADDRESS, &data, 4); - return err >= 0 ? be32_to_cpu(data) : 0; -} - -static void fwspk_card_free(struct snd_card *card) -{ - struct fwspk *fwspk = card->private_data; - - amdtp_out_stream_destroy(&fwspk->stream); - cmp_connection_destroy(&fwspk->connection); - fw_unit_put(fwspk->unit); - mutex_destroy(&fwspk->mutex); -} - -static const struct device_info *__devinit fwspk_detect(struct fw_device *dev) -{ - static const struct device_info griffin_firewave = { - .driver_name = "FireWave", - .short_name = "FireWave", - .long_name = "Griffin FireWave Surround", - .pcm_constraints = firewave_constraints, - .mixer_channels = 6, - .mute_fb_id = 0x01, - .volume_fb_id = 0x02, - }; - static const struct device_info lacie_speakers = { - .driver_name = "FWSpeakers", - .short_name = "FireWire Speakers", - .long_name = "LaCie FireWire Speakers", - .pcm_constraints = lacie_speakers_constraints, - .mixer_channels = 1, - .mute_fb_id = 0x01, - .volume_fb_id = 0x01, - }; - struct fw_csr_iterator i; - int key, value; - - fw_csr_iterator_init(&i, dev->config_rom); - while (fw_csr_iterator_next(&i, &key, &value)) - if (key == CSR_VENDOR) - switch (value) { - case VENDOR_GRIFFIN: - return &griffin_firewave; - case VENDOR_LACIE: - return &lacie_speakers; - } - - return NULL; -} - -static int __devinit fwspk_probe(struct device *unit_dev) -{ - struct fw_unit *unit = fw_unit(unit_dev); - struct fw_device *fw_dev = fw_parent_device(unit); - struct snd_card *card; - struct fwspk *fwspk; - u32 firmware; - int err; - - err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card); - if (err < 0) - return err; - snd_card_set_dev(card, unit_dev); - - fwspk = card->private_data; - fwspk->card = card; - mutex_init(&fwspk->mutex); - fwspk->unit = fw_unit_get(unit); - fwspk->device_info = fwspk_detect(fw_dev); - if (!fwspk->device_info) { - err = -ENODEV; - goto err_unit; - } - - err = cmp_connection_init(&fwspk->connection, unit, 0); - if (err < 0) - goto err_unit; - - err = amdtp_out_stream_init(&fwspk->stream, unit, CIP_NONBLOCKING); - if (err < 0) - goto err_connection; - - card->private_free = fwspk_card_free; - - strcpy(card->driver, fwspk->device_info->driver_name); - strcpy(card->shortname, fwspk->device_info->short_name); - firmware = fwspk_read_firmware_version(unit); - snprintf(card->longname, sizeof(card->longname), - "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", - fwspk->device_info->long_name, - firmware >> 20, firmware & 0xffff, - fw_dev->config_rom[3], fw_dev->config_rom[4], - dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, "OXFW970"); - - err = fwspk_create_pcm(fwspk); - if (err < 0) - goto error; - - err = fwspk_create_mixer(fwspk); - if (err < 0) - goto error; - - err = snd_card_register(card); - if (err < 0) - goto error; - - dev_set_drvdata(unit_dev, fwspk); - - return 0; - -err_connection: - cmp_connection_destroy(&fwspk->connection); -err_unit: - fw_unit_put(fwspk->unit); - mutex_destroy(&fwspk->mutex); -error: - snd_card_free(card); - return err; -} - -static int __devexit fwspk_remove(struct device *dev) -{ - struct fwspk *fwspk = dev_get_drvdata(dev); - - amdtp_out_stream_pcm_abort(&fwspk->stream); - snd_card_disconnect(fwspk->card); - - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - - snd_card_free_when_closed(fwspk->card); - - return 0; -} - -static void fwspk_bus_reset(struct fw_unit *unit) -{ - struct fwspk *fwspk = dev_get_drvdata(&unit->device); - - fcp_bus_reset(fwspk->unit); - - if (cmp_connection_update(&fwspk->connection) < 0) { - amdtp_out_stream_pcm_abort(&fwspk->stream); - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - return; - } - - amdtp_out_stream_update(&fwspk->stream); -} - -static const struct ieee1394_device_id fwspk_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_GRIFFIN, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_LACIE, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - }, - { } -}; -MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table); - -static struct fw_driver fwspk_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - .probe = fwspk_probe, - .remove = __devexit_p(fwspk_remove), - }, - .update = fwspk_bus_reset, - .id_table = fwspk_id_table, -}; - -static int __init alsa_fwspk_init(void) -{ - return driver_register(&fwspk_driver.driver); -} - -static void __exit alsa_fwspk_exit(void) -{ - driver_unregister(&fwspk_driver.driver); -} - -module_init(alsa_fwspk_init); -module_exit(alsa_fwspk_exit); |