]> Git Repo - linux.git/commitdiff
Merge branch 'dice-driver-playback-only' of git://git.alsa-project.org/alsa-kprivate...
authorTakashi Iwai <[email protected]>
Tue, 22 Oct 2013 08:02:57 +0000 (10:02 +0200)
committerTakashi Iwai <[email protected]>
Tue, 22 Oct 2013 08:02:57 +0000 (10:02 +0200)
1  2 
sound/firewire/amdtp.c
sound/firewire/speakers.c

diff --combined sound/firewire/amdtp.c
index 4b08b25a4db8d7a749b59360d4156c4fd9c51193,5540f707bfdbdb3e9c74fd2155b64bb7fe3185f6..d3226892ad6b44953fd4d980d65874ac40535768
@@@ -42,9 -42,6 +42,6 @@@ static void pcm_period_tasklet(unsigne
  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);
@@@ -62,73 -59,91 +59,91 @@@ EXPORT_SYMBOL(amdtp_out_stream_init)
   */
  void amdtp_out_stream_destroy(struct amdtp_out_stream *s)
  {
-       WARN_ON(!IS_ERR(s->context));
+       WARN_ON(amdtp_out_stream_running(s));
        mutex_destroy(&s->mutex);
        fw_unit_put(s->unit);
  }
  EXPORT_SYMBOL(amdtp_out_stream_destroy);
  
+ const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = {
+       [CIP_SFC_32000]  =  8,
+       [CIP_SFC_44100]  =  8,
+       [CIP_SFC_48000]  =  8,
+       [CIP_SFC_88200]  = 16,
+       [CIP_SFC_96000]  = 16,
+       [CIP_SFC_176400] = 32,
+       [CIP_SFC_192000] = 32,
+ };
+ EXPORT_SYMBOL(amdtp_syt_intervals);
  /**
-  * amdtp_out_stream_set_rate - set the sample rate
+  * amdtp_out_stream_set_parameters - set stream parameters
   * @s: the AMDTP output stream to configure
   * @rate: the sample rate
+  * @pcm_channels: the number of PCM samples in each data block, to be encoded
+  *                as AM824 multi-bit linear audio
+  * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
   *
-  * The sample rate must be set before the stream is started, and must not be
+  * The parameters 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)
+ void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s,
+                                    unsigned int rate,
+                                    unsigned int pcm_channels,
+                                    unsigned int midi_ports)
  {
-       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, },
+       static const unsigned int rates[] = {
+               [CIP_SFC_32000]  =  32000,
+               [CIP_SFC_44100]  =  44100,
+               [CIP_SFC_48000]  =  48000,
+               [CIP_SFC_88200]  =  88200,
+               [CIP_SFC_96000]  =  96000,
+               [CIP_SFC_176400] = 176400,
+               [CIP_SFC_192000] = 192000,
        };
        unsigned int sfc;
  
-       if (WARN_ON(!IS_ERR(s->context)))
+       if (WARN_ON(amdtp_out_stream_running(s)))
                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;
-               }
+       for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc)
+               if (rates[sfc] == rate)
+                       goto sfc_found;
        WARN_ON(1);
+       return;
+ sfc_found:
+       s->dual_wire = (s->flags & CIP_HI_DUALWIRE) && sfc > CIP_SFC_96000;
+       if (s->dual_wire) {
+               sfc -= 2;
+               rate /= 2;
+               pcm_channels *= 2;
+       }
+       s->sfc = sfc;
+       s->data_block_quadlets = pcm_channels + DIV_ROUND_UP(midi_ports, 8);
+       s->pcm_channels = pcm_channels;
+       s->midi_ports = midi_ports;
+       s->syt_interval = amdtp_syt_intervals[sfc];
+       /* default buffering in the device */
+       s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+       if (s->flags & CIP_BLOCKING)
+               /* additional buffering needed to adjust for no-data packets */
+               s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
  }
- EXPORT_SYMBOL(amdtp_out_stream_set_rate);
+ EXPORT_SYMBOL(amdtp_out_stream_set_parameters);
  
  /**
   * 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().
+  * with amdtp_out_stream_set_parameters().
   */
  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;
