aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-04-25 09:44:45 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-26 08:11:57 -0400
commit4b7da117e5e1cdef2cb5bf4d11c1898ca8ad743a (patch)
tree0eec5743ab27d9e24146db70c0c609f82cc83ee9 /sound/firewire
parent3ff7e8f0d455d7c1d8417ad3e71c324d8e704fc9 (diff)
ALSA: firewire-lib: Split some codes into functions to reuse for both streams
Some codes can be reused to handle in-stream. This commit adds new functions. This commit also renames some functions to keep naming consistency. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/amdtp.c154
1 files changed, 81 insertions, 73 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 95c5a1515dad..790aa86da825 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -47,6 +47,8 @@
47#define INTERRUPT_INTERVAL 16 47#define INTERRUPT_INTERVAL 16
48#define QUEUE_LENGTH 48 48#define QUEUE_LENGTH 48
49 49
50#define OUT_PACKET_HEADER_SIZE 0
51
50static void pcm_period_tasklet(unsigned long data); 52static void pcm_period_tasklet(unsigned long data);
51 53
52/** 54/**
@@ -440,13 +442,73 @@ static void amdtp_fill_midi(struct amdtp_stream *s,
440 cpu_to_be32(0x80000000); 442 cpu_to_be32(0x80000000);
441} 443}
442 444
443static void queue_out_packet(struct amdtp_stream *s, unsigned int cycle) 445static void update_pcm_pointers(struct amdtp_stream *s,
446 struct snd_pcm_substream *pcm,
447 unsigned int frames)
448{ unsigned int ptr;
449
450 if (s->dual_wire)
451 frames *= 2;
452
453 ptr = s->pcm_buffer_pointer + frames;
454 if (ptr >= pcm->runtime->buffer_size)
455 ptr -= pcm->runtime->buffer_size;
456 ACCESS_ONCE(s->pcm_buffer_pointer) = ptr;
457
458 s->pcm_period_pointer += frames;
459 if (s->pcm_period_pointer >= pcm->runtime->period_size) {
460 s->pcm_period_pointer -= pcm->runtime->period_size;
461 s->pointer_flush = false;
462 tasklet_hi_schedule(&s->period_tasklet);
463 }
464}
465
466static void pcm_period_tasklet(unsigned long data)
467{
468 struct amdtp_stream *s = (void *)data;
469 struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
470
471 if (pcm)
472 snd_pcm_period_elapsed(pcm);
473}
474
475static int queue_packet(struct amdtp_stream *s,
476 unsigned int header_length,
477 unsigned int payload_length, bool skip)
478{
479 struct fw_iso_packet p = {0};
480 int err;
481
482 p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
483 p.tag = TAG_CIP;
484 p.header_length = header_length;
485 p.payload_length = (!skip) ? payload_length : 0;
486 p.skip = skip;
487 err = fw_iso_context_queue(s->context, &p, &s->buffer.iso_buffer,
488 s->buffer.packets[s->packet_index].offset);
489 if (err < 0) {
490 dev_err(&s->unit->device, "queueing error: %d\n", err);
491 goto end;
492 }
493
494 if (++s->packet_index >= QUEUE_LENGTH)
495 s->packet_index = 0;
496end:
497 return err;
498}
499
500static inline int queue_out_packet(struct amdtp_stream *s,
501 unsigned int payload_length, bool skip)
502{
503 return queue_packet(s, OUT_PACKET_HEADER_SIZE,
504 payload_length, skip);
505}
506
507static void handle_out_packet(struct amdtp_stream *s, unsigned int cycle)
444{ 508{
445 __be32 *buffer; 509 __be32 *buffer;
446 unsigned int index, data_blocks, syt, ptr; 510 unsigned int index, data_blocks, syt, payload_length;
447 struct snd_pcm_substream *pcm; 511 struct snd_pcm_substream *pcm;
448 struct fw_iso_packet packet;
449 int err;
450 512
451 if (s->packet_index < 0) 513 if (s->packet_index < 0)
452 return; 514 return;
@@ -479,55 +541,20 @@ static void queue_out_packet(struct amdtp_stream *s, unsigned int cycle)
479 541
480 s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; 542 s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
481 543
482 packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; 544 payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
483 packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL); 545 if (queue_out_packet(s, payload_length, false) < 0) {
484 packet.skip = 0;
485 packet.tag = TAG_CIP;
486 packet.sy = 0;
487 packet.header_length = 0;
488
489 err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer,
490 s->buffer.packets[index].offset);
491 if (err < 0) {
492 dev_err(&s->unit->device, "queueing error: %d\n", err);
493 s->packet_index = -1; 546 s->packet_index = -1;
494 amdtp_stream_pcm_abort(s); 547 amdtp_stream_pcm_abort(s);
495 return; 548 return;
496 } 549 }
497 550
498 if (++index >= QUEUE_LENGTH)
499 index = 0;
500 s->packet_index = index;
501
502 if (pcm) {
503 if (s->dual_wire)
504 data_blocks *= 2;
505
506 ptr = s->pcm_buffer_pointer + data_blocks;
507 if (ptr >= pcm->runtime->buffer_size)
508 ptr -= pcm->runtime->buffer_size;
509 ACCESS_ONCE(s->pcm_buffer_pointer) = ptr;
510
511 s->pcm_period_pointer += data_blocks;
512 if (s->pcm_period_pointer >= pcm->runtime->period_size) {
513 s->pcm_period_pointer -= pcm->runtime->period_size;
514 s->pointer_flush = false;
515 tasklet_hi_schedule(&s->period_tasklet);
516 }
517 }
518}
519
520static void pcm_period_tasklet(unsigned long data)
521{
522 struct amdtp_stream *s = (void *)data;
523 struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
524
525 if (pcm) 551 if (pcm)
526 snd_pcm_period_elapsed(pcm); 552 update_pcm_pointers(s, pcm, data_blocks);
527} 553}
528 554
529static void out_packet_callback(struct fw_iso_context *context, u32 cycle, 555static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
530 size_t header_length, void *header, void *private_data) 556 size_t header_length, void *header,
557 void *private_data)
531{ 558{
532 struct amdtp_stream *s = private_data; 559 struct amdtp_stream *s = private_data;
533 unsigned int i, packets = header_length / 4; 560 unsigned int i, packets = header_length / 4;
@@ -540,31 +567,10 @@ static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
540 cycle += QUEUE_LENGTH - packets; 567 cycle += QUEUE_LENGTH - packets;
541 568
542 for (i = 0; i < packets; ++i) 569 for (i = 0; i < packets; ++i)
543 queue_out_packet(s, ++cycle); 570 handle_out_packet(s, ++cycle);
544 fw_iso_context_queue_flush(s->context); 571 fw_iso_context_queue_flush(s->context);
545} 572}
546 573
547static int queue_initial_skip_packets(struct amdtp_stream *s)
548{
549 struct fw_iso_packet skip_packet = {
550 .skip = 1,
551 };
552 unsigned int i;
553 int err;
554
555 for (i = 0; i < QUEUE_LENGTH; ++i) {
556 skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1,
557 INTERRUPT_INTERVAL);
558 err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0);
559 if (err < 0)
560 return err;
561 if (++s->packet_index >= QUEUE_LENGTH)
562 s->packet_index = 0;
563 }
564
565 return 0;
566}
567
568/** 574/**
569 * amdtp_stream_start - start transferring packets 575 * amdtp_stream_start - start transferring packets
570 * @s: the AMDTP stream to start 576 * @s: the AMDTP stream to start
@@ -594,11 +600,12 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
594 mutex_lock(&s->mutex); 600 mutex_lock(&s->mutex);
595 601
596 if (WARN_ON(amdtp_stream_running(s) || 602 if (WARN_ON(amdtp_stream_running(s) ||
597 (!s->pcm_channels && !s->midi_ports))) { 603 (s->data_block_quadlets < 1))) {
598 err = -EBADFD; 604 err = -EBADFD;
599 goto err_unlock; 605 goto err_unlock;
600 } 606 }
601 607
608 s->data_block_counter = 0;
602 s->data_block_state = initial_state[s->sfc].data_block; 609 s->data_block_state = initial_state[s->sfc].data_block;
603 s->syt_offset_state = initial_state[s->sfc].syt_offset; 610 s->syt_offset_state = initial_state[s->sfc].syt_offset;
604 s->last_syt_offset = TICKS_PER_CYCLE; 611 s->last_syt_offset = TICKS_PER_CYCLE;
@@ -612,7 +619,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
612 s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, 619 s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
613 FW_ISO_CONTEXT_TRANSMIT, 620 FW_ISO_CONTEXT_TRANSMIT,
614 channel, speed, 0, 621 channel, speed, 0,
615 out_packet_callback, s); 622 out_stream_callback, s);
616 if (IS_ERR(s->context)) { 623 if (IS_ERR(s->context)) {
617 err = PTR_ERR(s->context); 624 err = PTR_ERR(s->context);
618 if (err == -EBUSY) 625 if (err == -EBUSY)
@@ -624,10 +631,11 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
624 amdtp_stream_update(s); 631 amdtp_stream_update(s);
625 632
626 s->packet_index = 0; 633 s->packet_index = 0;
627 s->data_block_counter = 0; 634 do {
628 err = queue_initial_skip_packets(s); 635 err = queue_out_packet(s, 0, true);
629 if (err < 0) 636 if (err < 0)
630 goto err_context; 637 goto err_context;
638 } while (s->packet_index > 0);
631 639
632 err = fw_iso_context_start(s->context, -1, 0, 0); 640 err = fw_iso_context_start(s->context, -1, 0, 0);
633 if (err < 0) 641 if (err < 0)