diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:44:45 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:11:57 -0400 |
commit | 4b7da117e5e1cdef2cb5bf4d11c1898ca8ad743a (patch) | |
tree | 0eec5743ab27d9e24146db70c0c609f82cc83ee9 /sound/firewire | |
parent | 3ff7e8f0d455d7c1d8417ad3e71c324d8e704fc9 (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.c | 154 |
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 | |||
50 | static void pcm_period_tasklet(unsigned long data); | 52 | static 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 | ||
443 | static void queue_out_packet(struct amdtp_stream *s, unsigned int cycle) | 445 | static 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 | |||
466 | static 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 | |||
475 | static 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; | ||
496 | end: | ||
497 | return err; | ||
498 | } | ||
499 | |||
500 | static 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 | |||
507 | static 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 | |||
520 | static 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 | ||
529 | static void out_packet_callback(struct fw_iso_context *context, u32 cycle, | 555 | static 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 | ||
547 | static 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) |