+       return 8 + s->syt_interval * s->data_block_quadlets * 4;
  }
  EXPORT_SYMBOL(amdtp_out_stream_get_max_payload);
  
@@@ -138,19 -153,26 +153,26 @@@ static void amdtp_write_s16(struct amdt
  static void amdtp_write_s32(struct amdtp_out_stream *s,
                            struct snd_pcm_substream *pcm,
                            __be32 *buffer, unsigned int frames);
+ static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s,
+                                    struct snd_pcm_substream *pcm,
+                                    __be32 *buffer, unsigned int frames);
+ static void amdtp_write_s32_dualwire(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.
+  * The sample format must be set after the other paramters (rate/PCM channels/
+  * MIDI) and 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)))
+       if (WARN_ON(amdtp_out_stream_running(s)))
                return;
  
        switch (format) {
                WARN_ON(1);
                /* fall through */
        case SNDRV_PCM_FORMAT_S16:
-               s->transfer_samples = amdtp_write_s16;
+               if (s->dual_wire)
+                       s->transfer_samples = amdtp_write_s16_dualwire;
+               else
+                       s->transfer_samples = amdtp_write_s16;
                break;
        case SNDRV_PCM_FORMAT_S32:
-               s->transfer_samples = amdtp_write_s32;
+               if (s->dual_wire)
+                       s->transfer_samples = amdtp_write_s32_dualwire;
+               else
+                       s->transfer_samples = amdtp_write_s32;
                break;
        }
  }
@@@ -248,7 -276,7 +276,7 @@@ static unsigned int calculate_syt(struc
        s->last_syt_offset = syt_offset;
  
        if (syt_offset < TICKS_PER_CYCLE) {
-               syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+               syt_offset += s->transfer_delay;
                syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
                syt += syt_offset % TICKS_PER_CYCLE;
  
@@@ -268,7 -296,7 +296,7 @@@ static void amdtp_write_s32(struct amdt
  
        channels = s->pcm_channels;
        src = (void *)runtime->dma_area +
 -                      s->pcm_buffer_pointer * (runtime->frame_bits / 8);
 +                      frames_to_bytes(runtime, s->pcm_buffer_pointer);
        remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
        frame_step = s->data_block_quadlets - channels;
  
@@@ -294,7 -322,7 +322,7 @@@ static void amdtp_write_s16(struct amdt
  
        channels = s->pcm_channels;
        src = (void *)runtime->dma_area +
 -                      s->pcm_buffer_pointer * (runtime->frame_bits / 8);
 +                      frames_to_bytes(runtime, s->pcm_buffer_pointer);
        remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
        frame_step = s->data_block_quadlets - channels;
  
        }
  }
  
+ static void amdtp_write_s32_dualwire(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, frame_adjust_1, frame_adjust_2, i, c;
+       const u32 *src;
+       channels = s->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+       frame_adjust_1 = channels - 1;
+       frame_adjust_2 = 1 - (s->data_block_quadlets - channels);
+       channels /= 2;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *buffer = cpu_to_be32((*src >> 8) | 0x40000000);
+                       src++;
+                       buffer += 2;
+               }
+               buffer -= frame_adjust_1;
+               for (c = 0; c < channels; ++c) {
+                       *buffer = cpu_to_be32((*src >> 8) | 0x40000000);
+                       src++;
+                       buffer += 2;
+               }
+               buffer -= frame_adjust_2;
+       }
+ }
+ static void amdtp_write_s16_dualwire(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, frame_adjust_1, frame_adjust_2, i, c;
+       const u16 *src;
+       channels = s->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+       frame_adjust_1 = channels - 1;
+       frame_adjust_2 = 1 - (s->data_block_quadlets - channels);
+       channels /= 2;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *buffer = cpu_to_be32((*src << 8) | 0x40000000);
+                       src++;
+                       buffer += 2;
+               }
+               buffer -= frame_adjust_1;
+               for (c = 0; c < channels; ++c) {
+                       *buffer = cpu_to_be32((*src << 8) | 0x40000000);
+                       src++;
+                       buffer += 2;
+               }
+               buffer -= frame_adjust_2;
+       }
+ }
  static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s,
                                   __be32 *buffer, unsigned int frames)
  {
@@@ -344,8 -434,17 +434,17 @@@ static void queue_out_packet(struct amd
                return;
        index = s->packet_index;
  
-       data_blocks = calculate_data_blocks(s);
        syt = calculate_syt(s, cycle);
+       if (!(s->flags & CIP_BLOCKING)) {
+               data_blocks = calculate_data_blocks(s);
+       } else {
+               if (syt != 0xffff) {
+                       data_blocks = s->syt_interval;
+               } else {
+                       data_blocks = 0;
+                       syt = 0xffffff;
+               }
+       }
  
        buffer = s->buffer.packets[index].buffer;
        buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
        s->packet_index = index;
  
        if (pcm) {
+               if (s->dual_wire)
+                       data_blocks *= 2;
                ptr = s->pcm_buffer_pointer + data_blocks;
                if (ptr >= pcm->runtime->buffer_size)
                        ptr -= pcm->runtime->buffer_size;
@@@ -455,9 -557,8 +557,8 @@@ static int queue_initial_skip_packets(s
   * @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.
+  * amdtp_out_stream_set_parameters() and amdtp_out_stream_set_pcm_format(),
+  * 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)
  {
  
        mutex_lock(&s->mutex);
  
-       if (WARN_ON(!IS_ERR(s->context) ||
+       if (WARN_ON(amdtp_out_stream_running(s) ||
                    (!s->pcm_channels && !s->midi_ports))) {
                err = -EBADFD;
                goto err_unlock;
@@@ -573,7 -674,7 +674,7 @@@ void amdtp_out_stream_stop(struct amdtp
  {
        mutex_lock(&s->mutex);
  
-       if (IS_ERR(s->context)) {
+       if (!amdtp_out_stream_running(s)) {
                mutex_unlock(&s->mutex);
                return;
        }
index fe9e6e2f2c5b2a825ae24a432541d45de8f029fb,eb3f7dce1d6c0f71b60f7e6fc5976dcedd716617..cc8bc3a51bc147ab7a13c0a38ec84134b55f9da3
@@@ -49,10 -49,10 +49,9 @@@ 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;
@@@ -188,10 -188,9 +187,9 @@@ static int fwspk_close(struct snd_pcm_s
  
  static void fwspk_stop_stream(struct fwspk *fwspk)
  {
-       if (fwspk->stream_running) {
+       if (amdtp_out_stream_running(&fwspk->stream)) {
                amdtp_out_stream_stop(&fwspk->stream);
                cmp_connection_break(&fwspk->connection);
-               fwspk->stream_running = false;
        }
  }
  
@@@ -246,8 -245,10 +244,10 @@@ static int fwspk_hw_params(struct snd_p
        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_parameters(&fwspk->stream,
+                                       params_rate(hw_params),
+                                       params_channels(hw_params),
+                                       0);
  
        amdtp_out_stream_set_pcm_format(&fwspk->stream,
                                        params_format(hw_params));
@@@ -285,7 -286,7 +285,7 @@@ static int fwspk_prepare(struct snd_pcm
        if (amdtp_out_streaming_error(&fwspk->stream))
                fwspk_stop_stream(fwspk);
  
-       if (!fwspk->stream_running) {
+       if (!amdtp_out_stream_running(&fwspk->stream)) {
                err = cmp_connection_establish(&fwspk->connection,
                        amdtp_out_stream_get_max_payload(&fwspk->stream));
                if (err < 0)
                                        fwspk->connection.speed);
                if (err < 0)
                        goto err_connection;
-               fwspk->stream_running = true;
        }
  
        mutex_unlock(&fwspk->mutex);
@@@ -362,7 -361,8 +360,7 @@@ static int fwspk_create_pcm(struct fwsp
                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;
 +      snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
        return 0;
  }
  
@@@ -647,7 -647,7 +645,7 @@@ static u32 fwspk_read_firmware_version(
        int err;
  
        err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
-                                OXFORD_FIRMWARE_ID_ADDRESS, &data, 4);
+                                OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0);
        return err >= 0 ? be32_to_cpu(data) : 0;
  }
  
This page took 0.068452 seconds and 4 git commands to generate.